正如人们已经发现的那样,当试图将文件加载到Imagick中时,无论出于何种原因它都无法处理,它将抛出一个无法捕获的异常。
我创建了一个ICO文件并尝试使用readImageFile()加载它:
$image = new imagick();
$handle = fopen('icon.ico', 'rb');
$image->readImageFile($handle);
这将抛出:
PHP Fatal error: Uncaught exception 'ImagickException' with message 'no decode delegate for this image format `' @ error/constitute.c/ReadImage/501'
当我指定图像将是ICO文件时,它可以工作。所以这段代码运行良好:
$image = new imagick();
$image->setFormat('ICO');
$handle = fopen('icon.ico', 'rb');
$image->readImageFile($handle);
使用readFile而不是readImageFile,它显然会查看扩展名,因为这段代码运行正常:
$image = new imagick();
$image->readimage('icon.ico');
但是,当我将ICO文件重命名为icon.jpg并运行时:
$image = new imagick();
$image->readimage('icon.jpg');
失败并出现以下错误:
PHP Fatal error: Uncaught exception 'ImagickException' with message 'Not a JPEG file: starts with 0x00 0x00 `icon.jpg' @ error/jpeg.c/JPEGErrorHandler/322'
但是,以下代码处理重命名为icon.jpg的ICO文件:
$image = new imagick();
$image->setFormat('ICO');
$handle = fopen('icon.jpg', 'rb');
$image->readImageFile($handle);
显然,处理图像的最佳方法是不要查看扩展名,这可能是任何内容,但请查看实际文件。 Imagick显然没有做到这一点。我们有PHP函数,如mime_content_type(),getimagesize()和finfo_buffer()(PHP.net建议我认为)。但是它们将返回类似“image / x-icon”的东西,setFormat()函数不会这样做。
最好的方法是什么?
答案 0 :(得分:0)
确实,您无法信任文件名,但某些文件格式没有唯一的魔术文件签名,或者具有模糊的标识符。当ImageMagick读取图像时,它会尝试信任魔术签名FIRST,如果无法解析图像类型,则会回退到文件扩展名。
正如您所发现的那样,从文件描述符中读取图片并不允许ImageMagick回退到文件扩展名,因此您需要负责告诉Imagick
关于调用Imagick::readImageFile
之前的格式。
最好的方法是什么?
你必须明白允许的内容。内置的FileInfo方法mime_content_type
& finfo_buffer
是一个好的开始(但不是万无一失)。但是如果您已经打开了文件描述符,我会建议"偷看"在数据......
$filename = 'untrusted';
$handle = open($filename, 'rb');
// Allow the most common & modern formats to work as expected.
try {
$image = new Imagick();
// Pass original file name for IM fall-back
$image->setFilename($filename);
$image->readImageFile($handle);
// Attempt to handle specific formats.
} catch (ImagickException $e) {
// Create new instance
$image = new Imagick();
// Rewind FD
fseek($handle, 0);
// Read first four bytes
$peek = fread($handle, 4);
// Collect MIME-TYPE
$mime = mime_content_type($filename);
// Explicitly allow KNOWN formats. (also see http://www.garykessler.net/library/file_sigs.html)
if ($mime == 'image/x-icon' && $peek == "\x00\x00\x01\x00") {
$image->setFormat('ICO');
} else if ($mime == 'image/x-icon' && $peek == "\x00\x00\x02\x00") {
$image->setFormat('CUR');
} else {
// Error handle
}
fseek($handle, 0); // Rewind again.
$image->readImageFile($handle);
}
YMMV,我确信有更好的PHP人员可以提供帮助。