Определение порога размера для отправляемых файлов

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

Основной метод изменения лимита загрузки файлов в PHP

Наиболее распространённый и эффективный способ задать максимальный размер загружаемого файла – редактирование основного конфигурационного файла PHP – php.ini. Этот метод подходит для сред с полным доступом к серверу (VPS, выделенный сервер, локальная разработка).

В файле php.ini необходимо изменить (или добавить) следующие директивы:

; Максимальный размер одного загружаемого файла
upload_max_filesize = 20M

; Общий максимальный размер данных POST-запроса (включает все файлы и поля)
post_max_size = 25M

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

; Максимальное время на получение входных данных (POST, GET)
max_input_time = 300

; Лимит памяти для скрипта (должен быть достаточным для обработки загруженного файла)
memory_limit = 128M

Пояснение шагов:

  • upload_max_filesize – определяет максимальный размер одного файла. Значение по умолчанию обычно 2M.
  • post_max_size – должен быть больше upload_max_filesize, так как POST-данные включают сам файл и дополнительные поля формы. Рекомендуется устанавливать на 5-10M больше.
  • max_execution_time – увеличивается для возможности обработки больших файлов.
  • max_input_time – время, отведённое на получение входных данных. При загрузке крупных файлов рекомендуется увеличить.
  • memory_limit – должно быть не меньше ожидаемого размера файла, если скрипт загружает его целиком в память. Для потоковой обработки можно оставить меньшее значение.

Типичные ошибки и их решения:

  • Ошибка UPLOAD_ERR_INI_SIZE (1): файл превышает значение upload_max_filesize. Решение – увеличить эту директиву.
  • Ошибка UPLOAD_ERR_FORM_SIZE (2): файл превышает значение, указанное в скрытом поле MAX_FILE_SIZE в HTML-форме. Решение – увеличить это поле или удалить его.
  • Пустой массив $_FILES после отправки большого файла: причина – превышение post_max_size. Весь POST-запрос обрывается, и данные не передаются. Решение – увеличить post_max_size.
  • Ошибка 500 Internal Server Error при изменении memory_limit или max_execution_time – возможно, указано недопустимое значение (например, -1 без ограничений) или конфликт с настройками хостинга.

После изменения php.ini необходимо перезапустить веб-сервер или PHP-FPM. Проверить текущие значения можно с помощью функции phpinfo().

Как изменить лимит без доступа к php.ini с помощью .htaccess?

Если у пользователя нет доступа к основному конфигурационному файлу (shared hosting), но веб-сервер Apache с модулем mod_php, можно использовать файл .htaccess в корне сайта или в каталоге, где требуется загрузка.

php_value upload_max_filesize 10M
php_value post_max_size 12M
php_value max_execution_time 300
php_value max_input_time 300

Важно: директива php_value работает только если на сервере разрешена опция AllowOverride Options или AllowOverride All. Иначе появится ошибка 500. Узнать это можно у хостинг-провайдера или через тестовый .htaccess с простой директивой.

Проблема: при попытке установить php_value для директив, требующих PHP_INI_SYSTEM, возникает ошибка. upload_max_filesize и post_max_size относятся к PHP_INI_PERDIR и могут быть установлены через .htaccess. А max_execution_time и memory_limit также подходят. Если ошибка всё же появляется, проверьте, что ваш хостинг использует mod_php, а не CGI/FastCGI.

Как использовать файл .user.ini на серверах с PHP-FPM?

Для сред с PHP-FPM (часто используется в современных хостингах) можно разместить файл .user.ini в корневой директории сайта. Он действует подобно .htaccess, но для PHP.

upload_max_filesize = 15M
post_max_size = 18M
max_execution_time = 200
memory_limit = 128M

Файл .user.ini применяется автоматически без перезагрузки сервера. Однако изменения вступают в силу не сразу (обычно кеш на несколько секунд).

Можно ли изменить лимит динамически в скрипте через ini_set?

К сожалению, директива upload_max_filesize имеет режим PHP_INI_SYSTEM и PHP_INI_PERDIR, но не PHP_INI_ALL. Это значит, что её нельзя изменить во время выполнения скрипта с помощью ini_set(). Аналогично для post_max_size.

// Следующий код НЕ сработает
ini_set('upload_max_filesize', '20M');  // Ошибка: недопустимая директива для ini_set
// Можно изменить только ограничения времени и памяти:
ini_set('max_execution_time', 600);
ini_set('memory_limit', '256M');

Таким образом, динамическое изменение размера файла возможно только через конфигурационные файлы на уровне приложения. Изменение max_execution_time и memory_limit помогает скрипту справиться с обработкой уже загруженного большого файла, но не влияет на сам лимит приёма.

Ошибка: если в скрипте вызвать ini_set('upload_max_filesize'), PHP вернёт false и может выдать предупреждение. Проверка не даст эффекта.

Как настроить лимиты на стороне веб-сервера (nginx, Apache)?

Если загрузка происходит через прокси-сервер (например, nginx перед PHP-FPM), файл может быть отвергнут на уровне веб-сервера ещё до передачи PHP. Поэтому необходимо увеличить соответствующие параметры.

Для nginx (в блоке server или location):

client_max_body_size 20M;

Для Apache (в конфигурации виртуального хоста или .htaccess):

