Экспорт в Excel в Laravel: инструкция и частые ошибки
За полчаса настроите выгрузку данных в файл .xlsx через пакет Laravel Excel: от установки до скачивания в браузере, с разбором ошибок, на которые наступают почти все.

В конце у вас будет кнопка «Скачать Excel», которая отдаёт файл .xlsx с данными из базы. На чистом проекте это занимает 20–30 минут вместе с установкой пакета. Работать будем с самым распространённым решением — пакетом maatwebsite/excel (актуальная линейка 3.1), он использует библиотеку PhpSpreadsheet под капотом.
Что нужно иметь до начала
Проверьте это заранее, чтобы не застрять на середине:
- Laravel 10.x или 11.x и PHP 8.1+ (пакет 3.1 требует именно эти версии; на PHP 8.0 установка упадёт при
composer require). - Установленное PHP-расширение
ext-zip. Формат.xlsx— это zip-архив, без расширения экспорт молча не создаст файл или выбросит ошибку про ZipArchive. - Composer и доступ к терминалу проекта.
- Хотя бы одна таблица с данными и модель Eloquent к ней. Для примера возьмём модель
User, которая есть в стандартной поставке.
Проверить расширения: выполните php -m и найдите в списке zip. Если его нет — доставьте (на Ubuntu это php-zip, точное имя пакета зависит от версии PHP).
Шаг 1. Установка пакета
В корне проекта выполните:
composer require maatwebsite/excel
Composer подтянет и PhpSpreadsheet как зависимость. Проверка: в файле composer.json в разделе require появилась строка maatwebsite/excel, а команда завершилась без красных сообщений.
Шаг 2. Создаём класс экспорта
Пакет работает через отдельные классы-экспорты. Сгенерируйте заготовку artisan-командой:
php artisan make:export UsersExport --model=User
Проверка: появился файл app/Exports/UsersExport.php. Откройте его — внутри будет класс с методом collection(), который возвращает данные.
Наполняем класс
По умолчанию экспорт выгрузит все поля модели, включая password и служебные колонки. Это первая ловушка, поэтому сразу опишем заголовки и нужные столбцы:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
class UsersExport implements FromCollection, WithHeadings, WithMapping
{
// Какие данные берём из базы
public function collection()
{
// select с явными полями, чтобы не тащить password и remember_token
return User::select('id', 'name', 'email', 'created_at')->get();
}
// Первая строка файла — заголовки колонок
public function headings(): array
{
return ['ID', 'Имя', 'Email', 'Дата регистрации'];
}
// Приводим каждую строку к нужному виду
public function map($user): array
{
return [
$user->id,
$user->name,
$user->email,
// форматируем дату, иначе в ячейке будет ISO-строка
$user->created_at->format('d.m.Y H:i'),
];
}
}
Проверка: файл сохраняется без синтаксических ошибок, редактор не подсвечивает неизвестные классы.
Шаг 3. Маршрут и контроллер
Добавьте маршрут в routes/web.php:
use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\Route;
Route::get('/export/users', function () {
// Второй аргумент — имя файла, которое увидит пользователь
return Excel::download(new UsersExport, 'users.xlsx');
});
Проверка: откройте в браузере /export/users. Должен начаться скачивание файла users.xlsx. Откройте его — увидите четыре колонки с заголовками на русском и данными из таблицы.
Главное правило экспорта: класс-экспорт не должен возвращать модель целиком. Всегда явно выбирайте столбцы черезselect()и приводите их вmap()— иначе в файл утекут хеши паролей, токены и служебные поля.
Если не получилось
Пять ошибок, на которые новички наступают чаще всего.
Class "Maatwebsite\Excel\Facades\Excel" not found
Composer не подхватил автозагрузку или пакет не установился. Выполните composer dump-autoload. Если не помогло — повторите composer require maatwebsite/excel и убедитесь, что версия PHP подходит.
Скачивается файл, но при открытии Excel ругается на повреждение
Почти всегда причина — лишний вывод до заголовков ответа: пробел или пустая строка перед <?php, отладочный dd(), echo или BOM в файле класса. Уберите любой вывод из контроллера и классов, участвующих в экспорте. Проверьте, что в файлах нет пустых строк после закрывающего ?> — лучше вообще не ставить закрывающий тег в PHP-файлах.
Дата и число выглядят не так, как ожидалось
Если created_at в модели не приведён к типу даты через $casts, вызов ->format() упадёт с ошибкой «Call to a member function format() on string». Либо добавьте поле в casts модели, либо оберните значение через \Carbon\Carbon::parse($user->created_at)->format(...).
Память кончается на большой таблице
Метод collection() тянет все строки в память сразу. На десятках тысяч записей это упирается в memory_limit и падает с «Allowed memory size exhausted». Для больших выгрузок замените интерфейс FromCollection на FromQuery и добавьте WithChunkReading — пакет будет читать данные пачками. Это отдельная тема, здесь только фиксируем сам симптом.
Русские заголовки превратились в кракозябры
С форматом .xlsx такого обычно не бывает — он хранит текст в UTF-8. Проблема вылезает при экспорте в .csv, который открывают в Excel на Windows: программа читает файл в системной кодировке. Если вам нужен именно CSV, задайте кодировку через настройки CSV-экспорта пакета — точный набор опций смотрите в разделе документации про CSV, он менялся между минорными версиями.
Мелочи, которые экономят время
- Автоширина колонок. Подключите интерфейс
ShouldAutoSize, чтобы столбцы подгонялись под содержимое, а не обрезали текст. - Формат файла. Метод
download()определяет формат по расширению во втором аргументе. Хотите.csv— передайте'users.csv', отдельного флага не нужно. - Экспорт в очередь. Тяжёлые выгрузки лучше делать через
Excel::queue()и отдавать пользователю ссылку на готовый файл, а не держать HTTP-запрос открытым.
Что настроить дальше
Базовый экспорт работает — теперь смотрите в сторону трёх вещей. Первое: если файл большой, переведите его на FromQuery с чанками и проверьте потребление памяти под реальным объёмом данных. Второе: вынесите тяжёлые выгрузки в очередь (queue), чтобы веб-сервер не держал соединение минутами. Третье: изучите форматирование ячеек и стили в документации PhpSpreadsheet, если от файла ждут не сырых данных, а готового отчёта с шапкой и числовыми форматами.
Разбор научной статьи: Сложный текст — понятным языком, с терминами
Спросить за 12 ₽Источники: Laravel Excel — официальная документация, PhpSpreadsheet — документация
Частые вопросы
А если у меня Laravel 9 или PHP 8.0?
Не сработало: файл скачивается, но Excel говорит, что он повреждён. Что делать?
Как выгрузить не всю таблицу, а результат конкретного запроса с условиями?
Экспорт падает с ошибкой нехватки памяти на большой таблице.
Нужен CSV, а не xlsx. Как переключить формат?
Как не выгрузить в файл пароли и служебные поля модели?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.