0

Excel ファイルを解析するための Web アプリを作成しています。それぞれに大量のデータ (~47 列と数千行) が含まれています。フレームワークは Laravel 4.2 で、使用するパッケージは laravel-excel (maatwebsite/excel) です。

私がすべてのコードを書いたとき、私は顧客からサンプル ファイルを受け取りました。これには 620 行が含まれていて、すべて正常に動作しました。現在、一部のファイルは機能しますが、ほとんどのファイルは機能しません。エラーは奇妙です。わかりました、一歩一歩:

論理

ユーザーが を介してファイルを選択する<input type="file">と、このファイルが を介してサーバーに送信されます。サーバーは、このファイルのプロパティを$.ajax使用してインスタンスを作成し、Jobこのインスタンスをクライアントに返します。クライアントはこのJobインスタンスを受け取りprogress、これJob(つまり、解析された行数total) が(つまり、合計行数) より小さいかどうかを確認します。そうである場合、クライアントはこれを実行するようにサーバーに要求を送信しますJob(つまり、特定の量の行をさらに解析するように、たとえば 200 )。したがって、クライアントとサーバーの間には常に次のような対話があります。

  • クライアント: サーバー様、このファイルをアップロードしますorders_123.xlsx
  • サーバー: クライアント様、ありがとうございます。ファイルを保存し、 で を作成しましJobid = 27。ファイルにはtotal = 623行があり、現在のprogress = 0.
  • クライアント: サーバー様、ありがとうございます。これJobid = 27で実行してください200。できるだけ早く返信してください。
  • サーバー: 親愛なるクライアント様、私はあなたが求めたことを実行しJobましid = 27progress = 200
  • クライアント: わかりました、サーバー、どうぞ、これJobを何度も実行して、200行を取得してください。
  • そして、ジョブが終了するまで続きます。

サーバーにすべての行をインポートするように要求するのではなく、なぜそんなに奇妙なことをしたのかと思うかもしれませんが、ここでも、ここにいくつかの暗い魔法が関係していることがわかりました。ほとんどの場合、この方法が唯一の方法です (それ以外の場合、サーバーは失敗します)。

JavaScript

function uploadFile(file) {
    var data = new FormData();
    data.append("file", file);
    showProgressBar(file.name);
    $.ajax({
        type: "POST",
        url: "/import/orders",
        data: data,
        cache: false,
        processData: false,
        contentType: false,
        success: function(response) {
            if (response.status == "error") {
                hideProgressBar(file.name + ": Error! " + response.data, response.status);  
            } else if (response.status == "success") {
                executeJob(response.job, 100);
            }
        },
        xhr: function() {
            var xhr = $.ajaxSettings.xhr();
            if (typeof xhr.upload === "object") {
                xhr.upload.addEventListener("progress", function(e) {
                    if (e.lengthComputable) {
                        var val = Math.floor(100 * e.total / e.loaded)
                        updateProgressBar(val);
                    }
                }, false);
            }
            return xhr;
        }
    });
}

function executeJob(job, take) {
    $.ajax({
        type: "POST",
        url: "/jobs/execute",
        data: {
            job: job,
            take: take
        },
        success: function(response) {
            if (response.status == "error") {
                hideProgressBar(job.original_name + ": Error! " + response.data, response.status);
            } else if (response.status == "success") {
                updateProgressBar(Math.floor(100 * response.job.progress / response.job.total));
                if (val >= 100) {
                    hideProgressBar(job.original_name + ": Success!", response.status)
                    deleteJob(job);
                } else {
                    executeJob(job, take);
                }
            }
        }
    }, "json");
}

ルート

Route::post('/import/orders', array('before' => 'csrf', 'uses' => 'OrdersFPController@handleOrdersImport'));
Route::post('/jobs/execute', array('before' => 'csrf', 'uses' => 'JobsController@handleExecute'));
Route::post('/jobs/delete', array('before' => 'csrf', 'uses' => 'JobsController@handleDelete'));

OrdersFPController@handleOrdersImport

class OrdersFPController extends BaseController {

    public function handleOrdersImport()
    {
        $file = Input::file('file');
        $fields = ['order', 'location', ...];

        if (!$file->isValid()) {
            return Response::json(array('status' => 'error', 'data' => 'File is invalid.'));
        }

        $filename = $file->getClientOriginalName();
        $extension = $file->getClientOriginalExtension();
        $extension_guessed = $file->guessExtension();

        if ($extension != $extension_guessed) {
            return Response::json(array('status' => 'error', 'data' => 'Wrong extension of the file: ".' . $extension . '", should be ".' . $extension_guessed . '".'));
        }

        $filename_new = str_random(20) . '.' . $extension;
        $path = public_path() . '/assets/import/orders';
        $file->move($path, $filename_new);

        $sheet = Excel::load($path . '/' . $filename_new, function($reader) {})->get();

        if (is_null($sheet)) {
            File::delete($path . '/' . $filename_new);
            return Response::json(array('status' => 'error', 'data' => 'Could not load any sheets in the file.'));
        }

        $job_total = $sheet->count();
        if ($job_total < 1) {
            File::delete($path . '/' . $filename_new);
            return Response::json(array('status' => 'error', 'data' => 'No data could be read in the file.'));
        }

        $sample = $sheet[0];

        foreach($fields as $f) {
            if (!isset($sample->$f)) {
                File::delete($path . '/' . $filename_new);
                return Response::json(array('status' => 'error', 'data' => 'Fields are missing for the selected type.'));
            }
        }


        $job = new Job;
        $job->type = 'orders';
        $job->link = $path . '/' . $filename_new;
        $job->original_name = $filename;
        $job->total = $job_total;
        $job->user()->associate(Auth::user());
        $job->save();

        return Response::json(array('status' => 'success', 'job' => $job, 'data' => 'File uploaded.'));
    }

}

問題は、スクリプトが に到達すると、サーバーが を返すことがあるということです。時々、サーバーを強制終了して(冗談ではありません)、ターミナルでコマンドを停止します。いくつかのスクリーンショット:$sheet = Excel::load($path . '/' . $filename_new, function($reader) {})->get();Error 500 (Internal server error)php artisan serve

サファリ

サファリ1 http://i.stack.imgur.com/3gkpr.png

サファリ2 http://i.stack.imgur.com/m8V4s.png

ファイアフォックス

Firefox 1 http://i.stack.imgur.com/QVceP.png

Firefox 2 http://i.stack.imgur.com/IcOQF.png

Firefox 3 http://i.stack.imgur.com/xvFoN.png

Firefox 4 http://i.stack.imgur.com/flx3K.png

さて、これが問題です。サーバーは何も返しません。エラーだけで、説明はありません。

編集:

@lukasgeiter で述べたように、ログ ファイルを確認しました。コードが のExcel::filter('chunk')->load($path . '/' . $filename_new)->chunk(50, function($results) { /// });場合、出力は次のようになります。

[2015-01-28 20:00:02] production.ERROR: exception 'Symfony\Component\Debug\Exception\FatalErrorException' with message 'Maximum execution time of 60 seconds exceeded' in /Users/antonsinyakin/Documents/projects/sites/foodpanda/vendor/phpoffice/phpexcel/Classes/PHPExcel/Reader/Excel2007.php:834
Stack trace:
#0 [internal function]: Illuminate\Exception\Handler->handleShutdown()
#1 {main} [] []

レギュラー$sheet = Excel::load($path . '/' . $filename_new, function($reader) {})->get();が使用されている場合、ログ ファイルには何も書き込まれません。

4

0 に答える 0