45

I am using the following code to get a list of images in a directory:

$files = scandir($imagepath);

but $files also includes hidden files. How can I exclude them?

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Sino
  • 970
  • 3
  • 12
  • 27
  • The answers here are about Linux hosting. For all people who wish to read about Windows hosting, see here: [http://stackoverflow.com/questions/30290663/does-php-scandir-exclude-hidden-files-under-windows](http://stackoverflow.com/questions/30290663/does-php-scandir-exclude-hidden-files-under-windows) – peter_the_oak May 17 '15 at 18:38

11 Answers11

82

On Unix, you can use preg_grep to filter out filenames that start with a dot:

$files = preg_grep('/^([^.])/', scandir($imagepath));
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
mario
  • 144,265
  • 20
  • 237
  • 291
6
$files = array_diff(scandir($imagepath), array('..', '.'));

or

$files = array_slice(scandir($imagepath), 2);

might be faster than

$files = preg_grep('/^([^.])/', scandir($imagepath));
Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Agnel Vishal
  • 564
  • 6
  • 13
5

I tend to use DirectoryIterator for things like this which provides a simple method for ignoring dot files:

$path = '/your/path';
foreach (new DirectoryIterator($path) as $fileInfo) {
    if($fileInfo->isDot()) continue;
    $file =  $path.$fileInfo->getFilename();
}
robjmills
  • 18,438
  • 15
  • 77
  • 121
  • 15
    Just to clarify, `isDot()` doesn't ignore files that starts with `.`. Just tried on my system PHP 5.3.5. – resting Mar 11 '13 at 06:11
  • 4
    This answer is wrong. "Dot files" or "hidden files" on Unix are *any* files whose name starts with a dot. But, per [the documentation](http://php.net/manual/en/directoryiterator.isdot.php), `isDot` matches only if the file is `.` or `..`. A quick test confirms that it will not match most dot files. – Mark Amery May 30 '15 at 12:19
4
function nothidden($path) {
    $files = scandir($path);
    foreach($files as $file) {
        if ($file[0] != '.') $nothidden[] = $file;
        return $nothidden;
    }
}

Simply use this function

$files = nothidden($imagepath);
Henrik Albrechtsson
  • 1,707
  • 2
  • 17
  • 17
  • 1
    If you don't want to use `preg_grep` because regexes frighten you, *this* is the way to go - check whether the filename starts with a dot by *getting the first character and checking whether it's a dot*. It's not rocket science, but it doesn't need to be. The "cleverer" incantations involving string functions used by some other answers here, besides being inefficient or wrong, are needlessly more complicated than this approach. – Mark Amery May 30 '15 at 12:43
1

I encountered a comment from php.net, specifically for Windows systems: http://php.net/manual/en/function.filetype.php#87161

Quoting here for archive purposes:

I use the CLI version of PHP on Windows Vista. Here's how to determine if a file is marked "hidden" by NTFS:

function is_hidden_file($fn) {

    $attr = trim(exec('FOR %A IN ("'.$fn.'") DO @ECHO %~aA'));

    if($attr[3] === 'h')
        return true;

    return false;
}

Changing if($attr[3] === 'h') to if($attr[4] === 's') will check for system files.

This should work on any Windows OS that provides DOS shell commands.

Oytun
  • 474
  • 5
  • 15
1

I reckon because you are trying to 'filter' out the hidden files, it makes more sense and looks best to do this...

$items = array_filter(scandir($directory), function ($item) {
    return 0 !== strpos($item, '.');
});

I'd also not call the variable $files as it implies that it only contains files, but you could in fact get directories as well...in some instances :)

1

use preg_grep to exclude files name with special characters for e.g.

$dir = "images/";
$files = preg_grep('/^([^.])/', scandir($dir));

http://php.net/manual/en/function.preg-grep.php

Vrushal Raut
  • 1,050
  • 2
  • 15
  • 20
1

Assuming the hidden files start with a . you can do something like this when outputting:

foreach($files as $file) {
    if(strpos($file, '.') !== (int) 0) {
        echo $file;
    }
}

Now you check for every item if there is no . as the first character, and if not it echos you like you would do.

stefandoorn
  • 1,032
  • 8
  • 12
  • 2
    Using `strpos` to check if the first character of a filename is a dot is unnecessarily complicated - and inefficient, since it searches whole string when you only care about one character. Also, it makes no sense at all to cast the literal `0` to an `int`; it already is one. Just do `if ($file[0] != '.') {...}` instead. – Mark Amery May 30 '15 at 12:29
0

Use the following code if you like to reset the array index too and set the order:

$path = "the/path";
$files = array_values(
    preg_grep(
        '/^([^.])/', 
        scandir($path, SCANDIR_SORT_ASCENDING)
));

One line:

$path = "daten/kundenimporte/";
$files = array_values(preg_grep('/^([^.])/', scandir($path, SCANDIR_SORT_ASCENDING)));
Black
  • 18,150
  • 39
  • 158
  • 271
0

scandir() is a built-in function, which by default select hidden file as well, if your directory has only . & .. hidden files then try selecting files

$files = array_diff(scandir("path/of/dir"),array(".","..")) //can add other hidden file if don't want to consider

  • Keep in mind that `Keys in the [resulting] array are preserved` resulting in an array that eg. may miss values for keys 1 or 2. – Johan Dec 13 '22 at 10:46
-1

I am still leaving the checkmark for seengee's solution and I would have posted a comment below for a slight correction to his solution.

His solution masks the directories(. and ..) but does not mask hidden files like .htaccess

A minor tweak solves the problem:

foreach(new DirectoryIterator($curDir) as $fileInfo) {
    //Check for something like .htaccess in addition to . and ..
    $fileName = $fileInfo->getFileName();
    if(strlen(strstr($fileName, '.', true)) < 1) continue;

     echo "<h3>" . $fileName . "</h3>";
}
calmcajun
  • 173
  • 1
  • 4
  • 17
  • 2
    This is an insanely overcomplicated way of checking whether `$fileName` starts with a dot; I had to study the [`strstr`](http://php.net/strstr) man page to even make sense of what you're doing here. It's also *broken*; this filters out not only filenames that start with a dot, but also file names with no dot in them at all (since in that case `strstr` returns `FALSE` and `strlen(FALSE)` returns 0, which is less than 1. There's absolutely no need for this complexity; just do `if ($fileName[0] == '.') continue` instead. – Mark Amery May 30 '15 at 12:32