Ответ
Обработка загрузки файлов — стандартная, но критичная с точки зрения безопасности задача. Мой опыт охватывает как простые формы загрузки аватаров, так и сложные системы для контента с валидацией, обработкой и загрузкой в облако.
Безопасность — это приоритет. Моя типичная реализация включает:
- Валидацию на стороне сервера: Проверку MIME-типа через
finfo_file(), а не только расширения. Ограничение размера файла. - Санацию имен: Удаление опасных символов из оригинального имени файла с помощью
preg_replace(). - Генерацию уникального имени: Использование
uniqid()или хеша от содержимого файла, чтобы избежать перезаписи и инъекций в путь. - Проверку
is_uploaded_file()иmove_uploaded_file()для предотвращения атак на файловую систему.
Пример безопасной загрузки изображения:
if ($_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
$tmpPath = $_FILES['avatar']['tmp_name'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $tmpPath);
finfo_close($finfo);
// Разрешаем только JPEG и PNG
$allowedTypes = ['image/jpeg', 'image/png'];
if (!in_array($mimeType, $allowedTypes)) {
throw new Exception('Недопустимый тип файла.');
}
// Генерируем безопасное имя и перемещаем файл
$extension = pathinfo($_FILES['avatar']['name'], PATHINFO_EXTENSION);
$safeFileName = uniqid('avatar_') . '.' . $extension;
$targetPath = '/var/www/uploads/avatars/' . $safeFileName;
if (move_uploaded_file($tmpPath, $targetPath)) {
// Дополнительная обработка: создание превью через GD/Imagick
createThumbnail($targetPath, 150, 150);
}
}
Для проектов с высокой нагрузкой интегрировал загрузку напрямую в Amazon S3 или подобные облачные хранилища, используя их SDK, чтобы разгрузить сервер приложения.
Ответ 18+ 🔞
Да ты посмотри, какая тема простая на первый взгляд — загрузить файл. Ну, казалось бы, хуй с горы: форма, input type="file, и вперёд. Но нет, ёпта, тут подводных камней — овердохуища! Если не уследить, такую дыру в безопасности проделаешь, что потом волосы дыбом встанут.
Безопасность — это, блядь, святое. Я всегда делаю по полной программе, чтобы потом не охуеть от того, что на сервере какой-нибудь скрипт-вредитель оказался.
- Валидация на сервере — железобетонная. Смотрю MIME-тип через
finfo_file(), потому что доверия к расширению файла — ноль ебать. Размер тоже режу в зародыше. - Имена чищу. Оригинальное имя файла — это же сплошное «подозрение ебать чувствую». Все лишние символы — нахуй, через
preg_replace(). - Уникальное имя генерирую.
uniqid()или хеш от содержимого — чтобы никаких перезаписей и инъекций в путь. Исходное имя — в базу, если надо, а на диске — только эта сгенерированная абракадабра. - Обязательно
is_uploaded_file()иmove_uploaded_file(). Это священный ритуал, чтобы отсечь любые попытки наебать систему и сунуть файл не через форму.
Вот, смотри, как это выглядит в коде, когда всё по уму:
if ($_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
$tmpPath = $_FILES['avatar']['tmp_name'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $tmpPath);
finfo_close($finfo);
// Разрешаем только JPEG и PNG
$allowedTypes = ['image/jpeg', 'image/png'];
if (!in_array($mimeType, $allowedTypes)) {
throw new Exception('Недопустимый тип файла.');
}
// Генерируем безопасное имя и перемещаем файл
$extension = pathinfo($_FILES['avatar']['name'], PATHINFO_EXTENSION);
$safeFileName = uniqid('avatar_') . '.' . $extension;
$targetPath = '/var/www/uploads/avatars/' . $safeFileName;
if (move_uploaded_file($tmpPath, $targetPath)) {
// Дополнительная обработка: создание превью через GD/Imagick
createThumbnail($targetPath, 150, 150);
}
}
А если проект серьёзный, с кучей трафика, то тут уже терпения ноль ебать возиться с дисками своего сервака. Тут уже тянем сразу в Amazon S3 или его аналоги через их SDK. Сервер приложения разгружается, масштабируется всё легко, и голова не болит, где там эти гигабайты пользовательских котиков хранить.