4

I'm using usort() and filemtime() to sort files by modification date, but it randomly returns files in the wrong order. I guess I'm missing something really simple but I can't figure out what.

usort($user_files, function($a, $b) {
    return filemtime($a) > filemtime($b);
});
foreach ($user_files as $f) {
    echo $f . "<br />";
}

After that I upload the file. Complete code.

When uploading the files 1.txt ... 10.txt to test what was going on the results displayed were:

6.txt
5.txt
4.txt
3.txt
2.txt
1.txt
7.txt Uploaded!

As expected. Then, when I reached 8.txt:

6.txt
7.txt
5.txt
4.txt
2.txt
3.txt
1.txt
8.txt Uploaded!

Another time it was fine until I reached 10.txt:

7.txt
8.txt
9.txt
6.txt
5.txt
2.txt
3.txt
4.txt
1.txt
10.txt Uploaded!

While ls -t returned:

10.txt  9.txt  8.txt  7.txt  6.txt  5.txt  4.txt  3.txt  2.txt  1.txt

So... What's going on there?

Debian Wheezy 7.4, up-to-date.
PHP Version 5.4.4-14+deb7u8
Linux pc 3.2.0-4-amd64 #1 SMP Debian 3.2.54-2 x86_64
FPM/FastCGI
nginx/1.2.1
Alex
  • 1,416
  • 4
  • 16
  • 42

2 Answers2

4

Man usort says http://www.php.net/manual/en/function.usort.php

value_compare_func

The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.

But The provided callback has only ">" operator:

{
    return filemtime($a) > filemtime($b);
}

and the Man says (http://www.php.net/manual/en/language.operators.comparison.php) that "Greater than" aka > operator return only true or false, but not the negative/zero/positive number, as requested.

$a > $b Greater than TRUE if $a is strictly greater than $b.

What you think about using The "Subtraction" "-" operator between two filemtimes, because Man again says that filemtime is the integer (http://www.php.net/manual/en/function.filemtime.php).

And there is duplicate answer somewhere on this site (googled with filemtime usort and feeling lucky - the first result is): Order this array by date modified? and the answer was by Michael Berkowski, who says:

  if (filemtime($a) === filemtime($b)) return 0;
  return filemtime($a) < filemtime($b) ? -1 : 1; 
Community
  • 1
  • 1
osgx
  • 90,338
  • 53
  • 357
  • 513
  • Thanks! But that did not work. Oddly enough, now it seems that the order gets scrambled always at the 6th file upload. I'm guessing the issue is something unrelated to the `usort()` then, but I can't figure out what. I edited the question with the complete code. – Alex Apr 14 '14 at 05:08
  • 1
    +1, even if that was not the good answer, this was a good guess, as soon as *some* threatment could take shorter time than 1sec to process several files. – Alain Tiemblo Apr 15 '14 at 22:55
0

I figured out what was wrong and, as expected, it had nothing to do with usort. The function used to get the files was getting only the file names, not the absolute path to them. So filemtime was being called with a meaningless string. I have no idea why php raised no warnings about that.

Alex
  • 1,416
  • 4
  • 16
  • 42
  • 300 bounty for a simple user error :) But there is no warning because "2.txt" is a valid path. It just couldnt find the file and thus it returns FALSE as there was a failure. Also it was fairly obvious that you only got the filename. As your test `foreach` is working with the same data as the usort function. – Hugo Delsing Apr 14 '14 at 09:41