高效检测损坏的jpeg文件?

19

有没有一种有效的方法来检测jpeg文件是否损坏?

背景信息:
  解决方案需要在php脚本内执行
  jpeg文件存储在磁盘上
  手动检查不可行(用户上传数据)

我知道imagecreatefromjpeg(string $filename);可以做到。但是它在执行这个任务时速度很慢。

有人知道更快/更有效的解决方案吗?

8个回答

18

从命令行可以使用jpeginfo查看jpeg文件是否正常。

$ jpeginfo -c test.jpeg

test.jpeg 260 x 264 24位 JFIF N 15332 [OK]

从php中调用jpeginfo应该很简单。


2
请注意 OP 关于慢的备注:派生一个外部进程并处理返回值可能比 imagecreatefromjpeg() 还要慢! - Willem
虽然分叉外部进程速度较慢,但这是更好的选择。PHP在读取图像文件时对内存需求和速度都很糟糕。请参见特拉维斯的答案 - Jacco
1
ImageMagick中的'identify'功能还能检测出损坏的JPEG文件。 - Roger Lipscombe
1
谢谢。我尝试使用ImageMagick进行识别,虽然它可以工作,但速度很慢。 - Tom
识别工作...您可以使用类似于identify * | grep insufficient的命令在目录中使用它来查找有问题的JPEG文件,假设所有文件都是JPEG格式,否则只需使用*.jpeg来查找JPEG文件即可... - IamSierraCharlie
显示剩余2条评论

9

我最简单(也是最快)的解决方案:


function jpeg_file_is_complete($path) {
    if (!is_resource($file = fopen($path, 'rb'))) {
        return FALSE;
    }
    // check for the existence of the EOI segment header at the end of the file
    if (0 !== fseek($file, -2, SEEK_END) || "\xFF\xD9" !== fread($file, 2)) {
        fclose($file);
        return FALSE;
    }
    fclose($file);
    return TRUE;
}

function jpeg_file_is_corrupted($path) {
    return !jpeg_file_is_complete($path);
}

注意:此功能仅检测损坏的文件结构,但无法检测损坏的图像数据。

2
这的确很快,但无法检测到不完整的数据(在jpeg图像的下部显示为黑色)。 - Jacco
很高兴找到那些没有完全传输的图片。 - Max Sohrt
2
这种方法速度快但不准确。有效的JPEG文件在FFD9之后可能会有字节,而无效的JPEG文件可能以FFD9结尾。因此,这种方法会产生误报和漏报。 - Tom

7
FYI--我已经使用上面的方法(jpeg_file_is_complete来测试我知道是损坏的JPEG文件(例如,当我在浏览器中加载它们时,底部是灰色的,即图像被“截断”)。无论如何,当我对该图像运行上述测试时,它没有检测到它是损坏的。
到目前为止,使用imagecreatefromjpeg()可以工作,但速度不是很快。我发现使用jpeginfo也可以检测这些类型的损坏图像,并且比imagecreatefromjpeg更快(我在我的PHP中使用microtime()进行了基准测试)。

1
谢谢,检查jpeg_file_is_complete()功能仍在我的待办事项列表中。这样可以省下我时间 :) - Jacco
2
一个快速的跟进。我一直成功地使用"jpeginfo"来测试JPG文件,效果非常好。它运行速度快,并且不会出现误报。 - Travis

0
请尝试一下。
<?php
$img = $_GET['img'];
$str_exec = 'jpeginfo -c /chroot/home/www/html/media/'.$img;
$result = exec($str_exec);
if(strpos($result, 'ERROR'))
{
    echo 'ERROR';
}
else
{
    echo 'OK';
}
?>

注意在公共Web服务器上使用此功能时要小心:您正在直接将GET输入传递到命令行,从而可以轻松地进行shell漏洞攻击:如果我使用?img= rm - rf . 调用上述页面会怎样?它可能会删除当前目录中的所有文件。 - PanMan

0

只是一个小提示 - 如何在 Windows(64 位)上获取 jpeginfo? 作者的 GitHub 上没有 win32/win64 二进制文件,但您可以执行以下操作:

1)从此存档中获取jpeginfo.exe https://github.com/MoserMichael/cstuff/raw/master/img-archive/img-archive.zip

2)从此存档中获取cygwin1.dllftp://mirror.internode.on.net/pub/cygwin/x86/release/cygwin64/cygwin64-2.6.0-1.tar.xz

从命令行测试是否正常工作:jpeginfo --help 。 如果有信息,则表示可以正常工作。

如何测试jpeginfo输出?

jpeginfo返回0表示文件正常,但当它发现无法理解的内容时,它不仅会返回1,而且还会在生成以下消息:

警告:未知的JFIF修订号2.01 1280 x 720 24位JFIF N 122550 [WARNING]

对于损坏的文件,它将返回1和以下消息:

1328 x 2048 24位JFIF N 1310080 JPEG文件过早结束 [WARNING]

因此,您可能希望测试实际输出,而不仅仅是返回代码。


-1

您也可以尝试基于MD5生成文件哈希,并将其用作校验和以验证JPEG数据的各个步骤。例如,在从文件读取后,传输后等。


这适用于在系统内部移动文件,而不适用于检测进入系统之前已经损坏的文件。 - Jacco

-1

-3

我有另一种解决方案,可以使用简单的getimagesize()

if(!getimagesize($image_url)) echo 'Image is corrupt or not readable';

损坏的 Exif 数据可能会破坏文件的其余部分,但这种方法无法检测到它。 - S..
从PHP文档中:“*注意 此函数期望文件名是一个有效的图像文件。如果提供了非图像文件,则可能会错误地将其检测为图像,并且该函数将成功返回,但数组可能包含无意义的值。 不要使用getimagesize()来检查给定文件是否为有效图像。而应使用专门的解决方案,例如Fileinfo扩展。”*(http://php.net/manual/en/function.getimagesize.php) - Pang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接