Ответ 1
Вы можете использовать getimagesize()
, который возвращает нули для размера без изображений.
Я хочу проверить, является ли загруженный файл файлом изображения (например, png, jpg, jpeg, gif, bmp) или другим файлом. Проблема в том, что я использую Uploadify для загрузки файлов, что изменяет тип mime и дает "text/octal" или что-то вроде типа mime, независимо от того, какой тип файла вы загружаете.
Есть ли способ проверить, является ли загруженный файл изображением отдельно от проверки расширения файла с помощью PHP?
Вы можете использовать getimagesize()
, который возвращает нули для размера без изображений.
Моя мысль о предмете проста: все загруженные изображения злы.
И не только потому, что они могут содержать вредоносные коды, но особенно из-за мета-тегов. Я знаю о сканерах, которые просматривают веб-страницы, чтобы найти защищенные изображения, используя свои скрытые метатеги, а затем играть с их авторскими правами. Возможно, немного параноидально, но поскольку загруженные пользователем изображения не контролируют проблемы авторского права, я принимаю это во внимание.
Чтобы избавиться от этих проблем, я систематически конвертирую все загруженные изображения в png с помощью gd. У этого есть много преимуществ: изображение чиста от возможных вредоносных кодов и мета-тегов, у меня есть только один формат для всех загруженных изображений, я могу настроить размер изображения в соответствии со своим стандартом и... Я сразу же знаю если изображение верное или нет! Если изображение невозможно открыть для преобразования (используя imagecreatefromstring, который не уход за форматом изображения), то я считаю изображение недействительным.
Простая реализация может выглядеть так:
function imageUploaded($source, $target)
{
// check for image size (see @DaveRandom comment)
$size = getimagesize($source);
if ($size === false) {
throw new Exception("{$source}: Invalid image.");
}
if ($size[0] > 2000 || $size[1] > 2000) {
throw new Exception("{$source}: Too large.");
}
// loads it and convert it to png
$sourceImg = @imagecreatefromstring(@file_get_contents($source));
if ($sourceImg === false) {
throw new Exception("{$source}: Invalid image.");
}
$width = imagesx($sourceImg);
$height = imagesy($sourceImg);
$targetImg = imagecreatetruecolor($width, $height);
imagecopy($targetImg, $sourceImg, 0, 0, 0, 0, $width, $height);
imagedestroy($sourceImg);
imagepng($targetImg, $target);
imagedestroy($targetImg);
}
Чтобы проверить это:
header('Content-type: image/png');
imageUploaded('http://www.dogsdata.com/wp-content/uploads/2012/03/Companion-Yellow-dog.jpg', 'php://output');
Это точно не отвечает на ваш вопрос, поскольку это такой же взлом, как и принятый ответ, но я даю вам свои причины для его использования, по крайней мере: -)
Вы можете проверить тип изображения, проверив магические числа в начале файла.
Например: каждый файл JPEG начинается с блока "FF D8 FF E0" .
Подробнее о магических номерах
Если Uploadify действительно изменяет тип mime - я считаю это ошибкой. Это не имеет никакого смысла, поскольку это блокирует разработчиков от работы с Функции на основе mime-типа в PHP:
Это небольшая вспомогательная функция, которая возвращает тип mime на основе первых 6 байтов файла.
/**
* Returns the image mime-type based on the first 6 bytes of a file
* It defaults to "application/octet-stream".
* It returns false, if problem with file or empty file.
*
* @param string $file
* @return string Mime-Type
*/
function isImage($file)
{
$fh = fopen($file,'rb');
if ($fh) {
$bytes = fread($fh, 6); // read 6 bytes
fclose($fh); // close file
if ($bytes === false) { // bytes there?
return false;
}
// ok, bytes there, lets compare....
if (substr($bytes,0,3) == "\xff\xd8\xff") {
return 'image/jpeg';
}
if ($bytes == "\x89PNG\x0d\x0a") {
return 'image/png';
}
if ($bytes == "GIF87a" or $bytes == "GIF89a") {
return 'image/gif';
}
return 'application/octet-stream';
}
return false;
}
Вы можете проверить первые несколько байтов файла для магического номера, чтобы определить формат изображения.
Попробуйте использовать exif_imagetype для получения фактического типа изображения. Если файл слишком мал, он выдаст ошибку, и если он не сможет найти его, он вернет false
Невозможно ли допросить файл с помощью finfo_file?
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $filename); //should contain mime-type
finfo_close($finfo);
Этот ответ не проверен, но основан на этом обсуждении форума на форумах Uploadify.
Я также хотел бы указать, что finfo должен "попытаться угадать тип содержимого и кодировку файла, ища определенные последовательности байт-байт в определенных положениях в пределах file" , поэтому, по моему мнению, это все равно должно работать, даже если в программе Uploaded указан неправильный тип mime.