This is a document written using ReMarkable, a shorthand syntax for generating HTML.

{	"date"		:	200906071513,
	"updated"	:	200906071513,
	"licence"	:	"cc-by",
	"tags"		:	["web-dev"]
}

<section>
# 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.

~~~ PHP ~~~>
//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`` (//uk3.php.net/manual/en/function.usort.php)> 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.

~~~ PHP ~~~>
return	is_dir ($a)
<~~~

If the first item is a directory then…

~~~ PHP ~~~>
? (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`` (//uk2.php.net/manual/en/function.strnatcasecmp.php)> will return “-1”, “0” or “1” accordingly.

~~~ PHP ~~~>
: (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

~~~ PHP ~~~>
strcasecmp (pathinfo ($a, PATHINFO_EXTENSION), pathinfo ($b, PATHINFO_EXTENSION)) == 0
<~~~

If the file extensions are equal then compare the file names

~~~ PHP ~~~>
? strnatcasecmp ($a, $b)
<~~~

Finally, if the file extensions are not equal, compare them again, this time returning the result

~~~ PHP ~~~>
: strcasecmp (pathinfo ($a, PATHINFO_EXTENSION), pathinfo ($b, PATHINFO_EXTENSION))
<~~~

And that’s it!
¬¬
Enjoy.

</section>