лучший способ определить, является ли URL-адрес изображением в PHP

Используя PHP, учитывая URL-адрес, как определить, является ли это образ?

Нет контекста для URL-адреса – он находится только в середине простого текстового файла или, может быть, просто строка сама по себе.

Мне не нужны высокие накладные расходы (например, чтение содержимого URL-адреса), поскольку это может быть вызвано для многих URL-адресов на странице. Учитывая это ограничение, не обязательно, чтобы все изображения были идентифицированы, но я хотел бы получить довольно хорошее предположение.

На данный момент я просто смотрю на расширение файла, но похоже, что должен быть лучший способ, чем это.

Вот что я сейчас имею:

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; } 

Edit: В случае, если это полезно для кого-то еще, это последняя функция, использующая технику из ответа Эмиля 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; } 

Вы можете использовать запрос HTTP HEAD и проверить тип содержимого. Это может быть хорошим компромиссом. Это можно сделать с помощью PHP Streams . У Wez Furlong есть статья, в которой показано, как использовать этот подход для отправки почтовых запросов, но он может быть легко адаптирован для отправки запросов HEAD. Вы можете получить заголовки из ответа HTTP с помощью stream_get_meta_data () .

Конечно, это не на самом деле 100%. Некоторые серверы отправляют неверные заголовки. Однако он будет обрабатывать случаи, когда изображения доставляются через скрипт, а правильное расширение файла недоступно. Единственный способ быть действительно уверенным в том, чтобы фактически получить изображение – либо все, либо первые несколько байтов, как было предложено thomasrutter.

Существует несколько разных подходов.

  • Понюхайте контент, ища волшебное число в начале файла. Например, GIF использует GIF87 или GIF89 в качестве первых пяти байтов файла (в ascii). К сожалению, это не может сказать вам, есть ли ошибка в изображении или изображение содержит вредоносный контент. Вот несколько магических чисел для различных типов файлов изображений (не стесняйтесь их использовать):

     "\ 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',
    

    Обнюхать контент, подобный этому, вероятно, будет лучше соответствовать вашим требованиям; вам нужно будет только прочитать и, следовательно, загрузить первые несколько байтов файла (за заголовком).

  • Загрузите изображение с помощью библиотеки GD, чтобы узнать, загружается ли он без ошибок. Это может сказать вам, является ли изображение действительным, без ошибок или нет. К сожалению, это, вероятно, не соответствует вашим требованиям, потому что это требует загрузки полного изображения.

  • Если вы действительно не хотите делать HTTP-запрос для изображения вообще, тогда это исключает как обнюхивание, так и получение заголовков HTTP. Тем не менее, вы можете попытаться определить, является ли что-то изображение контекстом, в котором он связан. Что-то связанное с использованием атрибута src в элементе <img – это почти наверняка изображение (или попытка XSS, но это еще одна история). Это скажет вам, что-то предназначено для изображения. Он не скажет вам, действительно ли изображение действительно доступно или действительно; вам нужно будет найти по крайней мере первую небольшую часть (заголовок или магическое число) URL-адреса изображения, чтобы найти это.

К сожалению, файл может быть как допустимым, так и ZIP-файлом, содержащим вредоносное содержимое, которое может быть выполнено как Java вредоносным сайтом – см. Эксплойт GIFAR . Вы почти наверняка предотвратите эту уязвимость, загрузив изображение в библиотеке, например GD, и произнесете на ней какой-то нетривиальный фильтр, например, смягчая или затачивая его крошечным количеством (т. Е. Используя фильтр свертки) и сохраняя его в новом файле без переноса любые метаданные.

Попытка определить, является ли что-то изображение одним только своим типом контента, является довольно ненадежным, почти таким же ненадежным, как проверка расширения файла. При загрузке изображения с помощью элемента <img браузеры нюхают магическую строку.

 if(is_array(getimagesize($urlImg))) echo 'Yes it's an image!'; 

В дополнение к ответу Эмиля Х:

Используя get_headers() чтобы проверить тип содержимого URL- getimagesize() не загружая весь файл с помощью 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 } } 

Изменить: для статических изображений с популярным расширением изображения.

 <?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'; } ?> 

мы можем использовать exif_imagetype для проверки типа изображения, поэтому он не допускает каких-либо других типов содержимого. Это разрешает только изображения, и мы можем ограничить их несколькими типами изображений, после примера кода показано, как разрешить тип изображения GIF.

 if (exif_imagetype('image.gif') != IMAGETYPE_GIF) { echo 'The picture is not a gif'; } 

Вы можете использовать следующие типы изображений,

  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 

подробнее: ссылка

Как и в случае с некоторым ответом, но с немного иной логикой.

 $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. } 

@ – оператор управления ошибками .

Обратите внимание, что мы использовали «строгий» оператор === FALSE в условии, потому что strpos($headers['Content-Type'], 'image/') возвращает 0 в нашем случае, если игла находится в стоге сена. С типом casting с использованием == , который ошибочно будет интерпретироваться как FALSE .

Быстрое решение для сломанной или не найденной ссылки изображения
я рекомендую вам, чтобы не использовать getimagesize (), потому что он будет загружать 1-й снимок, тогда он будет проверять размер изображения +, если это не будет изображение, тогда он будет генерировать исключение, поэтому используйте ниже код

 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; } } 

Примечание: этот текущий код поможет вам идентифицировать сломанное или не найденное изображение URL-адреса, это не поможет вам определить тип изображения или заголовки