file_get_contents('notes.txt') читает весь файл и возвращает его одной строкой. Если файл нельзя прочитать, функция возвращает false. Для записи используйте file_put_contents('notes.txt', $text), которая создаёт файл или заменяет его содержимое.
Вывод:
Buy milk
Call Ada
Write docs
29 bytes
3 lines
Блок сначала записывает notes.txt, а потом читает его обратно, чтобы было с каким файлом работать. Путь вроде 'notes.txt' отсчитывается от текущего рабочего каталога; в веб-приложении стройте путь от папки самого скрипта через __DIR__ . '/notes.txt'.
Запись и дописывание через file_put_contents()
file_put_contents() возвращает число записанных байтов или false при сбое. По умолчанию она перезаписывает файл. Флаг FILE_APPEND вместо этого дописывает в конец, так работают простые логи, а LOCK_EX не даёт двум запросам писать в один и тот же момент:
Вывод:
Wrote 8 bytes
started
step 1 done
step 2 done
replaced
abc
5 bytes
Чтобы сохранить массив и получить его обратно массивом, запишите его в JSON через json_encode() и читайте через json_decode().
Чтение файла построчно через file()
file() читает файл в массив, где каждый элемент это строка. Каждая строка сохраняет перенос в конце, если не передать FILE_IGNORE_NEW_LINES, а FILE_SKIP_EMPTY_LINES отбрасывает пустые строки (работает только вместе с FILE_IGNORE_NEW_LINES):
Вывод:
string(9) "Buy milk
"
1. Buy milk
2. Call Ada
3. Write docs
3 tasks
file() и file_get_contents() загружают весь файл в память. Для файлов настроек и логов в несколько мегабайт это нормально. Для файла в сотни мегабайт читайте по строке через fopen() и fgets().
Проверка наличия файла перед чтением
Когда файла нет, file_get_contents() возвращает false, а PHP печатает предупреждение:
Warning: file_get_contents(missing.txt): Failed to open stream: No such file or directory in /home/index.php on line 2
Сначала проверьте через is_file() (файл существует и не является каталогом) или file_exists() (файл или каталог) и всегда сравнивайте результат с === false, потому что пустой файл возвращает "", а это тоже ложное значение:
Вывод:
empty.txt exists file
missing.txt missing
. exists directory
Cannot read missing.txt, using defaults
bool(false)
bool(true)
0 bytes
Не прячьте предупреждение через @file_get_contents(). Предварительная проверка или обработка false оставляет ошибку видимой, когда что-то ещё пойдёт не так.
Чтение части файла
Четвёртый и пятый аргументы это смещение в байтах, с которого начинать, и число байтов для чтения. Отрицательное смещение отсчитывается с конца файла. Именованные аргументы позволяют пропустить два аргумента между ними:
Вывод:
HEADER
line 2
last line
Смещения считаются в байтах, а не в символах. В UTF-8 японский символ занимает 3 байта, а буква кириллицы 2, поэтому смещение посреди символа разрезает его пополам. Чтобы работать с символами, прочитайте всю строку и используйте mb_substr().
Вывод текстового файла на веб-странице
Содержимое файла это текст, а текст, выводимый в HTML, нужно экранировать, иначе < в файле станет тегом. htmlspecialchars() экранирует его, а nl2br() превращает переносы строк в теги <br>. Запустите и посмотрите на вкладку Page:
Уберите htmlspecialchars() и запустите снова: теперь страница заканчивается на "v1.2: Fixed", потому что браузер читает <title> как настоящий тег и проглатывает всё после него как заголовок страницы. Почему это важно для всего, что может написать пользователь, рассказано на странице htmlspecialchars().
Чтение URL через file_get_contents()
При включённом allow_url_fopen (по умолчанию в php.ini) file_get_contents() читает и URL и возвращает тело ответа. Контекст потока добавляет метод, заголовки, тело и таймаут:
<?php
$html = file_get_contents('https://example.com/');
$context = stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => json_encode(['name' => 'Ada']),
'timeout' => 5,
'ignore_errors' => true, // return the body of 4xx/5xx responses too
],
]);
$response = file_get_contents('https://api.example.com/users', false, $context);
if ($response === false) {
// DNS failure, timeout, or a refused connection
}
Для повторов, редиректов с ограничениями и понятных кодов ошибок лучше подходит cURL или библиотека HTTP-клиента вроде Guzzle.
file_get_contents, file() и fopen()
| Что нужно | Что использовать | Память |
|---|---|---|
| Весь файл одной строкой | file_get_contents() | Весь файл |
| Строки в виде массива | file($path, FILE_IGNORE_NEW_LINES) | Весь файл |
| Записать или заменить файл одним вызовом | file_put_contents() | Записываемые данные |
| Добавить строку в лог | file_put_contents($path, $line, FILE_APPEND | LOCK_EX) | Одна строка |
| Читать большой файл построчно или строки CSV | fopen() с fgets() или fgetcsv() | Одна строка |
| Читать и писать в один и тот же открытый файл | fopen() с r+, a+ или c+ | То, что прочитано |
Функции с одним вызовом сами открывают файл, читают или пишут и закрывают его, поэтому они правильный выбор по умолчанию. Берите fopen(), когда файл слишком велик, чтобы держать его в памяти, или его нужно держать открытым между операциями.
Часто задаваемые вопросы
Как прочитать файл в строку в PHP?
Вызовите file_get_contents('path/to/file.txt'). Функция возвращает весь файл строкой или false, если файл нельзя прочитать, поэтому перед использованием сравните результат с === false.
Как дописать в файл в PHP?
Передайте флаг FILE_APPEND: file_put_contents('log.txt', "new line\n", FILE_APPEND);. Без него file_put_contents() заменяет весь файл. Добавьте LOCK_EX (FILE_APPEND | LOCK_EX), когда несколько запросов могут писать одновременно.
Как прочитать файл построчно в PHP?
Для небольших файлов file('data.txt', FILE_IGNORE_NEW_LINES) возвращает массив, где каждый элемент это строка. Для больших файлов откройте файл через fopen() и читайте по одной строке через fgets() в цикле while, тогда в памяти держится только одна строка.
Почему file_get_contents возвращает false?
Файла нет, путь отсчитывается не от того каталога, который вы думаете, или у PHP нет прав на чтение. PHP ещё и печатает предупреждение вроде Failed to open stream: No such file or directory. Проверяйте через is_file() и is_readable() и стройте пути от __DIR__.
Может ли file_get_contents прочитать URL?
Да, когда в php.ini включён allow_url_fopen: file_get_contents('https://example.com/') возвращает тело ответа. Для заголовков, POST-данных или таймаута передайте контекст из stream_context_create(); для чего-то более сложного cURL лучше обрабатывает ошибки.