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