Какой у вас опыт обработки загрузки файлов в PHP?

Ответ

Обработка загрузки файлов — стандартная, но критичная с точки зрения безопасности задача. Мой опыт охватывает как простые формы загрузки аватаров, так и сложные системы для контента с валидацией, обработкой и загрузкой в облако.

Безопасность — это приоритет. Моя типичная реализация включает:

  1. Валидацию на стороне сервера: Проверку MIME-типа через finfo_file(), а не только расширения. Ограничение размера файла.
  2. Санацию имен: Удаление опасных символов из оригинального имени файла с помощью preg_replace().
  3. Генерацию уникального имени: Использование uniqid() или хеша от содержимого файла, чтобы избежать перезаписи и инъекций в путь.
  4. Проверку 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, и вперёд. Но нет, ёпта, тут подводных камней — овердохуища! Если не уследить, такую дыру в безопасности проделаешь, что потом волосы дыбом встанут.

Безопасность — это, блядь, святое. Я всегда делаю по полной программе, чтобы потом не охуеть от того, что на сервере какой-нибудь скрипт-вредитель оказался.

  1. Валидация на сервере — железобетонная. Смотрю MIME-тип через finfo_file(), потому что доверия к расширению файла — ноль ебать. Размер тоже режу в зародыше.
  2. Имена чищу. Оригинальное имя файла — это же сплошное «подозрение ебать чувствую». Все лишние символы — нахуй, через preg_replace().
  3. Уникальное имя генерирую. uniqid() или хеш от содержимого — чтобы никаких перезаписей и инъекций в путь. Исходное имя — в базу, если надо, а на диске — только эта сгенерированная абракадабра.
  4. Обязательно 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. Сервер приложения разгружается, масштабируется всё легко, и голова не болит, где там эти гигабайты пользовательских котиков хранить.