Работа с JSON-файлами в PHP: от основ до продвинутых техник
Основы работы с JSON-файлами в PHP
Наиболее эффективный способ чтения и записи JSON-файлов в PHP - использование пары функций file_get_contents и file_put_contents вместе с json_decode и json_encode. Этот подход позволяет минимизировать количество операций ввода-вывода и работает с любым типом данных, которые могут быть представлены в JSON.
// Чтение JSON из файла
$jsonString = file_get_contents('data.json');
$data = json_decode($jsonString, true);
// Обработка ошибки декодирования
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('Ошибка декодирования JSON: ' . json_last_error_msg());
}
// Изменение данных (пример)
$data['counter']++;
// Запись обратно в файл
$newJsonString = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents('data.json', $newJsonString);
Json php файл (php: работа с json-файлом)
Пояснение шагов:
- file_get_contents - читает весь файл в строку. Подходит для файлов небольшого и среднего размера.
- json_decode($string, true) - преобразует JSON в ассоциативный массив. Второй аргумент true гарантирует получение массива, а не объекта.
- json_last_error() - проверяет успешность декодирования. Значение JSON_ERROR_NONE говорит об отсутствии ошибок.
- json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) - преобразует массив обратно в JSON с форматированием (отступы) и сохраняет кириллицу.
- file_put_contents - атомарно записывает строку в файл, создавая его при необходимости.
Как прочитать JSON из файла, используя потоковые функции fopen и fread?
Этот вариант полезен, когда нужно обрабатывать файл по частям или контролировать позицию чтения.
$handle = fopen('data.json', 'r');
if (!$handle) {
throw new RuntimeException('Не удалось открыть файл');
}
$jsonString = '';
while (!feof($handle)) {
$jsonString .= fread($handle, 1024);
}
fclose($handle);
$data = json_decode($jsonString, true);
Типичные ошибки:
- Забыть проверить результат fopen - может привести к ошибке чтения.
- Неправильный режим доступа (например 'w' вместо 'r') - уничтожит содержимое файла.
- Использование цикла без проверки feof - может вызвать бесконечный цикл при повреждённом файле.
Как записать JSON в файл, используя fwrite?
Подходит для случаев, когда нужно дописывать данные или использовать блокировки.
$data = ['name' => 'Иван', 'age' => 30];
$jsonString = json_encode($data, JSON_UNESCAPED_UNICODE);
$handle = fopen('output.json', 'w');
if (flock($handle, LOCK_EX)) {
fwrite($handle, $jsonString);
flock($handle, LOCK_UN);
}
fclose($handle);
Проблемы:
- Без использования flock при параллельных запросах может произойти повреждение данных.
- Запись в несуществующую директорию - нужно предварительно создать её.
Как обработать ошибки JSON с помощью исключений?
Использование флага JSON_THROW_ON_ERROR в PHP 7.3+ позволяет вместо проверки json_last_error() получать исключение.
try {
$data = json_decode(file_get_contents('data.json'), true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
error_log('Ошибка JSON: ' . $e->getMessage());
// альтернативные действия
}
Важно:
- Данный способ исключает необходимость писать условные конструкции с json_last_error().
- Однако он не перехватывает ошибки самого файлового ввода-вывода - их нужно обрабатывать отдельно.
Как загрузить JSON из удалённого источника (URL)?
Если файл находится на другом сервере, можно использовать file_get_contents с URL, либо cURL для более тонкого контроля.
$url = 'https://api.example.com/data.json';
$context = stream_context_create(['http' => ['timeout' => 10]]);
$jsonString = file_get_contents($url, false, $context);
if ($jsonString === false) {
throw new RuntimeException('Не удалось получить данные с удалённого сервера');
}
$data = json_decode($jsonString, true);
Возможные сложности:
- Необходимость включения директивы allow_url_fopen в php.ini.
- Ограничение времени ожидания (timeout) при медленном соединении.
- Обработка HTTP-статусов (например, 404) - file_get_contents не умеет отличать ошибку от пустого ответа.
Расширенные примеры работы с JSON-файлами
Пример 1. Чтение и обновление конфигурационного файла
$configFile = 'config.json';
// Чтение
$config = json_decode(file_get_contents($configFile), true);
// Изменение
$config['version'] = '2.0';
$config['last_updated'] = date('Y-m-d H:i:s');
// Запись с блокировкой
$tempFile = $configFile . '.tmp';
file_put_contents($tempFile, json_encode($config, JSON_PRETTY_PRINT));
rename($tempFile, $configFile); // атомарная замена
// Содержимое config.json после выполнения:
{
"version": "2.0",
"last_updated": "2025-03-18 14:22:10",
"other": "..."
}
Данный подход гарантирует, что файл не будет повреждён в случае сбоя во время записи.
Пример 2. Сохранение массива данных из формы
$newEntry = [
'name' => $_POST['name'],
'email' => $_POST['email'],
'timestamp' => time()
];
// Загрузка существующих записей
$file = 'submissions.json';
$existing = file_exists($file) ? json_decode(file_get_contents($file), true) : [];
// Добавление новой записи
$existing[] = $newEntry;
// Перезапись
file_put_contents($file, json_encode($existing, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
// submissions.json:
[
{
"name": "Анна",
"email": "anna@example.com",
"timestamp": 1710765600
},
{
"name": "Иван",
"email": "ivan@example.com",
"timestamp": 1710765700
}
]
Пример 3. Обработка большой JSON-структуры с вложенными объектами
$complexData = [
'users' => [
['id' => 1, 'roles' => ['admin', 'editor']],
['id' => 2, 'roles' => ['subscriber']]
],
'metadata' => [
'generated' => date('c'),
'version' => '1.0'
]
];
// Запись с флагом JSON_FORCE_OBJECT для числовых ключей (если нужно)
$json = json_encode($complexData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
file_put_contents('complex.json', $json);
// Чтение и поиск пользователя
$restored = json_decode(file_get_contents('complex.json'), true);
$adminUsers = array_filter($restored['users'], fn($u) => in_array('admin', $u['roles']));
print_r($adminUsers);
Array
(
[0] => Array
(
[id] => 1
[roles] => Array
(
[0] => admin
[1] => editor
)
)
)
Пример 4. Использование JSON_THROW_ON_ERROR и проверка целостности данных
try {
$raw = file_get_contents('corrupted.json');
if ($raw === false) {
throw new RuntimeException('Не удалось прочитать файл');
}
$data = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException | RuntimeException $e) {
error_log($e->getMessage());
// Восстановление из резервной копии
$data = json_decode(file_get_contents('backup.json'), true);
}
Применяется в критичных системах, где потеря данных недопустима.
Пример 5. Построчное чтение большого JSON-файла (JSON Lines)
$handle = fopen('large.ndjson', 'r');
if (!$handle) die('Cannot open file');
while (($line = fgets($handle)) !== false) {
$record = json_decode(trim($line), true);
if ($record === null && json_last_error() !== JSON_ERROR_NONE) {
continue; // пропускаем битые строки
}
// обработка записи $record
}
fclose($handle);
Формат NDJSON (Newline Delimited JSON) позволяет обрабатывать гигабайтные файлы без загрузки в память.