tags:

views:

171

answers:

7

Hi

I am trying to make a function that scans a folder for subfolders and then returns a numeric array with the names of those folders.

This is the code i use for testing. Once i get it to print out the folder names and not just "." and ".." for present and above folder all will be well, and I can finish the function.

<?php
function super_l_getthemes($dir="themes")
{

if ($handle = opendir($dir)) {
    echo "Handle: {$handle}\n";
    echo "Files:\n";


    while (false !== ($file = readdir($handle))) {
       echo "{$file}<br>";
    }

    closedir($handle);
}
?>

The above code works fine, and prints out all the contents of the folder: files, subfolders and the "." and ".."

but if i replace:

  while (false !== ($file = readdir($handle))) {
       echo "{$file}<br>";
    }

with:

while (false !== ($file = readdir($handle))) {
        if(file_exists($file) && is_dir($file)){echo "{$file}";}
    }

The function only prints "." and ".." , not the two folder names that I'd like it to print.

Any help is appreciated.

+2  A: 

You must provide the absolute path to file_exists, otherwise it will look for it in the current execution path.

while (false !== ($file = readdir($handle))) {
    $file_path = $dir . DIRECTORY_SEPARATOR . $file;
    if (file_exists($file_path) && is_dir($file_path)) {
        echo "{$file}";
    }
}
nuqqsa
No need for the quotes there. `echo $file` works just fine. Also, variable interpolation is in effect on double quotes anyway, so you don't need the braces either.
Jacob Relkin
Variable Interpolation is a new word for me, however, I saw that the code executed the same without the braces. (Looks up Variable Interpolation)Thanks for the quick answer, The code works now.
Rakoon
If you did it without the braces, also do it without to quotes, it's a.t.m. just an unnecessary step.
Wrikken
+1  A: 

You need to use:

while (false !== ($file = readdir($handle))) {
    if(file_exists($dir.'/'.$file) && is_dir($dir.'/'.$file)){echo "{$file}";}
}

See http://php.net/readdir

halfdan
Thanks for the reply, looks like another version of the two answers above.
Rakoon
A: 

I don't think you need both file_exists and is_dir,

You just need the is_dir function. From the manual:

is_dir Returns TRUE if the filename exists and is a directory, FALSE otherwise.

Use this:

while (false !== ($file = readdir($handle))) {
        if(is_dir($file)){echo "{$file}";}
    }

is_dir will also check whether it's a relative path or an absolute path.

Cetra
I'm not sure who decided to downvote me, but this works. I've tested it on my local apache server.
Cetra
It tests directory existence in the script's current working directory, regardless of what directory `$handle` is opened on. It does *not* work as expected.
amphetamachine
Try opening `$handle` to a directory that is not the current folder.
amphetamachine
A: 

The problem with readdir is that it only reads the strings of the named entries inside of the directory.

For instance, if you had file "foo" inside of directory "/path/to/files/", when using readdir on "/path/to/files/", you would eventually come to the string "foo".

Normally this wouldn't be a problem if it were in the same directory as the current working directory of the script, but, since you are reading from an arbitrary director, when you are attempting to inspect the entry (file, directory, whatever), you are calling is_dir on the bare string "foo".

I would try prefixing the name you pull out using readdir with the path to the file.


if ($handle = opendir($dir)) {
    echo "Handle: {$handle}\n";
    echo "Files:\n";

    while ($file = readdir($handle)) {
        /*** make $file into an absolute path ***/
        $absolute_path = $dir . '/' . $file;

        /*** NOW try stat'ing it ***/
        if (is_dir($absolute_path)) {
            /* it's a directory; do stuff */
        }
    }

    closedir($handle);
}
amphetamachine
This and the answer above both works. Thanks for the quick replies.
Rakoon
A: 
$files = array();
foreach(new DirectoryIteraror('/path') as $file){
    if($file->isDir() /* && !$file->isDot()*/) $files[] = $file->getFilename();
}

[edit: though you wanted to skip the dot, commented it out)

Wrikken
+1  A: 

If you only want the directories of the starting folder, you can simply do:

glob('/some/path/to/search/in/*', GLOB_ONLYDIR);

which would given you only those foldernames in an array. If you want all directories below a given path, try SPL's RecursiveDirectoryIterator

$fileSystemIterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator('/some/path/to/look/in'),
    RecursiveIteratorIterator::SELF_FIRST);

Iterators can be used with foreach:

$directories = array();
foreach($fileSystemIterator as $path => $fileSystemObject) {
    if($fileSystemObject->isDir()) {
        $directories[] = $path;
    }
}

You will then have an array $directories with all directories under the given path.

Gordon
A: 

I agree with nuqqsa's solution, however, I'd like to add something to it.

Instead of specifying the path, you can change the current directory instead.

For example,

// open directory handle
// ....
chdir($dir);
while (false !== ($file = readdir($handle)))
 if(is_dir($file))
  echo $file;
// close directory handle
Daniel
This is ultimately bad practice; a call to `chdir` from anywhere in PHP's path of execution will change the current working directory for the *entirety* of the rest of the script execution. I.E. If foo.php `include` s bar.php, which executes `chdir`, it will change the working directory for everything in foo.php after bar.php's inclusion.
amphetamachine