i have this function to return the full directory tree:
function getDirectory( $path = '.', $level = 0 ){
$ignore = array( 'cgi-bin', '.', '..' );
// Directories to ignore when listing output. Many hosts
// will deny PHP access to the cgi-bin.
$dh = #opendir( $path );
// Open the directory to the handle $dh
while( false !== ( $file = readdir( $dh ) ) ){
// Loop through the directory
if( !in_array( $file, $ignore ) ){
// Check that this file is not to be ignored
$spaces = str_repeat( ' ', ( $level * 4 ) );
// Just to add spacing to the list, to better
// show the directory tree.
if( is_dir( "$path/$file" ) ){
// Its a directory, so we need to keep reading down...
echo "<strong>$spaces $file</strong><br />";
getDirectory( "$path/$file", ($level+1) );
// Re-call this same function but on a new directory.
// this is what makes function recursive.
} else {
echo "$spaces $file<br />";
// Just print out the filename
}
}
}
closedir( $dh );
// Close the directory handle
}
but what i want to do is to search for a file/folder and return it's path, how can i do that? do you have such a function or can you give me some tips on how to do this?
Try to use RecursiveIteratorIterator in combination with RecursiveDirectoryIterator
$path = realpath('/path/you/want/to/search/in');
$objects = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
if($object->getFilename() === 'work.txt') {
echo $object->getPathname();
}
}
Additional reading:
http://www.phpro.org/tutorials/Introduction-to-SPL.html
do you have such a function or can you give me some tips on how to do
this?
Yes I do.
I actually asked a similar question earlier this morning, but I figure it out. The problem I was having is that the file names . and .. are returned by readdir() and they cause problems when attempting to opendir() with them. When I filtered these out, my recursion worked perfectly. You might want to modify the format in which it outputs the directories that fit the search. Or modify it to output all files and directories. Find an image for "go.jpg" and try it out.
I can't find my post to notify that I found the solution.
define ('HOME', $_SERVER['DOCUMENT_ROOT']);
function searchalldirectories($directory, $seachterm, $maxrecursions, $maxopendir){
$dircontent= '';
$dirs= array();
if ($maxopendir > 0){
$maxopendir--;
$handle= opendir( HOME.'/'.$directory);
while (( $dirlisting= readdir($handle)) !== false){
$dn= ''; $fn= ' File';
if ( is_dir( HOME.'/'.$directory.'/'.$dirlisting) && $maxrecursions>0 && strpos( $dirlisting, '.')!==0){
$dirs[ count($dirs)]= $directory.'/'.$dirlisting;
$dn= '/'; $fn= 'Dir';
}
if ( stripos($dirlisting, $seachterm) !== false){
$dircontent.= '<input type="image" src="go.jpg" name="cmd" value="home:/'.$directory.'/'.$dirlisting.'"> '.$fn.':// <b>'.$directory.'/'.$dirlisting.$dn.'/</b><br>';
}
}
closedir( $handle);
for ( $i=0; $i<count( $dirs); $i++){
$dircontent.= searchalldirectories( $dirs[$i], $seachterm, ($maxrecursions-1), $maxopendir);
}
}
return $dircontent;
}
Related
I have this function which supposed to lead to the correct image folder (images) and shows its images, but it shows the all the images in the root path & the ones in (images) folder. what I have to change to make it shows the images that belongs to (images) folder only?.
function searchSite( $path = 'images', $level = 0 ) {
$skip = array( 'cgi-bin', '.', '..' );
$look_for = array( '.jpg', '.gif', '.png', '.jpeg' );
$dh = #opendir( $path );
while ( false !== ( $file = readdir( $dh ) ) ) {
$file_ext = substr( $file, -4, 4 );
if ( !in_array( $file, $skip ) ) {
if ( is_dir( "$path/$file" ) ) {
searchSite( "$path/$file", ( $level + 1 ) );
} else if ( in_array( $file_ext, $look_for ) ) {
echo "<option value='$path/$file' />$file</option>";
}
}
closedir( $dh );
}
PHP got its own filesystem and filter classes. With these classes you can easily iterator recursivly over a directory tree to get all the files you want. Nowadays it is kinda deprecated to code your own functionality, because the build in iterator and filter classes are much more efficient and it is not necessary to re-invent the wheel.
Here 's a short example how to use the build in filesystem and filter classes.
<?php
declare(strict_types=1);
namespace Marcel;
use FilesystemIterator;
use RecursiveCallbackFilterIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
$directory = new RecursiveDirectoryIterator('../assets/images/', FilesystemIterator::FOLLOW_SYMLINKS);
$filter = new RecursiveCallbackFilterIterator($directory, function($current, $key, $iterator) {
if ($current->isDir()) {
return !in_array($current->getFilename(), ['.', '..', 'bla']);
} else {
return in_array($current->getExtension(), ['jpg', 'png']);
}
});
$iterator = new RecursiveIteratorIterator($filter);
$files = [];
foreach ($iterator as $file) {
$files[] = $file->getPathname();
}
var_dump($files);
I'm having an issue getting rid of brackets in uploaded files in a system.
I'm able to remove the brackets in the files of a single directory but I'm struggling to get this working recursively in the sub directories of the same folder.
I'm using str_replace to find the brackets [ ] and replacing them with a blank character.
$dir = $_SERVER["DOCUMENT_ROOT"]."/uploads" ; // what directory to parse
if ( $handle = opendir ( $dir)) {
print "Directory Handle = $handles\n" ;
print "Files : \n" ;
while ( false !== ($file = readdir($handle))) {
if ( $file != "." && $file != ".." ) {
$isdir = is_dir ( $file ) ;
if ( $isdir == "1" ) {} // if its a directory do nothing
else {
$file_array[] = "$file" ; // get all the file names and put them in an array
print "$file\n" ;
} // closes else
} // closes directory check
} // closes while
} // closes opendir
//Lets go through the array
$arr_count = count( $file_array ) ; // find out how many files we have found so we can initiliase the counter
for ( $counter=1; $counter<$arr_count; $counter++ ) {
print "Array = $file_array[$counter]\n" ; // tell me how many files there are
$illegals = array("[","]");
$new = str_replace ( $illegals, "", $file_array[$counter] ) ; // now create the new file name
$ren = rename ( "$dir/$file_array[$counter]" , "$dir/$new" ) ; // now do the actual file rename
print "$new\n" ; // print out the new file name
}
closedir ( $handle ) ;
echo $dir;
Ok so I took the code from the recursive renaming script and created my own sanitize script. Please let me know if I screwed anything up. Thanks for pointing me in the right direction NIC3500
$path = $_SERVER["DOCUMENT_ROOT"]."/uploads" ;
$illegals = array("[","]");
$di = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach($di as $name => $fio) {
//$newname = $fio->getPath() . DIRECTORY_SEPARATOR . strtolower( $fio->getFilename() );
$newname = $fio->getPath() . DIRECTORY_SEPARATOR . str_replace ( $illegals, "", $fio->getFilename() );
//echo $newname, "\r\n";
rename($name, $newname);
}
A php script should list all available "modules". A module is a subdirectory that contains at least an info.php file.
Now I want a list of all subdirectories that contain the "info.php" file (i.e. a list of all modules) and came up with this code:
$modules = array();
if ( $handle = opendir( MODULE_DIR ) ) {
while ( false !== ( $entry = readdir( $handle ) ) ) {
if ( $entry === '.' || $entry === '..' ) { continue; }
$info_file = MODULE_DIR . $entry . '/info.php';
if ( ! is_file( $info_file ) ) { continue; }
$modules[] = $entry;
}
closedir( $handle );
}
Question: Is there a shorter/nicer way to get the list, preferably without the loop?
A nice and clean solution can be achieved using the function glob():
foreach(glob('src/*/info.php') as $path) {
echo basename(dirname($path)) . PHP_EOL;
}
Take a look at the RecursiveDirectoryIterator
http://php.net/manual/en/class.recursivedirectoryiterator.php
In your case the code would look like this:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.'));
foreach($it as $key => $item) {
if(basename($key) === 'info.php') {
echo dirname($key) . PHP_EOL;
}
}
I have the following code in my PHP file - initializes $uploaded_files variable and then calls getDirectory (also listed below).
Now if I do a vardump($uploaded_files) I see the contents of my variable, but for some reason when I call <?php echo $uploaded_files; ?> in my HTML file I get a message stating "No Files Found" - am I doing something incorrect?
Can someone assist? Thank you.
/** LIST UPLOADED FILES **/
$uploaded_files = "";
getDirectory( Settings::$uploadFolder );
// Check if the uploaded_files variable is empty
if(strlen($uploaded_files) == 0)
{
$uploaded_files = "<li><em>No files found</em></li>";
}
getDirectory Function:
function getDirectory( $path = '.', $level = 0 )
{
// Directories to ignore when listing output. Many hosts
// will deny PHP access to the cgi-bin.
$ignore = array( 'cgi-bin', '.', '..' );
// Open the directory to the handle $dh
$dh = #opendir( $path );
// Loop through the directory
while( false !== ( $file = readdir( $dh ) ) ){
// Check that this file is not to be ignored
if( !in_array( $file, $ignore ) ){
// Its a directory, so we need to keep reading down...
if( is_dir( "$path/$file" ) ){
// We are now inside a directory
// Re-call this same function but on a new directory.
// this is what makes function recursive.
getDirectory( "$path/$file", ($level+1) );
}
else {
// Just print out the filename
// echo "$file<br />";
$singleSlashPath = str_replace("uploads//", "uploads/", $path);
if ($path == "uploads/") {
$filename = "$path$file";
}
else $filename = "$singleSlashPath/$file";
$parts = explode("_", $file);
$size = formatBytes(filesize($filename));
$added = date("m/d/Y", $parts[0]);
$origName = $parts[1];
$filetype = getFileType(substr($file, strlen($file) - 4));
$uploaded_files .= "<li class=\"$filetype\">$origName $size - $added</li>\n";
// var_dump($uploaded_files);
}
}
}
// Close the directory handle
closedir( $dh );
}
You either need to add:
global $uploaded_files;
At the top of your getDirectory function, or
function getDirectory( &$uploaded_files, $path = '.', $level = 0 )
Pass it by reference.
You could also make $uploaded_files the return value of getDirectory.
More reading about globals and security: http://php.net/manual/en/security.globals.php
PHP knows nothing about scope.
When you declare a variable from within the body of a function it will not be available outside the scope of said function.
For example:
function add(){
$var = 'test';
}
var_dump($var); // undefined variable $var
This is exactly the problem you are having when trying to access the variable $uploaded_files.
I have a set of folders that has a depth of at least 4 or 5 levels. I'm looking to recurse through the directory tree as deep as it goes, and iterate over every file. I've gotten the code to go down into the first sets of subdirectories, but no deeper, and I'm not sure why. Any ideas?
$count = 0;
$dir = "/Applications/MAMP/htdocs/site.com";
function recurseDirs($main, $count){
$dir = "/Applications/MAMP/htdocs/site.com";
$dirHandle = opendir($main);
echo "here";
while($file = readdir($dirHandle)){
if(is_dir($file) && $file != '.' && $file != '..'){
echo "isdir";
recurseDirs($file);
}
else{
$count++;
echo "$count: filename: $file in $dir/$main \n<br />";
}
}
}
recurseDirs($dir, $count);
Check out the new RecursiveDirectoryIterator.
It's still far from perfect as you can't order the search results and other things, but to simply get a list of files, it's fine.
There are simple examples to get you started in the manual like this one:
<?php
$path = realpath('/etc');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
echo "$name\n";
}
?>
There is an error in the call
recurseDirs($file);
and in
is_dir($file)
you have to give the full path:
recurseDirs($main . '/' .$file, $count);
and
is_dir($main . '/' .$file)
However, like other anwerers, I suggest to use RecursiveDirectoryIteretor.
The call to is_dir and recurseDirs is not fully correct. Also your counting didn't work correctly. This works for me:
$dir = "/usr/";
function recurseDirs($main, $count=0){
$dirHandle = opendir($main);
while($file = readdir($dirHandle)){
if(is_dir($main.$file."/") && $file != '.' && $file != '..'){
echo "Directory {$file}: <br />";
$count = recurseDirs($main.$file."/",$count); // Correct call and fixed counting
}
else{
$count++;
echo "$count: filename: $file in $main \n<br />";
}
}
return $count;
}
$number_of_files = recurseDirs($dir);
Notice the changed calls to the function above and the new return value of the function.
So yeah: Today I was being lazy and Googled for a cookie cutter solution to a recursive directory listing and came across this. As I ended up writing my own function (as to why I even spent the time to Google for this is beyond me - I always seem to feel the need to re-invent the wheel for no suitable reason) I felt inclined to share my take on this.
While there are opinions for and against the use of RecursiveDirectoryIterator, I'll simply post my take on a simple recursive directory function and avoid the politics of chiming in on RecursiveDirectoryIterator.
Here it is:
function recursiveDirectoryList( $root )
{
/*
* this next conditional isn't required for the code to function, but I
* did not want double directory separators in the resulting array values
* if a trailing directory separator was provided in the root path;
* this seemed an efficient manner to remedy said problem easily...
*/
if( substr( $root, -1 ) === DIRECTORY_SEPARATOR )
{
$root = substr( $root, 0, strlen( $root ) - 1 );
}
if( ! is_dir( $root ) ) return array();
$files = array();
$dir_handle = opendir( $root );
while( ( $entry = readdir( $dir_handle ) ) !== false )
{
if( $entry === '.' || $entry === '..' ) continue;
if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
{
$sub_files = recursiveDirectoryList(
$root .
DIRECTORY_SEPARATOR .
$entry .
DIRECTORY_SEPARATOR
);
$files = array_merge( $files, $sub_files );
}
else
{
$files[] = $root . DIRECTORY_SEPARATOR . $entry;
}
}
return (array) $files;
}
With this function, the answer as to obtaining a file count is simple:
$dirpath = '/your/directory/path/goes/here/';
$files = recursiveDirectoryList( $dirpath );
$number_of_files = sizeof( $files );
But, if you don't want the overhead of an array of the respective file paths - or simply don't need it - there is no need to pass a count to the recursive function as was recommended.
One could simple amend my original function to perform the counting as such:
function recursiveDirectoryListC( $root )
{
$count = 0;
if( ! is_dir( $root ) ) return (int) $count;
$dir_handle = opendir( $root );
while( ( $entry = readdir( $dir_handle ) ) !== false )
{
if( $entry === '.' || $entry === '..' ) continue;
if( is_dir( $root . DIRECTORY_SEPARATOR . $entry ) )
{
$count += recursiveDirectoryListC(
$root .
DIRECTORY_SEPARATOR .
$entry .
DIRECTORY_SEPARATOR
);
}
else
{
$count++;
}
}
return (int) $count;
}
In both of these functions the opendir() function should really be wrapped in a conditional in the event that the directory is not readable or another error occurs. Make sure to do so correctly:
if( ( $dir_handle = opendir( $dir ) ) !== false )
{
/* perform directory read logic */
}
else
{
/* do something on failure */
}
Hope this helps someone...