it-swarm.com.ru

лучший способ определить, является ли 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;
  }

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

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

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

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

28
Emil H
if(is_array(getimagesize($urlImg)))
    echo 'Yes it is an image!';
13
Pedro Soares

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

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

13
thomasrutter

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

Использование 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

        }
    }
10
RafaSashi

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

<?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
TheMonkeyKing

Похоже на некоторый ответ, но с немного другой логикой.

$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 в нашем случае использования, если иголка найдена в стоге сена. При приведении типа с использованием == это будет ошибочно интерпретироваться как FALSE.

2
Martin Postma

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

более подробная информация: ссылка

1
Janith Chinthana

Быстрое решение для сломанных или не найденных изображений ссылка  
Я рекомендую вам не использовать 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, это не поможет вам определить тип изображения или заголовки

0
Hassan Saeed