Sorting a Directory Listing Folders First, Then by File Type, Then by Name in PHP
Something I think might be useful to people. This code takes a directory listing and then sorts the
contents listing folders first (in alphabetical order), then the files are sorted by file type and then
alphabetically for each file type.
//directory to list, you choose; here we’ll just use the webroot
$path = $_SERVER['DOCUMENT_ROOT'];
//warning: `is_dir` will need you to change to the parent directory of what you are testing
//see <uk3.php.net/manual/en/function.is-dir.php#70005> for details
chdir ($path);
//get a directory listing
$dir = array_diff (scandir ('.'),
//folders / files to ignore
array ('.', '..', '.DS_Store', 'Thumbs.db')
);
//sort folders first, then by type, then alphabetically
usort ($dir, create_function ('$a,$b', '
return is_dir ($a)
? (is_dir ($b) ? strnatcasecmp ($a, $b) : -1)
: (is_dir ($b) ? 1 : (
strcasecmp (pathinfo ($a, PATHINFO_EXTENSION), pathinfo ($b, PATHINFO_EXTENSION)) == 0
? strnatcasecmp ($a, $b)
: strcasecmp (pathinfo ($a, PATHINFO_EXTENSION), pathinfo ($b, PATHINFO_EXTENSION))
))
;
'));
//echo to screen
header ('content-type: text/plain');
print_r ($dir);
Here’s how this breaks down:
usort sorts an array
using another function given two items to compare. Return “-1” if the first should go above the other, 1 if the
second should go above the other and 0 if they are equal.
We create a function with $a and $b parameters corresponding to the two items being
compared for sorting as it goes through the list.
return is_dir ($a)
If the first item is a directory then…
? (is_dir ($b) ? strnatcasecmp ($a, $b) : -1)
Check if the second item is a directory. If both items are directories then compare them by name.
strnatcasecmp
will return “-1”, “0” or “1” accordingly.
: (is_dir ($b) ? 1 : (
Now if the first item is not a directory, check if the second item is. If the second item is a directory, it will go
above the first item—return “1”.
Else, compare file extensions
strcasecmp (pathinfo ($a, PATHINFO_EXTENSION), pathinfo ($b, PATHINFO_EXTENSION)) == 0
If the file extensions are equal then compare the file names
? strnatcasecmp ($a, $b)
Finally, if the file extensions are not equal, compare them again, this time returning the result
: strcasecmp (pathinfo ($a, PATHINFO_EXTENSION), pathinfo ($b, PATHINFO_EXTENSION))
And that’s it!
Enjoy.