readfile()
Функция readfile() в PHP читает содержимое файла и выводит его в браузер. Это удобный способ отображения и скачивания файлов.
Введение
Функция PHP readfile() читает файл и записывает его напрямую в буфер вывода, возвращая количество прочитанных байт. Поскольку она передаёт файл в вывод напрямую, не сохраняя содержимое в PHP-переменной, это наиболее экономичный по памяти способ отправить файл в браузер — именно поэтому она является стандартным инструментом для скачивания файлов.
В этой главе рассматриваются синтаксис и параметры readfile(), возвращаемые значения, отличия от родственных функций file_get_contents() и fread(), а также безопасное использование для отображения и скачивания файлов.
Синтаксис
readfile(
string $filename,
bool $use_include_path = false,
?resource $context = null
): int|false| Параметр | Описание |
|---|---|
$filename | Путь (или URL, если включён allow_url_fopen) к файлу для чтения и вывода. |
$use_include_path | Если true, PHP также выполняет поиск файла в include_path. По умолчанию false. |
$context | Необязательный ресурс контекста потока (создаётся функцией stream_context_create()). |
Возвращаемое значение: количество прочитанных байт или false при ошибке. Всегда проверяйте возвращаемое значение, а не игнорируйте его: отсутствующий файл вызывает предупреждение и всё равно отправляет частичный (зачастую пустой) ответ.
Как работает readfile()
При вызове readfile() PHP открывает файл, копирует его байты в буфер вывода частями и отправляет клиенту. Всё содержимое никогда не загружается в PHP-строку, поэтому потребление памяти остаётся низким даже для многогигабайтных файлов. Компромисс состоит в том, что у вас нет возможности преобразовать данные — на выходе получается побайтовая копия файла.
readfile() в сравнении с альтернативами
Выбор правильной функции имеет значение:
readfile()— потоковая передача файла напрямую в вывод. Лучший вариант для скачивания и передачи сырых файлов. Не возвращает строку, только количество отправленных байт.file_get_contents()— читает весь файл в строку, чтобы вы могли изменять, искать или хранить его. Потребляет память, пропорциональную размеру файла.fopen()+fread()— открывает дескриптор для точного позиционированного чтения; используется при необходимости читать управляемыми частями или перемещаться по файлу.highlight_file()— выводит файл с подсветкой синтаксиса PHP (для отображения исходного кода).
Правило большого пальца: если вам нужно только отправить файл, используйте readfile(); если нужно обработать файл, читайте его в переменную.
Примеры
Пример 1: Отображение текстового файла
<?php
readfile('example.txt');Это отправляет содержимое example.txt прямо в браузер. Если заголовок Content-Type не установлен, применяется значение по умолчанию сервера (обычно text/html).
Пример 2: Проверка возвращаемого значения
readfile() возвращает количество байт, что удобно для логирования или обработки ошибок:
<?php
$bytes = readfile('example.txt');
if ($bytes === false) {
http_response_code(404);
echo 'File not found.';
}Пример 3: Принудительное скачивание
Чтобы браузер скачивал файл вместо его отображения, отправьте нужные заголовки до любого вывода, затем вызовите readfile():
<?php
$file = 'report.pdf';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;Content-Type: application/octet-streamсообщает браузеру, что это двоичное скачивание.Content-Disposition: attachment; filename="..."вызывает диалог «Сохранить как» и задаёт предлагаемое имя файла.Content-Lengthпозволяет браузеру отображать точный индикатор выполнения.
Заголовки передаются функцией header() и должны быть отправлены до того, как функция выведет какие-либо байты — иначе возникнет ошибка «headers already sent».
Распространённые ошибки
- Никогда не передавайте в
$filenameнесанированные данные от пользователя. Значение вроде../../etc/passwdпозволит злоумышленнику читать произвольные файлы (атака обхода пути). Ограничьте допустимые файлы белым списком или обработайте путь черезbasename()и ограничьте его известным каталогом. - Никакого вывода до заголовков. Даже случайный пробел или BOM перед
<?phpсчитается выводом и сломаетContent-Disposition. - Очищайте буфер вывода для больших файлов. Если буферизация вывода включена, файл всё равно может буферизоваться в памяти. Вызовите
ob_end_clean()(илиflush()) передreadfile()при потоковой передаче очень больших файлов. - Чтение удалённых URL требует включения
allow_url_fopenвphp.ini.
Заключение
readfile() — основная функция PHP для отправки файла клиенту с минимальными накладными расходами на память: она передаёт байты прямо в вывод и возвращает количество отправленных байт. Используйте её для скачивания и передачи сырых файлов, применяйте совместно с header() для скачиваний, проверяйте имя файла во избежание атак обхода пути и обращайтесь к file_get_contents(), когда вам действительно нужно содержимое файла в переменной.