Welcome to WebmasterWorld Guest from 54.167.58.159

Forum Moderators: coopster & jatar k

Message Too Old, No Replies

Caching PHP GD Dynamic Images

Best approach to cache images on the fly?

     

whoisgregg

11:39 pm on Oct 14, 2005 (gmt 0)

WebmasterWorld Senior Member whoisgregg is a WebmasterWorld Top Contributor of All Time 10+ Year Member



I have a PHP script that takes a handful of parameters and outputs a graphic based on those parameters. The file name is a direct representation of the input parameters. For example (widgetized):

image.php?a=red&b=big&c=png
outputs the file
red.big.png
to the web accessible directory
/output/

I've actually already picked a way of caching the output of this script but would like to discuss possible alternatives and get a feel for "best practices" in this area. Here are the two general methods of caching I had originally considered:

Method A) The PHP script is called through an <img /> tag and first uses the file_exists() function to see if the image has already been made. If it does exist, the PHP script uses the header() function and the readfile() function to output that existing image. Or if it does not exist, it generates the image, writes it to the static position then uses header() and readfile() to output the image.

Method B) The images are called using the static path in an <img /> tag. The directory

/output/
uses a custom 404 error page (image.php) which parses out the
$_SERVER['REQUEST_URI']
with the explode() function to populate the input parameters and generate the image. It puts the image in the static folder, then uses header() and readfile() to output the image to the server.

1. What are the pro's and cons to these two different methods of caching the images?
2. Is there any reason why either method *can't* be used?
3. What other methods are there? Or, how would you improve on these methods?

I'd appreciate your input on this subject, or if you can recommend other Apache directives/PHP functions that would be useful in this scenario.

ergophobe

10:14 pm on Oct 15, 2005 (gmt 0)

WebmasterWorld Administrator ergophobe is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month



I would not want to send 404s for every image not yet created, which you can't really control because you don't arrive at your php script until after the request has failed and you've been sent on the 404 page.

The other method has a tiny bit more overhead, of course, but only a tiny bit, and it should allow you to send the proper status code.

whoisgregg

10:44 pm on Oct 15, 2005 (gmt 0)

WebmasterWorld Senior Member whoisgregg is a WebmasterWorld Top Contributor of All Time 10+ Year Member



So the readfile() function is essentially equivalent in overhead to apache serving that same file?

ergophobe

12:39 am on Oct 16, 2005 (gmt 0)

WebmasterWorld Administrator ergophobe is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month



Of course the simple request to Apache for a file is going to be the fastest possible interaction with the least overhead. So I wouldn't say it's equivalent because with readfile you're running things through the PHP parser, but this should be a very small amount of overhead if you benchmark with Apache Bench.

BTW, I've done similar simply by sending the right headers and using include() for the image file. In my case it wasn't that the image file might or might not be found, but someone wanted a specific item in the DB updated whenever specific images were called. So I just did the DB updates based on the request, then sent the headers and included the image file and it worked fine.... I think. I should dig that up and make sure ;-)

lobo235

1:17 am on Oct 16, 2005 (gmt 0)

10+ Year Member



I would do something like this:

<?php
$image = 'images/blue.png';
?>
<img src="<?php echo ( file_exists( $image ) ? $image : "image.php?a=red&b=big&c=png"; ?>" />

This should save you from any overhead that readfile might add.

dcrombie

10:23 am on Oct 16, 2005 (gmt 0)



Surely there's a solution that uses mod_rewrite and the -f flag to check whether the image exists, and otherwise call your PHP script, creating and saving the image so it exists the next time it's requested...

ergophobe

3:24 pm on Oct 16, 2005 (gmt 0)

WebmasterWorld Administrator ergophobe is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month



I was wondering about mod_rewrite...

Perhaps something like


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} ^.*\.(gif¦jpg¦jpeg¦png)$
RewriteRule ^.*/image_dir/(.*)\.(gif¦jpg¦jpeg¦png)$ php_image_generator?params=$1

whoisgregg

8:40 pm on Oct 17, 2005 (gmt 0)

WebmasterWorld Senior Member whoisgregg is a WebmasterWorld Top Contributor of All Time 10+ Year Member



Thank you lobo235 for a simple to implement method of eliminating readfile entirely. :)

Seems that keeping all the caching/serving logic in the PHP scripts adds to portability and ease of updating. Does anyone feel as though there is any significant difference between using the file_exists PHP function or mod_rewrite's -f flag? I'd use mod_rewrite if it was noticeably better -- but it seems that readfile is a low overhead function and I imagine that file_exists is too.

dcrombie

10:16 am on Oct 18, 2005 (gmt 0)



I haven't tested this but I'd expect that using mod_rewrite in httpd.conf would be the fastest followed by mod_rewrite in .htaccess with PHP file_exists being the slowest. But we're talking about fractions of seconds in any reasonable scenario so it's much of a muchness.

;)

ergophobe

7:48 pm on Oct 18, 2005 (gmt 0)

WebmasterWorld Administrator ergophobe is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month



Realistically, whenever I benchmark things like this, you have to get up to 1000 or even 10000 iterations to get noticeable differences in execution time. Creating an image needlessly or a bunch of needless DB queries starts to really hurt, but realistically, stuff like this only hurts with huge traffic of when repeated many many times in a big script.

That said, I think if you do benchmark, drcrombie's last post is almost certain to be right.

I'm not actually sure that having it in .htaccess or httpd.conf would make that much difference *if* you're already allowing .htaccess with Allow Override. I *think* that the main drag on the server from .htaccess is enabling it at all so that the server is forced to recurse up through the directory hierarchy and check every directory for any parent .htaccess that is in force. Once you've set it to Allow Override, is httpd.conf significantly faster?

Anyway, like he said, not much of a muchness (whatever that means!).

whoisgregg

10:09 pm on Oct 18, 2005 (gmt 0)

WebmasterWorld Senior Member whoisgregg is a WebmasterWorld Top Contributor of All Time 10+ Year Member



Excellent info everyone. Thank you all for chiming in!

I think the one overriding theme of this thread is that time is better spent optimizing other, more processor intensive portions of dynamic image scripts. :)

killroy

11:14 pm on Oct 24, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



U could use a 404 script to build the image, cahce it and output it (changing the headers back to a 200). This way there would be ZERO overhead if the image alread exists, and very little if it doesn't. It's also ellegant and simple.