Page 1 of 1
glob function recursive question
Posted: Fri Aug 20, 2010 2:58 am
by jackmn1
I need to create a function that lists subfolders of a given folder, that contain at least one .txt file.
I found the following function, which displays a list of file that match a pattern in a directory tree:
Code: Select all
function find($dir, $pattern){
$dir = escapeshellcmd($dir);
$files = glob("$dir/$pattern");
foreach (glob("$dir/{.[^.]*,*}", GLOB_BRACE|GLOB_ONLYDIR) as $sub_dir) //look in subdirectories
{
$arr = find($sub_dir, $pattern); //recursive call
$files = array_merge($files, $arr); // merge array with files from subdirectory
}
return $files;
}
$txtFiles=find("project/sys","*.txt");
foreach ($txtFiles as $txtFile)
{
echo '<h2>'.$txtFile.'</h2>'; //display all text files
}
My question is, how do I change the function to return only folders that contain at least one text file.
But, the functions should look inside child folders of "project/sys" and list a child folder only once if that folder or any of its child folders contain at least one text file.
I'll give an example of the output I'm looking for:
Folder list
project/sys/diagram
project/sys/bin
project/sys/scripts
project/sys/styles
project/sys/meta
The above folders may not contain a text file directly, but their children folders do. However, I'm not interested in their children folder and I want to list the above level folder only once for each folder.
Thanks in advance
Re: glob function recursive question
Posted: Fri Aug 20, 2010 3:02 am
by NModern
you can use an array and everytime before echo check is this folder already in array or not.
Re: glob function recursive question
Posted: Fri Aug 20, 2010 3:06 am
by jackmn1
Thanks, but how do I control the depth level I'm in in the recursion? I need to this this condition in the second level.
Can you please show me an example of how it should look?
Re: glob function recursive question
Posted: Fri Aug 20, 2010 6:25 am
by NModern
Code: Select all
function find($dir, $pattern){
$dir = escapeshellcmd($dir);
$files = glob("$dir/$pattern");
foreach (glob("$dir/{.[^.]*,*}", GLOB_BRACE|GLOB_ONLYDIR) as $sub_dir) //look in subdirectories
{
$arr = find($sub_dir, $pattern); //recursive call
$files = array_merge($files, $arr); // merge array with files from subdirectory
}
return $files;
}
$txtFiles=find("project/sys/","*.txt");
$path_array = array();
foreach ($txtFiles as $txtFile)
{
$path_info = pathinfo($txtFile);
if(!in_array($path_info['dirname'],$path_array)){
$path_array[] = $path_info['dirname'];
echo '<h2>'.$path_info['dirname'].'</h2>'; //display all text files
}
}
Re: glob function recursive question
Posted: Fri Aug 20, 2010 6:42 am
by jackmn1
Thanks. However, since my directory is huge, it will take too much time because it lists all possibilities in the array and only after wards output the unique values, right? What I wanted was to break the recursive loop after the first file is found, do you know how can I do it?
Re: glob function recursive question
Posted: Fri Aug 20, 2010 7:12 am
by NModern
Here is all in one function for you, returns an array
Code: Select all
$files_in_folder = array();
function filesInDir($tdir, $subdir, $src_param="*"){
global $files_in_folder;
if(is_dir($tdir)){
$dirs = scandir($tdir);
foreach($dirs as $file){
$file = str_replace($tdir."/", "", $file);
if (($file == '.')||($file == '..')){
}elseif (is_dir($tdir.'/'.$file) && $subdir==true){
filesInDir($tdir.'/'.$file, true, $src_param, true);
}else{
$glob_files = glob($tdir."/".$src_param);
if(in_array($tdir."/".$file, $glob_files) && !in_array($tdir."/",$files_in_folder)){
$files_in_folder[] = $tdir."/";
}
}
}
}
return $files_in_folder;
}
print_r(filesInDir("./a",true,"*.txt"));
Re: glob function recursive question
Posted: Fri Aug 20, 2010 7:42 am
by jackmn1
I appreciate it, but it still returns all the subfolders while what I need is to list only the first children level of project/sys and not all the 2nd and 3rd levels.
Re: glob function recursive question
Posted: Fri Aug 20, 2010 8:49 am
by NModern
aaaa I understood. wait second
Re: glob function recursive question
Posted: Fri Aug 20, 2010 8:54 am
by NModern
Code: Select all
$files_in_folder = array();
$sm_string = "";
function filesInDir($tdir, $subdir, $src_param="*"){
global $files_in_folder,$sm_string;
if($sm_string==""){
$sm_string = $tdir;
}
if(is_dir($tdir)){
$dirs = scandir($tdir);
foreach($dirs as $file){
$file = str_replace($tdir."/", "", $file);
if (($file == '.')||($file == '..')){
}elseif (is_dir($tdir.'/'.$file) && $subdir==true && $sm_string==$tdir){
filesInDir($tdir.'/'.$file, true, $src_param, true);
}else{
$glob_files = glob($tdir."/".$src_param);
if(in_array($tdir."/".$file, $glob_files) && !in_array($tdir."/",$files_in_folder)){
$files_in_folder[] = $tdir."/";
}
}
}
}
return $files_in_folder;
}
print_r(filesInDir("./blah/blah/",true,"*.txt"));
Re: glob function recursive question
Posted: Fri Aug 20, 2010 9:35 am
by jackmn1
Works better, but still, now it returns only 1st level folders that have text files directly in them. I need it to return all folders that are 1st level children and have at least one file contained directly in them or in any of their subfolders.
For example, it returns:
"project/sys/bin" because there is a file "project/sys/bin/f_index.txt"
but it doesn't return "project/sys/media" even though there is a file called "project/sys/media/files/imageList.txt".
(note that this file is contained in 2nd level subfolder and not in the 1st level).
If I knew PHP better I would have solved it, but I don't...so any help is appreciated.