150
votes

I'm looking for a PHP script that loops through all of the files in a directory so I can do things with the filename, such as format, print or add it to a link. I'd like to be able to sort the files by name, type or by date created/added/modified. (Think fancy directory "index".) I'd also like to be able to add exclusions to the list of files, such as the script itself or other "system" files. (Like the . and .. "directories".)

Being that I'd like to be able to modify the script, I'm more interested in looking at the PHP docs and learning how to write one myself. That said, if there are any existing scripts, tutorials and whatnot, please let me know.

9

9 Answers

266
votes

You can use the DirectoryIterator. Example from php Manual:

<?php
$dir = new DirectoryIterator(dirname(__FILE__));
foreach ($dir as $fileinfo) {
    if (!$fileinfo->isDot()) {
        var_dump($fileinfo->getFilename());
    }
}
?>
47
votes

If you don't have access to DirectoryIterator class try this:

<?php
$path = "/path/to/files";

if ($handle = opendir($path)) {
    while (false !== ($file = readdir($handle))) {
        if ('.' === $file) continue;
        if ('..' === $file) continue;

        // do something with the file
    }
    closedir($handle);
}
?>
28
votes

Use the scandir() function:

<?php
    $directory = '/path/to/files';

    if (!is_dir($directory)) {
        exit('Invalid diretory path');
    }

    $files = array();
    foreach (scandir($directory) as $file) {
        if ($file !== '.' && $file !== '..') {
            $files[] = $file;
        }
    }

    var_dump($files);
?>
20
votes

You can also make use of FilesystemIterator. It requires even less code then DirectoryIterator, and automatically removes . and ...

// Let's traverse the images directory
$fileSystemIterator = new FilesystemIterator('images');

$entries = array();
foreach ($fileSystemIterator as $fileInfo){
    $entries[] = $fileInfo->getFilename();
}

var_dump($entries);

//OUTPUT
object(FilesystemIterator)[1]

array (size=14)
  0 => string 'aa[1].jpg' (length=9)
  1 => string 'Chrysanthemum.jpg' (length=17)
  2 => string 'Desert.jpg' (length=10)
  3 => string 'giphy_billclinton_sad.gif' (length=25)
  4 => string 'giphy_shut_your.gif' (length=19)
  5 => string 'Hydrangeas.jpg' (length=14)
  6 => string 'Jellyfish.jpg' (length=13)
  7 => string 'Koala.jpg' (length=9)
  8 => string 'Lighthouse.jpg' (length=14)
  9 => string 'Penguins.jpg' (length=12)
  10 => string 'pnggrad16rgb.png' (length=16)
  11 => string 'pnggrad16rgba.png' (length=17)
  12 => string 'pnggradHDrgba.png' (length=17)
  13 => string 'Tulips.jpg' (length=10)

Link: http://php.net/manual/en/class.filesystemiterator.php

6
votes

You can use this code to loop through a directory recursively:

$path = "/home/myhome";
$rdi = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME);
foreach (new RecursiveIteratorIterator($rdi, RecursiveIteratorIterator::SELF_FIRST) as $file => $info) {
    echo $file."\n";
}
3
votes

glob() has provisions for sorting and pattern matching. Since the return value is an array, you can do most of everything else you need.

2
votes

For completeness (since this seems to be a high-traffic page), let's not forget the good old dir() function:

$entries = [];
$d = dir("/"); // dir to scan
while (false !== ($entry = $d->read())) { // mind the strict bool check!
    if ($entry[0] == '.') continue; // ignore anything starting with a dot
    $entries[] = $entry;
}
$d->close();
sort($entries); // or whatever desired

print_r($entries);
0
votes

Most of the time I imagine you want to skip . and ... Here is that with recursion:

<?php
$o_dir = new RecursiveDirectoryIterator('.', FilesystemIterator::SKIP_DOTS);
$o_iter = new RecursiveIteratorIterator($o_dir);
foreach ($o_iter as $o_name) {
   echo $o_name->getFilename();
}

https://php.net/class.recursivedirectoryiterator

0
votes

you can do this as well

$path = "/public";

$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);

foreach ($objects as $name => $object) {
  if ('.' === $object) continue;
  if ('..' === $object) continue;

str_replace('/public/', '/', $object->getPathname());

// for example : /public/admin/image.png => /admin/image.png