PHP fputcsv导出CSV时数据全部显示在单列的问题及解决方法
PHP动态表CSV导出列拆分异常修复
问题背景
应用开发过程中会生成大量动态数据表,需要将这些动态表的列数据导出为.csv格式文件。
初始实现方案与故障排查
最初的实现逻辑如下:
- 编写PDO预处理语句查询目标数据,以
PDO::FETCH_OBJ模式获取全部结果集 - 对结果集执行
json_encode编码再json_decode解码,遍历解码后的数据提取CSV表头 - 将每行数据的字段值通过
implode拼接为逗号分隔字符串,封装为单元素数组存入$csvData数组 - 通过
fputcsv依次写入表头和每行数据到内存文件流,输出为CSV下载
该方案导出的CSV文件存在明显异常:所有行的全部数据都仅显示在第一列,未按字段拆分到对应列。
打印$csvHeader和$csvData数组后定位到问题根源:每行数据被提前拼接为单个字符串传入fputcsv,函数会将整个字符串识别为单个单元格内容,因此无法实现按列拆分。同时原逻辑做了大量冗余的JSON编解码、字符串拼接操作,执行效率低。
修正方案
调整实现逻辑,去掉冗余操作:执行查询后先取一行PDO::FETCH_ASSOC格式的结果,提取其键名作为CSV表头字段,再获取全部PDO::FETCH_ASSOC格式的结果集,逐行直接将字段数组传入fputcsv写入,最终实现数据按列正常拆分导出。
错误实现代码
$secondsql = "SELECT * FROM ".$reslt->dname." WHERE userid=:userid AND eventid=:eventid"; $querysec = $dbh -> prepare($secondsql); $querysec-> bindParam(':userid', $usrid, PDO::PARAM_STR); $querysec-> bindParam(':eventid', $exporteventid, PDO::PARAM_STR); $querysec-> execute(); $ressec = $querysec -> fetchAll(PDO::FETCH_OBJ); $jsonString = json_encode($ressec); $jsonDecoded = json_decode($jsonString, true); $keys = array_keys(json_decode($jsonString, true)); $csvHeader=array(); $csvData=array(); foreach($jsonDecoded as $key => $val) { if (!$val) { }else{ if(!$csvHeader){ $csvHeader = array_keys($val); } } } $kcnt = count($csvHeader); $tempstring = ""; foreach($jsonDecoded as $val2) { $arrvals = array_values($val2); $resultStringValues = implode(",", $arrvals); $temparray=array(); array_push($temparray,$resultStringValues); array_push($csvData,$temparray); } $tempstring = rtrim($tempstring, ","); $delimiter = ","; $filename = $reslt->eventname. date('Y-m-d') . ".csv"; $f = fopen('php://memory', 'w'); fputcsv($f, $csvHeader, $delimiter); foreach($csvData as $fields){ fputcsv($f,$fields,$delimiter); } fseek($f, 0); header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="' . $filename . '";'); fpassthru($f);
错误逻辑下的数组结构
$csvHeader:包含id、eventid、userid、fullname、email、mobile、reg_date的索引数组$csvData:二维数组,每个子数组仅包含1个逗号拼接的完整行数据字符串元素
正确实现代码
$secondsql = "SELECT * FROM ".$reslt->dname." WHERE userid=:userid AND eventid=:eventid"; $querysec = $dbh -> prepare($secondsql); $querysec-> bindParam(':userid', $usrid, PDO::PARAM_STR); $querysec-> bindParam(':eventid', $exporteventid, PDO::PARAM_STR); $querysec-> execute(); $table_fields = array_keys($querysec->fetch(PDO::FETCH_ASSOC)); $ressec = $querysec -> fetchAll(PDO::FETCH_ASSOC); $delimiter = ","; $filename = $reslt->eventname. date('Y-m-d') . ".csv"; $f = fopen('php://memory', 'w'); fputcsv($f, $table_fields, $delimiter); foreach($ressec as $fields){ fputcsv($f,$fields,$delimiter); } fseek($f, 0); header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="' . $filename . '";'); fpassthru($f);
内容的提问来源于stack exchange,提问作者user1675571
相关产品推荐
相关产品推荐

