2011-06-26 27 views
24

Me gustaría comprobar si un archivo cargado es un archivo de imagen (por ejemplo, png, jpg, jpeg, gif, bmp) u otro archivo. El problema es que estoy usando Uploadify para subir los archivos, lo que cambia el tipo de mime y da un 'text/octal' o algo así como el tipo de mime, sin importar qué tipo de archivo cargues.¿Cómo comprobar si un archivo cargado es una imagen sin tipo de mime?

¿Hay alguna manera de verificar si el archivo cargado es una imagen además de verificar la extensión del archivo usando PHP?

Respuesta

32

Puede usar getimagesize(), que devuelve ceros para el tamaño en no imágenes.

+2

Hasta donde yo sé, este es realmente el truco aceptado para hacer esto. Me interesaría escuchar mejores métodos si existen. –

+0

Los documentos dicen que devuelve una matriz con 7 elementos, ¿qué elemento debo verificar para ver si es una imagen o no? –

+0

cero y uno para ancho y alto. –

3

Puede verificar los primeros bytes del archivo magic number para descubrir el formato de la imagen.

6

Puede verificar el tipo de imagen comprobando los números mágicos al principio del archivo. Por ejemplo, todos los archivos JPEG comienzan con un "FF D8 FF E0" bloque.

Aquí hay más información sobre magic numbers

+6

no seguro imo, un atacante podría "FF D8 FF E0" los primeros bytes, luego agregar algún código php que potencialmente podría ejecutarse – Reacen

+2

Reacen, nada es seguro, el código PHP puede así como ser inyectado en un archivo JPG válido haciendo uso de la sección de metadatos JPG. – rcode

3

Intente utilizar exif_imagetype para recuperar el tipo real de la imagen. Si el archivo es demasiado pequeño arrojará un error y si no puede encontrarlo, devolverá falso

37

Mi pensamiento sobre el tema es simple: todas las imágenes cargadas son malas.

Y no solo porque pueden contener códigos maliciosos, sino especialmente debido a las metaetiquetas. Soy consciente de que los rastreadores que navegan por la web encuentran algunas imágenes protegidas usando sus metaetiquetas ocultas y luego juegan con sus derechos de autor. Tal vez un poco paranoico, pero como las imágenes cargadas por el usuario están fuera de control sobre cuestiones de derechos de autor, lo tomo en serio en cuenta.

Para deshacerme de esos problemas, sistemáticamente convierto todas las imágenes cargadas a png usando gd. Esto tiene muchas ventajas: la imagen está limpia de eventuales códigos maliciosos y metaetiquetas, solo tengo un formato para todas las imágenes cargadas, puedo ajustar el tamaño de la imagen para que coincida con mi estándar, y ... Sé de inmediato si el la imagen es válida o no! Si la imagen no se puede abrir para la conversión (usando imagecreatefromstring, que no se preocupa del formato de imagen), considero que la imagen no es válida.

Una aplicación simple podría tener este aspecto:

function imageUploaded($source, $target) 
{ 
    // check for image size (see @DaveRandom's comment) 
    $size = getimagesize($source); 
    if ($size === false) { 
     throw new Exception("{$source}: Invalid image."); 
    } 
    if ($size[0] > 2000 || $size[1] > 2000) { 
     throw new Exception("{$source}: Too large."); 
    } 

    // loads it and convert it to png 
    $sourceImg = @imagecreatefromstring(@file_get_contents($source)); 
    if ($sourceImg === false) { 
     throw new Exception("{$source}: Invalid image."); 
    } 
    $width = imagesx($sourceImg); 
    $height = imagesy($sourceImg); 
    $targetImg = imagecreatetruecolor($width, $height); 
    imagecopy($targetImg, $sourceImg, 0, 0, 0, 0, $width, $height); 
    imagedestroy($sourceImg); 
    imagepng($targetImg, $target); 
    imagedestroy($targetImg); 
} 

para probarlo:

header('Content-type: image/png'); 
imageUploaded('http://www.dogsdata.com/wp-content/uploads/2012/03/Companion-Yellow-dog.jpg', 'php://output'); 

Esto no responde exactamente a su pregunta, ya que es el mismo tipo de truco que la respuesta aceptada, pero le doy mis razones para usarlo, al menos :-)

+0

Estoy totalmente de acuerdo con @Alain Tiemblo "Convertí sistemáticamente todas las imágenes cargadas a png usando gd". Esta es la forma de ir sobre la seguridad. – PauloASilva

+0

De hecho, uno de mis colegas señaló que esto no funciona si permites gifs animados. Cierto. –

+0

Estoy de acuerdo contigo PERO ... Todo el mundo sabe que los GIF pueden ser explotados ([example] (http://www.phpclasses.org/blog/post/67-PHP-security-exploit-with-GIF-images.html)). Si tiene que admitir GIF, tal vez tendrá que invertir algo de tiempo y esfuerzo para filtrar/desinfectar el formato. – PauloASilva

5

Si Uploadify realmente cambia el tipo de mimo, lo consideraría un error. No tiene sentido en absoluto, ya que bloquea los desarrolladores trabajar con funciones basadas de tipo MIME en PHP:

Esta es una pequeña función auxiliar que devuelve el tipo mime basado en los primeros 6 bytes de un archivo.

/** 
* Returns the image mime-type based on the first 6 bytes of a file 
* It defaults to "application/octet-stream". 
* It returns false, if problem with file or empty file. 
* 
* @param string $file 
* @return string Mime-Type 
*/ 
function isImage($file) 
{ 
    $fh = fopen($file,'rb'); 
    if ($fh) { 
     $bytes = fread($fh, 6); // read 6 bytes 
     fclose($fh);   // close file 

     if ($bytes === false) { // bytes there? 
      return false; 
     } 

     // ok, bytes there, lets compare.... 

     if (substr($bytes,0,3) == "\xff\xd8\xff") { 
      return 'image/jpeg'; 
     } 
     if ($bytes == "\x89PNG\x0d\x0a") { 
      return 'image/png'; 
     } 
     if ($bytes == "GIF87a" or $bytes == "GIF89a") { 
      return 'image/gif'; 
     } 

     return 'application/octet-stream'; 
    } 
    return false; 
} 
2

¿No es posible interrogar al archivo con finfo_file?

$finfo = finfo_open(FILEINFO_MIME_TYPE); 
$mimetype = finfo_file($finfo, $filename); //should contain mime-type 
finfo_close($finfo); 

Esta respuesta es no probado, pero basado en this forum discussion en los foros Uploadify.

También me gustaría señalar que finfo debería ser "try to guess the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file", así que en mi opinión esto debería seguir funcionando aunque Uploadify haya especificado el tipo de mime equivocado.

Cuestiones relacionadas