glob() - sort array of files by last modified datetime stamp

PhpArraysSortingFilemtime

Php Problem Overview


I'm trying to display an array of files in order of date (last modified).

I have done this buy looping through the array and sorting it into another array, but is there an easier (more efficient) way to do this?

Php Solutions


Solution 1 - Php

>Warning create_function() has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged.

For the sake of posterity, in case the forum post linked in the accepted answer is lost or unclear to some, the relevant code needed is:

<?php

$myarray = glob("*.*");
usort($myarray, create_function('$a,$b', 'return filemtime($a) - filemtime($b);'));

?>

Tested this on my system and verified it does sort by file mtime as desired. I used a similar approach (written in Python) for determining the last updated files on my website as well.

Solution 2 - Php

<?php
$items = glob('*', GLOB_NOSORT);
array_multisort(array_map('filemtime', $items), SORT_NUMERIC, SORT_DESC, $items);

Solution 3 - Php

This solution is same as accepted answer, updated with anonymous function1:

$myarray = glob("*.*");

usort( $myarray, function( $a, $b ) { return filemtime($a) - filemtime($b); } );

1 Anonymous functions have been introduced in PHP in 2010. Original answer is dated 2008.

Solution 4 - Php

Since PHP 7.4 the best solution is to use custom sort with arrow function:

usort($myarray, fn($a, $b) => filemtime($a) - filemtime($b));

You can also use the spaceship operator which works for all kinds of comparisons and not just on integer ones. It won't make any difference in this case, but it's a good practice to use it in all sorting operations.

usort($myarray, fn($a, $b) => filemtime($a) <=> filemtime($b));

If you want to sort in reversed order you can negate the condition:

usort($myarray, fn($a, $b) => -(filemtime($a) - filemtime($b)));
// or 
usort($myarray, fn($a, $b) => -(filemtime($a) <=> filemtime($b)));

Note that calling filemtime() repetitively is bad for performance. Please apply memoization to improve the performance.

Solution 5 - Php

This can be done with a better performance. The usort() in the accepted answer will call filemtime() a lot of times. PHP uses quicksort algorithm which has an average performance of 1.39*n*lg(n). The algorithm calls filemtime() twice per comparison, so we will have about 28 calls for 10 directory entries, 556 calls for 100 entries, 8340 calls for 1000 entries etc. The following piece of code works good for me and has a great performance:

exec ( stripos ( PHP_OS, 'WIN' ) === 0 ? 'dir /B /O-D *.*' : 'ls -td1 *.*' , $myarray );

Solution 6 - Php

Year 2020 - If you care about performance, consider not to use glob()!

If you want scan a lot of files in a folder without special wildcards, rulesets, or any exec(),

I suggest scandir(), or readdir().

glob() is a lot slower, on Windows it's even slower.


> quote by: aalfiann > > why glob seems slower in this benchmark? because glob will do > recursive into sub dir if you write like this "mydir/*". > > just make sure there is no any sub dir to make glob fast. > > "mydir/*.jpg" is faster because glob will not try to get files inside > sub dir.


> benchmark: glob() vs scandir() > > http://www.spudsdesign.com/benchmark/index.php?t=dir2 (external)


> discussion: readdir() vs scandir() > > https://stackoverflow.com/questions/8692764/readdir-vs-scandir (stackoverflow)


> readdir() or scandir() combined with these, for pretty neat performance. > > PHP 7.4 > > usort( $myarray, function( $a, $b ) { return filemtime($a) - filemtime($b); } ); > > source: https://stackoverflow.com/a/60476123/3626361 > > PHP 5.3.0 and newer > > usort($myarray, fn($a, $b) => filemtime($a) - filemtime($b)); > > source: https://stackoverflow.com/a/35925596/3626361


> if you wanna go even deeper the rabbit hole: > > The DirectoryIterator > --------------------- > > https://www.php.net/manual/en/class.directoryiterator.php > > https://www.php.net/manual/en/directoryiterator.construct.php (read the comments!) > > http://paulyg.github.io/blog/2014/06/03/directoryiterator-vs-filesystemiterator.html > > https://stackoverflow.com/questions/12532064/difference-between-directoryiterator-and-filesystemiterator


Last but not least, my Demo!

<?php
function files_attachment_list($id, $sort_by_date = false, $allowed_extensions = ['png', 'jpg', 'jpeg', 'gif', 'doc', 'docx', 'pdf', 'zip', 'rar', '7z'])
{
	if (empty($id) or !is_dir(sprintf('files/%s/', $id))) {
		return false;
	}
	$out = [];
	foreach (new DirectoryIterator(sprintf('files/%s/', $id)) as $file) {
		if ($file->isFile() == false || !in_array($file->getExtension(), $allowed_extensions)) {
			continue;
		}

		$datetime = new DateTime();
		$datetime->setTimestamp($file->getMTime());
		$out[] = [
			'title' => $file->getFilename(),
			'size' => human_filesize($file->getSize()),
			'modified' => $datetime->format('Y-m-d H:i:s'),
			'extension' => $file->getExtension(),
			'url' => $file->getPathname()
		];
	}

	$sort_by_date && usort($out, function ($a, $b) {
		return $a['modified'] > $b['modified'];
	});

	return $out;
}

function human_filesize($bytes, $decimals = 2)
{
	$sz = 'BKMGTP';
	$factor = floor((strlen($bytes) - 1) / 3);
	return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
}

// returns a file info array from path like '/files/123/*.extensions'
// extensions = 'png', 'jpg', 'jpeg', 'gif', 'doc', 'docx', 'pdf', 'zip', 'rar', '7z'
// OS specific sorting
print_r( files_attachment_list(123) );

// returns a file info array from the folder '/files/456/*.extensions'
// extensions = 'txt', 'zip'
// sorting by modified date (newest first)
print_r( files_attachment_list(456, true, ['txt','zip']) );

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncoleView Question on Stackoverflow
Solution 1 - PhpJayView Answer on Stackoverflow
Solution 2 - PhpAlf EatonView Answer on Stackoverflow
Solution 3 - Phpfusion3kView Answer on Stackoverflow
Solution 4 - PhpDharmanView Answer on Stackoverflow
Solution 5 - PhpSebastianView Answer on Stackoverflow
Solution 6 - PhpStefanoView Answer on Stackoverflow