2017-08-18 8 views
0

Comme les gens l'ont déjà constaté, lorsque vous tentez de charger un fichier dans Imagick qu'il ne peut pas gérer pour une raison quelconque, il lancera une exception qui ne peut pas être interceptée.Gestion des images inconnues avec imagick

J'ai créé un fichier ICO et tenter de le charger en utilisant readImageFile():

$image = new imagick(); 
$handle = fopen('icon.ico', 'rb'); 
$image->readImageFile($handle); 

Cela jette:

PHP Fatal error: Uncaught exception 'ImagickException' with message 'no decode delegate for this image format `' @ error/constitute.c/ReadImage/501' 

Quand je précise l'image sera un fichier ICO, cela fonctionne . Donc, ce code fonctionne très bien:

$image = new imagick(); 
$image->setFormat('ICO'); 
$handle = fopen('icon.ico', 'rb'); 
$image->readImageFile($handle); 

En utilisant readFile au lieu de readImageFile, il semble apparemment à l'extension, car ce code fonctionne aussi très bien:

$image = new imagick(); 
$image->readimage('icon.ico'); 

Cependant, quand je Renommez le fichier ICO à l'icône .jpg et exécutez ceci:

$image = new imagick(); 
$image->readimage('icon.jpg'); 

Il échoue avec l'erreur suivante:

PHP Fatal error: Uncaught exception 'ImagickException' with message 'Not a JPEG file: starts with 0x00 0x00 `icon.jpg' @ error/jpeg.c/JPEGErrorHandler/322' 

Le code suivant, cependant, gère le fichier ICO renommé icon.jpg fin:

$image = new imagick(); 
$image->setFormat('ICO'); 
$handle = fopen('icon.jpg', 'rb'); 
$image->readImageFile($handle); 

Il est évident que la meilleure façon de gérer les images est de ne pas regarder l'extension, ce qui pourrait être quelque chose, mais regardez au fichier réel. Imagick ne parvient apparemment pas à faire cela. Nous avons des fonctions PHP telles que mime_content_type(), getimagesize() et finfo_buffer() (que PHP.net recommande je pense). Mais ils renverront quelque chose comme "image/x-icon", que la fonction setFormat() ne prendra pas.

Quelle serait la meilleure façon de procéder?

Répondre

0

Il est vrai que vous ne pouvez pas faire confiance au nom de fichier, mais certains formats de fichiers n'ont pas de signature de fichier magique unique, ou ont un identifiant vague. Lorsque ImageMagick lit une image, il essaie de faire confiance à la signature magique FIRST et retombe à l'extension si elle ne peut pas résoudre le type d'image. Comme vous avez pu le constater, lire une image à partir d'un descripteur de fichier ne permet pas à ImageMagick de revenir sur l'extension de fichier. Vous devez donc indiquer le format Imagick avant d'appeler le Imagick::readImageFile.

What would be the best way to go about this?

Vous devez expliquer ce qui est autorisé. Les méthodes intégrées de FileInfo mime_content_type & finfo_buffer sont un bon début (mais pas la preuve de fou). Mais si vous avez déjà d'un descripteur de fichier ouvert, je recommanderais « jeter un oeil » à des données ...

$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, et je suis sûr qu'il ya des gens meilleurs PHP qui peuvent aider.

+0

Nice, Merci pour votre réponse! Malheureusement, ce ne sont pas seulement les fichiers ICO que je dois autoriser, mais tout un tas. J'ai convaincu le client de composer une liste blanche. J'espérais que finfo_buffer était suffisamment infaillible. Maintenir ma propre liste de signatures de 4 octets pour tout un tas de types de fichiers ne semble pas idéal. Je souhaitais juste que Imagick ne rate pas si spectaculairement chaque fois qu'il ne peut pas détecter le bon type de fichier. –

+0

Il est peut-être temps de réévaluer l'architecture de la solution. Vous devriez faire l'effort de passer le nom de fichier original 'Imagick'. Il est également très courant que des exceptions soient déclenchées, de sorte que l'application devrait être en mesure d'anticiper et de gérer ces exceptions. – emcconville

+0

Je ne suis pas sûr de pouvoir faire confiance au nom de fichier original, car je ne fais pas confiance à mes utilisateurs. Comme je comprends de cette question, quand Imagemagick jette une erreur fatale, il n'y a pas grand-chose que vous pouvez faire pour l'attraper: https://stackoverflow.com/questions/28156447/how-do-i-catch-an-imagick-fatal -error-in-php –