Загрузка файлов на PHP-сайте: что проверить в первую очередь
Проблемы с загрузкой файлов на PHP-сайте обычно проявляются просто: файл не загружается, форма зависает, появляется ошибка 413, картинка не открывается после загрузки или сервер принимает файл, который принимать не должен. Начинать лучше не с переписывания формы, а с проверки лимитов, прав и обработки файла.
Проверить форму
Для загрузки файла форма должна использовать POST и enctype multipart/form-data. Если enctype забыли, файл на сервер не придёт, даже если поле в браузере выглядит нормально.
<form method="post" enctype="multipart/form-data">
<input type="file" name="image">
<button type="submit">Загрузить</button>
</form>
В Yii2 при использовании ActiveForm это обычно задаётся в options:
<?= ActiveForm::begin([
'options' => ['enctype' => 'multipart/form-data'],
]) ?>
Проверить лимиты PHP
Если маленький файл загружается, а большой нет, первым делом смотрят лимиты PHP. Важны upload_max_filesize и post_max_size. post_max_size должен быть больше, чем максимальный размер загружаемого файла.
php -i | grep upload_max_filesize
php -i | grep post_max_size
php -i | grep max_file_uploads
Пример настроек:
upload_max_filesize = 20M
post_max_size = 24M
max_file_uploads = 20
После изменения php.ini нужно перезапустить PHP-FPM или веб-сервер, иначе настройки не применятся.
Проверить лимиты nginx
Если nginx возвращает 413 Request Entity Too Large, PHP может даже не получить запрос. В таком случае проверяют client_max_body_size.
server {
client_max_body_size 24m;
}
После изменения конфигурации:
nginx -t
sudo systemctl reload nginx
Права на директорию uploads
Сайт должен иметь право записывать файлы в директорию загрузок. Если директория принадлежит другому пользователю, загрузка может падать с permission denied.
ls -la web/uploads
mkdir -p web/uploads
chown -R www-data:www-data web/uploads
chmod -R ug+rw web/uploads
Пользователь www-data здесь только пример. На конкретном сервере это может быть nginx, apache или пользователь хостинга.
Проверка файла в Yii2
На backend нужно проверять не только факт загрузки, но и размер, расширение, ошибки и тип файла. В Yii2 для этого обычно используют UploadedFile и правила модели.
public function rules()
{
return [
[
['image'],
'file',
'skipOnEmpty' => false,
'extensions' => ['jpg', 'jpeg', 'png', 'webp'],
'maxSize' => 5 * 1024 * 1024,
],
];
}
Само сохранение может выглядеть так:
$file = UploadedFile::getInstance($model, 'image');
if ($file !== null && $model->validate()) {
$name = Yii::$app->security->generateRandomString(24) . '.' . $file->extension;
$path = Yii::getAlias('@webroot/uploads/') . $name;
if (!$file->saveAs($path)) {
Yii::error('Не удалось сохранить файл', 'upload');
}
}
Имя файла лучше генерировать заново. Пользовательское имя может содержать пробелы, кириллицу, спецсимволы или совпасть с уже существующим файлом.
Не выполнять загруженные PHP-файлы
Директория uploads не должна выполнять PHP. Даже если форма принимает только картинки, эту защиту лучше настроить на уровне веб-сервера.
location /uploads/ {
location ~ \.php$ {
deny all;
}
}
Дополнительно можно хранить оригиналы вне webroot, а через публичную директорию отдавать только обработанные изображения или файлы после проверки.
MIME-тип и расширение
Расширение файла само по себе не гарантирует безопасность. Файл может называться image.jpg, но внутри быть чем угодно. Для изображений полезно проверять MIME-тип и возможность прочитать картинку.
$info = getimagesize($file->tempName);
if ($info === false) {
throw new BadRequestHttpException('Файл не является изображением');
}
Для документов логика будет другой, но общий принцип тот же: не доверять только имени файла.
Логи загрузки
Если загрузка нестабильна, стоит добавить временное логирование. В лог можно писать размер, расширение, ошибку PHP и итоговый путь. Полное содержимое файла в лог писать не нужно.
Yii::info([
'name' => $file ? $file->name : null,
'size' => $file ? $file->size : null,
'error' => $file ? $file->error : null,
], 'upload');
Короткий чек-лист
- У формы есть enctype multipart/form-data.
- Поле file имеет правильное имя.
- upload_max_filesize и post_max_size достаточны.
- В nginx настроен client_max_body_size.
- Директория uploads существует и доступна на запись.
- Файл проверяется правилами модели.
- Имя файла генерируется сервером.
- В uploads запрещено выполнение PHP.
- Ошибки загрузки пишутся в лог.
Загрузка файлов — место, где удобство и безопасность легко конфликтуют. Поэтому лучше сразу настроить понятные ограничения, чем потом разбираться, почему сервер принял лишний файл или не может сохранить нормальное изображение.
Комментарии (0)
Пока нет комментариев. Будьте первым!