Размер файлов PHP: проверка, лимиты, удобный вывод

Раздел: Веб-разработка на PHP -> Загрузка файлов

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

Контроль размера загружаемых файлов - одна из ключевых задач веб-разработки. От этого зависит нагрузка на сервер, скорость обработки и безопасность. В статье рассмотрены основные подходы к получению, ограничению и форматированию размера файлов, а также типичные ошибки и способы их решения.

Наиболее эффективное решение: комбинированная проверка на клиенте и на сервере

Использование только серверной проверки может привести к отправке больших файлов, которые будут отклонены уже после полной загрузки. Клиентская проверка (HTML5 + JavaScript) отсеивает файлы до отправки, а серверная - гарантирует соблюдение лимитов.

Пример формы с атрибутами accept и max (для некоторых браузеров) и последующая обработка в 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="file" accept="image/*" />
  <input type="submit" value="Загрузить" />
</form>

<script>
document.querySelector('input[type="file"]').addEventListener('change', function() {
  if(this.files[0].size > 2 * 1024 * 1024) {
    alert('Файл слишком большой. Выберите файл до 2 МБ.');
    this.value = '';
  }
});
</script>

Php files size (размер файлов php)

<?php
// upload.php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
    $file = $_FILES['file'];
    $maxSize = 2 * 1024 * 1024; // 2 MB

    // Серверная проверка размера
    if ($file['error'] === UPLOAD_ERR_OK) {
        if ($file['size'] > $maxSize) {
            echo 'Файл превышает допустимый размер.';
        } else {
            // Перемещение файла
            move_uploaded_file($file['tmp_name'], 'uploads/' . $file['name']);
            echo 'Файл загружен успешно.';
        }
    } else {
        echo 'Ошибка загрузки: ' . $file['error'];
    }
}
?>

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

  • Скрытое поле MAX_FILE_SIZE подсказывает PHP, но не является обязательным.
  • Свойство files[0].size возвращает размер в байтах - клиентская проверка.
  • На сервере проверяется $file['size'] - реальное значение, переданное PHP.
  • Код состояния $file['error'] позволяет обработать разные сценарии (превышение лимита, частичная загрузка и т.д.).

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

  • Значение $_FILES['file']['size'] равно 0 при превышении upload_max_filesize. Решение: проверять не только размер, но и код ошибки UPLOAD_ERR_INI_SIZE (1).
  • Клиентская проверка обходится простым отключением JavaScript. Решение: обязательно дублировать проверку на сервере.
  • Атрибут max у input[type="file"] поддерживается не всеми браузерами. Положиться только на JS.

Как настроить глобальные лимиты размера файлов через php.ini?

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

; Пример для php.ini
upload_max_filesize = 10M
post_max_size = 12M
max_execution_time = 300
max_input_time = 300
; memory_limit также влияет - обычно >= post_max_size

Изменения вступают в силу после перезагрузки веб-сервера. Для некоторых хостингов доступно переопределение через .htaccess (если разрешено).

Если параметры не применяются, стоит проверить, в какой конфигурации они заданы (глобальный, .user.ini, .htaccess). Также есть ограничения веб-сервера (nginx client_max_body_size).

Как получить размер уже существующего на сервере файла?

Функция filesize() возвращает размер файла в байтах. Требуется путь к файлу.

$path = 'uploads/image.jpg';
if (file_exists($path)) {
    $bytes = filesize($path);
    echo "Размер файла: $bytes байт";
} else {
    echo 'Файл не найден';
}

Проблема: функция кеширует результаты, если включен clearstatcache не вызывать вручную. После изменения файла нужно сбросить кеш: clearstatcache(true, $path);.

Как отформатировать размер файла в читаемый вид (KB, MB, GB)?

Стандартная утилитарная функция:

function formatFileSize($bytes, $decimals = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $factor = floor((strlen($bytes) - 1) / 3);
    if ($factor >= count($units)) $factor = count($units) - 1;
    $value = $bytes / pow(1024, $factor);
    return round($value, $decimals) . ' ' . $units[$factor];
}

echo formatFileSize(filesize('uploads/video.mp4')); // например, "12.45 MB"

Как проверить размер удалённого файла, не загружая его?

Используется CURL-запрос с методом HEAD и извлечение заголовка Content-Length:

$url = 'https://example.com/file.zip';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
$size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
curl_close($ch);
if ($size > 0) {
    echo "Размер удалённого файла: $size байт";
} else {
    echo 'Не удалось определить размер';
}

Ошибка: сервер может не отдавать Content-Length, либо использовать chunked encoding.

Как загружать файлы частями (большие файлы) с контролем размера каждой части?

Реализация чанковой загрузки на JavaScript и PHP:

