Re: RecursiveDirectoryIterator and foreach

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Here's a RecursiveDirectoryIterator class I've written and find quite useful:

<?php
/**
 * This class encapsulates an iterator that iterates over all the files in a
 * directory recursively.  Only files that don't begin with a '.' are included
 * in this iteration.  This class essentially wraps an SPL DirectoryIterator
 * object and returns each file in the iteration as an SplFileInfo.
 *
 * @author <a href="mailto:philip@xxxxxxxxxxxx";>Philip Graham</a>
 */
class Util_RecursiveFileIterator implements Iterator {
    CONST SHOW_DOT_FILES = true;

    private $_basePath;
    private $_curDirIter;
    private $_dirStack;
    private $_showDots;

    /**
     * Constructor.  By default the iteration will skip any files that begin
     * with a '.' character but this can be changed by passing the class
     * constant SHOW_DOT_FILES as the second parameter.
     *
     * @param string $basePath - The base path of the directory to iterate 
over
     * @param boolean $showDots - Whether or not to include files that begin
     * with a '.' character in the iteration.
     */
    public function __construct($basePath, $showDots = false) {
        // PREPARE ... THE ... HUMANOID
        if(!is_dir($basePath)) {
            $basePath = dirname($basePath);
        }
        if(!$basePath) {
            $basePath = '.';
        }
        // If the given path is relative this function will transform it
        // into an equivalent path.  This call assumes that the relative path
        // is relative to the file that created this iterator.
        $this->_basePath = Util_File::getAbsolutePath($basePath, 2);

        $this->_showDots = $showDots;

    }

    /**
     * Returns the current value of the iteration
     *
     * @return FileInfoInfo
     */
    public function current() {
        return $this->_curDirIter->current();
    }

    /**
     * Returns the index of the current entry.
     *
     * @return string
     */
    public function key() {
        $curPath = $this->_curDirIter->getPathname();
        $relativeToBase = substr($curPath, strlen($this->_basePath));
        return $relativeToBase;
    }

    /**
     * Moves the directory iterator to the next element of the iteration.
     */
    public function next() {
        $this->_curDirIter->next();
        $good = false;
        while(!$good) {
            if(!$this->_curDirIter->valid()) {
                if(count($this->_dirStack) == 0) {
                    $good = true;
                } else {
                    $this->_curDirIter = array_pop($this->_dirStack);
                }
            } else if($this->_curDirIter->isDot()) {
                if(!$this->_showDots) {
                    $this->_curDirIter->next();
                } else {
                    $good = true;
                }
            } else if(!$this->_showDots &&
              substr($this->_curDirIter->getFileName(), 0, 1) == '.') {
                $this->_curDirIter->next();
            } else if($this->_curDirIter->isDir()) {
                // Create a new iterator for the sub-dir
                $newIter = new DirectoryIterator(
                    $this->_curDirIter->getPathname());

                // Make sure the current iterator is ready to go when it
                // gets popped off the stack
                $this->_curDirIter->next();

                // Push it... push it real good
                array_push($this->_dirStack, $this->_curDirIter);

                // Set the new iterator
                $this->_curDirIter = $newIter;
            } else {
                $good = true;
            }
        }
    }

    /**
     * Resets the iterator to first file in the object's base path.
     */
    public function rewind() {
        $this->_curDirIter = new DirectoryIterator($this->_basePath);
        $this->_dirStack = array();
        if(!$this->_showDots && $this->_curDirIter->isDot()) {
            $this->next();
        }
    }

    /**
     * Returns a boolean indicating wether or not there are anymore elements 
left
     * in the iteration.
     */
    public function valid() {
        return $this->_curDirIter->valid();
    }
}

Usage:

$dirIter = new Util_RecursiveFileIterator('/path/to/directory');
foreach($dirIter AS $fileName => $fileInfo) {
      // $fileName is the basename of the file and $fileInfo is a SplFileInfo
      // for the file
}

Hope this helps!


On February 23, 2009 11:31:04 Ryan Panning wrote:
> I have discovered that when I foreach over a RecursiveDirectoryIterator
> (see example below) the $item actually turns into a SplFileInfo object.
> I would expect it to be a RecursiveDirectoryIterator. How do I do a
> hasChildren() on SplFileInfo?
>
> However, if I change it to a non-recursive, DirectoryIterator, $item is
> what I would expect, DirectoryIterator. I've tested this with 5.2.8 and
> 5.3b1. I'm guessing this is an issue with my setup as I'm sure I've
> gotten this to work before...
>
>
> $dir = new RecursiveDirectoryIterator('/path/to/dir');
> foreach ($dir as $item) {
>      print get_class($item) . "\r\n";
> }
-- 
Philip Graham
Lightbox Technologies
Suite 312 240 Catherine St.
Ottawa, ON, K2P 2G8
613-686-1661 ext. 102

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux