簡體   English   中英

使用imagick處理未知圖像

[英]Handling unknown images with imagick

正如人們已經發現的那樣,當試圖將文件加載到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'

但是,以下代碼可以將ICO文件重命名為icon.jpg。

$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()函數將不接受。

最好的方法是什么?

的確,您不能信任文件名,但是某些文件格式沒有唯一的魔術文件簽名或模糊的標識符。 當ImageMagick讀取圖像時,它將嘗試信任魔術簽名FIRST,如果無法解析圖像類型,則回退到文件擴展名。

正如您已經正確發現的那樣,從文件描述符讀取圖像不允許ImageMagick退回文件擴展名,因此您有責任在調用Imagick::readImageFile之前告訴Imagick有關格式。

最好的方法是什么?

您必須說明允許的內容。 內置的FileInfo方法mime_content_typefinfo_buffer是一個很好的開始(但並非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人員可以提供幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM