Recursive Scan Directory


Recursively go through directories and find all of the contents, files and folders can either be put into a flat array or in a nested array format.


/**
 * @author Kato Twofold
 * @param string $dirPath the path to crawl from
 * @param bool $flatten
 * @param int $safety The safety number will decrese with each run fo the recursion, if this reaches 0 we will throw an exception instead of an infinite loop ( this can happen due to multiple reasons such as looping symlinks)
 * @return array The function will return an array of everything it will find.
 */
function rscandir(string $dirPath, bool $flatten = false, bool $getMime = true, int $safety = 10000): array {
    // Check if we're still safe
    if ( --$safety < 0 ) {
        throw new Exception("Recursion has exceeded the maximum safety of 10000, please check for broken symlinks or mounts.");
    }

    // Predefine the results array
    $results = [];

    // Check if the path is correct ( is_dir )
    if ( !is_dir($dirPath) )
        // Simply return an empty array.
        return $results;

    // Scan the dir for files and folders.
    $dirFiles = array_diff(scandir($dirPath), array('.', '..'));
    
    // Go through the files
    foreach( $dirFiles as $file ) {

        // Stitch together the full path of the file relative to the starting position
        $filePath = $dirPath . DIRECTORY_SEPARATOR . $file;

        // Check if the file is a directory
        if ( is_dir($filePath) ) {

            // Put all of the folder's data into one single assoc array
            $folderData = [
                "type"     => "folder",
                "name"     => $file,
                "path"     => $filePath,
                "parent"   => $dirPath,
            ];

            // Check if we should flatten the array or use a nested type
            if ( $flatten ) {
                // Simply merge the results with the directory's contents
                $results = array_merge($results, rscandir($filePath, $flatten, $getMime, $safety));
            } else {
                // Store the contents of the directory inside of it's own property
                $folderData["contents"] = rscandir($filePath, $flatten, $getMime, $safety);
            }

            // Append the folder data to the array
            $results[] = $folderData;
        } else {
            // Store the data of the file
            $f = [
                "type"   => "file",
                "name"   => $file,
                "path"   => $filePath,
                "parent" => $dirPath
            ];

            // Check if we should fetch the mime type as well
            if ( $getMime ) {
                // Get the mime type of the file
                $f['mime'] = mime_content_type($filePath);
            }

            // Append the file to the results
            $results[] = $f;
        }

    }

    // Return what we have found
    return $results;
}