В PHP существует удобный инструмент php://output, который, подобно конструкциям print и echo, позволяет выводить данные в выходной буфер, не загружая память сервера. Как его использовать? Прежде чем привести пример, отмечу, что в ООП экспорт данных (например, сохранение) должен выполняться в контроллере, а бизнес-логика (выборка, агрегация и т.д.) — в модели. Ниже представлен простой пример без использования ООП:
// Отключаем кэширование
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Expires: 0');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
// Устанавливаем заголовки для CSV
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="export.csv"');
header('Content-Transfer-Encoding: binary');
// Пример получения данных (заменить на реальную выборку из БД)
$list = [
['_id' => 1, 'date' => time(), 'user' => 'John'],
['_id' => 2, 'date' => time(), 'user' => 'Jane'],
// ... другие данные
];
// Заголовки для CSV
$titles = ['ID', 'Date', 'User'];
// Открываем поток php://output
$df = fopen('php://output', 'w');
if ($df === false) {
die('Ошибка открытия потока php://output');
}
// Записываем заголовки
fputcsv($df, $titles);
// Записываем данные
foreach ($list as $row) {
// Проверяем, не прервано ли соединение
if (connection_aborted()) {
fclose($df);
die('Соединение с клиентом прервано');
}
fputcsv($df, [
$row['_id'],
date('Y-m-d H:i:s', $row['date']),
$row['user'],
// Добавить другие поля, если нужно
]);
// Очищаем буфер для экономии памяти
flush();
}
// Закрываем поток
fclose($df);
При выполнении такого кода в браузере файл export.csv автоматически сохранится на вашем компьютере с указанным содержимым. При этом, независимо от количества строк, память будет использоваться только для текущей итерации цикла foreach.
Хотя этот подход позволяет обрабатывать сотни тысяч строк без перегрузки сервера, существует риск прерывания соединения между клиентом и сервером, что может привести к потере части данных.
В чем еще проблема? Несмотря на экономию серверной памяти, у метода есть недостаток: во время потоковой передачи данных в файл скрипт продолжает выполняться. Однако время выполнения скрипта ограничено (обычно около 15 секунд, если не изменять настройки). Если сохранение, например, 50 тысяч записей занимает больше 15 секунд, возникнет ошибка fatal error из-за превышения времени выполнения.
Комментариев нет:
Отправить комментарий