Загрузка файлов
Аватар, фотография товара, документ — пользователи постоянно загружают файлы. PHP принимает файл сам и кладёт его во временную папку; ваша задача — проверить его и перенести в постоянное место.
Примерам этого урока нужен веб-сервер, поэтому здесь они не запускаются.
Форма
Чтобы форма могла отправлять файлы, ей нужен метод post и атрибут enctype:
<form method="post" action="/upload.php" enctype="multipart/form-data">
<input type="file" name="avatar">
<button type="submit">Загрузить</button>
</form>Без enctype="multipart/form-data" на сервер придёт только имя файла.
Массив $_FILES
Сведения о загруженном файле лежат в $_FILES под именем поля:
<?php
$file = $_FILES['avatar'];
echo $file['name']; // photo.jpg — имя на компьютере пользователя
echo $file['size']; // размер в байтах
echo $file['tmp_name']; // путь к временному файлу на сервере
echo $file['error']; // код ошибки, 0 — всё в порядкеПроверка ошибки
Первым делом проверяют, что файл действительно загрузился:
<?php
$file = $_FILES['avatar'] ?? null;
if ($file === null || $file['error'] !== UPLOAD_ERR_OK) {
exit('Файл не загружен');
}Ошибка возникает, если файл не выбран или превышает лимит из настроек сервера upload_max_filesize.
Проверка размера и типа
Имени файла и типу, которые прислал браузер, доверять нельзя — их легко подделать. Настоящий тип определяют по содержимому:
<?php
$file = $_FILES['avatar'];
if ($file['size'] > 2 * 1024 * 1024) {
exit('Файл больше 2 МБ');
}
$type = mime_content_type($file['tmp_name']);
$allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp'];
if (!isset($allowed[$type])) {
exit('Разрешены только картинки');
}Сохранение
Временный файл исчезнет после окончания запроса. Функция move_uploaded_file() переносит его в постоянную папку. Имя придумывают сами — случайное, с расширением по проверенному типу:
<?php
$file = $_FILES['avatar'];
$allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp'];
$extension = $allowed[mime_content_type($file['tmp_name'])];
$name = bin2hex(random_bytes(16)) . '.' . $extension;
$target = __DIR__ . '/uploads/' . $name;
if (move_uploaded_file($file['tmp_name'], $target)) {
echo 'Сохранено: ' . $name;
}Случайное имя решает сразу две задачи: файлы разных пользователей не перезаписывают друг друга, а чужое имя файла не попадает в путь.
Несколько файлов
Полю дают имя с квадратными скобками и атрибут multiple. Тогда каждый элемент $_FILES становится массивом:
<?php
foreach ($_FILES['photos']['tmp_name'] as $index => $tmpName) {
if ($_FILES['photos']['error'][$index] === UPLOAD_ERR_OK) {
echo $_FILES['photos']['name'][$index];
}
}Частая ошибка
Нельзя сохранять файл под именем, которое прислал пользователь. Файл shell.php в папке, доступной из браузера, превратится в чужой код на вашем сервере, а имя вида ../../index.php перезапишет файлы сайта. Проверяйте содержимое, давайте своё имя и храните загрузки в папке, где сервер не выполняет PHP.