ホームページ  >  記事  >  バックエンド開発  >  PHPのCSVエクスポート

PHPのCSVエクスポート

不言
不言オリジナル
2018-04-20 10:04:392583ブラウズ



この記事では、確かな参考価値のあるphpのcsvエクスポートの内容を紹介しますので、必要な方はぜひ参考にしてください


最近、会社のプロジェクトでは、ページ出力に加えてデータをエクスポートする必要があります。これまでにもいくつかのエクスポート機能を実行しましたが、今回のデータ量は比較的多く、1 日に 7 個のデータが必要です。そのため、データの量は 100 万、さらには数千万を軽く超える可能性があるため、開発プロセス中にいくつかの落とし穴を発見し、それぞれから学びたいと思います。他の。


準備:

1. PHP 設定ピット:

set_time_limit – スクリプトの最大実行時間を設定します:

  • 一般に、データが小さい場合、この設定はデフォルトで 30 秒です。これは設定の問題である可能性がありますが、データがエクスポート用に 100 万レベルに達する場合は、30 秒では不十分な場合が多いため、スクリプトに set_time_limit(0) を追加して、スクリプトの実行時間がなくなるようにする必要があります。

memory_limit – PHP メモリ制限:

  • この設定は、PHP のデフォルトでは通常 128M です。以前に小さなデータを実行したことがある友人も、この設定を使用して多くの問題を解決できると考えているかもしれません。ビッグデータ用にこれを増やすだけで十分ですか?ローカルで 1G または無制限に設定できる場合は、問題ないかもしれませんが、これを行うと遅かれ早かれ問題が発生します。サーバーのハードウェアにこれを行うのは贅沢すぎると思います。したがって、この設定を大きくしないようにする必要があります。

  • 2. Excel ピット:

データをエクスポートするので、データを閲覧するのに非常に便利な Excel 形式を誰もがすぐに思いつきましたが、Excel にも気質があるとは予想していませんでした。

テーブルのデータ制限:

  • Excel 2003及以下的版本。一张表最大支持65536行数据,256列。
    Excel 2007-2010版本。一张表最大支持1048576行,16384列。

  • 1
  • 2

  • つまり、一度に何百万もの項目を簡単に EXCEL テーブルにインポートしたい場合は、そうではありません。少なくとも、データがテーブルあたり 104W を超えないようにするためにデータを分割する必要があります。

PHPexcelのメモリオーバーフロー:

  • データが104Wに制限されているため、データ分割はデータ分割であるため、一度に50Wのテーブルをインポートしようとしますが、PHPexcel内にはメモリを報告する関数がありますオーバーフロー エラーが発生し、その後調整を続ける データ量が少ない場合、一度に 5W をインポートするとメモリ オーバーフロー エラーが発生します。これはなぜでしょうか? 複数のデータ テーブルをインポートするためにデータを分割したにもかかわらず、最終的には PHPexcel はすべてのテーブル データを一度に 1 つの変数に入れてファイルを作成します。思い出が溢れないようにするのは本当に難しいです。

    (後でいくつかの記事を読んだところ、PHPExcel にも解決策があることがわかりました。PHPExcel_Settings::setCacheStorageMethod メソッドは、メモリ使用量を減らすためにバッファリング方法を変更します)
3. CSV ピット:


EXCEL は面倒なので、どうすればよいでしょうか。使わないの?保存には csv ファイルを使用します。数量に制限はありません。また、後でファイルをデータベースにインポートすることもできます。一石?やあ、素晴らしいアイデアですね、若いヒーロー!しかし、CSV には落とし穴もあります。

出力バッファが多すぎます:

  • PHP ネイティブ関数 putcsv() を使用する場合、実際には出力バッファを使用して数百万のデータを出力し続けると、出力バッファが多すぎます。エラーが報告されるため、一定時間ごとに出力キャッシュの内容を取り出し、出力待ち状態に設定する必要があります。具体的な操作は次のとおりです:

    ob_flush();flush();

1

  • 2

具体说明介绍:PHP flush()与ob_flush()的区别详解

  • EXCEL查看CSV文件数量限制:

大多数人看csv文件都是直接用EXCEL打开的。额,这不就是回到EXCEL坑中了吗?EXCEL有数据显示限制呀,你几百万数据只给你看104W而已。什么?你不管?那是他们打开方式不对而已?不好不好,我们解决也不难呀,我们也把数据分割一下就好了,再分开csv文件保存,反正你不分割数据变量也会内存溢出。

4、总结做法

分析完上面那些坑,那么我们的解决方案来了,假设数据量是几百万。

1、那么我们要从数据库中读取要进行数据量分批读取,以防变量内存溢出,

2、我们选择数据保存文件格式是csv文件,以方便导出之后的阅读、导入数据库等操作。

