Home > Software engineering >  PHP DirectoryIterator with natsort
PHP DirectoryIterator with natsort

Time:10-24

I am retrieving a list if photo files from a directory and echoing into a web page so that the page can be created automatically for any photo album.

The following is working fine, but the result is that the photos are not in natural order which is what I'd prefer:

<?php
$year = '2021/';
$folder = 'league/';
$n = 1;
$directory = $_SERVER['DOCUMENT_ROOT'].'/events/'.$folder.$year.'images/photos/album/medium';
$numFiles = count(scandir($directory))-2;
$files = new DirectoryIterator($directory);

natsort($files);
foreach ($files as $file) {
if($file->isDot()) continue;
echo '<div >'.PHP_EOL;
echo '<div >'.$n.' / '.$numFiles.'</div>'.PHP_EOL;
echo '<a target="_blank" href="/events/'.$folder.$year.'images/photos/album/large/'.$file->getFilename().'"><img src="/events/'.$folder.$year.'images/photos/album/medium/'.$file->getFilename().'" alt="'.$file->getFilename().'" style="width:100%"></a>'.PHP_EOL;
echo '</div>'.PHP_EOL.PHP_EOL;
$n  ;
}

?>

CodePudding user response:

natsort only works on string Arrays.

you could replace natsort with

usort($files, function($a, $b)
{
    return strnatcmp($a->getFilename(), $b->getFilename());
});

CodePudding user response:

$iterator = new DirectoryIterator($directory);

// Create an array with filenames as key and iterator index as value
$filenames = [];
foreach ($iterator as $index => $item) {
  $filenames[$item->getFilename()] = $index;
}

// Sort the filenames with 'natural compare'
uksort($filenames, static function ($filename1, $filename2) {
  return strnatcmp($filename1, $filename2);
});

// Filter out working directory and parent directory
$filenames = array_filter($filenames, static function ($filename) {
  return $filename !== '.' && $filename !== '..';
}, ARRAY_FILTER_USE_KEY);

// Do something with each DirectoryIterator entry
foreach ($filenames as $filename => $index) {
  $iterator->seek($index);
  ...
  echo $iterator->getFilename() . "\n";
  echo $iterator->getPathname() . "\n";
  etc.
  ...
}

CodePudding user response:

The sort category of functions only operate on arrays, but you can easily convert an iterator to an array with iterator_to_array(). However, since DirectoryIterator::current() returns the iterator itself, instead of SplFileInfo objects for each file, this will lead to undesired results.

My suggestion would therefore be to use FilesystemIterator (which extends DirectoryIterator), because it is a little more flexible and by default makes current() return SplFileInfo objects instead of the iterator itself and as a bonus skips dots as well.

Putting this all together then becomes:

$files = iterator_to_array(new FilesystemIterator($directory));

usort($files, function($a, $b)
{
  return strnatcmp($a->getFilename(), $b->getFilename());
});

foreach($files as $file) {
  echo $file->getFilename() . "\n";
}
  • Related