在 Yii2.0.55 中配置 Excel 导出需避开乱码、xlsx 识别失败、内存溢出三大问题:安装 moonlandsoft/yii2-phpexcel 1.3.0,确保 PHP 7.2–8.1 且启用 mbstring;导出时禁用闭包、强制设置 SimSun 字体;超 3 万数据改用 xlsxwriter。

在 Yii2.0.55 中配置 Excel 数据导出功能,需避开 moonlandsoft/yii2-phpexcel 的 UTF-8 乱码陷阱、.xlsx 识别失败、大表内存溢出三大典型问题,且必须适配该版本对 Composer 自动加载和命名空间的严格校验。
安装兼容扩展并验证 PHP 环境
进入项目根目录,执行:
composer require --prefer-dist moonlandsoft/yii2-phpexcel "^1.3.0"
确认 PHP 已启用 mbstring 扩展:运行 php -m | grep mbstring,无输出则必须安装,否则中文字段写入时会直接触发 mb_strlen() 警告并中断导出。
【关键前提】 项目 PHP 版本必须 ≥7.2 且 ≤8.1 —— Yii2.0.55 与 PHP 8.2+ 存在反射层兼容性断裂,PHPExcel 实例化会抛 Fatal error。
控制器中调用导出方法(含筛选参数透传)
在 Controller 中定义 actionExport 方法:
public function actionExport()
{
$params = Yii::$app->request->queryParams;
$query = YourModel::find();
if (isset($params['YourModelSearch'])) {
$searchModel = new YourModelSearch();
$dataProvider = $searchModel->search($params);
$models = $dataProvider->getModels();
} else {
$models = $query->asArray()->all();
}
return \moonland\phpexcel\Excel::export([
'models' => $models,
'fileName' => '导出数据_' . date('YmdHis'),
'columns' => ['id', 'name', 'status', 'created_at'],
'headers' => ['ID', '名称', '状态', '创建时间']
]);
}
注意:columns 必须为字符串数组,不可嵌套匿名函数——Yii2.0.55 的 Export 类不支持运行时闭包序列化,否则导出文件为空白 sheet。
修复中文乱码(三步强制生效)
方法一:修改 vendor/moonlandsoft/yii2-phpexcel/Excel.php 文件
定位到 export() 方法内 new \PHPExcel() 实例化后的位置,在 setActiveSheetIndex(0) 前插入三行:
$objExcel->getDefaultStyle()->getFont()->setName('SimSun');
$objExcel->getDefaultStyle()->getFont()->setSize(10);
$objExcel->getProperties()->setCreator('Yii2.0.55')->setLastModifiedBy('Yii2.0.55');
方法二:绕过扩展,手写响应头(更可靠)
将 export() 替换为原始 PHPExcel 输出:
$objPHPExcel = new \PHPExcel();
$objPHPExcel->getProperties()->setCreator("Yii2.0.55")->setLastModifiedBy("Yii2.0.55");
// 此处写入数据…
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8');
header('Content-Disposition: attachment; filename="data.xlsx"');
header('Cache-Control: max-age=0');
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
exit;
【致命坑点】 若使用方法二,必须删除所有 echo 或 var_dump 语句,任何前置输出都会导致 header 失效,浏览器收到空文件。
突破 26 列限制(AA、AB 列自动计算)
第一步:准备列标识映射数组
$colMap = [];
for ($i = 0; $i $char = '';
$n = $i;
do {
$char = chr(65 + ($n % 26)) . $char;
$n = intval($n / 26) - 1;
} while ($n >= 0);
$colMap[] = $char;
}
第二步:写入表头时用 $colMap[$index] 替代硬编码字母
foreach ($headers as $idx => $header) {
$objPHPExcel->getActiveSheet()->setCellValue($colMap[$idx] . '1', $header);
}
第三步:写入数据行时同步使用列映射
for ($row = 0; $row for ($col = 0; $col $objPHPExcel->getActiveSheet()->setCellValue($colMap[$col] . ($row + 2), $data[$row][$col]);
}
}
这一步必须做,否则第 27 列(AA1)开始的数据会全部挤进 A 列,PHPExcel 不会自动进位。
规避大数据量内存崩溃
当记录数 > 3 万时,立即弃用 moonlandsoft/yii2-phpexcel,改用 xlsxwriter:
composer require --prefer-dist rodriguezarturo/php-xlsx-writer
在控制器中:
require_once Yii::getAlias('@vendor') . '/rodriguezarturo/php-xlsx-writer/src/XLSXWriter.php';
$writer = new \XLSXWriter();
$writer->writeSheetRow('Sheet1', $headers, ['font-style'=>'bold']);
foreach ($data as $row) {
$writer->writeSheetRow('Sheet1', $row);
}
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="large_data.xlsx"');
$writer->writeToStdOut();
exit;
注意:xlsxwriter 不支持公式、合并单元格、样式微调,但导出速度是 PHPExcel 的 8 倍以上,且内存占用恒定在 2MB 内。


















