Jump to content

glob function recursive question


jackmn1

Recommended Posts

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:

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

Link to comment
Share on other sites

Hi

 

Quick play and something like this should do it

 

<?php

function find($dir, $pattern)
{
$dir = escapeshellcmd($dir);  
$files = glob("$dir/$pattern");  
$retvar = false;
if ($files)
{
	$retvar = true;
}
else
{
	foreach (glob("$dir/{.[^.]*,*}", GLOB_BRACE|GLOB_ONLYDIR) as $sub_dir) //look in subdirectories
	{
		$retvar = $retvar || find($sub_dir, $pattern); //recursive call
		if ($retvar) break;
	}  
}
return $retvar;
}  

if ($txtFiles=find("project/sys/diagram","*.txt")) echo "Folder project/sys/diagram contains a text file<br />" ;
if ($txtFiles=find("project/sys/bin","*.txt")) echo "Folder project/sys/bin contains a text file<br />" ;
if ($txtFiles=find("project/sys/scripts","*.txt")) echo "Folder project/sys/scripts contains a text file<br />" ;
if ($txtFiles=find("project/sys/styles","*.txt")) echo "Folder project/sys/styles contains a text file<br />" ;
if ($txtFiles=find("project/sys/meta","*.txt")) echo "Folder project/sys/meta contains a text file<br />" ;

?>

 

Call it with the base directory name and it will search through sub directories until it finds a text file at which point it will break out of the loop and come back with true.

 

All the best

 

Keith

Link to comment
Share on other sites

Thanks, kickstart, that helps a lot. But the folders I listed are just an example and there are in fact many many more subfolders to project/sys.

Therefore I need to somehow find the subfolder list (only 1st level children), and loop through that list instead of the:

if ($txtFiles=find("project/sys/diagram","*.txt")) echo "Folder project/sys/diagram contains a text file<br />" ;
if ($txtFiles=find("project/sys/bin","*.txt")) echo "Folder project/sys/bin contains a text file<br />" ;
if ($txtFiles=find("project/sys/scripts","*.txt")) echo "Folder project/sys/scripts contains a text file<br />" ;

Can you show me how to do this?

Link to comment
Share on other sites

Hi

 

This will find all the subdirectories of the current directory that contains a text file

 

<?php

function find($dir, $pattern)
{
$dir = escapeshellcmd($dir);  
$files = glob("$dir/$pattern");  
$retvar = false;
if ($files)
{
	$retvar = true;
}
else
{
	foreach (glob("$dir/{.[^.]*,*}", GLOB_BRACE|GLOB_ONLYDIR) as $sub_dir) //look in subdirectories
	{
		$retvar = $retvar || find($sub_dir, $pattern); //recursive call
		if ($retvar) break;
	}  
}
return $retvar;
}  

$dir = "./"; 
// Open a current directory and proceed to read its contents 
if (is_dir($dir)) {   
if ($dh = opendir($dir)) {     
	while (($file = readdir($dh)) !== false) 
	{
		if ($file != '.' && $file != '..' && is_dir($file))
		{
			if ($txtFiles=find($dir.$file,"*.txt")) echo "Folder $dir$file contains a text file<br />" ;
		} 
	}
	closedir($dh);   
} 
} 

?>

 

Set $dir to another directory if you do not want to use it on the current directory.

 

All the best

 

Keith

Link to comment
Share on other sites

Hi

 

Not sure.

 

Tried it on my PC and it worked OK

 

is_dir is a standard php function to determine if something is a directory.

 

Take out the checks for ".." and "." and double check (including those directories will give some spurious extra lines).

 

All the best

 

Keith

Link to comment
Share on other sites

Hi

 

Looking around there seem to be a fair few people having problems with is_dir depending on file systems, versions of php, etc.

 

One cheat might be to check instead that something isn't a file:-

 

if ($file != '.' && $file != '..' && !is_file($file))

 

That works on my machine (but then so did is_dir). Give it a try.

 

All the best

 

Keith

Link to comment
Share on other sites

This seems to work a lot better, however, I now noticed that it works only if I leave the $dir variable as $dir = "./", but it doesn't work with $dir = "./project/sys". This is strange, maybe I'm entering the path incorrectly (I'm still a newbie in PHP..).

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.