Управление размером загружаемых файлов в среде PHP

Раздел: Администрирование PHP -> Настройка PHP

Настройка загрузки файлов в PHP: параметры upload_max_filesize и post_max_size

Параметры upload_max_filesize и post_max_size в файле php.ini определяют максимальные размеры загружаемых файлов и всего POST-запроса соответственно. Корректная настройка необходима для работы форм с файлами, изображениями, архивами.

Основное решение: изменение файла php.ini

Как увеличить лимит загрузки файлов через прямой доступ к php.ini?

Наиболее надёжный способ - редактирование основного конфигурационного файла PHP. Необходимо найти файл php.ini (обычно в /etc/php/версия/cli/ или /etc/php/версия/apache2/), изменить значения и перезапустить веб-сервер.

; Пример: установка максимального размера одного файла 20MB
upload_max_filesize = 20M

; Максимальный размер всего POST-запроса (должен быть больше upload_max_filesize)
post_max_size = 25M

; Также стоит проверить memory_limit (рекомендуется > post_max_size)
memory_limit = 128M

; Максимальное время выполнения для загрузки (в секундах)
max_execution_time = 300
max_input_time = 300

После изменений выполнить команду:

sudo systemctl restart apache2   # для Apache
sudo systemctl restart nginx      # для Nginx с php-fpm

Типичные проблемы:

  • Значение post_max_size меньше upload_max_filesize - загрузка файла объёмом больше post_max_size приведёт к ошибке.
  • Недостаточный memory_limit - при обработке больших файлов скрипт может превысить лимит памяти.
  • Игнорирование max_execution_time и max_input_time - загрузка большого файла может прерваться по таймауту.

Альтернативные способы настройки

Как изменить лимиты через файл .htaccess на Apache?

Если нет доступа к php.ini, но используется Apache с mod_php или mod_suexec, можно применить директиву php_value в .htaccess.

php_value upload_max_filesize 20M
php_value post_max_size 25M
php_value max_execution_time 300
php_value max_input_time 300

Файл .htaccess должен находиться в корневой директории сайта. Действие распространяется на все вложенные каталоги.

Возможные проблемы:

  • Директивы могут быть заблокированы настройками сервера (AllowOverride не включает опции PHP).
  • Использование php_value в .htaccess невозможно при работе через FastCGI (например, php-fpm).

Решение:

Проверить конфигурацию Apache: AllowOverride All или использовать другой способ.

Как настроить параметры через файл .user.ini для PHP-FPM (CGI/FastCGI)?

При использовании PHP-FPM или CGI разрешён файл .user.ini (аналог .htaccess для PHP). Создать в корневой директории сайта файл .user.ini с теми же директивами, что в php.ini.

upload_max_filesize = 30M
post_max_size = 35M
max_execution_time = 600

Изменения вступают в силу без перезагрузки сервера, но кешируются на несколько секунд.

Ошибки:

  • Файл .user.ini не срабатывает, если не настроен сервер на его чтение (по умолчанию включено).
  • Директива memory_limit в .user.ini может быть недоступна (зависит от режима работы).

Как изменить лимиты непосредственно в PHP-скрипте с помощью ini_set()?

Функция ini_set() позволяет менять некоторые параметры во время выполнения скрипта. Подходит для гибкого управления (например, разные лимиты для разных форм).

<?php
ini_set('upload_max_filesize', '50M');
ini_set('post_max_size', '60M');
ini_set('max_execution_time', '600');
ini_set('max_input_time', '600');
// Обратите внимание: изменения действуют только в текущем скрипте
?>

Важно разместить вызовы ini_set в самом начале скрипта, до любого вывода. Параметр memory_limit с помощью ini_set изменить нельзя, если режим PHP запрещает (обычно разрешено).

Ограничения:

  • Некоторые хосты блокируют изменение критичных параметров через ini_set.
  • Параметры восстанавливаются после завершения скрипта; не влияют на другие запросы.
  • Не работает, если в PHP-конфигурации установлен режим PHP_INI_SYSTEM для директивы (upload_max_filesize имеет режим PHP_INI_PERDIR, поэтому доступен).

Как настроить лимиты загрузки в Nginx с PHP-FPM?

Nginx имеет собственный лимит размера тела запроса client_max_body_size. Он должен быть не меньше post_max_size.

# В блоке server или location:
client_max_body_size 50M;

# Также можно ограничить время:
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
fastcgi_send_timeout 600;
fastcgi_read_timeout 600;

После изменений перезагрузить Nginx.

sudo systemctl reload nginx

Частая ошибка:

Загрузка файла, превышающего client_max_body_size, приводит к ошибке 413 (Request Entity Too Large). Необходимо синхронизировать настройки Nginx и PHP.

Общие рекомендации и проверка

После настройки полезно создать тестовый скрипт для проверки:

<?php
phpinfo();
// Найдите строки upload_max_filesize, post_max_size, memory_limit
?>

Или создать форму загрузки и протестировать с файлом нужного размера.

Расширенные примеры настройки и работы с загрузкой файлов

Пример 1: Скрипт загрузки с проверкой лимитов и обработкой ошибок

Пример
<?php
// Получаем текущие лимиты
$uploadMax = ini_get('upload_max_filesize');
$postMax = ini_get('post_max_size');
$memoryLimit = ini_get('memory_limit');

echo "Текущие лимиты: upload_max_filesize = $uploadMax, post_max_size = $postMax, memory_limit = $memoryLimit\n";

// Устанавливаем свои (если разрешено)
ini_set('upload_max_filesize', '100M');
ini_set('post_max_size', '110M');
ini_set('memory_limit', '256M'); // может не сработать
ini_set('max_execution_time', '600');

