views:

534

answers:

4

Simple question for a newb and my Google-Fu is failing me. Using PHP, how can you count the number of files in a given directory, including any sub-directories (and any sub-directories they might have, etc.)? e.g. if directory structure looks like this:

/Dir_A/  
/Dir_A/File1.blah  
/Dir_A/Dir_B/  
/Dir_A/Dir_B/File2.blah  
/Dir_A/Dir_B/File3.blah  
/Dir_A/Dir_B/Dir_C/  
/Dir_A/Dir_B/Dir_C/File4.blah  
/Dir_A/Dir_D/  
/Dir_A/Dir_D/File5.blah

The script should return with '5' for "./Dir_A".

I've cobbled together the following but it's not quite returning the correct answer, and I'm not sure why:

function getFilecount( $path = '.', $filecount = 0, $total = 0 ){  
    $ignore = array( 'cgi-bin', '.', '..', '.DS_Store' );  
    $dh = @opendir( $path );  
    while( false !== ( $file = readdir( $dh ) ) ){  
        if( !in_array( $file, $ignore ) ){  
         if( is_dir( "$path/$file" ) ){  
          $filecount = count(glob( "$path/$file/" . "*"));  
          $total += $filecount;  
       echo $filecount; /* debugging */
       echo " $total"; /* debugging */
       echo " $path/$file
"; /* debugging */ getFilecount( "$path/$file", $filecount, $total); } } } return $total; }

I'd greatly appreciate any help.

A: 

Why are you passing $filecount? The [passed-in] value is not being used; the only usage is at "$total += $filecount" and you're overriding $filecount just before that.

You're missing the case when the function encounters a regular (non-dir) file.

Edit: I just noticed the call to glob(). It's not necessary. Your function is recursively touching every file in the whole directory tree, anyway. See @Paolo Bergantino's answer.

aib
+5  A: 

This should do the trick:

function getFileCount($path) {
    $size = 0;
    $ignore = array('.','..','cgi-bin','.DS_STORE');
    $files = scandir($path);
    foreach($files as $t) {
        if(in_array($t, $ignore)) continue;
        if (is_dir(rtrim($path, '/') . '/' . $t)) {
            $size += getFileCount(rtrim($path, '/') . '/' . $t);
        } else {
            $size++;
        }   
    }
    return $size;
}
Paolo Bergantino
This code works precisely as requested.
Nicholas Kreidberg
Hi. Thanks for the prompt assistance. This script is resulting in a timeout error for me. "Fatal error: Maximum execution time of 30 seconds exceeded". Not sure why. There are only 8 folders and 68 files in the target directory.
Try recopy-pasting the one that is currently there. My original answer had an error in it, this one is tested and works.
Paolo Bergantino
Much better, thanks! The number isn't quite adding up right though. I added echo "$size $t<br />"; after $size++; in order to debug - it appears that the .DS_Store files are still being counted. Any further advice would be great.
Nevermind - just moved if(in_array... one level up and that did the trick! Thanks again.
Ah, yes, mb. Glad it worked.
Paolo Bergantino
+4  A: 

Use the SPL, then see if you still get an error.

RecursiveDirectoryIterator

Usage example:

<?php

$path = realpath('/etc');

$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name => $object){
    echo "$name\n";
}

?>

This prints a list of all files and directories under $path (including $path ifself). If you want to omit directories, remove the RecursiveIteratorIterator::SELF_FIRST part.

Then just use isDir()

Andrew Clark
This also did the trick after I modified it for the $ignore array. Thanks!
A: 

Check the PHP manual on glob() function: http://php.net/glob

It has examples in comments as to how to make it recursive.

Ilya Birman