应使用 phpspreadsheet 而非 phpexcel,因后者自 2015 年停更,不兼容 php 7.2+ 且不支持 composer 自动加载;phpspreadsheet 原生支持 psr-4,可无缝集成 codeigniter 3.x 并导出格式化 excel。

直接用 header() 输出 HTML 表格是最简方案,但只适用于基础报表;真要控制列宽、边框、公式或兼容 .xlsx 格式,必须用 PhpSpreadsheet(PHPExcel 已停更,别再折腾旧包)。
为什么不能继续用 PHPExcel?
PHPExcel 自 2015 年起停止维护,PHP 7.2+ 下频繁报 Deprecated: Methods with the same name as their class will not be constructors 错误,且不支持 Composer 自动加载。CodeIgniter 3.x 项目若还卡在 PHPExcel,迟早会因 PHP 升级崩掉。
- CI 3.1.11+ 默认要求 PHP ≥ 5.6,而 PHPExcel 最后兼容版(1.8.2)在 PHP 7.4 上已无法实例化
PHPExcel类 -
IOFactory的静态方法调用在命名空间环境下极易冲突,手动改类名(如把PHPExcel_IOFactory改成IOFactory)治标不治本 - 新版
PhpSpreadsheet原生支持 PSR-4,$this->load->library('PhpSpreadsheet')可直接对接 CI 的 Loader 机制
用 PhpSpreadsheet 导出带格式的 Excel(.xlsx)
先通过 Composer 安装:composer require phpoffice/phpspreadsheet,然后在 application/libraries/ 下建 PhpSpreadsheet.php 文件,内容仅一行:require_once APPPATH . 'vendor/autoload.php';。之后在控制器中:
$this->load->library('PhpSpreadsheet');
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 写表头(第1行)
$fields = ['日期', '销售额', '地区'];
foreach ($fields as $col => $label) {
$sheet->setCellValueByColumnAndRow($col, 1, $label);
}
// 写数据(从第2行开始)
$data = $this->db->get('sales_data')->result_array();
$row = 2;
foreach ($data as $record) {
$col = 0;
foreach ($fields as $field) {
$sheet->setCellValueByColumnAndRow($col, $row, $record[$field] ?? '');
$col++;
}
$row++;
}
// 设置列宽(可选)
$sheet->getColumnDimension('A')->setWidth(12);
$sheet->getColumnDimension('B')->setWidth(15);
// 输出下载
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="sales_report.xlsx"');
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
exit;
导出时中文乱码或 Excel 打不开?检查这三点
不是编码问题就是头信息/输出污染 —— CI 框架里尤其容易踩坑:
- 控制器方法末尾不能有
echo、var_dump()或任何空白符(包括文件末尾的换行),否则php://output会混入非法字符,Excel 提示“文件已损坏” -
header()前不能有任何输出,确保没开启output_buffering之外的缓冲(CI 的output类默认接管输出,所以不要手动ob_start()) - 中文字段值若来自数据库,确认连接字符集是
utf8mb4(而非utf8),并在查询前执行$this->db->query("SET NAMES utf8mb4");
想把数据库行转成列(比如日报按天展开)?别硬写循环拼列名
这种“行列翻转”需求本质是数据预处理,不是 Excel 库的事。例如:要导出 7 天每日人数统计,先构造结构化数组:
// 假设 $raw_data 是原始查询结果:[ ['date' => '2026-04-10', 'count' => 12], ... ]
$days = ['2026-04-10', '2026-04-11', ..., '2026-04-16'];
$result = [
'header' => array_merge(['部门'], $days),
'rows' => []
];
// 按部门分组汇总
foreach ($raw_data as $row) {
$dept = $row['dept'];
if (!isset($result['rows'][$dept])) {
$result['rows'][$dept] = array_fill(0, count($days), 0);
}
$day_index = array_search($row['date'], $days);
if ($day_index !== false) {
$result['rows'][$dept][$day_index] = $row['count'];
}
}
之后再用上面 PhpSpreadsheet 的方式写入:第一行写 $result['header'],后续每行写一个 $result['rows'][$dept]。强行在 Excel 库里动态算列坐标(如用 'AA'、'AB' 字符串拼地址)极易越界或错位,不如把逻辑收在 PHP 数组里。











