FastExcelReader: обзор быстрого ридера Excel и CSV для PHP
Если вам нужно прочитать данные из Excel-файла в PHP, первое, что предложит поисковик, — PhpSpreadsheet. Это мощная библиотека, но за универсальность она платит скоростью и памятью: даже небольшие файлы «съедают» сотни мегабайт, а большие не читаются вовсе. Если ваша задача — именно прочитать данные (импорт, интеграция, миграция), а не редактировать книгу, есть инструмент точнее: avadim/fast-excel-reader. Разберём, что он умеет.
Что это за библиотека
FastExcelReader — часть семейства FastExcelPhp (рядом — FastExcelWriter для записи, FastExcelTemplator для шаблонов и FastExcelLaravel). Её философия: только чтение, зато очень быстрое и экономное. Работает на PHP 7.4+, ставится одной командой:
composer require avadim/fast-excel-reader
Поддерживаемые форматы в 3.0.0 — XLSX (Office 2007+) и CSV.
Главная архитектурная особенность — потоковое чтение. Библиотека не строит в памяти объектную модель книги: XML листа разбирается через XMLReader узел за узлом, а строки отдаются генератором. В памяти в каждый момент — только текущая строка, поэтому файл на 500 000 строк требует примерно столько же памяти, сколько файл на 5 000.
Быстрый старт
use avadim\FastExcelReader\Excel;
$excel = Excel::open('report.xlsx');
// весь лист в массив (для небольших файлов)
$rows = $excel->readRows();
// или построчно через генератор (для любых файлов)
$sheet = $excel->sheet();
foreach ($sheet->nextRow() as $rowNum => $rowData) {
// $rowData = ['A' => ..., 'B' => ...]
}
Несколько листов? Есть выбор по имени и итерация по всем:
$excel->getSheetNames(); // имена всех листов
$excel->selectSheet('Прайс'); // выбрать лист по имени
Удобные ключи результата
Буквы колонок в качестве ключей — неудобно. Библиотека умеет превращать первую строку в ключи ассоциативных массивов:
// первая строка листа — заголовки
$rows = $excel->sheet()->withHeader()->readRows();
// [2 => ['Артикул' => 'A-100', 'Цена' => 990], 3 => [...], ...]
Можно и задать собственные ключи по колонкам, и управлять нумерацией строк/колонок флагами KEYS_*:
$rows = $excel->readRows(['A' => 'sku', 'B' => 'price'], Excel::KEYS_FIRST_ROW | Excel::KEYS_ROW_ZERO_BASED);
Пустые строки и ячейки по умолчанию пропускаются, а флаги TRIM_STRINGS и TREAT_EMPTY_STRING_AS_EMPTY_CELL позволяют считать пустыми и ячейки с пробелами. Обратите внимание: пустые ячейки возвращаются как null (не как пустая строка).
Области чтения
Реальные файлы редко начинаются с A1: сверху «шапка-красота», данные — в середине листа. Область чтения задаётся явно — диапазоном или именованной областью книги:
$excel->selectSheet('Demo1')
->setReadArea('B4:D11', true) // true — первая строка области содержит заголовки
->readRows();
$excel->setReadArea('Values'); // defined name из книги
$cells = $excel->readCells();
Даты: без магических чисел
Excel хранит даты как серийные числа (например, 45123), и наивные ридеры их так и возвращают. FastExcelReader распознаёт даты по числовым форматам ячеек автоматически, а формат вывода настраивается:
$excel->setDateFormat('Y-m-d');
// ячейка с датой вернётся как '2023-10-05', а не 45123
Не только значения: стили, картинки, объединённые ячейки
Редкость для быстрых ридеров — FastExcelReader читает и оформление:
// значения вместе со стилями: ['v' => значение, 's' => стили, 'f' => формула]
$rows = $sheet->readRowsWithStyles();
// только стили: шрифты, заливки, границы, форматы
$styles = $sheet->readCellStyles();
Это позволяет, например, не импортировать строки, которые менеджер выделил красным, или отличить подытог (жирный шрифт) от обычной строки.
Объединённые ячейки — частая причина «дырок» при импорте (значение хранится только в первой ячейке диапазона). Библиотека отдаёт всю информацию о них:
$sheet->getMergedCells(); // все диапазоны: ['B3:B6', ...]
$sheet->isMerged('B4'); // true
$sheet->mergedRange('B4'); // 'B3:B6'
И — вишенка — извлечение изображений из XLSX. Прайс с фотографиями товаров перестаёт быть проблемой:
if ($sheet->hasImage('C7')) {
$sheet->saveImageTo('C7', $dir); // сохранить картинку из ячейки в каталог
}
$sheet->getImageBlob('C7'); // или получить бинарно
CSV: тот же API, те же возможности
Версия 3.0.0 читает и CSV — не через обёртку над fgetcsv(), а собственным парсером:
- автоопределение разделителя (запятая, точка с запятой, табуляция) и кодировки (UTF-8/16/32, windows-1251, KOI8-R, Shift_JIS и другие) — на выходе всегда UTF-8;
- полная поддержка RFC 4180: кавычки, экранирование, многострочные поля, BOM;
- режимы strict (строго по стандарту) и tolerant (вытащить максимум из «кривого» файла);
- пропуск пустых строк, строки-комментарии, обрезка пробелов.
$csv = Excel::openCsv('from-1c.csv', ['encoding' => 'Windows-1251', 'delimiter' => ';']);
foreach ($csv->withHeader()->nextRow() as $row) {
echo $row['Название'];
}
API сознательно повторяет XLSX-ридер: nextRow(), readRows(), withHeader() работают одинаково. Импорт «принимаем и Excel, и CSV» пишется одной веткой кода.
Чего библиотека не делает
Честные границы применимости:
- не пишет и не редактирует файлы — для этого есть FastExcelWriter;
- не вычисляет формулы — возвращает текст формулы и последнее рассчитанное значение;
- формат XLS (Excel 97-2003) в версии 3.0.0 не поддерживается — только XLSX и CSV.
Кому стоит присмотреться
FastExcelReader 3.0.0 — оптимальный выбор, когда задача звучит как «прочитать табличные данные и обработать»: импорт прайсов и каталогов, загрузка пользовательских файлов, интеграции и миграции. Вы получаете скорость и константную память потокового ридера — и при этом не теряете доступ к датам, стилям, объединённым ячейкам и картинкам, ради которых обычно приходится брать тяжёлые универсальные библиотеки.
composer require avadim/fast-excel-reader
Документация и примеры — в репозитории на GitHub.