使用PHP和MySQL缓存已调整大小的图像的最佳方法

时间:2008-09-26 17:13:31

标签: php image caching resize

使用PHP处理图像缓存的最佳实践方法是什么。

文件名目前存储在MySQL数据库中,该数据库在上传时重命名为GUID,以及原始文件名和alt标记。

当将图像放入HTML页面时,使用诸如'/images/get/200x200/{guid}.jpg之类的URL来完成它,该URL被重写为php脚本。这允许我的设计者指定(​​粗略地 - 源图像可能更小)文件大小。

php脚本然后创建一个大小的哈希值(在url中为200x200)和GUID文件名,如果之前生成了文件(TMP目录中存在哈希名称的文件),则从应用程序发送文件TMP目录。如果散列文件名不存在,则创建它,写入磁盘并以相同方式提供,

这有效吗? (它还支持对图像加水印,并且水印设置也存储在哈希中,但这超出了范围。)

9 个答案:

答案 0 :(得分:30)

我会以不同的方式做到这一点。

问题: 1.让PHP提供文件的效率低于可能的效率。 2.每次请求图像时,PHP都必须检查文件是否存在 3. Apache远比PHP好得多。

这里有一些解决方案。

您可以在Apache上使用mod_rewrite。可以使用mod_rewrite来测试文件是否存在,如果存在,则改为提供该文件。这完全绕过了PHP,使事情变得更快。但是,实现此目的的真正方法是生成应始终存在的特定URL模式,然后重定向到PHP。

例如:

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

因此,如果客户端请求/images/cached/<something>并且该文件尚不存在,则Apache会将请求重定向到/images/generate.php?/images/cached/<something>。然后,此脚本可以生成映像,将其写入缓存,然后将其发送到客户端。将来,除了新图像之外,永远不会调用PHP脚本。

使用缓存。正如另一张海报所说,使用诸如mod_expires,Last-Modified标头等内容来响应条件GET请求。如果客户端不必重新请求图像,则页面加载速度会急剧增加,服务器上的加载也会减少。

对于必须从PHP发送图像的情况,您可以使用mod_xsendfile来减少开销。有关此问题,请参阅the excellent blog post from Arnold Daniels,但请注意,他的示例适用于下载。要内联提供图像,请取出Content-Disposition标头(第三个header()调用)。

希望这会有所帮助 - 在我的偏头痛清除后更多。

答案 1 :(得分:10)

Dan Udey的重写示例中有两个错别字(我无法评论),应该是:

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

问候。

答案 2 :(得分:5)

值得添加的一个注意事项是确保您的代码不会生成这些图像的“未经授权”尺寸。

因此,如果尚不存在,则以下URL将创建200x200版本的图像1234。我高度建议您确保所请求的网址包含您支持的图片尺寸。

/images/get/200x200/1234.jpg

恶意的人可能会开始请求随机网址,总是会改变高度和高度。图像的宽度。这会导致你的服务器出现一些严重的问题b / c它会坐在那里,基本上受到攻击,生成你不支持的大小的图像。

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

这是一段随机的代码片段,说明了这一点:

<?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
    }
?>

答案 3 :(得分:1)

似乎很棒,但我的问题仍然没有解决。我无法在我的主机提供商中访问htaccess,因此不存在apache调整的问题。有没有办法为图像设置cace-control标头?

答案 4 :(得分:0)

你的方法似乎很合理 - 我想补充一点,应该建立一些机制来检查生成缓存版本的日期是在原始(源)映像文件的最后修改时间戳之后,如果没有重新生成缓存/重新调整版本。这将确保如果设计人员更改了图像,则缓存将被适当更新。

答案 5 :(得分:0)

这听起来像是一种可行的方式。下一步可能是超越PHP / MySQL。

也许,调整标题

如果您使用PHP发送MIME类型,您还可以使用“保持活动”和“缓存控制”标头来延长服务器上图像的使用寿命,并从PHP中获取一些负载/的MySQL。

另外,请考虑使用apache插件进行缓存。与mod_expires一样。

哦,还有一件事,你对服务器有多少控制权?我们应该将此对话限制为只是 PHP / MySQL吗?

答案 6 :(得分:0)

phpThumb 是一个动态生成调整大小的图像/缩略图的框架。它还实现了缓存,并且很容易实现。

调整图片大小的代码是:

<img src="/phpThumb.php?src=/path/to/image.jpg&w=200&amp;h=200" alt="thumbnail"/>

会给你一个200 x 200的缩略图;

它还支持水印。

查看时间: http://phpthumb.sourceforge.net/

答案 7 :(得分:0)

我设法在PHP中使用重定向标头来实现这一点:

if (!file_exists($filename)) {  

    // *** Insert code that generates image ***

    // Content type
    header('Content-type: image/jpeg'); 

    // Output
    readfile($filename);    

} else {
    // Redirect
    $host  = $_SERVER['HTTP_HOST'];
    $uri   = rtrim(dirname($_SERVER['PHP_SELF']), '/\\');
    $extra = $filename;
    header("Location: http://$host$uri/$extra");
}

答案 8 :(得分:0)

除了将文件地址保留在db中之外,我更喜欢在用户登录时向文件名中添加一个随机数。对于用户1234,这样的事情是这样的:image / picture_1234.png?rnd = 6534122341

如果用户在会话期间提交新图片,我只需刷新随机数。

GUID 100%解决缓存问题。然而,它更难以跟踪图片文件。使用此方法,用户可能会在将来登录时再次看到相同的图片。但是,如果您从十亿个数字生成随机数,则赔率很低。