yangweijie/stream-xlsx

Memory-efficient XLSX export builder powered by xlswriter C extension.

Maintainers

Package info

github.com/yangweijie/strem-xlsx

pkg:composer/yangweijie/stream-xlsx

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-08 06:00 UTC

This package is auto-updated.

Last update: 2026-08-08 06:01:48 UTC


README

# StreamXlsx

> Memory-efficient XLSX/CSV export builder powered by [xlswriter](https://github.com/viest/php-ext-xlswriter) C extension.

[![PHP](https://img.shields.io/badge/PHP-%5E7.4%20%7C%20%5E8.0-777BB4)](https://php.net)
[![License](https://img.shields.io/badge/License-MIT-blue)](LICENSE)

---

## Why

PhpSpreadsheet holds every cell in memory. Export 100,000 rows × 10 columns and you're looking at ~500MB peak RAM. StreamXlsx uses the [xlswriter](https://github.com/viest/php-ext-xlswriter) C extension to write rows directly to disk — **constant ~3MB memory, regardless of row count.**

| | PhpSpreadsheet (SpreedCore) | StreamXlsx (xlswriter) |
|---|---|---|
| 10 万行 × 10 列 内存 | ~480MB | ~3MB |
| 10 万行 耗时 | ~25s | ~3s |
| 依赖 | PHP 8.0+, Composer 包 | PHP 7.4+, C 扩展 |
| PhpSpreadsheet 依赖 || **** |

---

## Requirements

- PHP ≥ 7.4
- [xlswriter](https://github.com/viest/php-ext-xlswriter) 扩展 (`ext-xlswriter`)
- (可选)Laravel /illuminate/support — 用于 Laravel 响应集成

### 安装 xlswriter 扩展

```bash
pecl install xlswriter
echo "extension=xlswriter.so" >> php.ini

Installation

composer require yourvendor/stream-xlsx

Quick Start

use StreamXlsx\Engine\XlswriterBuilder;

XlswriterBuilder::make()
    ->headers(['ID', 'Name', 'Email', 'Amount', 'Created At'])
    ->rows(User::cursor())          // Generator — memory stays flat
    ->headerColor('#0F4C81')
    ->headerBold()
    ->alignCenter()
    ->currency('D')                 // D 列货币格式
    ->datetime('E')                 // E 列日期时间格式
    ->freezeHeader()                // 冻结表头
    ->filter()                      // 自动筛选
    ->alternateColor('#F5F5F5')     // 隔行变色
    ->autoWidth()                   // 自动列宽
    ->download('users.xlsx');

Output Modes

// 浏览器下载
$builder->download('report.xlsx');

// 存储到磁盘路径
$builder->store('/var/exports/report.xlsx');

// 浏览器内联预览
$builder->stream('report.xlsx');

// 获取原始文件内容(字符串)
$raw = $builder->raw('report.xlsx');

// CSV 模式(更轻量,无样式)
$builder->download('report.csv');

API Reference

Headers

平铺表头

->headers(['ID', 'Name', 'Email'])

嵌套表头(支持任意深度)

->headers([
    'ID',
    'Name',
    'Contact' => ['Email', 'Phone'],
    'Address' => ['City', 'Country' => ['Code', 'Name']],
])

表头样式

->headerColor('#0F4C81')        // 背景色(自动设置白色字体)
->headerFontColor('#FFFFFF')    // 自定义字体颜色
->headerBold()                  // 加粗
->headerItalic()                // 斜体
->headerFontSize(14)            // 字号

Rows

接受任何 iterable:数组、GeneratorIterator、Laravel Collection / LazyCollection、Eloquent cursor()、Think-ORM cursor() 等。

// Eloquent cursor
->rows(User::cursor())

// Generator
->rows((function () {
    for ($i = 1; $i <= 100000; $i++) {
        yield ['id' => $i, 'name' => "User {$i}"];
    }
})())

// 普通数组
->rows([
    ['Alice', 'alice@example.com'],
    ['Bob', 'bob@example.com'],
])

Column Formats

按列字母指定格式:

->currency('D')          // 1,234.56
->date('E')              // 2024-01-15
->datetime('F')          // 2024-01-15 14:30:00
->percentage('G')        // 85.5%
->number('H')            // 1,234

// 或批量指定
->columnFormat([
    'D' => 'currency',
    'E' => 'date',
])

Freeze

->freezeHeader()              // 冻结表头行
->freeze('B3')                // 冻结到 B3 单元格
->freezeColumn('A')           // 冻结 A 列
->freezeRow(5)                // 冻结前 5 行

Filter

->filter()                    // 在表头行启用自动筛选

Column Width

// 手动指定
->columnWidth(['A' => 5, 'B' => 30, 'C' => 40])

// 自动估算(默认 15 字符宽)
->autoWidth()

Merge

->merge('A1:C1')
->merge('D2:D5')

Body Style

->font('Calibri')             // 字体族
->fontSize(11)                // 正文字号
->alignCenter()               // 水平居中
->alignLeft()                 // 左对齐
->alignRight()                // 右对齐
->wrapText()                  // 自动换行

Row Style

->rowHeight(25)               // 行高
->alternateColor('#F5F5F5')   // 隔行背景色

Border

->border()                    // 全部边框(= borderAll)
->borderHeader()              // 仅表头边框
->borderBody()                // 仅正文边框
->borderAll()                 // 全部

Images

->image('A1', '/path/to/logo.png')
->image('B2', '/path/to/photo.jpg', 100, 80)

Title Block

->setTitle('Sales Report 2024')
->setSubtitle('Q4 Summary')
->setDescription('Generated by StreamXlsx')

Multiple Sheets

XlswriterBuilder::make()
    ->headers(['Name', 'Email'])
    ->rows(User::where('active', true)->cursor())
    ->headerColor('#0F4C81')
    ->freezeHeader()
    ->addSheet('Inactive', function ($sheet) {
        $sheet->headers(['Name', 'Email'])
              ->rows(User::where('active', false)->cursor())
              ->headerColor('#CC0000');
    })
    ->download('users.xlsx');

Style Callback

->style(function ($row, $index) {
    // 根据行数据动态返回样式(简化支持)
    if ($row['status'] === 'failed') {
        return ['backgroundColor' => '#FFCCCC'];
    }
    return null;
})

Migration from SpreedCore

StreamXlsx 的 Fluent API 与 SpreedCore 的 SpreadsheetBuilder 完全兼容。迁移只需两步:

1. 替换入口

// 之前
use SpreeCore\Spreadsheet\SpreadsheetBuilder;
$builder = SpreadsheetBuilder::make();

// 之后
use StreamXlsx\Engine\XlswriterBuilder;
$builder = XlswriterBuilder::make();

2. 其余代码不变

所有 ->headers()->rows()->headerColor()->freezeHeader()->download() 等链式调用保持一致。

不支持的功能

以下 SpreedCore 功能在 StreamXlsx 中不可用(受限于 xlswriter 能力):

功能 原因
Logo 自动下载 xlswriter 无法下载远程 URL 图片。请预下载到本地后用 ->image()
复杂样式回调 xlswriter 的格式化能力有限于 C 扩展提供的 Format API
ODS / PDF 导出 xlswriter 仅支持 XLSX 和 CSV

Architecture

XlswriterBuilder           ← Fluent API 入口(与 SpreedCore API 兼容)
    │
    ├── SheetBuilder       ← 逐 Sheet 配置,产出 SheetDefinition
    │
    ├── XlswriterAssembler ← 核心:遍历 SheetDefinition[],逐行直接写盘
    │       │
    │       ├── 标题块写入
    │       ├── 表头写入(支持嵌套合并)
    │       ├── 数据行流式写入 ← 数据源 → insertText() → 磁盘,不经内存模型
    │       ├── 冻结 / 筛选 / 列宽 / 合并 / 图片
    │       └── 产出 ExportResult(文件路径 + MIME)
    │
    └── OutputHandler      ← 下载 / 存储 / 流式 / 原始(与 SpreedCore 完全复用)

数据流:

DB cursor → Generator → RowSourceAdapterFactory → XlswriterAssembler → insertText() → 磁盘
                                                                        ↑ 逐行写入
                                                                        ↑ 无内存积累

Performance

测试环境:PHP 8.2, 16GB RAM, SSD, 10 列 × N 行随机数据。

行数 SpreedCore (PhpSpreadsheet) StreamXlsx (xlswriter) 内存差距
1,000 8MB / 0.3s 2MB / 0.1s
10,000 48MB / 2.5s 2.5MB / 0.4s 19×
50,000 240MB / 12s 2.8MB / 1.5s 86×
100,000 480MB / 25s 3MB / 3s 160×
500,000 OOM 💀 3.5MB / 15s

License

MIT


[快速开始](2-quick-start)
[架构概述](4-architecture-overview)
[SpreadsheetBuilder 入口](5-spreadsheetbuilder-entry-point)
[输出处理器](12-output-handlers)