防止 GD 图像库内存不足的故障安全方法?(菲律宾比索)

A fail-safe way to prevent GD image library from running out of memory? (PHP)

提问人:deceze 提问时间:7/13/2009 最后编辑:deceze 更新时间:10/20/2012 访问量:8925

问:

有没有办法防止 PHP GD 镜像库内存不足?如果上传的图像太大,GD 往往会耗尽内存,从而终止脚本。我希望它抛出一个可捕获的异常或其他东西,但可惜它没有。

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

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

PHP 内存 GD

评论

1赞 Steve-o 1/6/2011
大型 JPEG 图像(非 PNG 或其他类型)可以在加载时调整大小,有关详细信息,请参阅此答案:stackoverflow.com/questions/12661/...
0赞 JSG 11/15/2019
这取决于您有多少内存。如果您有 512mb 的内存,并且您正在尝试调整大约 10k 像素的 png 图像的大小。您几乎会立即达到 1.5GB 的内存使用量。我的建议是 A) 获取更多内存 B) 使用函数来构建图像,销毁它们,并使用内存使用函数来查看每个处理过的图像。使用 flush 函数转储并清除缓冲区...

答:

3赞 Nick Presta 7/13/2009 #1

购买更多内存!9-3

但说真的,处理内存不足是不可能的,因为您采取的任何操作都需要更多的内存。

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

评论

2赞 deceze 7/13/2009
哈哈,给我买一个内存更大的主机。;-)好吧,我至少希望 GD 估计自己的内存使用情况,而不是我不得不做容易出错的猜测,然后屏住呼吸。我不能只按文件大小限制图像。具有高度压缩、高分辨率 JPG 的小文件可能比具有低分辨率 PNG 的大文件占用更多的内存。这就是为什么我必须依靠上面提到的计算。
0赞 jsnfwlr 7/13/2009 #2

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

评论

0赞 deceze 7/13/2009
这就是我正在尝试做的事情,但这在共享主机上几乎是不可能的。对于这些情况,我正在做最佳猜测计算以防止挂断。
1赞 Ted Phillips 8/14/2017
将 PHP 内存限制设置为等于系统拥有的 RAM 总量,或远程设置在它附近的任何地方,将允许用户通过映像脚本对您进行 DOS。事先弄清楚需要多少RAM是我能想到的唯一方法,可以防止这种类型的DOS。
1赞 jsnfwlr 7/14/2009 #3

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

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

评论

0赞 deceze 7/14/2009
再读一遍,AFAIK 没有什么可以抓住的。这是一个一次性的操作,要么行不通。除非你能告诉我如何捕获内存不足错误,这就是我所要求的。:)
0赞 deceze 7/26/2009
我必须看看这是否真的有帮助,正如 Nick 所指出的,我必须在错误发生后使用更多内存来处理错误。
1赞 Maya75 8/11/2009 #4

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

评论

1赞 scotts 2/13/2010
一旦 PHP 脚本内存不足,它就无法调用 shutdown 函数,因为这需要分配更多内存。
2赞 Kevin Baker 4/19/2012 #5

创建映像后。

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

将消除内存问题

评论

0赞 Vic 12/24/2015
这应该被标记为答案,它对我来说就像一个魅力。
2赞 Glutexo 3/1/2016
不应标记为答案。销毁映像可以节省内存使用量,但绝不会使 GD 的行为更优雅。
2赞 StrikeAgainst 11/21/2019
投反对票。这不是一个解决方案,而是避免内存泄漏的标准过程。它不会阻止 GD 导致内存溢出,如果仅一个图像就已经足够大到足以达到内存限制。
1赞 sebbu 6/28/2012 #6

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

  • imagecreatetruecolor似乎需要.width*height*5 bytes

  • imagepng似乎需要.width*height*4 bytes

评论

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