subir - La mejor forma de determinar si una URL es una imagen en PHP
subir imagen con retrofit (8)
Además de la respuesta de Emil H:
Usando get_headers()
para verificar el tipo de contenido de una url sin descargar todo el archivo con getimagesize()
$url_headers=get_headers($url, 1);
if(isset($url_headers[''Content-Type''])){
$type=strtolower($url_headers[''Content-Type'']);
$valid_image_type=array();
$valid_image_type[''image/png'']='''';
$valid_image_type[''image/jpg'']='''';
$valid_image_type[''image/jpeg'']='''';
$valid_image_type[''image/jpe'']='''';
$valid_image_type[''image/gif'']='''';
$valid_image_type[''image/tif'']='''';
$valid_image_type[''image/tiff'']='''';
$valid_image_type[''image/svg'']='''';
$valid_image_type[''image/ico'']='''';
$valid_image_type[''image/icon'']='''';
$valid_image_type[''image/x-icon'']='''';
if(isset($valid_image_type[$type])){
//do something
}
}
Usando PHP, dado un URL, ¿cómo puedo determinar si es una imagen?
No hay contexto para la URL, está justo en el medio de un archivo de texto plano, o tal vez solo una cadena por sí mismo.
No quiero una sobrecarga (por ejemplo, leer el contenido de la URL), ya que podría llamarse a muchas URL en una página. Dada esta restricción, no es esencial que todas las imágenes estén identificadas, pero me gustaría tener una buena idea.
Por el momento solo estoy mirando la extensión de archivo, pero parece que debería haber una mejor manera de hacerlo.
Esto es lo que tengo actualmente:
function isImage( $url )
{
$pos = strrpos( $url, ".");
if ($pos === false)
return false;
$ext = strtolower(trim(substr( $url, $pos)));
$imgExts = array(".gif", ".jpg", ".jpeg", ".png", ".tiff", ".tif"); // this is far from complete but that''s always going to be the case...
if ( in_array($ext, $imgExts) )
return true;
return false;
}
Editar: en caso de que sea útil para cualquier otra persona, aquí está la función final usando la técnica de la respuesta de Emil H:
function isImage($url)
{
$params = array(''http'' => array(
''method'' => ''HEAD''
));
$ctx = stream_context_create($params);
$fp = @fopen($url, ''rb'', false, $ctx);
if (!$fp)
return false; // Problem with url
$meta = stream_get_meta_data($fp);
if ($meta === false)
{
fclose($fp);
return false; // Problem reading data from url
}
$wrapper_data = $meta["wrapper_data"];
if(is_array($wrapper_data)){
foreach(array_keys($wrapper_data) as $hh){
if (substr($wrapper_data[$hh], 0, 19) == "Content-Type: image") // strlen("Content-Type: image") == 19
{
fclose($fp);
return true;
}
}
}
fclose($fp);
return false;
}
Editar: para imágenes estáticas con extensión de imagen popular.
<?php
$imgExts = array("gif", "jpg", "jpeg", "png", "tiff", "tif");
$url =''path/to/image.png'';
$urlExt = pathinfo($url, PATHINFO_EXTENSION);
if (in_array($urlExt, $imgExts)) {
echo ''Yes, ''.$url.'' is an Image'';
}
?>
Hay algunos enfoques diferentes.
Detecta el contenido buscando un número mágico al comienzo del archivo. Por ejemplo, GIF usa GIF87 o GIF89 como los primeros cinco bytes del archivo (en ascii). Lamentablemente, esto no puede indicarle si hay un error en la imagen o si la imagen contiene contenido malicioso. Aquí hay algunos números mágicos para varios tipos de archivos de imagen (no dude en usarlos):
"/xff/xd8/xff" => ''image/jpeg'', "/x89PNG/x0d/x0a/x1a/x0a" => ''image/png'', "II*/x00" => ''image/tiff'', "MM/x00*" => ''image/tiff'', "/x00/x00/x01/x00" => ''image/ico'', "/x00/x00/x02/x00" => ''image/ico'', "GIF89a" => ''image/gif'', "GIF87a" => ''image/gif'', "BM" => ''image/bmp'',
Oler el contenido de esta manera probablemente se ajuste mejor a tus necesidades; solo tendrá que leer y, por lo tanto, descargar los primeros bytes del archivo (más allá del encabezado).
Cargue la imagen usando la biblioteca GD para ver si se carga sin error. Esto puede decirle si la imagen es válida, sin error o no. Desafortunadamente, esto probablemente no se ajusta a sus requisitos porque requiere la descarga de la imagen completa.
- Si realmente no desea realizar una solicitud HTTP para la imagen, entonces esto excluye tanto olfatear como obtener encabezados HTTP. Sin embargo, puede intentar determinar si algo es una imagen según el contexto en el que está vinculada. Algo relacionado con un atributo src en un elemento <img es casi seguro una imagen (o un intento en XSS, pero esa es otra historia). Esto le dirá si algo tiene la intención de ser una imagen. No le dirá si la imagen está realmente disponible o es válida; Tendrás que buscar al menos la primera parte pequeña (encabezado o número mágico) de la URL de la imagen para encontrarlo.
Desafortunadamente, es posible que un archivo sea tanto una imagen válida como un archivo ZIP que contenga contenido dañino que podría ser ejecutado como Java por un sitio dañino: vea el exploit GIFAR . Casi con seguridad puede evitar esta vulnerabilidad cargando la imagen en una biblioteca como GD y realizando algún filtro no trivial, como suavizarla o afilarla en una cantidad pequeña (es decir, usando un filtro de convolución) y guardarla en un archivo nuevo sin transferirla cualquier metadato a través
Tratar de determinar si algo es una imagen solo por su tipo de contenido es bastante poco confiable, casi tan poco fiable como verificar la extensión del archivo. Al cargar una imagen con un elemento <img, los navegadores olfatean una cadena mágica.
Puede usar una solicitud HTTP HEAD y verificar el tipo de contenido. Esto podría ser un buen compromiso. Se puede hacer usando PHP Streams . Wez Furlong tiene un article que muestra cómo usar este enfoque para enviar solicitudes de publicaciones, pero se puede adaptar fácilmente para enviar solicitudes HEAD en su lugar. Puede recuperar los encabezados de una respuesta http utilizando stream_get_meta_data() .
Por supuesto, esto no es realmente 100%. Algunos servidores envían encabezados incorrectos. Sin embargo, manejará los casos donde las imágenes se entregan a través de un script y la extensión de archivo correcta no está disponible. La única manera de estar realmente seguro es recuperar la imagen, ya sea todo o los primeros bytes, como sugiere thomasrutter.
Similar a alguna respuesta dada pero con una lógica ligeramente diferente.
$headers = @get_headers($url, 1); // @ to suppress errors. Remove when debugging.
if (isset($headers[''Content-Type''])) {
if (strpos($headers[''Content-Type''], ''image/'') === FALSE) {
// Not a regular image (including a 404).
}
else {
// It''s an image!
}
}
else {
// No ''Content-Type'' returned.
}
@ es un operador de control de errores .
Tenga en cuenta que utilizamos el operador "estricto" === FALSE
en la condición porque strpos($headers[''Content-Type''], ''image/'')
devuelve 0
en nuestro caso de uso si la aguja se encuentra en el pajar. Con la conversión de tipo utilizando ==
, se interpretaría erróneamente como FALSE
.
podemos usar exif_imagetype para verificar el tipo de imagen, por lo que no se permite a ningún otro tipo de contenido. Solo permite imágenes y podemos restringirlas a pocos tipos de imágenes, siguiendo el código de muestra que muestra cómo permitir el tipo de imagen GIF.
if (exif_imagetype(''image.gif'') != IMAGETYPE_GIF) {
echo ''The picture is not a gif'';
}
Puede usar los siguientes tipos de imágenes,
IMAGETYPE_GIF
IMAGETYPE_JPEG
IMAGETYPE_PNG
IMAGETYPE_SWF
IMAGETYPE_PSD
IMAGETYPE_BMP
IMAGETYPE_TIFF_II (intel byte order)
IMAGETYPE_TIFF_MM (motorola byte order)
IMAGETYPE_JPC
IMAGETYPE_JP2
IMAGETYPE_JPX
IMAGETYPE_JB2
IMAGETYPE_SWC
IMAGETYPE_IFF
IMAGETYPE_WBMP
IMAGETYPE_XBM
IMAGETYPE_ICO
más detalles: link
Solución rápida para enlaces de imágenes rotas o no encontradas
Te recomiendo que no utilices getimagesize () porque primero descargará la imagen y luego comprobará el tamaño de las imágenes + si esto no es una imagen, arrojará una excepción, así que utiliza el código siguiente
if(checkRemoteFile($imgurl))
{
//found url, its mean
echo "this is image";
}
function checkRemoteFile($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
// don''t download content
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if(curl_exec($ch)!==FALSE)
{
return true;
}
else
{
return false;
}
}
Nota: este código actual lo ayuda a identificar la URL defectuosa o no encontrada. Esto no le ayudará a identificar el tipo de imagen o los encabezados.
if(is_array(getimagesize($urlImg)))
echo ''Yes it''s an image!'';