PHPExcelと大きなファイル

PHPExcelは、xls、xlsx形式で作業するための巨大な機能を備えた優れたライブラリです。 読み取り、書き込み、書式の変更、数式の設定ができ、xlsxから写真を取り出すこともできます。



habraには、このライブラリに関する投稿がすでにありました。PHPExcelでのセルの普遍的な読み取りです 。 私はPHPExcelの主な欠点についてのみ説明します-常に十分なメモリがなく、常に「致命的なエラー:メモリ不足」エラーが発生しています。 この投稿はこれを回避することについてです。



ファイルを読む



大きなファイル(約25,000行)を読み取るために、包括的なソリューションを使用しました。



まず、ファイル全体ではなく、一度に数行を読み取ります。 これは次のように行われます。



import_xls.php



<?php require_once 'path/to/PHPExcel/IOFactory.php'; class chunkReadFilter implements PHPExcel_Reader_IReadFilter { private $_startRow = 0; private $_endRow = 0; public function setRows($startRow, $chunkSize) { $this->_startRow = $startRow; $this->_endRow = $startRow + $chunkSize; } public function readCell($column, $row, $worksheetName = '') { if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) { return true; } return false; } } session_start(); if ($_SESSION['startRow']) $startRow = $_SESSION['startRow']; else $startRow = 13; $inputFileType = 'Excel5'; $objReader = PHPExcel_IOFactory::createReader($inputFileType); $chunkSize = 20; $chunkFilter = new chunkReadFilter(); while ($startRow <= 65000) { $chunkFilter->setRows($startRow,$chunkSize); $objReader->setReadFilter($chunkFilter); $objReader->setReadDataOnly(true); $objPHPExcel = $objReader->load($fileName); //-     $startRow += $chunkSize; $_SESSION['startRow'] = $startRow; unset($objReader); unset($objPHPExcel); } echo "The End"; unset($_SESSION['startRow']); ?>
      
      







chunkReadFilterクラス自体が必要です。 ファイルを読み取るためのフィルターとして設定します。ファイルは完全にはダウンロードされず、特定の行数だけダウンロードされます。



次に、それに加えて、ReadDataOnlyなどの便利なオプションも使用します。 名前が示すように、ドキュメントの書式設定をロードせずにデータ用のスペースを解放できます。



そして第三に、もちろんunset()を使用します。 また、メモリの解放にも役立ちます。



しかし、メモリ不足に加えて、別の問題が発生します。 ほとんどの共有ホスティングサイトでは、メモリ使用量の制限に加えて、PHPスクリプトには実行時の制限があります。 そして、今回は十分ではない可能性が非常に高いです。 個人的には、セッションと繰り返しのajaxリクエストでこの問題を回避しました。 上記のコードでは、セッションの使用と最後の「The End」をすでに見てきました。



そして、これがクライアント側のコードです。



import_xls.html



 <html> <head> <title> -</title> <script src="/media/js/jquery.js" type="text/javascript"></script> <script src="/media/js/import-xls.js" type="text/javascript"></script> </head> <body> <h1> -</h1>   ,    ! <div id="progress-bar"> </div> <div id="content"> </div> </body> </html>
      
      







import-xls.js



 function repeat_import() { $.ajax({ url: "/import_xls.php", timeout: 50000, success: function(data, textStatus){ $("#progress-bar").append("I"); if (data == "The End") { $("#content").html("<h2> !</h2>"); } else { $("#content").html("<p>" + data + "</p>"); repeat_import(); } }, complete: function(xhr, textStatus){ if (textStatus != "success") { $("#progress-bar").append("I"); repeat_import(); } } }); } $(function (){ repeat_import(); });
      
      







つまり import_xls.phpスクリプトにajaxリクエストを送信し、応答を待ちます。答えが私たちに合わない場合は、新しいajaxリクエストを送信します。 私はAJAXを使用せずにネットワーク上のソリューションに会いました-PHP自体でリダイレクトを使用します。 ファイル処理は少数の行に分割され、その後コードが挿入されます。



 header ("Location: import_xls.php");).
      
      







しかし個人的には、AJAXを使用したソリューションの方が好きです。なぜなら、ここではプログレスバーやその他の小さなものやパンを簡単かつ簡単に追加できるからです。 ところで、注意深い読者は、私のコードでは最も簡単なプログレスバーが既に実装されていることに気付きました。 さらに重要な点:AJAXを使用したソリューションでは、スクリプトが1回のパスで処理できる行数を事前に知る必要はありません。



ファイルレコード



約25,000行のxlsファイルを作成するには、次のコードを使用すると非常に便利です。



  $cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp; $cacheSettings = array( 'memoryCacheSize ' => '256MB'); PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings);
      
      







キャッシュメソッドをいじることもできます。 キャッシュに加えて、 memcacheは php一時ディレクトリでもサポートされています。



 $cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_memcache; $cacheSettings = array( 'memcacheServer' => 'localhost', 'memcachePort' => 11211, 'cacheTime' => 600 );
      
      







cache_to_discISAMと同様に。



更新

ここにあるコードが恐ろしく提示されたことを皆に謝ります。 Habréの構文の強調表示(明らかに、遅い時刻が影響を受ける)をすぐに理解できず、急いでいた。 これから私は急ぐことはなく、賢くなります。



更新2

JavaScriptをやり直しました。 サーバーが応答しない場合に、タイムアウトでリクエストを送信するようになりました。



All Articles