Автоматическая загрузка файлов php на сервер. Отдаем файлы эффективно с помощью PHP. Файл успешно загружен на сервер
Что может быть общего у фотографий, находящихся в онлайн-фотоальбоме, прикреплённых к электронному письму или у файлов, представленных в онлайн-приложении для пакетной обработки? Всех их необходимо загрузить на сервер через интернет из веб-браузера. Действительно, загрузка файлов является важной особенностью многих сайтов и веб-приложений, которые мы используем ежедневно. Из этой статьи вы узнаете, как добавить к себе на сайт поддержку загрузки файлов используя для этого PHP.
Требования перед загрузкой файлов
Обработка загружаемых файлов - стандартный процесс, но существует несколько мелочей, на которые необходимо обратить внимание перед началом работы. Первое, в чем нужно удостовериться, что PHP настроен и позволяет загружать файлы. Для этого в php.ini стоит проверить директиву file_uploads , и, если она выключена, то включить.
File_uploads = On
Загружаемые файлы сначала сохраняются во временном каталоге (но не волнуйтесь... ваш PHP-скрипт впоследствии может переместить файлы в более подходящее место). Исходное местоположение является временным каталогом для системы по умолчанию. Вы можете указать другой каталог, используя директиву 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 форму. Крайне важно, чтобы ваш элемент
Стоит отметить, что разные браузеры будут визуализировать поле загрузки файла по-разному. IE, Firefox и Opera отображают его как текстовое поле с кнопкой рядом с ней надписью «Обзор» или «Выбрать». Safari отображает ее так же, как кнопку с надписью: «Выбрать файл». По большому счету это не проблема с тех пор, как пользователи привыкли к тому, как поле отображается в своем браузере и умеют его использовать. Иногда, однако, вы столкнетесь с клиентом или дизайнером, который непреклонно представляет его определенным образом. Количество CSS и JavaScript, которые могут применяться к файловому полю, крайне ограничено из-за соображений о безопасности, наложенных браузерами. Типизация файла может быть затруднена. Если внешний вид очень важен для вас, я рекомендую вам прочитать одну из статей «Питер-Пол Кох» типа ввода = «файл» .
Переходим на сервере и работаем с 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() мы можем перенести файл из своего временного каталога в постоянное место. Так же хорошей практикой является использовать именно её вместо copy() и rename() для этой цели, поскольку она выполняет дополнительные проверки, чтобы гарантировать, что файл был действительно загружен запросом HTTP методом POST.
Если вы собираетесь сохранить файл с исходным именем, предоставленным пользователем, рекомендуется убедиться, что это безопасно. Имя файла не должно содержать символов, которые могут повлиять на путь назначения, например, косая черта (слэш). Имя файла должно быть уникальным, чтоб избежать затирания существующих с тем же именем (если это не предусматривается вашим приложением). Гарантировать это можно заменяя любые символы символом подчеркивания, который не является буквой, а затем добавляя увеличивающийся номер, если файл с таким именем уже существует.
Вот так как выглядит получение и обработка загрузки файла при помощи PHP:
Define("UPLOAD_DIR", "/srv/www/uploads/"); if (!empty($_FILES["myFile"])) { $myFile = $_FILES["myFile"]; if ($myFile["error"] !== UPLOAD_ERR_OK) { echo "
Произошла ошибка.
"; exit; } // обеспечиваем безопасное имени файла $name = preg_replace("/[^A-Z0-9._-]/i", "_", $myFile["name"]); // не перезаписываем существующий файл $i = 0; $parts = pathinfo($name); while (file_exists(UPLOAD_DIR . $name)) { $i++; $name = $parts["filename"] . "-" . $i . "." . $parts["extension"]; } // сохраняем файл из временного каталога $success = move_uploaded_file($myFile["tmp_name"], UPLOAD_DIR . $name); if (!$success) { echo ""; exit; } // устанавливаем правильные права для нового файла chmod(UPLOAD_DIR . $name, 0644); }Сначала мы удостоверяемся, что PHP загрузка файла на сервер прошла без ошибок. Затем определяем безопасное имя файла, как я только что описал выше, а затем перемещаем файл в его конечный каталог с помощью move_uploaded_file() . И наконец делаем вызов chmod() , чтобы убедиться, что в новом файле установлены необходимые права доступа.
Вопросы безопасности
Один из них заключается в том, чтобы проверить тип загружаемого файла, каким он должен быть. Опираться на значение $_FILES["myFile"]["type"] или на расширение имени файла не является безопасным, поскольку оба могут легко подделываться. Скорее, используйте функцию exif_imagetype() , чтобы проверить содержимое файла и определить, действительно ли это GIF, JPEG или один из нескольких других поддерживаемых форматов изображений. Если exif_imagetype() недоступен (функция требует, чтобы расширение Exif было включено), вы можете использовать getimagesize() . Массив, возвращаемый ей, будет содержать тип изображения, если он распознан.
// проверяем файл GIF, JPEG или PNG $fileType = exif_imagetype($_FILES["myFile"]["tmp_name"]); $allowed = array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG); if (!in_array($fileType, $allowed)) { // тип файла не разрешен...
Для файлов без изображения вы можете использовать exec() для вызова утилиты файлов unix. он определяет тип файла, ища известные двоичные подписи в ожидаемых местах.
// проверяем файл в формате PDF $mime = "application/pdf; charset=binary"; exec("file -bi " . $_FILES["myFile"]["tmp_name"], $out); if ($out != $mime) { // файл не 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 так же, как я продемонстрировал для файла.
Exec("clamscan --stdout " . $_FILES["myFile"]["tmp_name"], $out, $return); if ($return) { // файл заражен...
Подводим итоги и делаем выводы
Сегодня вы узнали, как происходит настройка и осуществляется процесс PHP загрузки файлов на сервер с вашего сайта или веб-приложения. Чтобы загрузка была успешной, форма HTML должна быть отправлена через запрос POST с множественным форматированием данных, а PHP должен разрешать передачу, как указано, с помощью директивы file_uploads . После переноса файла, сценарий, ответственный за обработку загрузки, использует информацию, найденную в массиве $_FILES , чтобы переместить файл из временного каталога в нужное место. Я также поделился некоторыми дополнительными мерами предосторожности, которые вы можете предпринять, чтобы защитить себя и своих пользователей от некоторых рисков, связанных с возможностью загрузки файлов. Чтобы гарантировать свою безопасность - проверяйте тип файла, наложите жесткие ограничения на загрузку трафика и применяйте сканирование на наличие вирусов.
Для тех, кто может быть заинтересован, дополнительный код для этой статьи доступен на GitHub . Вы можете просматривать, загружать или клонировать репозиторий и играть с кодом, чтобы лучше понять, как работает процесс загрузки файлов.
Для того чтобы можно было загружать на сервер один или несколько файлов, в форме применяется специальное поле. В браузерах Firefox, IE и Opera такой элемент отображается как текстовое поле, рядом с которым располагается кнопка с надписью «Обзор...» (рис. 1). В Safari и Chrome доступна только кнопка «Выберите файл» (рис. 2).
Рис. 1. Вид поля для загрузки файла в Firefox
При нажатии на кнопку открывается окно для выбора файла, где можно указать, какой файл пользователь желает использовать.
Синтаксис поля для отправки файла следующий.
Атрибуты перечислены в табл. 1.
Прежде, чем использовать данное поле, в форме необходимо сделать следующее:
- задать метод отправки данных POST (method="post" );
- установить у атрибута enctype значение multipart/form-data .
Форма для загрузки файла продемонстрирована в примере 1.
Пример 1. Создание поля для отправки файла
HTML5 IE Cr Op Sa Fx
Хотя можно установить ширину поля через атрибут size , в действительности ширина никак не влияет на результат работы формы. В браузерах Safari и Chrome этот атрибут вообще никакого воздействия не оказывает.
Атрибут multiple более важен, он позволяет не ограничиваться одним файлом для выбора, а указать их сразу несколько для одновременной загрузки.
Если атрибут accept не указывать, тогда добавляются и загружаются файлы любого типа. Наличие accept позволяет ограничить выбор файла, что особенно важно, когда требуется загрузить только изображение или видео. В качестве значения выступает , несколько значений разделяются между собой запятой. Также можно использовать следующие ключевые слова:
- audio/* - выбор музыкальных файлов любого типа;
- image/* - графические файлы;
- video/* - видеофайлы.
В табл. 2 показаны некоторые допустимые значения атрибута accept .
Использование дополнительных атрибутов показано в примере 2.
HTML5 IE 10+ Cr Op Sa Fx
Не все браузеры поддерживают новые атрибуты. IE полностью игнорирует multiple и accept , Safari не поддерживает accept , а Firefox не работает с MIME-типом, только с ключевыми словами. Поэтому в примере выше специально для Firefox установлено значение image/*,image/jpeg . Также учтите странную ошибку в Опере, она не допускает пробелы после запятой внутри accept .
Результат примера показан на рис. 3. Обратите внимание, что из-за наличия multiple несколько изменился вид поля.
Как загрузить файл на сервер используя PHP? В этой статье мы подробно рассмотрим этот вопрос с примерами.
HTML-форма для отправки файла
Первое, что нужно знать для загрузка файлов на сервер - это особенности HTML-форм, которые отправляют файл.
Вот пример HTML-кода такой формы: