Что общего между изображениями в онлайн-фотоальбоме, вложениями электронной почты в веб-почтовом клиенте и файлами данных, переданными в онлайн-приложение для пакетной обработки? Все они полагаются на возможность загружать файлы через Интернет из веб-браузера пользователя. Действительно, загрузка файлов является важной особенностью многих сайтов и веб-приложений, которые мы используем ежедневно. В этой статье я покажу вам, как добавить поддержку загрузки файлов на ваш сайт с использованием PHP.
Требования
Обработка загрузки файлов не сложна, но есть несколько мелких деталей, которые должны быть правильными, иначе загрузка не удастся. Во-первых, вы должны убедиться, что PHP настроен на загрузку. Проверьте файл php.ini
и убедитесь, что директива file_uploads
включена.
file_uploads = On
Загруженные файлы сначала сохраняются во временном каталоге (не волнуйтесь… ваш PHP-скрипт может впоследствии переместить файлы в более постоянное место). По умолчанию начальным местоположением является временный каталог системы по умолчанию. Вы можете указать другой каталог с upload_tmp_dir
директивы upload_tmp_dir
в php.ini
. В любом случае, вы должны убедиться, что процесс PHP имеет надлежащие привилегии для записи в любой каталог, который используется.
upload_tmp_dir = "/ tmp" tboronczyk @ zarkov: ~ $ ls -l / | grep tmp drwxrwxrwt 13 root root 40960 2011-08-31 00:50 tmp
Убедившись, что конфигурация позволяет серверу принимать загруженные файлы, вы можете сосредоточиться на деталях HTML. Как и в случае большинства других взаимодействий на стороне сервера из HTML, при загрузке файлов используются формы. Обязательно, чтобы ваш элемент <form>
использовал метод POST и enctype
атрибут enctype
установленный в multipart/form-data
.
<form action="upload.php" method="post" enctype="multipart/form-data">
Сценарии процесса загрузки
Вероятно, вы можете догадаться, что загрузка файлов рабочего процесса проходит на основе вашего собственного опыта и проверок требований, которые я только что упомянул.
- Посетитель просматривает HTML-страницу с формой, специально написанной для поддержки загрузки файлов.
- Посетитель предоставляет файл, который он хочет загрузить, и отправляет форму
- Браузер кодирует файл и отправляет его как часть POST-запроса на сервер.
- PHP получает отправку формы, декодирует файл и сохраняет его во временной папке на сервере.
- PHP-скрипт, отвечающий за обработку сообщения формы, проверяет файл и обрабатывает его некоторым образом, часто перемещая его из временного местоположения в более постоянное место
Добавление поддержки для загрузки файлов требует, чтобы вы создали HTML-форму для представления пользователю и PHP-скрипт, чтобы заботиться о загруженном файле на сервере.
HTML
HTML-формы предоставляют интерфейс, через который пользователь инициирует загрузку файла. Помните, что для элемента <form>
должен быть установлен атрибут method
post
а enctype
атрибута enctype
— multipart/form-data
. Элемент <input>
file предоставляет поле, используемое для указания файла, который будет загружен. Как и любой другой элемент формы, важно предоставить атрибут name, чтобы вы могли ссылаться на него в сценарии PHP, который обрабатывает форму.
Вот как выглядит разметка для основной формы загрузки файлов:
<form action="upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="myFile"> <br> <input type="submit" value="Upload"> </form>
Стоит отметить, что разные браузеры отображают поле файла по-разному. IE, Firefox и Opera отображают его в виде текстового поля с кнопкой рядом с надписью «Обзор» или «Выбрать». Safari отображает его как кнопку с надписью «Выбрать файл». В большинстве случаев это не проблема. пользователи привыкли к тому, как поле отображается в выбранном браузере, и знают, как его использовать. Однако иногда вы сталкиваетесь с клиентом или дизайнером, который непреклонен в том, чтобы представить его определенным образом. Количество CSS и JavaScript, которые можно применить к файловому полю, крайне ограничено из-за соображений безопасности, навязанных браузерами. Стилизация поля файла может быть сложной. Если внешний вид важен для вас, я рекомендую вам ознакомиться со стилевым оформлением Питера-Пола Коха тип ввода = «file» .
PHP
Информация о загрузке файла доступна с помощью многомерного массива $_FILES
. Этот массив индексируется именами, присвоенными полям файла в форме HTML, так же, как индексируются $_GET
и $_POST
. Массив каждого файла содержит следующие индексы:
-
$_FILES["myFile"]["name"]
хранит исходное имя файла от клиента -
$_FILES["myFile"]["type"]
хранит mime-тип файла -
$_FILES["myFile"]["size"]
хранит размер файла (в байтах) -
$_FILES["myFile"]["tmp_name"]
хранит имя временного файла - $ _FILES [«myFile»] [«error»] хранит любой код ошибки, полученный в результате передачи
Функция move_uploaded_file()
перемещает загруженный файл из временного в постоянное местоположение. Для этой цели всегда следует использовать move_uploaded_file()
над такими функциями, как copy()
и rename()
поскольку он выполняет дополнительные проверки, чтобы убедиться, что файл действительно был загружен запросом HTTP POST.
Если вы планируете сохранить файл с исходным именем файла, предоставленным пользователем, рекомендуется убедиться, что это безопасно. Имя файла не должно содержать символов, которые могут повлиять на путь назначения, например косой черты. Имя не должно приводить к тому, что файл перезаписывает существующий файл с тем же именем (если только это не предназначено для вашего приложения). Я гарантирую безопасное имя файла, заменяя любые символы подчеркиванием, которые не являются буквой, цифрой или членом очень ограниченного набора знаков препинания, а затем добавляю увеличивающийся номер, когда файл с таким именем уже существует.
Вот как выглядит получение и обработка загрузки файла с помощью PHP:
<?php define("UPLOAD_DIR", "/srv/www/uploads/"); if (!empty($_FILES["myFile"])) { $myFile = $_FILES["myFile"]; if ($myFile["error"] !== UPLOAD_ERR_OK) { echo "<p>An error occurred.</p>"; exit; } // ensure a safe filename $name = preg_replace("/[^A-Z0-9._-]/i", "_", $myFile["name"]); // don't overwrite an existing file $i = 0; $parts = pathinfo($name); while (file_exists(UPLOAD_DIR . $name)) { $i++; $name = $parts["filename"] . "-" . $i . "." . $parts["extension"]; } // preserve file from temporary directory $success = move_uploaded_file($myFile["tmp_name"], UPLOAD_DIR . $name); if (!$success) { echo "<p>Unable to save file.</p>"; exit; } // set proper permissions on the new file chmod(UPLOAD_DIR . $name, 0644); }
Сначала код проверяет, загружен ли файл без ошибок. Затем он определяет безопасное имя файла, как я только что описал, и затем перемещает файл в его окончательный каталог, используя move_uploaded_file()
. Наконец, есть вызов chmod()
чтобы удостовериться, что для нового файла установлены права доступа.
Вопросы безопасности
Большинство из нас не позволяло бы совершенно незнакомым людям хранить случайные файлы на наших персональных компьютерах, и все же это именно то, что вы делаете, когда вы разрешаете загрузку файлов в нашем приложении. Вы можете захотеть, чтобы пользователь загрузил свою фотографию для страницы профиля, но что, если он попытается загрузить специально созданный, загруженный вирусом исполняемый файл? Я хотел бы поделиться несколькими шагами, которые вы можете предпринять, чтобы минимизировать риски безопасности, присущие разрешению загрузки файлов.
Один из них — проверить, какой тип загруженного файла должен быть. Использование значения $_FILES["myFile"]["type"]
либо расширения файла не является безопасным, поскольку оба могут быть легко подделаны. Вместо этого используйте функцию наподобие exif_imagetype()
чтобы проверить содержимое файла и определить, действительно ли это GIF, JPEG или один из нескольких других поддерживаемых форматов изображений. Если exif_imagetype()
недоступна (функция требует, чтобы расширение Exif было включено), тогда вы можете использовать getimagesize()
. Массив, возвращаемый getimagesize()
будет содержать тип изображения, если он распознан.
<?php // verify the file is a GIF, JPEG, or PNG $fileType = exif_imagetype($_FILES["myFile"]["tmp_name"]); $allowed = array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG); if (!in_array($fileType, $allowed)) { // file type is not permitted ...
Для файлов, не относящихся к изображениям, вы можете использовать exec()
для вызова утилиты Unix file
. file
определяет тип файла путем поиска известных двоичных сигнатур в ожидаемых местах.
<?php // verify the file is a PDF $mime = "application/pdf; charset=binary"; exec("file -bi " . $_FILES["myFile"]["tmp_name"], $out); if ($out[0] != $mime) { // file is not a PDF ...
Еще один шаг, который вы можете предпринять, это наложить жесткие ограничения на общий размер запроса POST и количество файлов, которые можно загрузить. Для этого укажите соответствующее значение для директив upload_max_size
, post_max_size
и max_file_uploads
в php.ini
. Директива upload_max_size
указывает максимальный размер загрузки файла. В дополнение к размеру загрузки вы можете ограничить размер всего запроса POST с помощью директивы post_max_size
. max_file_uploads
— это более новая директива (добавлена в версии 5.2.12), которая ограничивает количество загрузок файлов. Эти три директивы помогают защитить ваш сайт от атак, которые пытаются нарушить его доступность, вызывая большой сетевой трафик или нагрузку на систему.
post_max_size = 8M upload_max_size = 2M max_file_uploads = 20
Третий шаг, который вы можете предпринять, чтобы минимизировать риск, — это сканирование загруженных файлов с помощью антивирусного сканера. Это жизненно важно в наши дни и в эпоху широко распространенных вирусов и вредоносных программ, особенно если ваш сайт впоследствии делает загруженные файлы доступными для загрузки другими пользователями, например, с помощью вложений в веб-почтовом клиенте или (легальном) файлообменном сайте. , Существует расширение PHP , обеспечивающее доступ к ClamAV , но, конечно, вы можете вызывать утилиту командной строки ClamAV во многом так же, как я продемонстрировал для file
.
<?php exec("clamscan --stdout " . $_FILES["myFile"]["tmp_name"], $out, $return); if ($return) { // file is infected ...
Резюме
Вы узнали, как легко поддерживать загрузку файлов с вашего сайта или веб-приложения. Чтобы загрузка прошла успешно, HTML-форма должна быть отправлена через POST-запрос, закодированный в multipart/form-data
, и PHP должен разрешить передачу, как указано с file_uploads
директивы file_uploads
. После передачи файла скрипт, отвечающий за обработку загрузки, использует информацию, найденную в массиве $_FILES
для перемещения файла из временного каталога в нужное место. Я также поделился некоторыми дополнительными мерами предосторожности, которые вы можете предпринять, чтобы защитить себя и своих пользователей от некоторых рисков, связанных с разрешением загрузки файлов. Вы увидели, как можно обеспечить безопасность имени файла, проверить тип файла, наложить жесткие ограничения на загрузку трафика и выполнить сканирование на наличие вирусов.
Для тех, кто может быть заинтересован, дополнительный код для этой статьи доступен на GitHub. Вы можете просматривать, загружать или клонировать репозиторий и играть с кодом, чтобы лучше понять, как работает процесс загрузки файлов.
И если вам понравилось читать этот пост, вы полюбите Learnable ; место, чтобы узнать новые навыки и приемы у мастеров. Участники получают мгновенный доступ ко всем электронным книгам SitePoint и интерактивным онлайн-курсам, таким как Jump Start PHP .
Комментарии к этой статье закрыты. Есть вопрос по PHP? Почему бы не спросить об этом на наших форумах ?
Изображение через VolsKinvols / Shutterstock