Maatwebsite / Excel не удается импортировать с помощью Laravel 4.2

Я пишу веб-приложение для анализа файлов 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 Команда в терминале. Некоторые скриншоты:

Сафари

Сафари 1
http://i.stack.imgur.com/3gkpr.png

Сафари 2
http://i.stack.imgur.com/m8V4s.png

Fire Fox

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

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]