// Проверяем доступность загрузки
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
    $file = $_FILES['file'];
    if ($file['error'] !== UPLOAD_ERR_OK) {
        // Обработка ошибок
        $errorMessages = [
            UPLOAD_ERR_INI_SIZE   => 'Размер файла превышает upload_max_filesize в php.ini',
            UPLOAD_ERR_FORM_SIZE  => 'Размер файла превышает MAX_FILE_SIZE в HTML форме',
            UPLOAD_ERR_PARTIAL    => 'Файл был загружен только частично',
            UPLOAD_ERR_NO_FILE    => 'Файл не был загружен',
            UPLOAD_ERR_NO_TMP_DIR => 'Отсутствует временная папка',
            UPLOAD_ERR_CANT_WRITE => 'Не удалось записать файл на диск',
            UPLOAD_ERR_EXTENSION  => 'PHP расширение остановило загрузку',
        ];
        echo "Ошибка: " . ($errorMessages[$file['error']] ?? 'Неизвестная ошибка');
    } else {
        echo "Файл '{$file['name']}' успешно загружен (размер: {$file['size']} байт).";
    }
}
?>

<form method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="20971520" /><!-- 20MB -->
    <input type="file" name="file" />
    <input type="submit" value="Загрузить" />
</form>
Вывод при попытке загрузить файл > upload_max_filesize:
Текущие лимиты: upload_max_filesize = 20M, post_max_size = 25M, memory_limit = 128M
Ошибка: Размер файла превышает upload_max_filesize в php.ini

Пример 2: Загрузка нескольких файлов и проверка суммарного размера

Пример
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['files'])) {
    $totalSize = 0;
    $errors = [];
    foreach ($_FILES['files']['tmp_name'] as $key => $tmpName) {
        if ($_FILES['files']['error'][$key] === UPLOAD_ERR_OK) {
            $totalSize += $_FILES['files']['size'][$key];
        } else {
            $errors[] = "Файл '{$_FILES['files']['name'][$key]}' не загружен (код ошибки {$_FILES['files']['error'][$key]})";
        }
    }
    $postMaxBytes = (int)ini_get('post_max_size');
    // Преобразование шорт-значений в байты
    $unit = strtoupper(substr(ini_get('post_max_size'), -1));
    $value = (int)ini_get('post_max_size');
    if ($unit === 'M') $postMaxBytes = $value * 1024 * 1024;
    elseif ($unit === 'K') $postMaxBytes = $value * 1024;
    // Аналогично для G
    echo "Суммарный размер загруженных файлов: $totalSize байт. Лимит POST: $postMaxBytes байт.\n";
    if (!empty($errors)) {
        echo "Ошибки:\n" . implode("\n", $errors);
    }
}
?>
<form method="post" enctype="multipart/form-data" accept-charset="utf-8">
    <input type="file" name="files[]" multiple />
    <input type="submit" value="Загрузить несколько файлов" />
</form>
Пример вывода при успешной загрузке двух файлов по 5MB:
Суммарный размер загруженных файлов: 10485760 байт. Лимит POST: 26214400 байт.
Ошибок нет.

Пример 3: Динамическое определение лимита и предупреждение пользователя

Пример
<?php
function getMaxFileSize() {
    // Возвращает максимальный размер файла в байтах, учитывая upload_max_filesize и post_max_size
    $uploadMax = parseSize(ini_get('upload_max_filesize'));
    $postMax = parseSize(ini_get('post_max_size'));
    // Для одного файла лимит равен upload_max_filesize, но с учётом остальных данных POST
    return $uploadMax; // обычно меньше или равен post_max_size
}
function parseSize($size) {
    $unit = preg_replace('/[^bBkKmMgG]/', '', $size);
    $value = (int) $size;
    switch (strtoupper($unit)) {
        case 'G': return $value * 1024 * 1024 * 1024;
        case 'M': return $value * 1024 * 1024;
        case 'K': return $value * 1024;
        default: return $value;
    }
}
$maxFileSize = getMaxFileSize();
echo "Максимальный размер одного файла: " . ($maxFileSize / 1024 / 1024) . " MB";
?>
<form method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $maxFileSize; ?>" />
    <input type="file" name="file" />
    <input type="submit" value="Загрузить" />
</form>
Результат: на странице отображается "Максимальный размер одного файла: 20 MB", форма скрыто передаёт лимит.

Пример 4: Настройка .user.ini для разных подпапок

Пример
# В корне сайта /var/www/html/ создан .user.ini с:
upload_max_filesize = 10M
# В подпапке /var/www/html/upload/ создан другой .user.ini с:
upload_max_filesize = 100M
# Теперь файлы, загружаемые через скрипты в /upload/, могут иметь размер до 100M.
# При этом в корне сохраняется лимит 10M.
При обращении к скрипту в /upload/ значение upload_max_filesize будет 100M, что можно проверить через phpinfo().

Пример 5: Логгирование ошибок загрузки при превышении лимитов

Пример
<?php
// Включаем логгирование ошибок PHP
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php_upload_errors.log');
error_reporting(E_ALL);

// После попытки загрузки
if ($_FILES['file']['error'] === UPLOAD_ERR_INI_SIZE) {
    error_log("Превышен upload_max_filesize: файл {$_FILES['file']['name']}, размер {$_FILES['file']['size']}");
}
// В лог будет записано сообщение.
?>
Содержимое /var/log/php_upload_errors.log:
[15-Mar-2025 12:34:56 Europe/Moscow] PHP Notice:  Превышен upload_max_filesize: файл large.zip, размер 209715200

Настройка загрузки файлов в PHP (upload_max_filesize, post_max_size) - comments

En
Php ini upload (php)