Serving images via `print fread(...)` is slow, what to do?
I have a dynamic thumbnail script I found laying around the web and tweaked a bit. One of the things I added was a caching mechanism. Whenever a new thumb is generated, it is saved to disk, and the disk copy will be used if the same thumbnail (with all the same options) is requested again.
A snippet:
// name of cached fil开发者_如何学运维e
$thumb_file = $_SERVER['DOCUMENT_ROOT'].'/thumbs/cache/'.
str_replace('/', '_', $_REQUEST['p']).
".{$def_width}x{$def_height}".
($clamp ? '_'.implode('x',$clamp) : '').
($make_png?'.png':'.jpg');
// get it from cache if it's there
if ($use_cache && file_exists($thumb_file)) {
Header("Content-type: image/".($make_png?'png':'jpeg'));
// this part seems really slow
$fp=fopen($thumb_file, "rb");
while (!feof($fp)) print fread($fp, 4096);
exit();
}
However, print
ing the result of fread
seems to be very slow, and sometimes (very rarely) the images don't load completely.
So, how can I speed this up? Should I just redirect the browser to the image instead of fread
ing it, or is there another option?
I'm including the full PHP script below, just in case.
<?php
$use_cache = $_REQUEST['nc'] ? false : true;
// $use_cache = false;
$upfile = $_SERVER['DOCUMENT_ROOT'] .'/'. $_REQUEST['p'];
$def_width = $_REQUEST["w"];
$def_height = $_REQUEST["h"];
$clamp = $_REQUEST['c'] ? explode("x",$_REQUEST['c']) : null;
$make_png = $_REQUEST['png'];
if (!file_exists($upfile)) {
die(); // $upfile = "nophoto.jpg";
}
if (!"{$def_width}{$def_height}") {
$def_width = $def_height = '100';
}
// name of cached file
$thumb_file = $_SERVER['DOCUMENT_ROOT'].'/thumbs/cache/'.
str_replace('/', '_', $_REQUEST['p']).
".{$def_width}x{$def_height}".
($clamp ? '_'.implode('x',$clamp) : '').
($make_png?'.png':'.jpg');
// get it from cache if it's there
if ($use_cache && file_exists($thumb_file)) {
Header("Content-type: image/".($make_png?'png':'jpeg'));
$fp=fopen($thumb_file, "rb");
while (!feof($fp)) print fread($fp, 4096);
exit();
}
$ext = strtolower(substr($upfile, -3));
ini_set('memory_limit', '64M');
if ($ext=="gif")
$src = @ImageCreateFromGif ($upfile);
else if ($ext=="jpg")
$src = @ImageCreateFromJpeg($upfile);
else if ($ext=="png")
$src = @ImageCreateFromPng($upfile);
$size = GetImageSize($upfile);
$width = $size[0];
$height = $size[1];
$long_side = $def_width;
if ($def_width < $def_height) $long_side = $def_height;
if (!$def_width) {
$factor_h = $height / $def_height;
$def_width = $width / $factor_h;
}
if (!$def_height) {
$factor_w = $width / $def_width;
$def_height = $height / $factor_w;
}
$factor_w = $width / $def_width;
$factor_h = $height / $def_height;
if ($factor_w > $factor_h) {
$new_height = floor($def_height * $factor_h);
$new_width = floor($def_width * $factor_h);
} else {
$new_height = floor($def_height * $factor_w);
$new_width = floor($def_width * $factor_w);
}
if ((!$clamp[0])&&$clamp[0]!=='0') $clamp[0] = 50;
if ((!$clamp[1])&&$clamp[1]!=='0') $clamp[1] = 50;
$src_x = ceil(($width - $new_width) * ($clamp[0] / 100));
$src_y = ceil(($height - $new_height) * ($clamp[1] / 100));
$dst = ImageCreateTrueColor($def_width, $def_height);
@ImageCopyResampled($dst, $src, 0, 0, $src_x, $src_y,
$def_width, $def_height, $new_width, $new_height);
Header("Content-type: image/".($make_png?'png':'jpeg'));
if ($make_png) {
ImagePng($dst);
if ($use_cache) {
ImagePng($dst, $thumb_file);
}
} else {
ImageJpeg($dst, null, 95);
if ($use_cache) {
ImageJpeg($dst, $thumb_file, 95);
}
}
@ImageDestroy($src);
@ImageDestroy($dst);
?>
The function readfile
should be faster.
If you are using PHP as an Apache module, you can also look into virtual
.
Please define "seems" and "very slow" in terms of certain numbers.
Otherwise there can be answers only in the same terms - "it seems you can roughly get something".
Anyone who is asking "How can I speed up" should answer to these questions first:
- what certain operation I want to speed up
- what certain amount of time it takes at the moment.
- what certain amount of time will suit me.
According to my own not-so-perfect tests, serving pictures via PHP is 2 times slower than via web-server itself. Reasonable I'd say, not "very slow".
So, if it runs "very slow" there could be some other reasons. Like this caching mechanism is not working at all due to some mistake. Or something. Some profiling, as well as debugging is required before anyone can help.
Especially for ones who will squeak "This is not an answer!" (because of that silly assumption that answer counts only it it's direct and positive), here is a link for the OP to learn from:
http://shiftingpixel.com/2008/03/03/smart-image-resizer/
a same on the fly thumbnail creation script but with " Not Modified" HTTP cache implementation.
If your web server supports it, X-Sendfile
might help speed things up.
Move to PHP5.
PHP 4 had several bugs that caused all forms of fread to be slow down and leak memory. Based on your description, that's sounds like what you are up against.
Upgrade, preferably at least to 5.3+
精彩评论