Функционал, отвечающий за отправку файлов на сервер, реализуется довольно просто. Как и в примерах из предыдущих уроков, за это отвечает специальное поле формы. Но ее настройка имеет некоторые особенности.
При осуществлении загрузки фйалов нужно обратить особое внимание на атрибуты enctype и method, задающие способ кодирования отправляемых данных и HTTP-метод запроса.
Если ваша форма содержит поля, отвечающие за загрузку файлов, то элементу
необходимо явным образом установить атрибут enctype в значение multipart/form-data, а method задать как POST.Заметка
Приведенные выше значения атрибутов не связанны непосредственно с HTML. Они оптимизируют внутренние процессы браузера. Если вы правильным образом настроите элемент , отправка больших файлов будет произведена гораздо быстрее, а серверная программа сможет легко принять и обработать их.
В HTML для отправки файлов из формы используется многозадачный элемент . Его атрибут type должен иметь значение file. Браузер отобразит такое поле в виде кнопки с текстом «выберите файл» или аналогичным.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Пример создания поля загрузки файлов</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
<input name="user-file" type="file">
<br><br>
<input type="submit" value="Отправить">
</form>
</body>
</html>
При нажатии кнопки откроется проводник файловой системы. В нем можно перемещаться по директориям компьютера. Интерфейс интуитивно понятен любому пользователю. Все что нужно сделать — это найти нужный файл и нажать кнопку «Открыть». Отметим, что выбирать нужные документы и файлы может только сам пользователь. Явное указание атрибута value с именем или расположением какого-либо файла не приведет к успеху.
Чтобы выбранный файл был загружен при отправке формы, полю необходимо добавить атрибут name с уникальным значением.
По умолчанию пользователь может выбрать только один файл, предназначенный к отправке. HTML позволяет изменить это поведение. Множественный выбор станет доступным после добавления к полю атрибута multiple.
Также нужно отметить, что поле загрузки файлов можно заблокировать с помощью атрибута disabled. Это сделает невозможным какое-либо взаимодействие с ним. Если оно заблокировано после осуществления выбора файла, он не будет отправлен вместе с остальными данными формы. Такая ситуация может возникнуть при использовании встроенного в браузер языка программирования JavaScript.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Пример блокировки поля множественного выбора</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
<input disabled multiple name="user-file" type="file">
<br><br>
<input type="submit" value="Отправить">
</form>
</body>
</html>
Загрузка файла на сервер может быть выполнена как с помощью веб-формы, расположенной на странице сайта, так и прямым программным запросом. Для PHP-интерпретатора способ передачи файла не имеет значения. Спецификация HTTP-протокола приводит эти операции к единообразному виду.
Любой загружаемый файл будет помещен в специальную директорию для временного хранения, а связанная с ним информация добавлена в суперглобальный массив $_FILES. Если не переместить файл в другое место, после завершения скрипта произойдет его бесследное удаление. Директория временного хранения определяется настройкой upload_tmp_dir конфигурационного файла php.ini.
Если вместе с текущим запросом были загружены файлы, PHP-интерпретатор автоматически заполнит суперглобальный массив $_FILES соответствующей информацией. Его структура довольно проста. Элементы массива соответствуют именам параметров HTTP-запроса. Например, ваша веб-форма содержит поле загрузки файла с атрибутом «name="upload-file"». В таком случае информация будет добавлена в $_FILES['upload-file'].
Содержимое массива $_FILES:
- $_FILES['поле-запроса']['name'] — реальное имя файла, которое он имел до отправки.
- $_FILES['поле-запроса']['size'] — размер загруженного файла в байтах.
- $_FILES['поле-запроса']['type'] — MIME-тип файла.
- $_FILES['поле-запроса']['tmp_name'] — содержит имя файла, которое назначил ему интерпретатор при размещении во временную директорию;
- $_FILES['поле-запроса']['error'] — код ошибки, возникшей при загрузке. Если всё нормально, элемент будет иметь значение «0». http://php.net/manual/ru/features.file-upload.errors.php Поле веб-формы может иметь атрибут multiple, позволяющий осуществлять множественный выбор файлов. В таком случае элементы name, size, type, tmp_name и error будут являться массивами. Например, загружены два файла через поле формы с именем test-file. Получить имя первого файла можно в $_FILES['test-file']['name'][0], а второго $_FILES['test-file']['name'][1].
Заметка
Существует одно требование к HTML-разметке полей, осуществляющих множественный выбор и загрузку файлов. Их атрибут name должен быть составлен следующим образом «name="имя-атрибута[]"». Если вы опустите конструкцию [], PHP обработает только один файл.
Как говорилось выше, загружаемые файлы размещаются во временной директории сервера и автоматически удаляются PHP-интерпретатором после выполнения текущего запроса. Их можно сохранить, переместив в другое место. Использовать стандартные функции copy() или rename() крайне нежелательно.
Для перемещения загруженных файлов существует специальная функция move_uploaded_file(). Она принимает два обязательных строковых параметра. Первый указывает имя файла во временной директории, а второй - путь назначения. Функция возвращает true в случае успеха и false, если произошла ошибка.
С помощью функции is_uploaded_file() вы можете проверить, является ли файл загруженным в текущем запросе. Она принимает всего один параметр — имя файла, а возвращает результат логического типа.
//Определяем место сохранения загруженного файла и его имя
$destination = $_SERVER['DOCUMENT_ROOT']. '/uploads';
$fileTempName = $_FILES['parameter']['tmp_name'];
if (is_uploaded_file($fileTempName)) {
//Проверяем тип файла и меняем его имя в соответствии
$newFilename = $destination .'/user';
switch ($_FILES['parameter']['type']) {
case 'application/pdf':
$newFilename .= '-document.pdf';
break;
case 'video/mp4':
$newFilename .= '-video.mp4';
break;
default:
echo 'Файл неподдерживаемого типа';
exit;
}
//Перемещаем файл из временной папки в указанную
if (move_uploaded_file($fileTempName, $newFilename)) {
echo 'Файл сохранен под именем '. $newFilename;
} else {
echo 'Не удалось осуществить сохранение файла';
}
} else {
echo 'Файл не был загружен на сервер';
}
Важно
PHP позволяет изменять местоположение загруженных файлов с помощью обычных функций копирования или перемещения. Однако это довольно опасно. Существует ряд ухищрённых атак, основанных на таком недальновидном подходе.
Для перемещения и проверки существования загруженных файлов всегда используйте функции move_uploaded_file() и is_uploaded_file(). В процессе выполнения они осуществляют расширенные проверки и автоматически отсеивают ряд распространенных атак.
Ниже приводится пример PHP-скрипта. Если он вызывается в первый раз, либо в текущем запросе отсутствует загрузка файла, пользователю выводится форма. При загрузке, файл перемещается в корневую директорию сайта, а пользователю показывается информация, связанная с ним. Обрабатываются только изображения в форматах jpg, jpeg и png.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Простая форма загрузки файла</title>
</head>
<body>
<?php if (!isset($_FILES['upload']['tmp_name'])) : ?>
<!-- Данная форма будет показана, если не было загрузок -->
<form method="POST" enctype="multipart/form-data">
<input name="upload" type="file">
<br><br>
<input type="submit" value="Отправить">
</form>
<?php else: ?>
<?php
$newFilename = $_SERVER['DOCUMENT_ROOT']. '/uploaded-file';
$uploadInfo = $_FILES['upload'];
//Проверяем тип загруженного файла и дописываем расширение
switch ($uploadInfo['type']) {
case 'image/jpeg':
$newFilename .= '.jpg';
break;
case 'image/png':
$newFilename .= '.png';
break;
default:
echo 'Файл неподдерживаемого типа';
exit;
}
//Перемещаем файл из временной папки в указанную
if (!move_uploaded_file($uploadInfo['tmp_name'], $newFilename)) {
echo 'Не удалось осуществить сохранение файла';
}
?>
<!-- Выводим разметку, содержащую информацию о файле -->
<img src="/<?php echo basename($newFilename) ?>">
<ul>
<li>Размер файла: <?php echo $uploadInfo['size'] ?>байт</li>
<li>Имя до загрузки: <?php echo $uploadInfo['name'] ?></li>
<li>MIME-тип: <?php echo $uploadInfo['type'] ?></li>
</ul>
<?php endif; ?>
</body>
</html>