Реализация загрузки файлов средствами PHP: от простого к сложному
Основной способ загрузки файла через суперглобальный массив $_FILES
Как организовать стандартную загрузку одного файла с сервера?
Наиболее распространённый метод - использование элемента формы input type="file" и обработчика на PHP, который получает данные из массива $_FILES.
Пример формы (файл upload.html):
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="userfile">
<input type="submit" value="Загрузить">
</form>
Php file date (дата файла в php)
Пример обработчика (файл upload.php):
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$uploadDir = __DIR__ . '/uploads/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$tmpName = $_FILES['userfile']['tmp_name'];
$fileName = basename($_FILES['userfile']['name']);
if (move_uploaded_file($tmpName, $uploadDir . $fileName)) {
echo "Файл '$fileName' загружен успешно.";
} else {
echo "Ошибка при перемещении файла.";
}
}
?>
Php загрузка файла (загрузка файла в php)
Типичные проблемы:
- Файл не загружается (пустой $_FILES). Причина: не указан атрибут enctype="multipart/form-data" в форме.
- Ошибка «Не удалось переместить файл». Проверить права на папку назначения и её существование.
- Превышение лимита upload_max_filesize. Настроить php.ini или использовать .htaccess.
Варианты реализации загрузки
Как загрузить несколько файлов одновременно?
Используется массив в имени поля формы, например name="files[]". В PHP каждый файл будет доступен как элемент массива $_FILES['files'].
<form action="multi_upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="files[]" multiple>
<input type="submit" value="Загрузить все">
</form>
обработка файлов php (обработка файлов в php)
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$uploadDir = __DIR__ . '/uploads/';
foreach ($_FILES['files']['tmp_name'] as $key => $tmpName) {
if ($_FILES['files']['error'][$key] === UPLOAD_ERR_OK) {
$name = basename($_FILES['files']['name'][$key]);
move_uploaded_file($tmpName, $uploadDir . $name);
}
}
}
?>
Files show php file (показ файлов в php)
Как реализовать асинхронную загрузку через AJAX?
Для отправки файла без перезагрузки страницы используется объект FormData и fetch/XMLHttpRequest.
// frontend (JavaScript)
const form = document.getElementById('uploadForm');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(form);
const response = await fetch('ajax_upload.php', { method: 'POST', body: formData });
const result = await response.text();
console.log(result);
});
прочитать php (чтение данных в php)
<?php // ajax_upload.php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$uploadDir = __DIR__ . '/uploads/';
$tmp = $_FILES['file']['tmp_name'];
$name = basename($_FILES['file']['name']);
if (move_uploaded_file($tmp, $uploadDir . $name)) {
echo "Файл $name отправлен асинхронно.";
} else {
http_response_code(500);
echo "Ошибка загрузки.";
}
}
?>
Php get file type (определение типа файла в php)
Как обеспечить безопасную загрузку с проверкой MIME-типа и расширения?
Используется комбинация mime_content_type() или finfo для проверки типа и проверка расширения файла.
$allowedMime = ['image/jpeg', 'image/png', 'application/pdf'];
$allowedExt = ['jpg', 'jpeg', 'png', 'pdf'];
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($fileInfo, $_FILES['file']['tmp_name']);
finfo_close($fileInfo);
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
if (!in_array($mime, $allowedMime) || !in_array($ext, $allowedExt)) {
die("Недопустимый тип файла.");
}
Потенциальные ошибки при валидации:
- MIME-тип не совпадает с расширением. Злоумышленник может переименовать .exe в .jpg. Рекомендуется проверять именно mime-тип содержимого.
- Переполнение буфера при очень большом файле. Установить лимит через upload_max_filesize и post_max_size.
Как загрузить файл и переименовать его для предотвращения конфликтов?
Генерация уникального имени через uniqid() или md5(time()).
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$newName = uniqid('upload_', true) . '.' . $ext;
$destination = __DIR__ . '/uploads/' . $newName;
move_uploaded_file($_FILES['file']['tmp_name'], $destination);
Расширенные примеры с кодом и результатом
Пример 1: загрузка с проверкой размера и созданием миниатюры для изображений
<?php
// image_upload.php
$maxSize = 2 * 1024 * 1024; // 2 MB
$uploadDir = __DIR__ . '/uploads/';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['image'])) {
if ($_FILES['image']['error'] !== UPLOAD_ERR_OK) {
die("Ошибка загрузки.");
}
if ($_FILES['image']['size'] > $maxSize) {
die("Файл слишком большой.");
}
$tmp = $_FILES['image']['tmp_name'];
$ext = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
$newName = 'img_' . uniqid() . '.' . $ext;
$dest = $uploadDir . $newName;
if (move_uploaded_file($tmp, $dest)) {
// Создание миниатюры (только для JPEG)
if (in_array($ext, ['jpg', 'jpeg'])) {
$src = imagecreatefromjpeg($dest);
$thumb = imagescale($src, 150, 150);
$thumbName = 'thumb_' . $newName;
imagejpeg($thumb, $uploadDir . $thumbName, 80);
imagedestroy($src);
imagedestroy($thumb);
echo "Файл загружен: $newName
";
echo "Миниатюра: $thumbName";
} else {
echo "Файл загружен: $newName";
}
} else {
echo "Не удалось сохранить файл.";
}
}
?>
Результат (вывод при успешной загрузке):
Файл загружен: img_64f2a1b3c0d5e.jpg Миниатюра: thumb_img_64f2a1b3c0d5e.jpg
Пример 2: Загрузка с использованием потоковой обработки (для больших файлов)
<?php
// stream_upload.php
$input = fopen("php://input", "rb");
$dest = fopen(__DIR__ . '/uploads/stream_' . date('Ymd_His') . '.dat', 'wb');
stream_copy_to_stream($input, $dest);
fclose($input);
fclose($dest);
echo "Файл принят через поток.";
?>
Примечание: этот вариант не использует стандартную форму, а получает сырые данные, например, при отправке через fetch с Content-Type: application/octet-stream.
Пример 3: Обработка ошибок загрузки с переводом кодов ошибок
<?php
$errorMessages = [
UPLOAD_ERR_OK => 'Загрузка успешна',
UPLOAD_ERR_INI_SIZE => 'Размер файла превышает upload_max_filesize',
UPLOAD_ERR_FORM_SIZE => 'Размер файла превышает MAX_FILE_SIZE в форме',
UPLOAD_ERR_PARTIAL => 'Файл загружен частично',
UPLOAD_ERR_NO_FILE => 'Файл не выбран',
UPLOAD_ERR_NO_TMP_DIR => 'Отсутствует временная папка',
UPLOAD_ERR_CANT_WRITE => 'Ошибка записи на диск',
UPLOAD_ERR_EXTENSION => 'Загрузка остановлена расширением PHP',
];
$errorCode = $_FILES['file']['error'] ?? UPLOAD_ERR_NO_FILE;
echo $errorMessages[$errorCode] ?? 'Неизвестная ошибка';
?>
Результат (если файл не выбран):
Файл не выбран
Пример 4: Загрузка с проверкой на существование файла и автоматическим добавлением суффикса
<?php
$uploadDir = __DIR__ . '/uploads/';
$baseName = 'document';
$ext = 'pdf';
$counter = 1;
$fileName = "$baseName.$ext";
while (file_exists($uploadDir . $fileName)) {
$fileName = $baseName . '_' . $counter . '.' . $ext;
$counter++;
}
move_uploaded_file($_FILES['file']['tmp_name'], $uploadDir . $fileName);
echo "Сохранили как $fileName";
?>
Результат (если уже есть document.pdf):
Сохранили как document_1.pdf