Skip to content

Instantly share code, notes, and snippets.

@FoggyK
Last active January 5, 2021 17:48
Show Gist options
  • Save FoggyK/0c2ec85cdab5d3e92231f0a444f4c06b to your computer and use it in GitHub Desktop.
Save FoggyK/0c2ec85cdab5d3e92231f0a444f4c06b to your computer and use it in GitHub Desktop.
Лекция 6 Загрузка файлов

Принципы загрузки фалов через форму

Функционал, отвечающий за отправку файлов на сервер, реализуется довольно просто. Как и в примерах из предыдущих уроков, за это отвечает специальное поле формы. Но ее настройка имеет некоторые особенности.

При осуществлении загрузки фйалов нужно обратить особое внимание на атрибуты 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.

Суперглобальный массив $_FILES

Если вместе с текущим запросом были загружены файлы, 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() вы можете проверить, является ли файл загруженным в текущем запросе. Она принимает всего один параметр — имя файла, а возвращает результат логического типа.

PHP
//Определяем место сохранения загруженного файла и его имя
$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.

PHP
<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment