Загрузка файлов методом POST
Через этот механизм загружают как текстовые, так и бинарные файлы.
Через PHP-функции аутентификации и работы с файлами программист получает
полный контроль над тем, кому можно загружать файлы на сервер, и что делать с файлом после загрузки.
PHP умеет принимать загруженные файлы из браузеров,
которые совместимы со стандартом RFC-1867.
Замечание:
Смежные замечания по конфигурации
Ознакомьтесь также с описанием директив конфигурационного
файла php.ini:
file_uploads,
upload_max_filesize,
upload_tmp_dir,
post_max_size
и max_input_time.
PHP также поддерживает загрузку файлов методом PUT,
через который загружают файлы на сервер клиенты Netscape Composer
и Amaya консорциума W3C. Подробнее
об этом методе рассказывает раздел
«Поддержка метода PUT».
Пример #1 Форма для загрузки файлов
Страница загрузки файлов на сервер реализуется
через форму, которая выглядит примерно так:
<!-- Тип кодирования данных, enctype, требуется указывать только так, как показывает пример -->
<form enctype="multipart/form-data" action="__URL__" method="POST">
<!-- Поле MAX_FILE_SIZE требуется указывать перед полем загрузки файла -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- Название элемента input определяет название элемента в суперглобальном массиве $_FILES -->
Отправить файл: <input name="userfile" type="file" />
<input type="submit" value="Отправить файл" />
</form>
В приведённом примере значение __URL__
нужно заменить ссылкой
на PHP-файл.
Скрытое поле MAX_FILE_SIZE
(значение
требуется указывать в байтах) должно идти перед полем
выбора файла. Значение поля указывает максимальный
размер файла, который принимает PHP.
Рекомендуется добавлять этот элемент в форму, поскольку
он не заставляет пользователя ждать окончания передачи большого
файла, а только потом узнавать, что файл оказался
слишком большим и передача не состоялась.
Имейте в виду: обойти это ограничение на стороне браузера
легко, поэтому не рассчитывайте, что эта функция
заблокирует файлы большего размера. Это только удобная функция
для пользователей клиентской части приложения.
Однако серверные PHP-настройки, которые касаются максимального размера,
обойти невозможно.
Замечание:
Проверьте, что форма загрузки содержит атрибут
enctype="multipart/form-data"
, иначе
загрузка файлов на сервер не будет работать.
Суперглобальный массив $_FILES содержит полную информацию о файлах,
которые загрузили на сервер. Содержимое массива после отправки приведённой формы выводит пример на этой странице.
Обратите внимание, здесь элемент с выбором файла называется userfile,
как в приведённом примере. Полю выбора файла разрешается присваивать произвольное имя.
- $_FILES['userfile']['name']
-
Исходное название файла на компьютере клиента.
- $_FILES['userfile']['type']
-
MIME-тип файла, если браузер отправил такую информацию.
Пример MIME-типа: «image/gif
».
MIME-тип не проверяется на стороне PHP, поэтому значение не принимают
без проверки.
- $_FILES['userfile']['size']
-
Размер принятого файла в байтах.
- $_FILES['userfile']['tmp_name']
-
Временное имя файла, под которым PHP хранил файл, который загрузили на сервер.
- $_FILES['userfile']['error']
-
Код ошибки,
которая возникает при загрузке файла.
- $_FILES['userfile']['full_path']
-
Полный путь, который отправил браузер. Это значение не всегда содержит реальную структуру
каталогов и ему нельзя доверять. Поле доступно с PHP 8.1.0.
По умолчанию PHP сохраняет принятые файлы на сервере в стандартной
вре́менной папке до тех пор, пока через директиву upload_tmp_dir
конфигурационного файла php.ini не зададут другой каталог.
На сервере директорию по умолчанию можно изменить через переменную TMPDIR того окружения,
в котором работает PHP. Установка переменной
функцией putenv() внутри PHP-скрипта работать
не будет. Через эту переменную окружения также проверяют,
что другие операции тоже работают с принятыми файлами.
Пример #2 Проверка файлов, которые загрузили на сервер
Дополнительную информацию дают описания функций
is_uploaded_file()
и move_uploaded_file(). Следующий пример
принимает и обрабатывает файл, который загрузили на сервер через форму.
<?php
$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
echo '<pre>';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "Файл не содержит ошибок и успешно загрузился на сервер.\n";
} else {
echo "Возможная атака на сервер через загрузку файла!\n";
}
echo 'Дополнительная отладочная информация:';
print_r($_FILES);
print "</pre>";
?>
PHP-скрипт, который принимает файл, должен реализовывать логику
определения того, что требуется сделать с файлом, который загрузили на сервер.
Можно, например, проверить переменную $_FILES['userfile']['size'],
чтобы отсечь чрезмерно большие или слишком мелкие файлы. Можно также
использовать переменную $_FILES['userfile']['type'],
чтобы выбросить файлы, которые не соответствуют заданным критериям типа файла.
Но выполняйте такую проверку только как первую в серии проверок, потому что это значение
контролируется клиентом и не проверяется на стороне PHP.
Кроме того, можно использовать переменную $_FILES['userfile']['error']
и планировать логику поведения кода с учётом кодов ошибок.
При любой логике требуется либо удалить файл из временного каталога,
либо переместить файл в другую директорию.
Если при отправке формы файл не выбрали, PHP установит
для переменной $_FILES['userfile']['size'] значение 0, а переменной
$_FILES['userfile']['tmp_name'] — none.
PHP удалит файл из временного каталога в конце запроса, если файл не переместили
или не переименовали.
Пример #3 Загрузка массива файлов
PHP поддерживает передачу массива из HTML-формы
даже с файлами.
<form action="" method="post" enctype="multipart/form-data">
<p>Изображения:
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="submit" value="Отправить" />
</p>
</form>
<?php
foreach ($_FILES["pictures"]["error"] as $key => $error) {
if ($error == UPLOAD_ERR_OK) {
$tmp_name = $_FILES["pictures"]["tmp_name"][$key];
// Функция basename() помогает защититься от атак на файловую систему;
// иногда требуется дополнительная проверка или очистка имени файла
$name = basename($_FILES["pictures"]["name"][$key]);
move_uploaded_file($tmp_name, "data/$name");
}
}
?>
Полосу прогресса загрузки файлов можно реализовать через
«Отслеживание прогресса загрузки файлов через сессии».