Best way to cache resized images using PHP and MySQL Best way to cache resized images using PHP and MySQL php php

Best way to cache resized images using PHP and MySQL


I would do it in a different manner.

Problems:1. Having PHP serve the files out is less efficient than it could be.2. PHP has to check the existence of files every time an image is requested3. Apache is far better at this than PHP will ever be.

There are a few solutions here.

You can use mod_rewrite on Apache. It's possible to use mod_rewrite to test to see if a file exists, and if so, serve that file instead. This bypasses PHP entirely, and makes things far faster. The real way to do this, though, would be to generate a specific URL schema that should always exist, and then redirect to PHP if not.

For example:

RewriteCond %{REQUEST_URI} ^/images/cached/RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-fRewriteRule (.*) /images/generate.php?$1 [L]

So if a client requests /images/cached/<something> and that file doesn't exist already, Apache will redirect the request to /images/generate.php?/images/cached/<something>. This script can then generate the image, write it to the cache, and then send it to the client. In the future, the PHP script is never called except for new images.

Use caching. As another poster said, use things like mod_expires, Last-Modified headers, etc. to respond to conditional GET requests. If the client doesn't have to re-request images, page loads will speed dramatically, and load on the server will decrease.

For cases where you do have to send an image from PHP, you can use mod_xsendfile to do it with less overhead. See the excellent blog post from Arnold Daniels on the issue, but note that his example is for downloads. To serve images inline, take out the Content-Disposition header (the third header() call).

Hope this helps - more after my migraine clears up.


There is two typos in Dan Udey's rewrite example (and I can't comment on it), it should rather be :

RewriteCond %{REQUEST_URI} ^/images/cached/RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-fRewriteRule (.*) /images/generate.php?$1 [L]

Regards.


One note worth adding is to make sure you're code does not generate "unauthorized" sizes of these images.

So the following URL will create a 200x200 version of image 1234 if one doesn't already exist. I'd highly suggest you make sure that the requested URL contains image dimensions you support.

/images/get/200x200/1234.jpg

A malicious person could start requesting random URLs, always altering the height & width of the image. This would cause your server some serious issues b/c it will be sitting there, essentially under attack, generating images of sizes you do not support.

/images/get/0x1/1234.jpg/images/get/0x2/1234.jpg.../images/get/0x9999999/1234.jpg/images/get/1x1/1234.jpg...etc

Here's a random snip of code illustrating this:

<?php    $pathOnDisk = getImageDiskPath($_SERVER['REQUEST_URI']);    if(file_exists($pathOnDisk)) {        // send header with image mime type         echo file_get_contents($pathOnDisk);        exit;    } else {        $matches = array();        $ok = preg_match(            '/\/images\/get\/(\d+)x(\d+)\/(\w+)\.jpg/',             $_SERVER['REQUEST_URI'], $matches);        if(! $ok) {            // invalid url            handleInvalidRequest();        } else {            list(, $width, $height, $guid) = $matches;            // you should do this!            if(isSupportedSize($width, $height)) {                // size is supported. all good                // generate the resized image, save it & output it            } else {                // invalid size requested!!!                handleInvalidRequest();            }        }    }    // snip    function handleInvalidRequest() {        // do something w/ invalid request                  // show a default graphic, log it etc    }?>