3、以防不方便excel读取csv文件,我们需要104W之前就得把数据分割进行多个csv文件保存

4、多个csv文件输出给用户下载是不友好的,我们还需要把多个csv文件进行压缩,最后提供给一个ZIP格式的压缩包给用户下载就好。

代码:

 //导出说明:因为EXCEL单表只能显示104W数据,同时使用PHPEXCEL容易因为数据量太大而导致占用内存过大,
    //因此,数据的输出用csv文件的格式输出,但是csv文件用EXCEL软件读取同样会存在只能显示104W的情况,所以将数据分割保存在多个csv文件中,并且最后压缩成zip文件提供下载
    function putCsv(array $head, $data, $mark = 'attack_ip_info', $fileName = "test.csv")
    {
        set_time_limit(0);        $sqlCount = $data->count();        // 输出Excel文件头,可把user.csv换成你要的文件名
        header('Content-Type: application/vnd.ms-excel;charset=utf-8');
        header('Content-Disposition: attachment;filename="' . $fileName . '"');
        header('Cache-Control: max-age=0');        $sqlLimit = 100000;//每次只从数据库取100000条以防变量缓存太大
        // 每隔$limit行,刷新一下输出buffer,不要太大,也不要太小
        $limit = 100000;        // buffer计数器
        $cnt = 0;        $fileNameArr = array();        // 逐行取出数据,不浪费内存
        for ($i = 0; $i < ceil($sqlCount / $sqlLimit); $i++) {            $fp = fopen($mark . &#39;_&#39; . $i . &#39;.csv&#39;, &#39;w&#39;); //生成临时文件
      //     chmod(&#39;attack_ip_info_&#39; . $i . &#39;.csv&#39;,777);//修改可执行权限
            $fileNameArr[] = $mark . &#39;_&#39; .  $i . &#39;.csv&#39;;        // 将数据通过fputcsv写到文件句柄
            fputcsv($fp, $head);            $dataArr = $data->offset($i * $sqlLimit)->limit($sqlLimit)->get()->toArray();            foreach ($dataArr as $a) {                $cnt++;                if ($limit == $cnt) {                    //刷新一下输出buffer,防止由于数据过多造成问题
                    ob_flush();
                    flush();                    $cnt = 0;
                }
                fputcsv($fp, $a);
            }
            fclose($fp);  //每生成一个文件关闭
        }        //进行多个文件压缩
        $zip = new ZipArchive();        $filename = $mark . ".zip";        $zip->open($filename, ZipArchive::CREATE);   //打开压缩包
        foreach ($fileNameArr as $file) {            $zip->addFile($file, basename($file));   //向压缩包中添加文件
        }        $zip->close();  //关闭压缩包
        foreach ($fileNameArr as $file) {
            unlink($file); //删除csv临时文件
        }        //输出压缩文件提供下载
        header("Cache-Control: max-age=0");
        header("Content-Description: File Transfer");
        header(&#39;Content-disposition: attachment; filename=&#39; . basename($filename)); // 文件名
        header("Content-Type: application/zip"); // zip格式的
        header("Content-Transfer-Encoding: binary"); //
        header(&#39;Content-Length: &#39; . filesize($filename)); //
        @readfile($filename);//输出文件;
        unlink($filename); //删除压缩包临时文件
    }
  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

  • 11

  • 12

  • 13

  • 14

  • 15

  • 16

  • 17

  • 18

  • 19

  • 20

  • 21

  • 22

  • 23

  • 24

  • 25

  • 26

  • 27

  • 28

  • 29

  • 30

  • 31

  • 32

  • 33

  • 34

  • 35

  • 36

  • 37

  • 38

  • 39

  • 40

  • 41

  • 42

  • 43

  • 44

  • 45

  • 46

  • 47

  • 48

  • 49

  • 50

  • 51

  • 52

  • 53

  • 54

  • 55

  • 56

  • 57

  • 58

总结:

其实上面代码还是有优化的空间的,比如说用异常捕捉,以防因为某些错误而导致生成了一些临时文件又没有正常删除,还有PHPexcel的缓存设置也许能解决内存溢出问题,可以生成一个EXCEL文件多个工作表的形式,这样对于文件阅读者来说更友好。

以上便是本人对PHP大数据导出的见解,希望能帮到您们,同时不足的地方请多多指教!

———————————————————————————————————— 
2017年12月17日 
PS:最近了解其实关于内存溢出的问题,用迭代器来处理会方便多了。

版权声明:每一篇原创文章都是我的心血,欢迎转载,但请转载前留个评论,感谢您的支持!!! https://blog.csdn.net/Tim_phper/article/details/77581071

相关推荐:

php 逐行读取csv数据入库

PHP进行读取CSV文件数据和生成CSV文件

以上がPHPのCSVエクスポートの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:PHPの標準入出力次の記事:PHPの標準入出力