Camen Design

c share + remix

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.