Я хотел бы проверить, является ли загруженный файл файлом изображения (например, 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's 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://img.ruphp.com/php/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 должен «попытаться угадать тип контента и кодирование файла, просмотрев определенные последовательности байт-байт на определенных позициях в файле», поэтому, на мой взгляд, это все равно должно работать, даже если программа «Загрузить» указала неправильный мим тип.