Asked  7 Months ago    Answers:  5   Viewed   47 times

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?

 Answers

16

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
Wednesday, March 31, 2021
 
drowneath
answered 7 Months ago
48

I'll try to clean it up a bit, but this works:

$needle = ["chapter one", 'foo', 'bar'];
$array = [
    [
        "name" => "Intro",
        "id" => "123",
        "children" => [
            "name" => "foo",
            "id" => "234",
            "children" => [
                "name" => "mur",
                "id" => "445",
            ]
        ]
    ],[
        "name" => "chapter one",
        "id" => "9876",
        "children" => [
            "name" => "foo",
            "id" => "712",
            "children" => [
                "name" => "bar",
                "id" => "888",
            ]
        ]
    ]
];

function searchTree($needle, $haystack, $strict=false) {
    if(!is_array($haystack)) {
        return false;
    }
    $match = false;
    if(array_keys($haystack) !== range(0, count($haystack) - 1) && !empty($needle)) {
        if(($strict && $haystack['name'] === $needle[0]) || (!$strict && $haystack['name'] == $needle[0])) {
            $match = true;
            array_shift($needle);
            if (!empty($needle)) {
                return searchTree($needle, $haystack['children'], $strict);
            }
        }
    } else {
        foreach ($haystack as $key => $value) {
            if (is_array($value) && !empty($needle)) {
                if (($strict && $value['name'] === $needle[0]) || (!$strict && $value['name'] == $needle[0])) {
                    $match = true;
                    array_shift($needle);
                    if (!empty($needle)) {
                        return searchTree($needle, $value['children'], $strict);
                    } else {
                        $haystack = $haystack[$key];
                    }
                }
            }
        }
    }
    return (isset($haystack['id']) && $match) ? $haystack['id'] : false;
}

echo searchTree($needle, $array);

output:

888
Wednesday, March 31, 2021
 
Packy
answered 7 Months ago
85
action='/ProjectName/helpers/login.php'

Assuming your root is http://localhost then the above link should always resolve to http://localhost/ProjectName/helpers/login.php whether it's called from http://localhost/ProjectName/index.php or http://localhost/ProjectName/subdir/index.php

If you don't want to hardcode "ProjectName" into many different scripts, you can use a global variable and define it in a config file:

helpers/ConfigOptions.php:

<?php
$ProjectName = "ProjectName";
?>

Then in your scripts, include the config file and use the variable you defined:

index.php:

include $_SERVER['DOCUMENT_ROOT'] . '/helpers/ConfigOptions.php';

...

echo "
  <form action='/$ProjectName/helpers/login.php'>
  ....
";

More about DOCUMENT_ROOT:

DOCUMENT_ROOT is defined in the server configuration file and is the root on the filesystem of where scripts are executing, not the web address you would type in a browser. In the above example, I'm assuming that document root looks something like /home/user/www/ProjectName. If DOCUMENT_ROOT is only /home/user/www then you can change your include path to this:

include $_SERVER['DOCUMENT_ROOT'] . '/ProjectName/helpers/ConfigOptions.php';

or use a relative path. My vote would be on the latter since you wouldn't need to hardcode "ProjectName".

So include() and require() would take either:

  1. An absolute path to the file
  2. A path that's relative to the current executing script. If A includes B and B includes C, when B includes C it needs to provide a path that is relative to A.

So when do you need to use DOCUMENT_ROOT? Usually with templates where a relative path like ../helpers/file.php can resolve to different absolute paths depending on what's including the file. In the above example where index.php is including ConfigOptions.php, you probably don't need to use DOCUMENT_ROOT since index.php is not a template. I used it anyway to be safe, but maybe I opened up a whole can of worms here. I hope I didn't confuse you even more.

Wednesday, March 31, 2021
 
hjalpmig
answered 7 Months ago
41

A recursive solution could look something like:

function createMenuHTML($dir){
    $html = "";
    if(is_dir($dir)){
        //Directory - add sub menu
        $html .= "<li><a href='#'>Sub Menu Name</a><ul>";
        if ($dh = opendir($dir)) {
            while (($file = readdir($dh)) !== false) {
                $html .= createMenuHTML($dir.$file);
            }
            closedir($dh);
        }
        $html .= "</ul>"
    }else{
        //File so  just add list item
        $html .= "<li><a href='#'>".basename($dir)."</a></li>"
    }
    return $html;
}

This is entirely untested but should hopefully help.

Saturday, May 29, 2021
 
godot
answered 5 Months ago
11

Erm... in fact a modern implementation will likely use the

  • ftw
  • nftw calls

ftw is short for file tree walk

See also a very useful resource: http://rosettacode.org/wiki/Walk_a_directory/Recursively#Library:_POSIX

Friday, August 13, 2021
 
user729076
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :