Quick Tip: Loop Through Folders with PHP’s Glob()

Quick Tip: Loop Through Folders with PHP’s Glob()

Tutorial Details
  • Technology: PHP
  • Estimated Completion Time: 5-10 Minutes

Are you still using opendir() to loop through folders in PHP? Doesn’t that require a lot of repetitive code everytime you want to search a folder? Luckily, PHP’s glob() is a much smarter solution.


Introduction

Here’s an example of echoing out some information from a folder, using the traditional opendir() function.


	$dir = "/etc/php5/";

	// Open a known directory, and proceed to read its contents
	if (is_dir($dir))
	{

		if ($dh = opendir($dir))
		{

			while (($file = readdir($dh)) !== false)
			{
				echo "filename: $file : filetype: " . filetype($dir . $file) . "\n";
			}

			closedir($dh);

		}

	}

That should look somewhat familiar. We can massively shorten the code above with:

	$dir = "/etc/php5/*";

	// Open a known directory, and proceed to read its contents
	foreach(glob($dir) as $file)
	{
		echo "filename: $file : filetype: " . filetype($file) . "<br />";
	}

Isn’t that much easier? Eager to learn how the method works? If yes, then let’s get on with it.

glob() supports a total of two arguments, with the second argument being optional. The first argument is the path to the folder, however, it’s a bit more powerful than that.


Step 1. The First Argument

