Search code examples
phpscandir

Is it save to skip the first (.) and second value (..) of PHPs scandir function when searching for files or directories?


I'm actually asking this myself for years now: is it save to skip the first and second value of an array fetched by scandir?

By now I'm iterating over an array fetched by scandir (more or less) like this:

for ( $scan = scandir('path/to/dir/'), $i = 0, $c = count( $scan ); $i < $c; ++$i )
{
    if ( $scan[ $i ][ 0 ] != '.' )
    {
        // $scan[ $i ] is file name or dir name
    }
}

This works perfectly fine as well but seems to be redundant if $scan[ 0 ][ 0 ] is always . and $scan[ 1 ][ 0 ] is always ...

So would it be save to skip the first and second value like this:

for ( $scan = scandir('path/to/dir/'), $i = 2/* starting with 2 instead of 0 */, $c = count( $scan ); $i < $c; ++$i )
{
    // $scan[ $i ] is file name or dir name
}

When I var_dump a scandir I always get and got a structure like this:

var_dump( scandir('path/to/dir/') );
array(
    0 => '.',  // is this the case for each
    1 => '..', // and every environment
    2 => 'filename.ext',
    [...]
)

But I'm mostly working in my own server environment and haven't seen too much different server environments. So can I be sure that in each and every environment (OS, PHP version, etc.) I will find a structure fetched by scandir that will look similar like the one above?


Solution

  • No, you cannot safely assume that . and .. will be returned first.

    By default, the results from scandir() are returned in alphabetical order, as if the result had been passed to sort(). However, there are characters that will sort above . -- for instance, a file named !README will be returned before ..

    If you want to skip these entries, check for them explicitly, e.g.

    foreach (scandir("path/to/dir") as $file) {
        if ($file === "." || $file === "..")
            continue;
    
        // do stuff with $file
    }