LimitRequestBody 20971520  # 20 MB в байтах

Цель: избежать ошибки 413 Request Entity Too Large. Настройки nginx/Apache должны быть не меньше, чем post_max_size в PHP.

Если после настройки php.ini загрузка большого файла всё равно не работает, проверьте логи веб-сервера. Например, в nginx ошибка будет выглядеть как client intended to send too large body.

Как задать значения через конфигурацию пула PHP-FPM?

При использовании PHP-FPM можно задать директивы непосредственно в файле пула (обычно /etc/php/8.x/fpm/pool.d/www.conf или аналогичном):

php_value[upload_max_filesize] = 50M
php_value[post_max_size] = 55M
php_value[max_execution_time] = 500

После внесения изменений требуется перезагрузка PHP-FPM:

systemctl reload php8.2-fpm

Примечание: этот метод часто используется на выделенных серверах и VPS, где администратор управляет пулами.

Расширенные примеры настройки и отладки

Пример 1. Проверка и обработка ошибок при загрузке файла

Код ниже демонстрирует, как проанализировать коды ошибок из массива $_FILES и дать пользователю понятное сообщение.

Пример
// form.php
<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="2097152" /> <!-- 2 MB -->
    <input type="file" name="userfile" />
    <input type="submit" value="Загрузить" />
</form>
Пример
// upload.php
$allowed_errors = [
    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  => 'Загрузка остановлена расширением.',
];

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['userfile'])) {
    $error_code = $_FILES['userfile']['error'];
    echo $allowed_errors[$error_code] ?? 'Неизвестная ошибка.';
    if ($error_code === UPLOAD_ERR_OK) {
        echo ' Имя файла: ' . $_FILES['userfile']['name'];
    }
}
В случае, если файл превышает upload_max_filesize, пользователь увидит: «Размер файла превышает значение upload_max_filesize.»

Пример 2. Проверка текущих лимитов с помощью phpinfo()

Для быстрой диагностики можно создать скрипт, выводящий значения всех релевантных директив.

Пример
<?
phpinfo(INFO_CONFIGURATION);
?>

После запуска скрипта ищите разделы Core и найдите параметры: upload_max_filesize, post_max_size, max_execution_time, memory_limit. Также обратите внимание на max_file_uploads – максимальное количество файлов, загружаемых за один запрос.

Пример 3. Расчёт необходимого memory_limit при обработке изображения

При загрузке изображения и его обработке (например, изменение размера с помощью GD) PHP загружает изображение в память целиком. Потребление памяти может быть в несколько раз больше размера файла.

Пример
// Допустим, загружается JPEG изображение размером 10 МБ.
// Для декодирования в несжатый формат (RGB) потребуется:
// ширина * высота * 3 байта (для 24-битного цвета).
// Если изображение 4000x3000 пикселей:
$memory_needed = 4000 * 3000 * 3; // 36 000 000 байт ≈ 34.3 MB
// Плюс накладные расходы PHP: memory_limit должен быть около 64-128M.
echo 'Расчётная необходимая память: ' . round($memory_needed / 1024 / 1024, 1) . ' MB';
Расчётная необходимая память: 34.3 MB

Пример 4. Обработка загрузки через поток (stream) без загрузки всего файла в память

Для больших файлов (более 100 MB) можно избежать увеличения memory_limit, читая файл частями. Однако это не влияет на лимиты приёма файла, а только на его обработку.

Пример
$inputStream = fopen('php://input', 'r');
$outputFile = fopen('/tmp/large_file.dat', 'w');
stream_copy_to_stream($inputStream, $outputFile);
fclose($inputStream);
fclose($outputFile);
echo 'Файл сохранён в потоке.';

Данный скрипт принимает тело POST-запроса (которое уже прошло проверку на upload_max_filesize и post_max_size) и записывает его напрямую в файл, не создавая временной копии в памяти. Однако такой подход требует отключения обработки multipart-форм (обычно используется для application/octet-stream).

Пример 5. Настройка nginx совместно с PHP-FPM для загрузки файлов до 100 MB

Конфигурация nginx (фрагмент):

Пример
server {
    listen 80;
    server_name example.com;
    client_max_body_size 100M;

    location /upload/ {
        proxy_pass http://127.0.0.1:9000;
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
    }
}

Пул PHP-FPM (фрагмент):

Пример
php_value[upload_max_filesize] = 95M
php_value[post_max_size] = 100M
php_value[max_execution_time] = 600
php_value[max_input_time] = 600

Почему в PHP установлено 95M, а не 100M? Небольшой запас оставляется для учёта накладных расходов multipart-запроса. Тогда nginx пропустит запрос, а PHP успешно примет файл.

Пример 6. Использование .user.ini на разных уровнях каталогов

Файл .user.ini может располагаться не только в корне, но и в подкаталогах. Настройки применяются ко всем вложенным директориям, если не переопределены.

Пример
# /var/www/site/public/.user.ini
upload_max_filesize = 50M

# /var/www/site/public/admin/.user.ini
upload_max_filesize = 10M   ; для панели администратора лимит снижен

Такая иерархия удобна на сайтах с разными ролями пользователей.

Настройка максимального размера загружаемого файла в PHP - comments

En
Php размер загружаемого файла (php)