Here’s a very handy script which will scan through a directory of images, form an array of the contents of that directory and then return the array in JSON format to the client-side where the images will be preloaded into the user’s cache.
There are two components to this: the PHP script and some simple JavaScript:
The Code (PHP):
/* PHP file, e.g. scanImageDirectory.json.php */ // Check that a callback function has been specified: if (!isset($_GET['callback']) || !isset($_GET['directory'])) exit; // Use PHP5's scandir function to scan all // of images directory: $dirContents = scandir($_GET['directory']); // Define function to confirm each // filename is a valid image name/extension: function isImageFile($src) { return preg_match('/^.+.(gif|png|jpe?g|bmp|tif)$/i', $src); } // Loop through directory files and add to // $arrayContents on each iteration: $arrayContents = ''; foreach($dirContents as $image) { if (isImageFile($image)) { $arrayContents .= !empty($arrayContents) ? ',' : ''; $arrayContents .= '"' . 'images/' . $image . '"'; } } // Prepate JSON(P) output $output = $_GET['callback'] . '({'images':[' . $arrayContents . ']});'; // Output the output: echo $output; |
The above PHP script will use PHP5’s scandir
to scan the ‘images’ directory and it outputs a list of all images in JSON format. (so it can be used by our JavaScript). The JavaScript is below:
The Code (JavaScript):
/* JavaScript Component */ function preloadImagesFromDirectory(dir) { if(!dir) return; function getJSON(URL,success){ // Create new function (within global namespace) // (With unique name): var uniqueID = 'json'+(+(new Date())); window[uniqueID] = function(data){ success && success(data); }; // Append new SCRIPT element to DOM: document.getElementsByTagName('body')[0].appendChild((function(){ var script = document.createElement('script'); script.type = 'text/javascript'; script.src = URL.replace('callback=?','callback=' + uniqueID); return script; })()); } function preload(srcArray) { for(var i = 0; i < srcArray.length; i++) { (new Image()).src = srcArray[i]; } } // Get that JSON data: getJSON('scanImageDirectory.php?directory=' + encodeURIComponent(dir) + '&callback=?', function(data){ return data.images ? preload( data.images ) : false; }); } |
The above JavaScript uses JSONP to load the PHP file into a SCRIPT element as if it were a JavaScript file itself, then the automatically generated function is fired which then executes the specified callback (‘success’) function which is specified when calling getJSON
. The callback then preloads the passed data (i.e. the array of images).
Usage:
// We don't want to disturb anything so we'll wait // until everything's done loading before preloading: window.onload = function(){ preloadImagesFromDirectory('images/'); } |
Security concerns:
Since the directory to be scanned is specified in a query string it would be VERY easy for ANYONE to gain information on your file structure/nomenclature. The regular expression used to validate the image names on the server-side (the PHP script) will stop any files from being listed that do not end in gif, png, jpg, jpeg, bmp or tif. If you’re still concerned then simply specify the directory to be scanned from within the PHP script instead of having it passed through the query string.
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
You shouldn’t use count($dirContents) in the for loop because it gets called every time the loop is run. 😉
Nice. We don’t see too much of those “pure JavaScript” blog posts since libraries became so popular.
I’m not sure to understand the reason why you went through so much trouble though.
Couldn’t you have simply passed a JSON object from PHP (with json_encode()) containing the filenames and use your preload function to load the images?
I am not a JavaScript expert, I may simply be missing the point here.
Thanks Vasili, I’ve changed it to a foreach loop; should be a little more efficient. 🙂
@Antione, I could have just used PHP to output the JSON within the page on the server-side instead of requesting it but I thought this might make it a little more interesting + you’re not limited to one request this way – so if the contents of the directory changes while a user is browsing they will still have the latest. (You’d have to change the JS to use some type of setInterval though). To be honest this was more of a proof of concept than anything else. Also, I didn’t use
json_encode
because all I wanted was an array with the first property of an object, I’d heard thatjson_encode
tends to make normal arrays into associative arrays (~objects) which I didn’t want…If you’re using a library I know a few of them have their own JSON request methods, so you can just swap out ‘getJSON’ for that…
Hi James
Plz could you explain to me how this line works
Hi Ibrahim, yep sure, I’ll explain:
It is a ternary operator which is really a shortcut to using
if{}else{}
. This is the format of a ternary operator:Thanks James 🙂
What was the code block that you use in the foreach loop?
I tried using this “moments ago” and for some reason the
php code block destroys all coding below it? Weird…
insert method was just
[code] [/code]
JS on page. Any ideas?
looks like it blanked my codeblock….
was coded text
Excellent script James, thanks for your work on it. I am fairly green with PHP and JavaScript, is there a way to pre-load not only all the images in a given directory but also in any sub-directories of the given directory?
Thank you