Sivo 悉见

PHP导出大数据CSV

匿名 · 更新于 2021/6/28

/**
 * 导出excel(csv)
 * @param $sql   sql语句
 * @param $total 数据总数
 * @param $headlist 第一行,列名
 * @param $filename 文件名称
 * @param $rule 数据处理规则
 * @param $psize 数据分段大小(分页数量) 每隔$psize(一页数据),刷新一下输出buffer,不要太大,也不要太小
 */
function export_csv($sql, $total, $headlist, $filename, $rule = [], $params = [], $psize = 1000) {



    set_time_limit(0);
    $open_exoprt = true;
    if($open_exoprt){
        header('Content-Type: application/vnd.ms-excel');
        header('Content-Disposition: attachment;filename="'.iconv('utf-8', 'gbk', $filename).'.csv"');
        header('Cache-Control: max-age=0');
        //打开PHP文件句柄,php://output 表示直接输出到浏览器
        $fp = fopen('php://output', 'a');
    }



    //输出Excel列名信息
    foreach ($headlist as $key => $value) {
        //CSVExcel支持GBK编码,一定要转换,否则乱码
        $headlist[$key] = iconv('utf-8', 'gbk', $value);
    }

    if($open_exoprt){
        //将数据通过fputcsv写到文件句柄
        fputcsv($fp, $headlist);
    }







    //计算最后一页数量 防止当前联合查询机制导致的数据重复
    $lastnum = $total % $psize;
    //计算总页数
    $totalpage = ceil($total / $psize);


    //记录原sql防止每次查询都是第一页数据
    $oldsql = $sql;
    //开始循环分页输出数据
    for ($pindex = 1; $pindex <= $totalpage; $pindex++) {





        $limit = " LIMIT " . ($pindex - 1) * $psize . ',' . $psize.' ';

        //防止联合查询数据重复  仅查询剩余数量
        if($pindex == $totalpage){
            $psize = $lastnum;
        }


        //替换sql标识 如果不是用oldsql会导致每次查询的都是前1000条 数据重复
        $sql = str_replace(['$limit','$psize'],[$limit,$psize],$oldsql);



        if(empty($params)){
            $list = pdo_fetchall($sql);
        }else{
            $list = pdo_fetchall($sql,$params);
        }


        if($open_exoprt){
            //逐行取出数据,不浪费内存
            foreach ($list as $k => $row){
                //处理数据
                foreach ($row as $key => $value) {
                    $row[$key] = iconv('utf-8', 'gbk', $value);
                    //处理/格式化数据
                    if(isset($rule[$key])){
                        foreach ($rule[$key] as $v){
                            switch ($v['type']){
                                case 'time':
                                    $row[$key] = date($v['format'],$row[$key]);
                                    break;
                                case 'string':
                                    $row[$key] = $row[$key]."\t";
                                    break;
                            }
                        }
                    }
                }

                    fputcsv($fp, $row);

            }
        }



        if($open_exoprt){
            //刷新一下输出buffer,防止由于数据过多造成问题
            ob_flush();
            flush();
        }

    }

}