使用 PHP 和 MySQL 缓存调整大小的图像的最佳方法
使用 PHP 处理图像缓存的最佳实践方法是什么?
文件名当前存储在 MySQL 数据库中,该数据库在上传时与原始文件名和 alt 标记一起重命名为 GUID。
当图像被放入 HTML 页面时,它是使用 '/images/get/200x200/{guid}.jpg 之类的 url 来完成的,该 url 被重写为 php 脚本。 这允许我的设计师指定(粗略地 - 源图像可能更小)文件大小。
然后,php 脚本创建大小(url 中为 200x200)和 GUID 文件名的散列,如果之前已生成该文件(TMP 目录中存在具有散列名称的文件),则从应用程序 TMP 目录发送该文件。 如果散列文件名不存在,则会创建它,将其写入磁盘并以相同的方式提供服务,
这是否高效? (它还支持对图像加水印,并且水印设置也存储在哈希中,但这超出了范围。)
What would be the best practice way to handle the caching of images using PHP.
The filename is currently stored in a MySQL database which is renamed to a GUID on upload, along with the original filename and alt tag.
When the image is put into the HTML pages it is done so using a url such as '/images/get/200x200/{guid}.jpg which is rewritten to a php script. This allows my designers to specify (roughly - the source image maybe smaller) the file size.
The php script then creates a hash of the size (200x200 in the url) and the GUID filename and if the file has been generated before (file with the name of the hash exists in TMP directory) sends the file from the application TMP directory. If the hashed filename does not exist, then it is created, written to disk and served up in the same manner,
Is this efficient as it could be? (It also supports watermarking the images and the watermarking settings are stored in the hash as well, but thats out of scope for this.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我会用不同的方式来做。
问题:
1. 让 PHP 提供文件服务的效率低于其应有的水平。
2. PHP每次请求图像时都必须检查文件是否存在
3. Apache 在这方面比 PHP 做得更好。
这里有一些解决方案。
您可以在 Apache 上使用
mod_rewrite
。 可以使用 mod_rewrite 来测试文件是否存在,如果存在,则提供该文件。 这完全绕过了 PHP,并且使速度变得更快。 不过,真正做到这一点的方法是生成一个应该始终存在的特定 URL 架构,如果不存在则重定向到 PHP。例如:
如果客户端请求
/images/cached/
并且该文件尚不存在,Apache 会将请求重定向到/images/generate.php?/图片/缓存/<某事>
。 然后,该脚本可以生成图像,将其写入缓存,然后将其发送到客户端。 将来,除了新图像之外,不再调用 PHP 脚本。使用缓存。 正如另一位发帖者所说,使用 mod_expires、Last-Modified 标头等来响应条件 GET 请求。 如果客户端不必重新请求图像,页面加载速度将显着加快,服务器上的负载也会减少。
对于必须从 PHP 发送图像的情况,您可以使用 mod_xsendfile 以更少的开销来完成此操作。 请参阅 Arnold Daniels 关于此问题的优秀博客文章,但请注意,他的示例用于下载。 要内联提供图像,请取出 Content-Disposition 标头(第三个 header() 调用)。
希望这会有所帮助——在我的偏头痛消失后会有更多帮助。
I would do it in a different manner.
Problems:
1. Having PHP serve the files out is less efficient than it could be.
2. PHP has to check the existence of files every time an image is requested
3. Apache is far better at this than PHP will ever be.
There are a few solutions here.
You can use
mod_rewrite
on Apache. It's possible to use mod_rewrite to test to see if a file exists, and if so, serve that file instead. This bypasses PHP entirely, and makes things far faster. The real way to do this, though, would be to generate a specific URL schema that should always exist, and then redirect to PHP if not.For example:
So if a client requests
/images/cached/<something>
and that file doesn't exist already, Apache will redirect the request to/images/generate.php?/images/cached/<something>
. This script can then generate the image, write it to the cache, and then send it to the client. In the future, the PHP script is never called except for new images.Use caching. As another poster said, use things like
mod_expires
, Last-Modified headers, etc. to respond to conditional GET requests. If the client doesn't have to re-request images, page loads will speed dramatically, and load on the server will decrease.For cases where you do have to send an image from PHP, you can use
mod_xsendfile
to do it with less overhead. See the excellent blog post from Arnold Daniels on the issue, but note that his example is for downloads. To serve images inline, take out the Content-Disposition header (the third header() call).Hope this helps - more after my migraine clears up.
Dan Udey 的重写示例中有两个拼写错误(我无法对此发表评论),它应该是:
问候。
There is two typos in Dan Udey's rewrite example (and I can't comment on it), it should rather be :
Regards.
值得添加的一个注释是确保您的代码不会生成这些图像的“未经授权”大小。
因此,以下 URL 将创建图像 1234 的 200x200 版本(如果尚不存在)。 我强烈建议您确保请求的网址包含您支持的图像尺寸。
恶意者可能会开始请求随机 URL,并始终更改高度和长度。 图像的宽度。 这会导致您的服务器出现一些严重的问题,因为它会坐在那里,基本上受到攻击,生成您不支持的尺寸的图像。
这是一段随机的代码片段来说明这一点:
One note worth adding is to make sure you're code does not generate "unauthorized" sizes of these images.
So the following URL will create a 200x200 version of image 1234 if one doesn't already exist. I'd highly suggest you make sure that the requested URL contains image dimensions you support.
A malicious person could start requesting random URLs, always altering the height & width of the image. This would cause your server some serious issues b/c it will be sitting there, essentially under attack, generating images of sizes you do not support.
Here's a random snip of code illustrating this:
看起来很棒的帖子,但我的问题仍然没有解决。 我无法访问我的主机提供商中的 htaccess,因此不存在 apache 调整的问题。 真的有办法为图像设置 cace-control 标头吗?
Seems great post, but my problem still remains unsolved. I dont have access to htaccess in my host provider, so no question of apache tweaking. Is there really a way to set cace-control header for images?
您的方法似乎相当合理 - 我想补充一点,应该采取某种机制来检查缓存版本的生成日期是否在原始(源)图像文件的最后修改时间戳之后,如果不重新生成缓存/调整大小的版本。 这将确保如果设计者更改图像,缓存将得到适当更新。
Your approach seems quite reasonable - I would add that some mechanism should be put into place to check that the date the cached version was generated was after the last modified timestamp of the original (source) image file and if not regenerate the cached/resized version. This will ensure that if an image is changed by the designers the cache will be updated appropriately.
这听起来是一个可靠的方法。 下一步可能会超越 PHP/MySQL。
也许,调整您的标头:
如果您使用 PHP 发送 MIME 类型,您还可以使用“Keep-alive”和“Cache-control”标头来延长图像在服务器上的寿命并减轻 PHP/MySQL 的一些负担。
另外,还可以考虑使用 apache 插件进行缓存。 就像 mod_expires 一样。
哦,还有一件事,你对你的服务器有多少控制权? 我们是否应该将此对话限制为仅仅 PHP/MySQL?
That sounds like a solid way to do it. The next step may be to go beyond PHP/MySQL.
Perhaps, tweak your headers:
If you're using PHP to send MIME types, you might also use 'Keep-alive' and 'Cache-control' headers to extend the life of your images on the server and take some of the load off of PHP/MySQL.
Also, consider apache plugin(s) for caching as well. Like mod_expires.
Oh, one more thing, how much control do you have over your server? Should we limit this conversation to just PHP/MySQL?
我已经成功地使用 PHP 中的重定向标头来做到这一点:
I've managed to do this simply using a redirect header in PHP:
与将文件地址保留在数据库中不同,我更喜欢在用户登录时向文件名中添加一个随机数。对于用户 1234 来说是这样的: image/picture_1234.png?rnd=6534122341
如果用户在登录期间提交新图片session我只是刷新随机数。
GUID 100% 解决了缓存问题。 然而,这使得跟踪图片文件变得更加困难。 使用此方法,用户有可能在将来登录时再次看到相同的图片。 然而,如果您从十亿个数字中生成随机数,则几率很低。
Instead of keeping the file address in the db I prefer adding a random number to the file name whenever the user logs in. Something like this for user 1234: image/picture_1234.png?rnd=6534122341
If the user submits a new picture during the session I just refresh the random number.
GUID tackles the cache problem 100%. However it sort of makes it harder to keep track of the picture files. With this method there is a chance the user might see the same picture again at a future login. However the odds are low if you generate your random number from a billion numbers.
phpThumb 是一个可以动态生成调整大小的图像/缩略图的框架。 它还实现了缓存并且非常容易实现。
调整图像大小的代码是:
将为您提供 200 x 200 的缩略图;
它还支持水印。
检查一下:
http://phpthumb.sourceforge.net/
phpThumb is a framework that generates resized images/thumbnails on the fly. It also implements caching and it's very easy to implement.
The code to resize an image is:
will give you a thumbnail of 200 x 200;
It also supports watermarking.
Check it out at:
http://phpthumb.sourceforge.net/