防止GD图像库内存不足的故障安全方法? (PHP)

Posted

技术标签:

【中文标题】防止GD图像库内存不足的故障安全方法? (PHP)【英文标题】:A fail-safe way to prevent GD image library from running out of memory? (PHP) 【发布时间】:2009-07-13 00:49:24 【问题描述】:

有没有办法防止 php GD image library 内存不足?如果上传的图片太大,GD 往往会耗尽内存,终止脚本。我希望它抛出一个可捕获的异常或类似的东西,但可惜它没有。

现在我正在使用一个拼凑的脚本,它首先发出一个ini_set('memory_limit', '128M'),如果这样我通常都准备好了。取决于服务器配置,尽管这可能是不可能的,所以我依靠一种算法来尝试估计所需的内存量(考虑分辨率、颜色深度、通道和软糖因素),然后将其与memory_get_usage()如果函数存在,则进行粗略估计。

到目前为止,整个事情都有效,但它远非优雅,并且在某些极端情况下会失败,我敢肯定。有没有更好的方法来做到这一点,即如果必须让 GD 优雅地失败,而不是让一切都停下来?

【问题讨论】:

大型 JPEG 图像(非 PNG 或其他类型)可以在加载时调整大小,有关详细信息,请参阅此答案:***.com/questions/12661/… 这取决于你有多少内存。如果您有 512mb 的内存,并且您正在尝试调整大约 10k 像素的 png 图像的大小。您将几乎立即达到 1.5GB 的 ram 使用量。我的建议是 A) 获得更多内存 B) 使用函数来构建图像并破坏它们,并使用内存使用函数来查看每个处理后的图像。使用刷新函数转储和清除缓冲区... 【参考方案1】:

购买更多内存! :-P

说真的,无法处理内存不足的问题,因为您执行的任何操作都需要更多内存。

最好的办法是根据当前内存设置限制上传的图片大小。

【讨论】:

大声笑,给我买一台内存更大的主机。 ;-) 好吧,我至少希望 GD 估计它自己的内存使用情况,而不是我不得不做容易出错的猜测然后屏住呼吸。我不能只通过文件大小来限制图像。具有高度压缩、高分辨率 JPG 的小文件可能比具有低分辨率 PNG 的大文件占用更多内存。这就是为什么我不得不依靠上面提到的计算。【参考方案2】:

创建图像后。

imagepng($image);
imagedestroy($image);

将消除内存问题

【讨论】:

这应该被标记为答案,它对我来说就像一个魅力。 这应该被标记为答案。销毁图像可以节省内存使用,但绝不会使 GD 表现得更优雅。 投反对票。这不是解决方案,而是避免内存泄漏的标准过程。如果仅一个图像已经大到足以达到内存限制,它不会阻止 GD 导致内存溢出。【参考方案3】:

还有另一种方法,但它可能会很耗时,因为图像编辑过程的某些部分会重复多次,但您可以将内存限制设置为您的估计值,然后尝试处理图像,如果它失败捕获异常,增加内存限制,然后再次处理图像 - 重复此操作直到你成功或达到某个内存限制 - 此时你会向用户抛出一条错误消息,解释他们的图像太大而无法使用。

编辑:要捕获内存不足错误,您可以使用以下解决方案:http://au2.php.net/set_error_handler#35622

【讨论】:

再读一遍,AFAIK 没有什么可捕获的东西被抛出。这是一个一次性的工作或它不操作。除非你能告诉我如何捕捉内存不足的错误,这就是我所要求的。 :) 我必须看看这是否真的有帮助,正如 Nick 所说,我必须在错误发生后使用更多内存来处理错误。【参考方案4】:

要捕获 PHP 的致命错误,例如“内存不足”或“PHP 致命错误:允许的内存大小为 8388608 字节已用尽(试图分配…字节)”,请参见此处:http://php.net/manual/en/function.set-error-handler.php#88401

【讨论】:

一旦 PHP 脚本内存不足,它就无法调用关闭函数,因为这需要分配更多内存。【参考方案5】:

做一些测试来检查每个gd函数需要多少内存。

imagecreatetruecolor 似乎需要width*height*5 bytes

imagepng 似乎需要width*height*4 bytes

【讨论】:

为什么imagecreatetruecolor 每个像素需要 5 个字节?听起来是个奇数。 因为 alpha 支持是在 imagecreate 之后很久才添加的,而且很多函数可能假设第 4 字节总是 0,所以它不能被使用......或者他们认为/看到它太复杂了,无法使用它并创建了一个新的。 您是否也有在其上加载现有图像的经验?例如对于jpg还是png?我使用 x * y * ~5 表示 jpg, ~8 表示 png,在当前内存使用情况之上。如果超过内存限制,我设置一个例外。但是:将 64M 设置为限制并上传 2MB 的 jpg 有时会破坏操作。 Jpg 似乎有时会使用更多的内存。压缩?还有其他exif数据吗?哪里可以改进计算? 所有对 imagepng、imagejpeg、imagegif、imagebmp、imagewbmp、imagexbm、imagewebp、imagegd、imagegd2 的调用将使用宽度 * 高度 * 一些 coef 字节,除了现有的资源(来自所有 imagecreate , imagecreatetruecolor 和 imagecreatefrom*) (可能还有一些用于压缩、格式和所有的临时内存)。 imageloadfont 和 imagepsloadfont 也会使用一些内存。必须使用 imdestroy 销毁旧资源以避免泄漏。【参考方案6】:

您最好的选择是停止尝试计算它需要多少内存,一开始就将其最大化 - 如果您有 4 GB 可用,请告诉图像脚本使用 2 到 4 GB 左右,当脚本结束时,让它恢复正常,这将涵盖所有潜在的致命情况。无论如何,这是我能想到的唯一“故障安全”方式......

【讨论】:

这就是我正在尝试做的事情,但这在共享主机上几乎不可能。对于这些情况,我正在做最佳猜测计算以防止挂断。 将 PHP 内存限制设置为等于系统拥有的 RAM 总量,或任何远程接近它的地方,将允许用户通过您的图像脚本对您执行 DOS。事先确定需要多少 RAM 是我能想到的唯一方法,这可以防止这种类型的 DOS。

以上是关于防止GD图像库内存不足的故障安全方法? (PHP)的主要内容,如果未能解决你的问题,请参考以下文章

GD 中支持的格式以使用 php 保存图像

GD中支持的格式使用php保存图像

PHP使用GD2库画图,图像无法输出解决方法

PHP GD 方法 imagecopy 比原始图像更大的图像文件

提高 PHP GD 生成图像的质量

实现这种图像效果的最佳方法是啥?使用 PHP GD 或 JS Canvas?