Is There A Way To glob() Only Files?
Asked Answered
A

8

45

I know that glob can look for all files or only all directories inside a folder :

echo "All files:\n";
$all = glob("/*");
var_dump($all);

echo "Only directories\n";
$dirs = glob("/*", GLOB_ONLYDIR);
var_dump($dirs);

But I didn't found something to find only files in a single line efficiently.

$files = array_diff(glob("/*"), glob("/*", GLOB_ONLYDIR));

Works well but reads directory twice (even if there are some optimizations that make the second browsing quicker).

Achilles answered 29/12, 2012 at 17:53 Comment(1)
you can glob("*.*") this doesn't work though if a folder contains a . in it, or a file doesn't have an extension.Bromberg
A
64

I finally found a solution :

echo "Only files\n";
$files = array_filter(glob("/*"), 'is_file');
var_dump($files);

But take care, array_filter will preserve numeric keys : use array_values if you need to reindex the array.

Achilles answered 29/12, 2012 at 17:53 Comment(1)
Nice! Using foreach loop will resolve the issue of preserved numeric keys from array_filter.Explicate
D
8

You can use GLOB_BRACE to match documents against a list of known file extensions:

$files = glob("/path/to/directory/*.{jpg,gif,png,html,htm,php,ini}", GLOB_BRACE);

see: http://www.electrictoolbox.com/php-glob-find-files/

Dagney answered 10/6, 2014 at 14:20 Comment(2)
Will work in most cases, but take care as directories can also be named toto.jpg if you wish.Achilles
I learned that having a space between the file types in the brace does in fact matter. Don't do it like I did and save yourself some time!Sarcophagus
S
7

There is an easier way, just one line:

$files = glob("/path/to/directory/*.{*}", GLOB_BRACE);

the {*} means all file endings, so every file, but no folder!

Suckle answered 19/6, 2015 at 13:41 Comment(2)
Nope, {} replaces any character on files or folders without distinction.Achilles
Also note that folders can have dot in their nameRazid
R
0

10% faster compared to the solution of @AlainTiemblo, because it does not use an additional is_file check:

$files = array_filter(glob("/*", GLOB_MARK), function($path){ return $path[ strlen($path) - 1 ] != '/'; });

Instead it uses the inbuild GLOB_MARK flag to add a slash to each directory and by that we are able to remove those entries through array_filter() and an anonymous function.

Since PHP 7.1.0 supports Negative numeric indices you can use this instead, too:

$files = array_filter(glob("/*", GLOB_MARK), function($path){return $path[-1] != '/';});

No relevant speed gain, but it helps avoiding the vertical scrollbar in this post ^^

As array_filter() preserve the keys you should consider re-indexing the array with array_values() afterwards:

$files = array_values($files);
Reindeer answered 23/3, 2017 at 12:53 Comment(4)
Nope! I thought it worked at first but it lists folders as well.Geber
@JensTörnell php.net says: GLOB_MARK "Adds a slash to each directory returned" So if you get folders this would be a bug in glob. Did you test glob("/*", GLOB_MARK) alone to verify your discovery? Or did you use $path[-1] with an too old PHP version?Reindeer
Not compatible with Windows because "GLOB_MARK - Adds a slash (a backslash on Windows) to each directory returned" whereas the answer uses only '/' to check.Chromosphere
Jens and DrL: Change '/' to DIRECTORY_SEPARATOR in both proposed answers in both proposed answers (PHP 7.0 and later vs PHP before 7.0) then this answer will work on all operating systems where directory separator is one character. I have always used the array_filter with 'is _file' as the second parameter and found it plenty fast for typical directories but if you have a large enough directory to glob, this solution does work and should be marginally faster.Farant
T
0

Invert regexp do the job.

preg_grep(
    ';^.*(\\\\|/)$;',
    glob("/*", GLOB_MARK),
    PREG_GREP_INVERT
);

\\\\ is for Windows backslash 🤯🔫

Tameka answered 5/10, 2021 at 19:54 Comment(0)
F
0
function glob_file_only($path){
    return array_filter(glob($path,GLOB_MARK),function($file){
        return substr($file,-1)!=DIRECTORY_SEPARATOR;
    });
}

This builds on the work of others that answered. It only touches the directory once instead of twice and it works for windows as well as linux.

Farant answered 1/7, 2022 at 10:18 Comment(0)
I
-1

This worked for me. if this helps anyone.

for file_name in glob.glob('**/*', recursive=True):
    # we get all files and dirs
    if os.path.isfile(file_name):
        # we have only the files
Inerrable answered 30/11, 2021 at 12:55 Comment(1)
The question asks for PHP, not Python.Euchromatin
J
-10
$all = glob("/*.*");

this will list everything with a "." after the file name. so basically, all files.

Jett answered 9/4, 2013 at 21:54 Comment(1)
Since when do files need to have an extension? And what makes you think that a directory cannot have a dot in its name?Glavin

© 2022 - 2024 — McMap. All rights reserved.