This first argument supports a pattern. This means that you can limit the search to specific filetypes or even multiple directories at the same time by using multiple asterixes “*”. Let’s assume that you have a website that allows users to upload images (just because I read this). Each user has his/her own folder within the folder “userImages.” Inside these folder are two additional folders, called “HD” and “TN,” for high definition (full-sized) images, and for thumbnails. Let’s imagine that you want to loop through all your users’ “TN” folders and print the filenames. This would require a relatively large snippet of code if you were to use open_dir(); however, with glob(), it’s easy.

	foreach(glob('userImages/*/TN/*') as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

This will search userImages/any/TN/any and will return a list of the files that match the pattern.

	Filename: userImages/username1/TN/test.jpg
	Filename: userImages/username1/TN/test3.jpg
	Filename: userImages/username1/TN/test5.png
	Filename: userImages/username2/TN/subfolder
	Filename: userImages/username2/TN/test2.jpg
	Filename: userImages/username2/TN/test4.gif
	Filename: userImages/username3/TN/styles.css

We can even take things a step further, and be more specific by including a file format in our foreach statement:

	foreach(glob('userImages/*/TN/*.jpg') as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

Now, this will only return Jpegs.

	Filename: userImages/username1/TN/test.jpg
	Filename: userImages/username1/TN/test3.jpg
	Filename: userImages/username2/TN/test2.jpg

It gets even better. What if, for instance, you require Jpegs, but also Gifs; nothing else? Or what if you want to print only folder names? This is where the second argument comes into play.


Step 2. The Second Argument

The second argument is, as mentioned previously, optional. It does, however, provide a very nice set of optional flags. These will allow you to change the way your glob() behaves.

  • GLOB_MARK: Adds a slash to each directory returned
  • GLOB_NOSORT: Return files as they appear in the directory (no sorting)
  • GLOB_NOCHECK: Return the search pattern if no files matching it were found
  • GLOB_NOESCAPE: Backslashes do not quote metacharacters
  • GLOB_BRACE: Expands {a,b,c} to match ‘a’, ‘b’, or ‘c’
  • GLOB_ONLYDIR: Return only directory entries which match the pattern
  • GLOB_ERR: Stop on read errors (like unreadable directories), by default errors are ignored

As you see, the potential requirements that we noted at the end of Step 1 can easily be fixed with GLOB_BRACE:

	foreach(glob('userImages/*/TN/{*.jpg,*.gif}', GLOB_BRACE) as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

which will return this:

	Filename: userImages/username1/TN/test.jpg
	Filename: userImages/username1/TN/test3.jpg
	Filename: userImages/username2/TN/test2.jpg
	Filename: userImages/username2/TN/test4.gif

If we wish to only print subfolder names, we could use GLOB_ONLYDIR:

	foreach(glob('userImages/*/TN/*', GLOB_ONLYDIR) as $image)
	{
		echo "Filename: " . $image . "<br />";
	}

which will print:

	Filename: userImages/username2/TN/subfolder

Conclusion and One More Example

This method has been available since PHP 4.3, however, it’s not used very often, strangely. I didn’t learn it until quite late myself. Now, I often use glob() when loading plugins into my framework:

	foreach(glob('includes/plugins/*.php') as $plugin)
	{
		include_once($plugin);
	}

That’s all; I hope you enjoyed this quick tip, and let me know if you have any questions!

Add Comment

Discussion 40 Comments

  1. tanmay joshi says:

    Good to know such tips.

    Thanks
    Keep up the good work.

    Tanmay

  2. glob() is a wonderful tool, however unless you know the files will be accessible at time of writing (which is never really for sure), you should put the output of glob into a variable and check for errors before feeding it to foreach(). If glob returns an error it will return FALSE which will cause foreach to spit out a nasty error message. For example:

    if ($results = glob($path))
    {
    foreach($results as $entry)
    {
    // do stuff
    }
    }
    else
    {
    // handle error
    }

    If you use PHP 5 & OOP you can use a try() block as well:

    try
    {
    foreach(glob($path) as $entry)
    {
    // do stuff
    }
    }
    catch (Exception $e)
    {
    // handle error
    }

    And of course, needless to say, if you pass any user input to the path parameter of glob(), make sure you properly filter and validate it first! :)

  3. Matthieu says:

    Very helpful, Thks!

  4. Davidmoreen says:

    Hmm, I have never heard of this function before… I need to stop doing things the old fashioned way.

  5. WP Tricks says:

    PHP is popular server programing so far, easy to develop and many server available to use. That make PHP growing very quickly…

    About this functions, this is the first time I hear it :)

  6. Bretticus says:

    I haven’t written directory code (been using frameworks for awhile now) for so long that I was not aware of this function either (as another poster admitted.) Thanks. Certainly very useful from what I can see.

    I find it a little disturbing that I see the PHP manual using a function call as the array expression inside for loops in their glob examples also. Didn’t Rasmus or another top PHP core developer explain that this is suboptimal coding practice? Or is this another area where my PHP knowledge is falling a bit behind the times?

    • Peter says:

      The PHP manual page examples are intended to show, as simply and clearly as possible, the usage of the particular item being documented. Micro-optimisations are generally not at the forefront of the documentor’s mind when trying to give a concise example.

  7. Angus Li says:

    Cool~ The usage of glob() is always one of my frequent asked interview questions — please give me an easiest way to find the files with certain format(e.g. .gif/.jpg) under a given folder; mostly of the time I got a disappointing answer…

    • Dale Hurley says:

      Angus – Don’t you think that those sort of questions in an interview is redundant?

      Maybe it is because I am a mere mortal and am not as brilliant as you, since you know EVERY function in PHP.

      A lot of programming is on the fly finding solutions. A brilliant programmer may of never needed to find files in a particular directory before. There you go asking him about some obscure function which those sort of questions are purely to make yourself feel elitist rather than test the ability of the programmer. You would be much better off finding out how he would approach the task rather then the final solution.

      So I hope you feel good in your ivory tower making people feel crap when they are already nervous in an interview because they do not know about one little PHP function which is one of the lesser known functions.

      Seriously you are the type that gives web developers a bad reputation.

      Dale

  8. Daigo says:

    Thanks for this :) Haven’t heard of it either!

    Can you tell me something about performance? Especially in comparison with PHP’s DirectoryIterator? Thx :)

    Regards,
    Daigo

  9. Mohamed Zahran says:

    It’s my favorite function, I was always using it but I was missing (Step 2)
    Thanks, That’s really helped me.

  10. Well this function would of saved me a lot of time when I was building an FTP photo library a few weeks back! Really well explained, nice work.

  11. Patrick says:

    Ouh, that’s why i don’t call me a pro. Thank you for broadening my horizon.

  12. Great Tutorail. I will add this in my memory when ever have to use Directories in PHP.

  13. Matt Bridges says:

    Wow. I had never heard of this function before. This article is definitely going to be sitting in my developer bookmarks for while until I have mastered it. Fantastic!

  14. The functions glob is really powerful and cool. I was always using opendir() to get files in some folder, and I had to check if the current file is (.) or (..). It’s bored. I like the wildcard chars in glob function, it helps to reduce checking curtain files. Thanks for the post.

  15. That is really helpful when reading a contents of a folder.

  16. Ben says:

    Very cool. Thanks.

  17. Aaron says:

    Thanks for pointing this out. I’ve never seen it before and I will definitely find use for it.

  18. Bill Karwin says:

    glob() is convenient, but it can be several times *slower* than using readdir(). At least you should use GLOB_NOSORT if you don’t care about the order. This mitigates the performance cost a lot.

    This came up on Stack Overflow in January. I benchmarked several methods that other users suggested for reading a directory. My code and the results is here:

    http://stackoverflow.com/questions/2120287/directory-to-array-with-php/2120496#2120496

    The results ranged from 12.4 seconds down to 1.2 seconds. That’s a pretty wide spread, so it’s worth paying attention to performance as well as coding convenience.

  19. idont says:

    Looping through folders without SPL is criminal…. ;)

    http://www.php.net/manual/en/recursivedirectoryiterator.construct.php

  20. Giorgos says:

    Very helpful, but I found that opendir is a little bit faster than glob

    I put the following script

    <?php
    $dir = "pics/sports/b/";
    if($handle = opendir($dir)) {
    while($file = readdir($handle)) {
    clearstatcache();
    if(is_file($dir.'/'.$file))
    echo '‘;
    }
    closedir($handle);
    }
    ?>

    in a page and it worked faster than glob

  21. Ryan Reed says:

    Looks very cool. I am used to using opendir/readdir. I am curious, though: is it possible to search for all ,jpg images, like you have, except leave off any images with say *_tn.jpg? This would be awesome if it were possible without having to explode the filename.

  22. Kevin Dean says:

    5 years ago this was a great tip, before PHP 5 became the de-facto and PHP 4 a rarity only found on ancient servers.

    These days PHP has a built in function to facilitate this, its called scandir(). Over a thousand iterations of looping through a directory, the times were:

    glob(dir/*) – 0.13954
    scandir(dir) – 0.06261

    Note that scandir is more than twice as fast, and avoids the need for unintuitive wildcards.
    Also note that setting scandir results into a variable first, as someone suggested for the glob(), offers no change, it would be premature optimization, unless thats just how you like to do it.

  23. Jack Bliss says:

    I actually like it.

    foreach(glob(‘libraries/*.js’) as $js){
    echo ”;
    }

    And you can do the same thing for stylesheets.

  24. Thai says:

    Wow, this little method saved me lines of code. Thank you!

  25. a77icu5 says:

    Say goodbye to readir() and say hello to glob() =D !!!

  26. fractalbit says:

    Excellent, a time saver, thanks!

  27. quang trung says:

    How to scan folder which name is unicode like this dir\olá
    Sample with case file have a unicode name ă.jpg

  28. Piyush Rahate says:

    That was real time saver quick tip. I was used to “opendir” and didn’t ever realized that glob will make life so easy.

    @Bill, thanks to you as well for the comparison provided.

    @Kevin, will check scandir :)

  29. ollly says:

    Thank you! Great tutorial.

  30. You should’ve also pointed out that OpenDir is PHP native and portable while glob is system dependent. e.g.: it will not work on Sun Solaris and some unix and linux systems.

    My 2 cents to readers: keep it portable and avoid system dependencies.

    My 2 cents to the writer: tell the complete story or you’ll make a fool out of yourself by confusing learning users. Think about how many of them wonder why opendir exists at all after reading your… “post”.

    • dbind says:

      @Mike Edward Moras (e-sushi™), did you happen to think that maybe he didn’t know that? This is not a PHP Core developer writing, so he might ignore a few things about PHP. Yeah, normal people tend to not know stuff, not like you. Next time you could try a constructive aproach like “I found out this and that, should you want to know”. See how less full-of-yourself you could sound?

      Now my two cents: I’ve had problems with glob correctly listing paths with ‘[' and ']‘ in them. Couldn’t find a good workaround in the net yet, so I’m sticking to scandir for this task. Great article anyway, thank you!

      • dbind says:

        Got it! You escape special chars by putting them between square brackets, like this:

        [ becomes [[]
        ] becomes []]

        …and so on.

        Might work with non-ascii chars (someone mentioned them above), haven’t tried.

      • @dbind

        I’m so glad you’re not a troll but a specialist finding my comment 3 months later and missing the point that my critique went against the article writer.

        Especially when he’s “not a PHP Core developer writing, so he might ignore a few things about PHP”, he should try to do his research instead of posting incomplete information.

        And related to your problems: you could have asked; or at least taken my comment as a good hint related to portability… and if everything would have failed you could have simply acknowledged that my comment gave you the solution to your problem: use OpenDir.

        But you were too busy preparing a rant to see that, weren’t you?

      • Let me add that the example used in “Conclusion and One More Example” and the code shown is actually a great example of a security issue waiting to be exploited.

        Why?

        The used code would include EVERY php file. Look at it twice:

        foreach(glob(‘includes/plugins/*.php’) as $plugin)

        Why not try “unlink *.*” too instead of waiting for the exploit to happen? ;)

      • Tanax says:

        @Mike- You seem like a friendly guy. Hmm. In any case, please explain what you mean with “exploit to happen”?

  31. Steven says:

    Nice tut, thanks. Though that last snippet of code looks pretty dangerous >

    foreach(glob(‘includes/plugins/*.php’) as $plugin)
    {
    include_once($plugin);
    }

    If a user with bad intentions manages to get access to your ftp and just pastes one of his own malicious “plugin” files in that folder it will automatically be included in your site.

  32. Keith says:

    Hi,

    Was wondering if the output can be alphabetically sorted, inclusive of lower and uppercase.

    Thanks in advance

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.