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

Используя 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;
  }

Ответы [ 8 ]

28 голосов
/ 24 марта 2009

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

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

14 голосов
/ 17 сентября 2011
if(is_array(getimagesize($urlImg)))
    echo 'Yes it is an image!';
13 голосов
/ 24 марта 2009

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

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

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

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

10 голосов
/ 24 июля 2014

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

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

        }
    }
6 голосов
/ 23 мая 2012

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

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

?>
2 голосов
/ 14 июля 2015

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

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

1 голос
/ 28 июля 2013

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

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

0 голосов
/ 23 января 2017

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...