Подтвердить что ты не робот

Лучший способ определить, является ли 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 always going to be the case...
    if ( in_array($ext, $imgExts) )
      return true;
    return false;
  }

Изменить: В случае, если это полезно для кого-то еще, это последняя функция, использующая технику из ответа Эмиля Н:

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

Ответ 1

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

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

Ответ 2

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

  • Понюхайте контент, ища волшебное число в начале файла. Например, 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 браузеры нюхают магическую строку.

Ответ 3

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

Ответ 4

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

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

        }
    }

Ответ 5

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

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

?>

Ответ 6

мы можем использовать 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

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

Ответ 7

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

$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 an image!
  }
}
else {
  // No 'Content-Type' returned.
}

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

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

Ответ 8

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

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-адрес, это не поможет вам определить тип изображения или заголовки