Загрузка файлов методом 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");
}
}

?>

Полосу прогресса загрузки файлов можно реализовать через «Отслеживание прогресса загрузки файлов через сессии».