CSV下载为空的主因是BOM污染HTTP头部:PHP文件、引入文件或.env若含UTF-8 BOM(EF BB BF),会提前触发输出缓冲,导致header()失效,浏览器无法识别CSV格式;需逐层检测并清除BOM。

CSV文件下载为空?先查BOM是否污染了HTTP头部
CodeIgniter中导出CSV时浏览器拿到空文件,大概率不是逻辑写错了,而是输出缓冲被BOM头提前触发。PHP一旦向浏览器输出了任何字节(包括UTF-8 BOM的\xEF\xBB\xBF),header()就再也发不出去了——后续的Content-Type: text/csv会被忽略,浏览器按HTML或text/plain处理响应体,自然看不到内容。
常见诱因有三个:
① index.php或控制器文件本身带BOM(尤其Windows下用记事本保存过);
② 模型或辅助函数里引入了带BOM的PHP文件;
③ .env文件是UTF-8 with BOM编码(CI4特别敏感)。
- 用
hexdump -C index.php | head -n1检查前3字节,出现ef bb bf即确认存在BOM - VS Code打开后右下角看编码,点击切换为
UTF-8(非UTF-8 with BOM),再保存 - CI4项目根目录下的
.env必须是无BOM的UTF-8,否则ENVIRONMENT常量可能失效,间接导致错误不报、日志不写,掩盖真实问题
fopen写CSV前手动跳过BOM头
即使服务端PHP文件干净,用户上传的CSV文件也可能带BOM(比如他们用Excel另存为CSV,或Windows记事本改后缀)。直接fopen($uploaded_file, 'r')读取,第一行数据会多出乱码字段。不能靠trim()解决,因为BOM只在开头,且不同编码的BOM字节不同。
稳妥做法是在读取前检测并截断:
使用 qbo-mileage CLI 及用户凭证,从 Airtable、Outlook 或 Google Calendar 记录生成 QuickBooks Online 里程 CSV 文件。
function remove_bom($str) {
if (substr($str, 0, 3) === "\xEF\xBB\xBF") {
return substr($str, 3);
}
return $str;
}
$handle = fopen($uploaded_file, 'r');
if ($handle) {
$first_line = fgets($handle);
$first_line = remove_bom($first_line); // 清掉BOM再解析
// 后续用fgetcsv()继续读
}
- 仅对UTF-8 BOM做判断,若需兼容UTF-16LE(
FF FE)或UTF-16BE(FE FF),得扩展substr($str, 0, 2)分支 - 不要用
file_get_contents()一次性读全再处理——大文件会爆内存,fgets()流式处理更安全 - 如果用
str_getcsv()解析单行,务必传入清理后的字符串,否则str_getcsv($first_line)第一个元素会是"\u{feff}Company"
Excel导出报Undefined offset: 0?PHPExcel写单元格前没校验数组长度
错误信息Undefined offset: 0出现在PHPExcel/Worksheet.php第1674行,本质是代码试图往空数组或未初始化索引写值。典型场景:循环$data['details']时,某次迭代中$data['details'][$x]为空或根本不存在,但循环体里仍强行访问$data['details'][$x][$i]['rating']。
- 在
foreach ($data['details'] as $x => $row)内部,加if (empty($row)) continue;跳过脏数据 - 所有嵌套访问前用
isset()兜底,例如isset($data['details'][$x][$i]['rating']) && $data['details'][$x][$i]['rating'] == 1 - PHPExcel已停止维护,CI3项目建议迁移到
phpspreadsheet,其setCellValue()对空坐标更宽容,且支持原生UTF-8无需BOM处理
CI4环境下Excel兼容性问题根源在public/index.php加载顺序
CI4导出Excel失败,常被归咎于Excel库,其实更可能是框架启动阶段就埋了雷。关键点在于public/index.php顶部的环境加载顺序:如果.env含BOM,DotEnv::create()会解析失败,导致CI_ENVIRONMENT保持默认production,而生产模式下错误被静默吞掉,你看到的只是空白页或500,根本不知道PHPExcel类根本没加载成功。
- 检查
public/index.php是否在require FCPATH . 'vendor/autoload.php';之前就调用了new DotEnv(...),且该.env文件确定无BOM - 临时在
index.php顶部加var_dump(file_get_contents(FCPATH . '.env'));,确认输出开头没有这类乱码 - 若用
phpspreadsheet,确保composer.json里"phpoffice/phpspreadsheet": "^1.24"版本与PHP 8.x兼容(旧版1.18以下不支持)
BOM问题从来不是“要不要去掉”的选择题,而是“在哪一层被注入、在哪一层必须拦截”的定位问题。服务端PHP文件、用户上传文件、框架配置文件——三层都可能藏BOM,漏掉任何一层,修复就永远差一口气。

















