maatwebsite/Excel 处理导入 Excel 文件, phpfpm 内存飙升, 有没有解决办法。

maatwebsite/excel 处理导入excel文件, phpfpm内存飙升,
最新版本: 3.1
文件数据不管多大, php-fpm 都飙升。
file
有没有解决办法。

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 3

@yanthink maatwebsite/excel 这个包的最新版对处理csv有个bug, 检测csv的类型的时候用的是“application/octet-stream” 是使用的php的函数 mime_content_type()获取到的文件类型是 application/octet-stream, 但是在比较的使用的是 text/csv, 这样对比就有问题了。 maatwebsite/excel 直接返回false, 报错找不到文件。

5年前 评论

@anziguoer csv 自己写个方法实现更方便

function export_csv($filename, $data, $columns = [], $chunk = 1000000)
{
    if (!$columns) {
        $firstRow = $data instanceof Generator ? $data->current() : current($data);

        if (!$firstRow) {
            exit;
        }

        foreach ($firstRow AS $key => $value) {
            $columns[] = [
                'title' => $key,
                'index' => $key,
            ];
        }
    }

    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['index'])
                    ? (is_object($item) ? $item->{$column['index']} : $item[$column['index']])
                    : 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;
}

$sql = "SELECT * FROM users";
$users = DB::cursor($sql);
$columns = [
    [
        'title' => '用户ID',
        'index' => 'id',
    ],
    [
        'title' => '用户名称',
        'index' => 'name',
    ],
    [
        'title' => '电子邮箱',
        'index' => 'email',
    ],
    [
        'title' => '注册日期',
        'index' => 'created_at',
        'render' => function ($createdAt, $item) {
            return substr($createdAt, 0, 10);
        }
    ],
];

export_csv('用户列表', $users, $columns);
5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!