Every now and then the requirement for an application to upload files to the server comes into play.  Over time, due to any number of reasons, the directory to which files are uploaded to by said application may tend to fill up with orphan files; that is, files that are associate to and accessed by absolutely nothing.  Figuring out which files are orphans and which files can be daunting at first.  The fear of the repercussions from removing a file that is not an orphan is nearly paralyzing, especially if said repercussions are legal and could potentially cost an organization both sleep and revenue.

What I’m about to share with you will save both sleepless nights, potential loss of revenue, and space on your servers.  Ladies and gentlemen, prepare to allow your OCD to take a deep sigh of relief.

Directory Clean UpI wrote the script below for an application that allows users to upload files to our servers.  The application allows users to create courses. A course may have multiple files uploaded that attendees will need for the course (when they attend said course) or after the course (continued learning materials, presentation slides, instructor promised additional materials, etc.).

Now, it should be told that the application removes files when the corresponding record is removed from the database. However, deification occurs. There are any number of scenarios that may occur that could cause the creation of orphan files. I will not bore you with a list of said possibilities, especially in the light that I am certain that I would omit possibilities that even I have yet to encounter.

I did my best to comment the code heavily in the hope that what’s happening in the code is clear. Hopefully you will find this useful in your application.  Cheers!

<?php
  
    /*/////////////////////////////////////////////////
        /////////////////////////////////////////////////
            Author: Brian M Falls
            Purpose: File Upload Directories Maintenance
            Action: Generates two arrays, one based on files associate to records in the database, and one associate to files in a directory on the server.  If a file on the server is not in the array of files from the database, said file is removed from the server.
                /////////////////////////////////////////////////
                    /////////////////////////////////////////////////*/

    require_once 'appConfig.php';
    require_once BASEPATH . COREPHP . 'DB.class.php';

    $dbRead = new DB(WEBDBREAD);

    // generate list fo files associate to courses in COURSE_ATTACHMENTS table
    $sql = sprintf("
        SELECT      FILE_NAME
        FROM        COURSE_ATTACHMENTS
        ORDER BY    FILE_NAME ASC
    ");
    $ATTACHMENTS = $dbRead->runQuery($sql);
    // convert our query result (multidimensional array) into a single dimension array
    $COURSE_DOCUMENTS = array();
    for ($i = 0; $i <= count($ATTACHMENTS) - 1; $i++) {
        $COURSE_DOCUMENTS[$i] = $ATTACHMENTS[$i]['FILE_NAME'];
    };

    // generate list of files in directory
    $DIRECTORY = $_SERVER['DOCUMENT_ROOT'] .'path/to/uploads/directory/coursesFiles/';
    // read files from previously defined directory
    $FILES = scandir($DIRECTORY);

    // set default message (will display if there are no files to 'clean up')
    $MESSAGE = 'All files in the directory <span>('.$DIRECTORY.')</span> are associate to current and/or previous courses.';

    // the ul will encapsulate any orphan files that will be displayed (if any exist)
    echo '<ul>';
    for ($i = 0; $i <= count($FILES) - 1; $i++) {
        if (!in_array($FILES[$i], $COURSE_DOCUMENTS) && strlen($FILES[$i]) > 2) {
            // remove file from server
            unlink($DIRECTORY.$FILES[$i]);
            // display a list of files that were removed from server
            echo '<li>'.$FILES[$i].'</li>';
            // set message to display explaining that orphan files were found and removed from the server 
            $MESSAGE = 'The file(s) in the directory <span>('.$DIRECTORY.')</span> listed below are NOT associate to any courses and have been removed from the server.';
        };
    };
    echo '</ul>';
    // display message
    echo '<h3>'.$MESSAGE.'</h3>';

?>

<!-- completly unnecessary, unless your OCD has a sense of style -->
<style>
    body {
        background: rgb(206,220,231);
        background: -moz-linear-gradient(top, rgba(206,220,231,0.91) 0%, rgba(89,106,114,0.91) 100%);
        background: -webkit-linear-gradient(top, rgba(206,220,231,0.91) 0%,rgba(89,106,114,0.91) 100%);
        background: linear-gradient(to bottom, rgba(206,220,231,0.91) 0%,rgba(89,106,114,0.91) 100%);
        color: #5c3317;
        filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#cedce7', endColorstr='#596a72',GradientType=0 );
        font-family: Lucida Sans Unicode;
        height: 100%;
    }
    h3 {
        font-size: 13px;
        left: 28px;
        position: absolute;
        top: 7px;
        width: 100%;
    }
    span {
        font-weight: normal;
        font-style: italic;
    }
    ul {
        left: 28px;
        padding: 0px 14px;
        position: absolute;
        top: 56px;
        width: 100%;
    }
    li {
        font-size: 12px;
        list-style: none;
    }
</style>