phpThumb
phpThumb copied to clipboard
Longer load time than original source image?
One of the reasons I'm considering using phpThumb is to help with page load performance. We've been scaling down larger images into thumbnail-sized dimensions. phpThumb is most certainly reducing the file size considerably. In one test, it is creating a 100 pixel wide image at 2.7 KB from a 675 pixel wide image at 49.4 KB. Very nice. However, according to various browser developer tools, the phpThumb image is taking longer to load. In one test via a desktop browser requesting images on an internal Apache web server on the same network, the original is loading in 7ms while the one generated by phpThumb is loading in 37ms. The offending phase appears to be "waiting", which is 36ms for the phpThumb version and only 5ms. Is this to be expected or am I missing something?
Something like phpThumb will always trade off server load and processing time for less data transferred.
Requesting a static image file is easy for the server: it just sends it. The downside for a large image is that it might be a lot of data to transfer, possibly more than is needed for a large image displayed small.
Filtering the request through some server-side script (whether phpThumb or something else) could at best take a small amount of time to find a cached version of the thumbnailed image and send it, or possibly a longer time (and server load) to resize/process the source image and then send it.
phpThumb attempts to respond to requests as efficiently as possible (some more recent changes have improved the browser-side caching aspect, so make sure you're using the current version), but it's inevitable that images will be served slower through phpThumb (or similar) than directly from image files. The optimal solution is to render all large images to static thumbnails on your server (for example, when a new image is uploaded to your server then pre-generate a thumbnail version at 100px or whatever size(s) your site is likely to use them at. The object mode of phpThumb is suited for this kind of scripted rendering, see for example the object-mode demos: https://github.com/JamesHeinrich/phpThumb/blob/master/demo/phpThumb.demo.object.php https://github.com/JamesHeinrich/phpThumb/blob/master/demo/phpThumb.demo.object.simple.php
Thanks James for your prompt response. This is what I had suspected. I have an idea for a solution but it would require knowing in advance the path to the cached image, which the FAQ clearly explains you should use the object mode. I'd prefer not to do this so I can continue to leverage the built-in cache handling that you devised. Ideally, I love to have more control over the suffix of the cache filename. For my purposes, something simple that incorporated width (w) or height (h) and the new size. Something like: w_100_source.jpg. But even using the hash would work I believe -- at least in my case. Otherwise, I think I may be able to build something based on the code in SetCacheFilename(). Any additional thoughts before closing this ticket?
I assume your solution is something along the lines of check if the cached file already exists in which case use that, if not call phpThumb. But that's the exact same overhead that I was talking about above. It's only serving straight image files with no processing that gets you optimal speed -- if you need to check if the cached file exists then you could just let phpThumb.php do that :)
Yes, but I would use mod_rewrite to check if the directory and file exist via RewriteCond, which I presume would be relatively faster. If not, use RewriteRule to redirect to phpThumb.
On May 14, 2014, at 11:27 PM, "James Heinrich" [email protected] wrote:
I assume your solution is something along the lines of check if the cached file already exists in which case use that, if not call phpThumb. But that's the exact same overhead that I was talking about above. It's only serving straight image files with no processing that gets you optimal speed -- if you need to check if the cached file exists then you could just let phpThumb.php do that :)
— Reply to this email directly or view it on GitHub.
It's possible (probable) that a mod_rewrite check will be significantly faster than the more-complex checking in phpThumb, especially with the overhead of invoking PHP, but in theory it will still be slower than a straight file serve. In the real world, however, if you get it working then the difference between straight file and mod_rewrite would probably be small enough to safely ignore. You'll have to find out by experimentation. Please post back when you do as I'm curious to the results.
Will do, though I'm running into a challenge. I realized that if I set $PHPTHUMB_CONFIG['cache_default_only_suffix'] then my $_GET parameters are ignored. I'm curious to why this is the case and if you can think of a workaround.
As an alternative approach, I'm toying around with the idea of renaming the object class 'phpthumb' to something like 'phpthumbCore' and creating a new class 'phpthumb' that extends 'phpthumbCore' and redefines the function SetCacheFilename() to suit my needs. Do you see any issues with this?
Along these lines, and I have no idea if this is a good idea, would you consider an advanced configuration option that let's you set which object class to use? The default would be 'phpthumb', but a developer could create their own class that extends 'phpthumb' and update the config file as necessary. This would facilitate my idea without the need to edit source code, as well as make the project more extensible overall.
$PHPTHUMB_CONFIG['cache_default_only_suffix'] ignores GET parameters and only uses the default parameters because all the info on possible variants of input are lost if you use a simplified cache filename, and so any cache requests for the source filename will match and the cached thumbnail returned, even if it's inappropriate (wrong size or some other non-matching parameter).
One other approach you might want to take would be to create your own simplified cache structure of whatever type meets your needs (e.g. /images/cache/w100/sourcefilename.jpg). Check if the cached file exists, if it does then pass it through; if it does not then pass the request to a simplified helper script that uses phpthumb object to render the thumbnail to your cache file, then either outputs it or redirects to the cache file. Next time the image is called the cached file will exist. Your helper script should really only be a few lines long, something like https://github.com/JamesHeinrich/phpThumb/blob/master/demo/phpThumb.demo.object.simple.php
So I'm pleased to report that serving a thumbnail directly from the cache (assuming it exists) with the help of mod_rewrite rules is faster than via phpThumb. Of course, this required knowing the filename in the cache in advance, which was achieved by using $PHPTHUMB_CONFIG['cache_default_only_suffix'] and dynamically setting defaults (and working around a reported bug that ignored default settings).
What follows is my recipe. I should note that at present I'm only planning on simply creating a thumbnail based on a new width or height.
Key configurations in phpThumb.config.php:
$PHPTHUMB_CONFIG['cache_default_only_suffix'] = '*_' . (!empty($_GET['hash']) ? strip_tags($_GET['hash']) : 'thumb');
$PHPTHUMB_CONFIG['output_format'] = !empty($_GET['f']) ? strip_tags($_GET['f']) : 'jpeg';
$PHPTHUMB_DEFAULTS['w'] = !empty($_GET['w']) ? strip_tags($_GET['w']) : '';
$PHPTHUMB_DEFAULTS['h'] = !empty($_GET['h']) ? strip_tags($_GET['h']) : '';
$PHPTHUMB_DEFAULTS['sia'] = !empty($_GET['sia']) ? strip_tags($_GET['sia']) : '';
And here are my rewriting rules. First, check if the file exists in the cache. (Note the special condition for .jpg as it appears that these are saved as .jpeg in the cache -- anyway to avoid this?) If the thumbnail hasn't been cached yet, then send to phpThumb for processing.
# expecting a URI like so:
# /images/t/w/100/342669c87c5009e611034c8d45626f4c/path/to/source/image.jpg
# | | | | | |
# | | | | | -- file extentsion (6)
# | | | | -- filename (5)
# | | | -- directory (4)
# | | -- md5 hash of parameters (3)
# | -- new size (2)
# -- resize based on width (w) or height (h)? (1)
# first check if cache exists and if it does skip phpThumb
RewriteCond %{REQUEST_URI} ^/images/t/(w|h)/([0-9]*)/([0-9a-fA-F]*)/(.+/)*(.+)\.(png|gif|jpeg)$
RewriteCond %{DOCUMENT_ROOT}/phpthumb/cache/%5.%6_%3.%6 -f
RewriteRule (.*) /phpthumb/cache/%5.%6_%3.%6 [L]
# do special check for 'jpg' since it will be saved as 'jpeg'
RewriteCond %{REQUEST_URI} ^/images/t/(w|h)/([0-9]*)/([0-9a-fA-F]*)/(.+/)*(.+)\.(jpg)$
RewriteCond %{DOCUMENT_ROOT}/phpthumb/cache/%5.%6_%3.jpeg -f
RewriteRule (.*) /phpthumb/cache/%5.%6_%3.jpeg [L]
# cache must not exist, use phpThumb
RewriteCond %{REQUEST_URI} ^/images/t/(w|h)/([0-9]*)/([0-9a-fA-F]*)/(.+/)*(.+)\.(png|gif|jpg|jpeg)$
RewriteRule (.*) /phpthumb/phpThumb.php?src=/%4%5.%6&%1=%2&f=%6&sia=%5&hash=%3 [L]
One drawback I've encountered is that when using $PHPTHUMB_CONFIG['cache_default_only_suffix'], the $PHPTHUMB_CONFIG['cache_directory_depth'] setting is ignored, which means all thumbnails get cached in the same directory, which is not desirable. I tried using my own scheme based on the hash when setting the filename, but the DIRECTORY_SEPARATOR is getting URL-encoded and saved as part of the filename. I also tested by dynamically setting the cache directory, but then learned that each subfolder I created would also contain the cache text files that are created. There may be other reasons to do this last approach.
Is there a reason when $PHPTHUMB_CONFIG['cache_default_only_suffix'] is used it ignores $PHPTHUMB_CONFIG['cache_directory_depth']? I realize the intention is to only ever create one thumbnail per source image in this case, but this may be used on a site with thousands of images that have thumbnails created and you wouldn't want these all stored in the same directory.
Thanks for posting your results and "recipe".
There's no reason that cache_directory_depth is ignored, other than I was either lazy when implementing that option, or more likely it was implemented before the cache_directory_depth config option was added and I missed adding in code to handle that. Feel free to fix the oversight and submit a patch.