2008-09-26 93 views
14

使用PHP处理图像缓存的最佳实践方式是什么?使用PHP和MySQL缓存调整大小的图像的最佳方法

当前文件名存储在MySQL数据库中,该数据库与原始文件名和alt标记一起被重命名为上传的GUID。

当图像被放入HTML页面时,使用诸如'/images/get/200x200/{guid}.jpg'这样的URL来重写为一个php脚本。这允许我的设计人员指定(大致 - 源图像可能更小)的文件大小。

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

这是否有效,因为它可能是? (它也支持加水印图像和水印设置存储在哈希中,但这不在此范围内)。

回答

10

有于丹Udey的重写例如两个错别字(我不能对此发表评论),它应该是:

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

问候。

0

您的方法看起来相当合理 - 我会补充说一些机制应该到位检查缓存版本的生成日期是否是原始(源)图像文件的最后修改时间戳之后,如果不重新生成缓存/调整大小的版本。这将确保如果设计者更改了图像,缓存将被适当更新。

+0

不错的建议,但... 如果通过上传的新映像(通过管理界面)更改源,则会生成新的GUID,并且缓存的文件名将不再匹配。 图像不应该与(s)FTP上传,但我们都知道假设。 ;) 无论如何将看看实现。 – 2008-09-26 17:31:46

+0

我还检查图像是否被缓存_after_对缓存脚本进行了任何修改,即if(filemtime($ cached_image)> filemtime($ _ SERVER ['SCRIPT_FILENAME'])){...}` – 2011-05-01 12:33:52

0

这听起来像一个坚实的方式来做到这一点。下一步可能是超越PHP/MySQL。

也许,调整你的头

如果您使用PHP发送MIME类型,你也可以使用“保活”和“缓存控制”头扩展您的图像的生活在服务器上,并采取一些PHP/MySQL的负载。

另外,考虑apache插件(s)为缓存以及。像mod_expires

哦,还有一件事,你有多少控制你的服务器?我们是否应该限制这个对话只是 PHP/MySQL?

+0

该应用程序托管在VPS上,所以我有root权限。 mod_expires已安装,因此看起来像一个简单的.htaccess调整可以减少服务器的负载。 好的提示,谢谢。 – 2008-09-26 17:35:16

0

phpThumb是一个框架,可以即时生成调整大小的图像/缩略图。它也实现了缓存,实现起来非常简单。

来调整图像的代码是:

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

会给你的200×200的缩略图;

它还支持加水印。

瞧瞧吧: http://phpthumb.sourceforge.net/

5

一注值得加入是为了确保你的代码不会产生这些图像的“未经授权”的大小。

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

/images/get/200x200/1234.jpg 

有恶意的人可以先要求随机网址,总是改变图像的高度&宽度。这将导致您的服务器出现一些严重问题,它将坐在那里,基本上处于受到攻击的状态,从而生成您不支持的尺寸图像。

/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 
    } 
?> 
+0

使用die()是可怕的代码。您基本上都会纾困,将一行文本转储到客户端,而不进行任何纠错。如果在生产中使用此示例,请使用替换图像或有用的错误替换die()调用。 – 2008-09-26 19:19:32

+0

我同意你的意见。它只是示例代码,以获得只是 – phatduckk 2008-09-27 05:16:18

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标头(第三个标头()调用)。

希望这可以帮助 - 更多的是在我的偏头痛结束后。

1

似乎伟大的文章,但我的问题仍然没有解决。我没有访问我的主机提供商的htaccess,所以没有问题的Apache调整。真的有办法为图像设置cace-control标题吗?

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"); 
} 
0

而是保持文件的地址在数据库中,我更喜欢加入一个随机数的文件名每当事情是这样的,用户登录用户1234:?图像/ picture_1234.png RND = 6534122341

如果用户在会议期间提交了一张新照片,我只刷新了随机数。

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