// JavaScript (фрагмент)
const file = fileInput.files[0];
const chunkSize = 1024 * 1024; // 1 MB
let offset = 0;
while (offset < file.size) {
    const chunk = file.slice(offset, offset + chunkSize);
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('offset', offset);
    formData.append('filename', file.name);
    fetch('upload_chunk.php', { method: 'POST', body: formData });
    offset += chunkSize;
}
<?php // upload_chunk.php
$chunk = $_FILES['chunk'];
$offset = $_POST['offset'];
$filename = basename($_POST['filename']);
$dest = 'temp/' . $filename;
file_put_contents($dest, file_get_contents($chunk['tmp_name']), FILE_APPEND);
// Проверка общего размера после каждого чанка
if (filesize($dest) > 10 * 1024 * 1024) { // 10 MB лимит
    unlink($dest);
    echo 'Превышен общий лимит';
} else {
    echo 'ok';
}
?>

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

Дополнительные примеры и их результаты

Пример 1. Обработка ошибок при превышении лимита сервера

Код PHP, который выводит человекочитаемые сообщения для каждого из возможных кодов ошибки загрузки:

Пример
$errorMessages = [
    UPLOAD_ERR_OK => 'Ошибок нет',
    UPLOAD_ERR_INI_SIZE => 'Файл превышает размер, разрешённый php.ini',
    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 => 'Расширение остановило загрузку',
];
$errorCode = $_FILES['file']['error'];
echo $errorMessages[$errorCode] ?? 'Неизвестная ошибка';
Вывод (при превышении upload_max_filesize):
Файл превышает размер, разрешённый php.ini

Пример 2. Определение MIME-типа и размера одновременно

Часто вместе с размером проверяют тип файла (image/png, application/pdf и т.д.):

Пример
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
$maxSize = 5 * 1024 * 1024;
$file = $_FILES['file'];

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['file']['tmp_name']);

if (!in_array($mime, $allowedTypes)) {
    echo 'Неподдерживаемый тип файла.';
} elseif ($file['size'] > $maxSize) {
    echo 'Файл слишком большой.';
} else {
    echo 'Всё в порядке, можно загружать.';
}

Пример 3. Логирование попыток загрузки с размерами

Пример
$logFile = 'uploads.log';
$logData = date('Y-m-d H:i:s') . ' | ' . $_SERVER['REMOTE_ADDR'] . ' | ' . $_FILES['file']['name'] . ' | ' . $_FILES['file']['size'] . ' байт | error: ' . $_FILES['file']['error'] . PHP_EOL;
file_put_contents($logFile, $logData, FILE_APPEND | LOCK_EX);
Содержимое uploads.log:
2025-04-06 14:32:11 | 192.168.1.1 | myphoto.jpg | 245760 байт | error: 0

Пример 4. Сравнение скорости работы filesize() и SplFileInfo

Пример
$path = 'largefile.iso';
$start = microtime(true);
$size1 = filesize($path);
$time1 = microtime(true) - $start;

$start = microtime(true);
$size2 = (new SplFileInfo($path))->getSize();
$time2 = microtime(true) - $start;

echo "filesize: $size1 байт, время: $time1 секунд\n";
echo "SplFileInfo: $size2 байт, время: $time2 секунд";
filesize: 1073741824 байт, время: 0.0021 секунд
SplFileInfo: 1073741824 байт, время: 0.0025 секунд

Разница незначительна, но SplFileInfo может быть удобнее в ООП-контексте.

Пример 5. Отправка размера файла из JavaScript в PHP через скрытое поле

Пример
<form id="uploadForm" method="post" enctype="multipart/form-data">
  <input type="file" id="fileInput" name="file" />
  <input type="hidden" name="file_size_hidden" id="fileSizeHidden" value="" />
  <input type="submit" value="Загрузить" />
</form>
<script>
document.getElementById('fileInput').addEventListener('change', function() {
  if (this.files[0]) {
    document.getElementById('fileSizeHidden').value = this.files[0].size;
  }
});
</script>
Пример
<?php
$clientSize = $_POST['file_size_hidden'] ?? 0;
$serverSize = $_FILES['file']['size'] ?? 0;
if ($clientSize != $serverSize) {
    // потенциальное несоответствие, но можно принять любое
    echo "Предупреждение: размеры не совпадают.";
}
?>

Пример 6. Использование filter_var для проверки размера как целого числа

Пример
$maxSize = 1048576; // 1 MB
$size = $_FILES['file']['size'] ?? 0;
if (filter_var($size, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => $maxSize]]) === false) {
    echo 'Размер файла вне допустимого диапазона.';
}

Пример 7. Получение размера временного файла до перемещения

Уже показано в основном примере, но акцент на том, что $_FILES['file']['size'] - это размер оригинального файла, а не временного. Если нужен размер временного после загрузки, можно вызвать filesize($_FILES['file']['tmp_name']), но он совпадёт.

Пример 8. Ограничение суммарного размера нескольких загружаемых файлов

Пример
$totalSize = 0;
foreach ($_FILES['files']['tmp_name'] as $key => $tmpName) {
    if ($_FILES['files']['error'][$key] === UPLOAD_ERR_OK) {
        $totalSize += $_FILES['files']['size'][$key];
    }
}
if ($totalSize > 10 * 1024 * 1024) {
    echo 'Суммарный размер всех файлов превышает 10 МБ.';
} else {
    echo 'Общий размер в пределах лимита.';
}

размер файлов PHP - comments

En
Php files size (php)