PHP Glob - Scan in Subfolders For a File

php glob - scan in subfolders for a file

There are 2 ways.

Use glob to do recursive search:

<?php

// Does not support flag GLOB_BRACE
function rglob($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge(
[],
...[$files, rglob($dir . "/" . basename($pattern), $flags)]
);
return $files;
}

// usage: to find the test.zip file recursively
$result = rglob($_SERVER['DOCUMENT_ROOT'] . '/test.zip');
var_dump($result);
// to find the all files that names ends with test.zip
$result = rglob($_SERVER['DOCUMENT_ROOT'] . '/*test.zip');
?>

Use RecursiveDirectoryIterator

<?php
// $regPattern should be using regular expression
function rsearch($folder, $regPattern) {
$dir = new RecursiveDirectoryIterator($folder);
$ite = new RecursiveIteratorIterator($dir);
$files = new RegexIterator($ite, $regPattern, RegexIterator::GET_MATCH);
$fileList = array();
foreach($files as $file) {
$fileList = array_merge($fileList, $file);
}
return $fileList;
}

// usage: to find the test.zip file recursively
$result = rsearch($_SERVER['DOCUMENT_ROOT'], '/.*\/test\.zip/'));
var_dump($result);
?>

RecursiveDirectoryIterator comes with PHP5 while glob is from PHP4. Both can do the job, it's up to you.

How to check if a folder has sub folders using glob?

