Quick Tip: Loop Through Folders with PHP’s Glob()
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!