我正在编写一个网络应用程序来解析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
行。你可能会问我为什么这么奇怪,而不是只是要求服务器导入所有行,但在这里,我再次发现某些黑暗魔法在这里,这种方式是大多数时候它的唯一工作方式(否则服务器会失败)。
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'));
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
命令。一些截图:
http://i.stack.imgur.com/3gkpr.png
http://i.stack.imgur.com/m8V4s.png
http://i.stack.imgur.com/QVceP.png
http://i.stack.imgur.com/IcOQF.png
http://i.stack.imgur.com/xvFoN.png
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();
,则不会将任何内容写入日志文件。