OK albeit not the way I wanted to, but after glob for some reason refuses to behave as expected I I instead opted to just scan the directory again and sorted it so that folders are first in the array. Then I just checked if the first element is a directory.

            if(is_dir($link))
{
$folders = scandir($link, 1);
if(is_dir($link.'/'.$folders[0]))
{
echo $link." ";
echo "Has Sub-folders ";
}

Foreach glob to include files in a subdirectory

Use this for testing:

foreach (glob("addons/*.php", GLOB_NOCHECK) as $filename) {
PRINT $filename . "\n";
}

Should the directory not exist relatively to the current, then it will show addons/*.php as output.

search for files with established criteria php

The following syntax can be used:

^.*(FRGHSD02D5102T|005878).+$

This would match any line that contains FRGHSD02D5102T or 005878:

00256_FRGHSD02D5102T0013005878.TXT ✅
FRGHSD02D5102T00256_0013005878.TXT ✅
_FRGHSD02D5102T001300587800256.TXT ✅
00256_005878.TXT ✅
FRGHSD02D5102T.TXT ✅
00058_GHT52DSF56S03U0014002545.TXT ❌
00256_005873.TXT ❌

This can be combined with glob to search through all folders and subfolders for the specific pattern:

$folder = __DIR__ . '/data';
$pattern = '/^.*(FRGHSD02D5102T|005878).+$/';

$dir = new RecursiveDirectoryIterator($folder);
$ite = new RecursiveIteratorIterator($dir);
$files = new RegexIterator($ite, $pattern, RegexIterator::GET_MATCH);

foreach($files as $file) {
echo 'found matching file: ' . $file[0] . PHP_EOL;
}

the folder structure:

data
|-- 00256_FRGHSD02D5102T0013005878.TXT
|-- example.TXT
`-- test
`-- YES256_FRGHSD02D5102T0013005878.TXT

the result:

found matching file: /Users/stackoverflow/dev/data/00256_FRGHSD02D5102T0013005878.TXT
found matching file: /Users/stackoverflow/dev/data/test/YES256_FRGHSD02D5102T0013005878.TXT

When searching for an specific extension the following snippet can be used:

.pdf

$pattern = '/^.*(FRGHSD02D5102T|005878|001|002).*\.pdf$/';

.txt

$pattern = '/^.*(FRGHSD02D5102T|005878|001|002).*\.TXT$/';

.pdf, .PDF, .PdFm, contains 001 and 002 OR 002 and 001

$pattern = '/^.*(FRGHSD02D5102T|005878|001.*002|002.*001).*\.pdf/i';

matches:

data
|-- 00256_FRGHSD02D5102T0013005878.TXT ❌
|-- example.TXT ❌
|-- hell001hello.pdf ❌
|-- hell001hello002.pdf ✅
|-- hell002hello001.pdf ✅
`-- test
`-- YES256_FRGHSD02D5102T0013005878.TXT ❌

The /i makes it case-insensitive so it will match any casing of PDF.

The \. escapes the . because we need to match the literal . instead of matching all characters.

Scan directory for files with specific extensions recursively

It looks like the PHP glob() function does what you want:

The glob() function searches for all the pathnames matching pattern
according to the rules used by the libc glob() function, which is
similar to the rules used by common shells.

foreach (glob("*.txt") as $filename) {
echo "$filename size " . filesize($filename) . "\n";
}

And here is a nifty function by agd243 that uses glob() to find all files by extension an return it as an array:

function findFiles($directory, $extensions = array()) {
function glob_recursive($directory, &$directories = array()) {
foreach(glob($directory, GLOB_ONLYDIR | GLOB_NOSORT) as $folder) {
$directories[] = $folder;
glob_recursive("{$folder}/*", $directories);
}
}
glob_recursive($directory, $directories);
$files = array ();
foreach($directories as $directory) {
foreach($extensions as $extension) {
foreach(glob("{$directory}/*.{$extension}") as $file) {
$files[$extension][] = $file;
}
}
}
return $files;
}
var_dump(findFiles("C:\\baseFolder", array (

"src",
"in",
"out",
"rc"
)));

How to create subdirectory arrays with glob

You have a fixed low depth, so you don't really need recursive imho.

You can use wildcard * to mark different levels and GLOB_ONLYDIR to retrieve folders only :

$level1 = glob('MainFolder/*', GLOB_ONLYDIR);
$level2 = glob('MainFolder/*/*', GLOB_ONLYDIR);
$level3 = glob('MainFolder/*/*/*', GLOB_ONLYDIR);

If you want to store the last folder instead of full path you can use array_map() and basename() :

$level1 = array_map('basename', glob('MainFolder/*', GLOB_ONLYDIR));
...

PHP - reading folder, all subfolders, and files in subfolders

I think your issue comes from here :

while (false !== ($file = readdir($handle))) // it reads again the same directory as it did in the first while loop

Try to replace it with

if ($sub_handle = opendir($dir . $folder)) {
while (false !== ($file = readdir($sub_handle))) {
...
}
closedir($sub_handle);
}

Also, in your case, I would use php glob() function

See a working example for your case :

$dir = './inspections/';
if ($handle = opendir($dir)) {
$blacklist = array('.', '..', 'default', 'default.php', 'desc.txt');
while (false !== ($folder = readdir($handle))) {
if (!in_array($folder, $blacklist)) {
foreach (glob($dir . $folder . "/*.png") as $filename) {
echo "$filename was found !";
echo "\r\n";
}
}
}
closedir($handle);
}

Output :

./inspections/location_4/img_1.png was found !
./inspections/location_4/img_2.png was found !
./inspections/location_4/img_3.png was found !
./inspections/location_4/img_4.png was found !
./inspections/location_4/img_5.png was found !
./inspections/location_4/img_6.png was found !
./inspections/location_3/img_1.png was found !
./inspections/location_3/img_2.png was found !
./inspections/location_3/img_3.png was found !
./inspections/location_3/img_4.png was found !
./inspections/location_3/img_5.png was found !
./inspections/location_3/img_6.png was found !
./inspections/location_2/img_1.png was found !
./inspections/location_2/img_2.png was found !
./inspections/location_2/img_3.png was found !
./inspections/location_2/img_4.png was found !
./inspections/location_2/img_5.png was found !
./inspections/location_2/img_6.png was found !
./inspections/location_1/img_1.png was found !
./inspections/location_1/img_2.png was found !
./inspections/location_1/img_3.png was found !
./inspections/location_1/img_4.png was found !
./inspections/location_1/img_5.png was found !
./inspections/location_1/img_6.png was found !

EDIT

To loop in the /inspections/location1/thumbs/ directories, this would work :

foreach (glob($dir . $folder . "/thumbs/*.png") as $filename) {
echo "$filename was found !";
echo "\r\n";
}

RE-EDIT

To glob multiple folders with the glob() function, your code should look like :

foreach (glob($dir.$folder."{/thumbs/*.png,/*.png}", GLOB_BRACE) as $filename) {
echo "$filename was found !";
echo "\r\n";
}


Related Topics



Leave a reply



Submit