TalkPHP
 
 
Account Login
Latest Articles
» The basic usage of PHPTAL, a XML/XHTML template library for PHP
» Vulnerable methods and the areas they are commonly trusted in.
» Simple way to protect a form from bot
» The Basics On: How Session Stealing Works
» How to keep your forms from double posting data
IRC Channel
IRC Speech Bubble Join the friendly bunch on IRC...
(#TalkPHP on Freenode)

...Also available via a web interface.

See this thread for information on the TalkPHP Free Hugs Initiative™. Subject to availability.
Associates
Associates
CSS Tutorials
Reply
 
LinkBack Thread Tools Search this Thread Display Modes
Old 06-03-2010, 05:07 AM   #1 (permalink)
The Contributor
 
Join Date: Feb 2007
Posts: 64
Thanks: 9
Killswitch is on a distinguished road
Default Iterating over directories only

I have seen many scripts that recurse over directories listing files, but what I am trying to do, with no success, is list the directories only.

It doesn't help that the directory I am trying to list all directories of is quite large, but it's what I need to do :(

Can anyone help me figure out how to do this? I figured using DirectoryIterator would probably be the best option, but documentation explaining it is incredibly scarce, and not many user submitted examples.

I have tried doing this the old fashion way reading a directory and recursively listing only those that are directories, but it times out.
Killswitch is offline  
Reply With Quote
Old 06-03-2010, 07:36 AM   #2 (permalink)
The Acquainted
 
EyeDentify's Avatar
 
Join Date: Nov 2007
Location: Sweden
Posts: 106
Thanks: 13
EyeDentify is on a distinguished road
Default

Have you taken an look at the often forgotten function glob() ?

Its really helpfull in many situations.

Good luck.
__________________
Of course the whole point of a doomsday machine, would have been lost if you keep it a secret.
EyeDentify is offline  
Reply With Quote
Old 06-03-2010, 08:20 AM   #3 (permalink)
The Prestige
Upcoming Programmer Inquisitive 
 
Tanax's Avatar
 
Join Date: Sep 2007
Location: Sweden, Stockholm
Posts: 1,080
Thanks: 115
Tanax is on a distinguished road
Default

I wrote this tutorial that got accepted here: http://net.tutsplus.com/tutorials/ph...ith-phps-glob/

That will help you find your answer.
__________________
Tanax is offline  
Reply With Quote
Old 06-03-2010, 11:30 AM   #4 (permalink)
The Prestige
Advanced Programmer Top Contributor Good Samaritan 
 
sketchMedia's Avatar
 
Join Date: Oct 2007
Location: Manchester, UK
Posts: 854
Thanks: 32
sketchMedia is on a distinguished road
Default

We could also use PHP's SPL objects, namely the DirectoryIterator, which as the name suggests, does just that!
PHP Code:
    try
    {
        foreach ( new 
DirectoryIterator('.') as $pItem )
        {
            if(
$pItem->isFile() || $pItem->isDot()) { continue; }
            echo 
$pItem '<br />';
        }
    }
    catch(
Exception $e)
    {
        echo 
$e->getMessage();
    } 
Yea the documentation isn't the greatest in for the SPL stuff, its a shame coz most of it is hot stuff!
__________________
mysql> SELECT * FROM `users` WHERE `users`.`clue` > 0;
Empty set (0.00 sec)
sketchMedia is offline  
Reply With Quote
Old 06-03-2010, 06:46 PM   #5 (permalink)
The Contributor
 
Join Date: Feb 2007
Posts: 64
Thanks: 9
Killswitch is on a distinguished road
Default

Thanks, I've been using directory iterator and iterator iterator, but the problem I believe is with Windows ( I just installed Windows two days ago, darn it).

If I use getType to print what each entry is, I get a massive list of nothing but file, with the last entry being null. No dir listed anywhere.

Also, if I use isDir over the iteration, I am simply returned null. I am making sure to continue the iteration as well.

I think it just boils down to being a Windows based issue.

Thanks for your help all. Incase anyone was wondering, this is how it's being used.

Code:
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $item) {
     echo $item->getType();
}
Using that, I am simply listed 'file' a few thousand times :)
Killswitch is offline  
Reply With Quote
Old 06-03-2010, 08:15 PM   #6 (permalink)
Moderateur
RegEx Guru PHP Guru Top Contributor Advanced Programmer 
 
Salathe's Avatar
 
Join Date: Apr 2007
Posts: 1,393
Thanks: 5
Salathe is on a distinguished road
Default

The default mode for the RecursiveIteratorIterator is to provide leaves only. For a RecursiveDirectoryIterator, that means files only.

In order to include directories, you can use one of the other iteration modes that RecursiveIteratorIterator recognises: namely either children first (directory contents are shown earlier than the directory itself) or self first (directory contents are shown after the directory itself).

Note about snippets: short variable names and crazy line-wrapping is used to avoid horizontal scrolling due to the teeny tiny code boxes here.





Showing files and directories with SELF_FIRST
PHP Code:
$dit = new RecursiveDirectoryIterator(__DIR__);
$rit = new RecursiveIteratorIterator(
    
$ditRecursiveIteratorIterator::SELF_FIRST);

