PHP 百万级数据导出方案(多 CSV 文件压缩)

ps:来源 :https://laravel-china.org/articles/15944/php-million-level-data-export-scheme-multi-csv-file-compression

/**
     * 导出csv文件
     * @param $filename
     * @param $data
     * @param array $columns
     * @param int $chunk 限制每个文件条数
     */
    function exportCsv($filename, $data, $columns = [], $chunk = 10000)
    {

        header('Content-Type: application/csv; charset=UTF-8');
        header('Content-Disposition: attachment; filename="' . $filename . '.csv"');
        header('Cache-Control: max-age=0');

        $storageDir = rtrim(sys_get_temp_dir(), '/');
        $prefix = str_random(10);

        $fileList = []; // 文件集合
        $fileList[] = $file = "$storageDir/${prefix}_${filename}_1.csv";

        $fp = fopen($file, 'w');
        fputs($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
        $head = array_pluck($columns, 'title');
        fputcsv($fp, $head);

        // 计数器
        $i = 0;
        // 每隔$limit行刷新一下输出buffer,不要太大,也不要太小
        $limit = 10000;
        // 行上限
        $maxLimit = 100000000;

        foreach ($data as $item) {
            if ($i >= $maxLimit) {
                break;
            }

            if ($i > 0 && $i % $chunk == 0) {
                fclose($fp);  // 关闭上一个文件
                $j = $i / $chunk + 1;
                $fileList[] = $file = "$storageDir/${prefix}_${filename}_$j.csv";

                $fp = fopen($file, 'w');
                fputs($fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
                fputcsv($fp, $head);
            }

            $i++;

            if ($i % $limit == 0) {
                ob_flush();
                flush();
            }

            $row = [];

            foreach ($columns AS $column) {
                $value = isset($column['key'])
                    ? (is_object($item) ? $item->{$column['key']} : $item[$column['key']])
                    : null;
                $render = array_get($column, 'render');
                if ($render && $render instanceof \Closure) {
                    $row[] = $render($value, $item);
                } else {
                    if (is_numeric($value) && strlen($value) > 10) {
                        $value .= "\t";
                    }
                    $row[] = $value;
                }
            }

            fputcsv($fp, $row);
            unset($row);
        }

        fclose($fp);
        if (count($fileList) > 1) {
            $zip = new ZipArchive();
            $oldFilename = $filename;
            $filename = "$storageDir/${prefix}_${filename}.zip";
            $zip->open($filename, ZipArchive::CREATE); // 打开压缩包

            foreach ($fileList as $file) {
                $zip->addFile($file, str_replace("${prefix}_", '', basename($file)));   // 向压缩包中添加文件
            }
            $zip->close(); // 关闭压缩包

            foreach ($fileList as $file) {
                @unlink($file); // 删除csv临时文件
            }

            // 输出压缩文件提供下载
            header("Cache-Control: max-age=0");
            header("Content-Description: File Transfer");
            header('Content-disposition: attachment; filename=' . $oldFilename . '.zip');
            header("Content-Type: application/zip"); // zip格式的
            header("Content-Transfer-Encoding: binary");
            header('Content-Length: ' . filesize($filename));
        } else {
            $filename = head($fileList);
        }

        @readfile($filename);
        @unlink($filename); // 删除临时文件

        exit;
    }

 

posted @ 2018-09-29 17:12  pengcx  阅读(1140)  评论(0编辑  收藏  举报