使用Laravel 4.2导入Maatwebsite / Excel失败

时间:2015-01-28 10:27:29

标签: php excel laravel jqxhr laravel-excel

我正在编写一个网络应用程序来解析Excel文件,每个文件包含大量数据(约47列和数千行)。框架是Laravel 4.2,使用的包是laravel-excel(maatwebsite / excel)。

当我编写所​​有代码时,我有一个来自客户的示例文件,它包含620行,一切正常。现在,有些文件可以正常工作,而且大部分都没有。错误很奇怪。好的,一步一步:

逻辑

用户通过<input type="file">选择文件,然后通过$.ajax将此文件发送到服务器,服务器创建一个具有此文件属性的Job实例,并将此实例返回给客户端。客户端会收到此Job个实例,并查看此progress即解析的行数)的Job是否低于total即总行数)。如果是这样,则客户端向服务器发送请求以执行此Job,即更多地解析一定数量的行,例如200 )。所以客户端和服务器之间始终存在对话,如下所示:

  • 客户:尊敬的服务器,特此我上传此文件orders_123.xlsx
  • 服务器:尊敬的客户,谢谢,我存储了您的文件,并使用Job创建了id = 27。您的文件包含total = 623行和当前progress = 0
  • 客户:尊敬的服务器,谢谢,请Job执行此id = 27,获取200行。尽快回复。
  • 服务器:亲爱的客户,我完成了您的要求,Job id = 27现已progress = 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命令。一些截图:

Safari浏览器

Safari 1 http://i.stack.imgur.com/3gkpr.png

Safari 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();,则不会将任何内容写入日志文件。

0 个答案:

没有答案