foreach (
$rit as $fileinfo) {
    echo 
$fileinfo->getPathname() . PHP_EOL;

The above uses RecursiveIteratorIterator::SELF_FIRST, as you should hopefully see, to iterator over __DIR__ (or whatever path you choose) showing directories and their contents.

Now, how about getting only directories? Well there are a couple of different ways to do this and I'll go over some just to give an idea: it's entirely up to you which you prefer (I have my favourite).





Filtering within the loop
PHP Code:
$dit = new RecursiveDirectoryIterator(__DIR__);
$rit = new RecursiveIteratorIterator(
    
$ditRecursiveIteratorIterator::SELF_FIRST);
foreach (
$rit as $fileinfo) {
    if ( ! 
$fileinfo->isDir()) continue; // Skip non-directories
    
echo $fileinfo->getPathname() . PHP_EOL;

This approach is quick and might be the most obvious approach to ignoring what we don't want. It's also the most crude and easiest to get out of hand (imagine a number of different checks that you want to do).





Filtering using a Filtering Iterator
PHP Code:
class DirsOnlyFilter extends RecursiveFilterIterator {
    public function 
__construct($path) {
        
// Custom constructor takes a filesystem path
        
parent::__construct(new RecursiveDirectoryIterator($path));
    }
    public function 
accept() {
        
// Only accept directories
        
return $this->getInnerIterator()->isDir();
    }
    public function 
getChildren() {
        
// Get children (directory contents) wrapped in this filter
        
return new DirsOnlyFilter($this->getInnerIterator()->getPathname());
    }
}

$dirs = new DirsOnlyFilter(__DIR__);
$rit  = new RecursiveIteratorIterator(
    
$dirsRecursiveIteratorIterator::SELF_FIRST);
foreach (
$rit as $fileinfo) {
    echo 
$fileinfo->getPathname() . PHP_EOL;

Here we make use of a filtering iterator which implements the accept method (whose task is to determine what we want to accept when iterating). The other methods are in place to ensure that the filtering happens throughout the recursion. This may seem complicated but is the best way (of those outlined in this post) of moving towards the more complex, customised filtering that you might want to do (e.g. give my only audio/video files greater than 10MB, last modified after this time last week, owned by user bob or in group developers) which would be a nightmare if you had to do it every time it is needed in a foreach loop. The "inner iterator" referred to will be the RecursiveDirectoryIterator.





Shortcut with the ParentIterator
PHP Code:
$dit = new RecursiveDirectoryIterator(__DIR__);
$pit = new ParentIterator($dit);
$rit = new RecursiveIteratorIterator(
    
$pitRecursiveIteratorIterator::SELF_FIRST);
foreach (
$rit as $fileinfo) {
    echo 
$fileinfo->getPathname() . PHP_EOL;

This quickie works because the ParentIterator only iterates over items which have children -- so it only iterates over directories.




Aside: If you have any feedback or criticism about the SPL docs, please do email me (see my signature) and I'll take on board any thoughts.
P.S. Sorry for any typos.
Salathe is offline  
Reply With Quote
Old 06-03-2010, 09:09 PM   #7 (permalink)
is cute and cuddly
 
delayedinsanity's Avatar
 
Join Date: Mar 2008
Location: Vegas, Baby
Posts: 963
Thanks: 31
delayedinsanity is on a distinguished road
Default

The following may not be the prettiest but it seems to get the job done - tested on a directory containing roughly 50,000+ files; 3-4 seconds execution time. If you're still timing out, you could a) change the timeout in php.ini, b) change it in your .htaccess or c) use set_time_limit(0)

php Code:
$iterator = new RecursiveDirectoryIterator( $directory );

$dirs = array();

foreach ( new RecursiveIteratorIterator( $iterator ) as $d )
    $dirs[] = $d->getPath();

print_r( array_unique( $dirs ) );
delayedinsanity is offline  
Reply With Quote
Old 06-03-2010, 09:11 PM   #8 (permalink)
is cute and cuddly
 
delayedinsanity's Avatar
 
Join Date: Mar 2008
Location: Vegas, Baby
Posts: 963
Thanks: 31
delayedinsanity is on a distinguished road
Default

Holy carp Salathe. I took took too long posting I see, and have been humbled in the process.

When's the new TalkPHP book from aPress coming out, huh? ;)
delayedinsanity is offline  
Reply With Quote
Old 06-04-2010, 10:31 AM   #9 (permalink)
The Prestige
Advanced Programmer Top Contributor Good Samaritan 
 
sketchMedia's Avatar
 
Join Date: Oct 2007
Location: Manchester, UK
Posts: 854
Thanks: 32
sketchMedia is on a distinguished road
Default

Great post and explanation as always Salathe.
__________________
mysql> SELECT * FROM `users` WHERE `users`.`clue` > 0;
Empty set (0.00 sec)
sketchMedia is offline  
Reply With Quote
Old 06-04-2010, 04:06 PM   #10 (permalink)
Moderateur
RegEx Guru PHP Guru Top Contributor Advanced Programmer 
 
Salathe's Avatar
 
Join Date: Apr 2007
Posts: 1,393
Thanks: 5
Salathe is on a distinguished road
Default

I hope it helped. If there are any other SPL/docs questions feel free to ask. :)
Salathe is offline  
Reply With Quote
Reply



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

Similar Threads
Thread Thread Starter Forum Replies Last Post
List Directories, not files buildakicker Absolute Beginners 19 03-13-2013 08:08 AM
Traverse Directories the Easy Way with Glob() ! Wildhoney Absolute Beginners 6 12-02-2008 11:07 PM
Auto-populating Directories? clenard General 3 08-05-2005 08:16 PM


All times are GMT. The time now is 06:07 AM.

 
     

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0
Inactive Reminders By Icora Web Design