PHP 2615 ~ 4 мин.

PHP 8.1: $_FILES: Новое значение full_path для загрузки каталогов

PHP 8.1: $_FILES: Новое значение full_path для загрузки каталогов

В PHP 8.1 $_FILES будет содержать новый ключ с именем full_path, который содержит полный путь к файлу, указанный браузером.

$_FILES - суперглобальная переменная PHP. Она содержит имена, размеры и MIME-типы файлов, загруженных в текущем HTTP-запросе.

В полях загрузки HTML-файла можно загрузить весь каталог с атрибутом webkitdirectory. webkitdirectory- это атрибут HTML, который можно использовать в элементах HTML input с расширением type=file. Это не стандарт браузера, но его поддерживают все основные браузеры, включая Chrome 6+, Firefox 50+, Edge 13+ и Safari 11.1+.


<form action="" method="post" enctype="multipart/form-data">
    <input name="files[]" type="file" webkitdirectory multiple />
    <input type="submit" />
</form>

До PHP 8.1 $_FILES содержали относительные пути в файловой системе пользователя для учета подкаталогов, содержащих файлы с одинаковыми именами.  Например, если пользователь загружает каталог foo, значение name массива $_FILES содержит только имя файла без относительного пути:


foo
 ├── dir1
 │    └── file.txt
 └── dir2
      └── file.txt

Если посмотрим содержимое $_FILES:


var_dump($_FILES);


array(1) {
  ["files"]=> array(6) {
    ["name"]=> array(2) {
      [0]=> string(8) "file.txt"
      [1]=> string(8) "file.txt"
    }
    ["tmp_name"]=> array(2) {
      [0]=> string(14) "/tmp/phpK1J4UI"
      [1]=> string(14) "/tmp/phpgRqHHs"
    }
    // ... так же содержит поля error, type, size
  }
}

 До PHP 8.1 было невозможно принять каталог как файл, загруженный из браузера пользователя, и сохранить их с точной структурой каталогов или получить доступ к относительным путям, потому что PHP не передавал эту информацию в массиве $_FILES.

В PHP 8.1 такая возможность появилась, благодаря новому ключу с именем full_path, который содержит полный путь, указанный браузером.


var_dump($_FILES);
array(1) {
  ["files"]=> array(6) {
    ["name"]=> array(2) {
      [0]=> string(8) "file.txt"
      [1]=> string(8) "file.txt"
    }
    ["full_path"]=> array(2) {
      [0]=> string(19) "foo/dir1/file.txt"
      [1]=> string(19) "foo/dir2/file.txt"
    }
    ["tmp_name"]=> array(2) {
      [0]=> string(14) "/tmp/phpK1J4UI"
      [1]=> string(14) "/tmp/phpgRqHHs"
    }
    // ... + error, type, size
  }
}

 

Имея информацию из full_path, можно сохранить относительные пути или восстановить тот же каталог на сервере.

В приведенном выше примере массив $_FILES['files']['full_path'] содержит путь к загруженному файлу, включая его путь. Это более полезно в отличие от массива $_FILES['files']['name'], который содержит повторяющиеся записи, потому что оба dir1 и dir2 содержат файл с тем же именем file.txt.  

Временный путь для загруженных файлов ($_FILES['files']['tmp_name']) остается уникальным и не сохраняется во вложенных каталогах. Можно безопасно продолжать использовать значения tmp_name с функцией move_uploaded_file.
Массив full_path будет всегда существовать для всех загрузок файлов, включая стандартные одиночные или множественные загрузки файлов, и в некоторых случаях будет просто идентичен массиву name.

Повышение безопасности

PHP анализирует только информацию об относительном пути, отправленную браузером, и передает эту информацию в массив $_FILES. Нет гарантии, что значения в массиве full_path  содержат реальную структуру каталогов, и приложения PHP не должны доверять этой информации.

Значения в массиве full_path вводятся пользователем, и им нельзя доверять!

Приложения, которые принимают загрузку каталога и хранят файлы в соответствии со значениями full_path, должны обеспечить правильную проверку информации в full_path, перед перемещением загруженных файлов во вложенный каталог.

Некоторые варианты угроз:

  • Атаки с обходом каталогов, отправляя путь, который ведет к другому каталогу, например foo/../../../etc/password.
  • Атаки на исчерпание ресурсов, отправляя путь с глубоко вложенными путями, например foo/a/a/a/a/a/a/a/a/a/a/a/a/a.jpg, или очень длинное имя, которое приведет к ограничению пути в определенных файловых системах.
  • Нарушение целостности из-за предоставления имени файла, которое не может быть создано, например CON, недопустимое имя файла - Файловые системы Windows.

Чтобы предотвратить такие атаки, всегда ограничивайте уровень вложенности, убедитесь, что файл не существует перед записью, и запрещайте пути, которые позволяют обход каталога. Кроме того, ни в коем случае нельзя удалять стандартные проверки содержимого файла (такие как проверка расширения файла и типов MIME).

Влияние на обратную совместимость

Ключ массива full_path в $_FILES - это новая функция в PHP 8.1. Существующие значения массива name не изменяются, и они продолжают содержать только имя файла без пути к файлу.


Использование full_path в более старых версиях PHP

К сожалению, нет простого способа перенести эту функциональность в более старые версии PHP.

Для загрузки файлов требуется наличие в форме HTML атрибута enctype="multipart/form-data". Из-за этого атрибута PHP поток в php://input будет пустой, потому что PHP заполняет суперглобальные переменные $_POST и $_FILES и опустошает php://input поток. Это исключает получение предоставленной браузером информации о пути к файлу при чтении потока php://input.

Однако директива enable_post_data_reading=0  в PHP INI - запрещает PHP заполнять $_POST и $_FILES, оставляя таким образом значения потока php://input нетронутыми. В качестве хак-подхода, можно парсить запрос необработанного HTTP и заполнять $_POST и $_FILES массивы или объектов PSR-7 HTTP запроса. Эта информация содержит предоставленный браузером относительный путь к файлу. 

В качестве альтернативы, было бы проще постепенно улучшать взаимодействие с пользователем в веб-браузерах, используя клиентский подход JavaScript для отправки содержимого файлов и путей к файлам в отдельном поле.

Что думаешь?

Категории
  • PHP 65
  • Заметки 15
  • Безопасность 3
  • Флуд 2
  • Nginx 2
  • ИТ новости 2
  • Видео 1
  • Docker 1
  • Roadmap 1
  • Архитектура 0

Хочешь поддержать сайт?

Делаем из мухи слона

sergeymukhin.com

персональный блог о веб-разработке от Сергея Мухина. Блог был основан в 2018 году, и собирался уделять основное внимание последним тенденциям, учебным пособиям, а также советам и рекомендациям, позволяющим начинающим девелоперам встать быстрее на правильную дорогу веб разработки, но что-то пошло не так 😃

Релизы PHP 8.4

Дата Релиз
8 Июня 2024 Альфа 1
20 Июня 2024 Альфа 2
04 Июля 2024 Альфа 3
16 Июля 2024 Feature freeze
18 Июля 2024 Бета 1
01 Августа 2024 Бета 2
15 Августа 2024 Бета 3
29 Августа 2024 RC 1
12 Сентября 2024 RC 2
26 Сентября 2024 RC 3
10 Октября 2024 RC 4
24 Октября 2024 RC 5
07 Ноября 2024 RC 6
21 Ноября 2024 GA

Что нового?