Здравствуйте есть код который импортуирет файлы xlsx в базу MySQL.
<?php
session_save_path(dirname($_SERVER['DOCUMENT_ROOT']).'/public_html/tmp');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
ini_set('memory_limit', '-1');
set_time_limit('0');
require_once __DIR__ . "/../../vendor/autoload.php";
require_once __DIR__ . "/../../component/Db.php";
$db = Db::connectDB();
$file_url = "/admin/files/prices/prices_1529587320.xlsx";
$what_row = "2";
$col_article = "2";
$col_articleSearch = "0";
$brand = "Volkswagen";
$col_description = "3";
$col_group_price = "5";
$col_price = "4";
$col_min_value = "6";
$col_exchange = "7";
$date = "2018-01-04";
// чистим на пустоту
foreach(['file_url', 'what_row', 'col_article', 'col_articleSearch', 'brand', 'col_description', 'col_group_price', 'col_price', 'col_min_value', 'col_exchange', 'date'] as $field) {
$$field = trim($$field);
}
// переводим в INT
foreach(['what_row', 'col_article', 'col_description', 'col_group_price', 'col_price', 'col_min_value', 'col_exchange'] as $field) {
$$field = (int) $$field;
if($$field === 0) $$field = '';
}
$filePath = realpath(__DIR__ . "/../../" . $file_url);
$row = $what_row;
/*
* Обновляем статус всех прайсов на old
*/
$sql = "UPDATE `dk_prices` SET status = 'old', price = '0' WHERE brand = '$brand'";
$db->query($sql);
$reader = PhpOffice\PhpSpreadsheet\IOFactory::load($filePath);
foreach ($reader->getWorksheetIterator() as $line) {
$highestRow = $line->getHighestRow();
for($row; $row <= $highestRow; $row++) {
$article = $line->getCellByColumnAndRow( $col_article, $row )->getValue();
if($col_articleSearch == "0") {
$searchArticle = str_replace(' ', '', $article);
} else {
$searchArticle = $line->getCellByColumnAndRow( $col_articleSearch, $row )->getValue();
}
$description = $line->getCellByColumnAndRow( $col_description, $row )->getValue();
$group_price = $line->getCellByColumnAndRow( $col_group_price, $row )->getValue();
$price = $line->getCellByColumnAndRow( $col_price, $row )->getValue();
$min_value = $line->getCellByColumnAndRow( $col_min_value , $row )->getValue();
$exchange = $line->getCellByColumnAndRow( $col_exchange, $row )->getValue();
// проверяем на пустоту
foreach(['article', 'searchArticle', 'brand', 'description', 'group_price', 'price', 'min_value', 'exchange'] as $field) {
if(is_null( $$field )) {
$$field = "";
}
}
/*
* Если такой артикул и бренд существует, то обновляем данные
*/
$sql = "SELECT searchArticle and brand from `dk_prices` where searchArticle = ?s and brand = ?s";
$result = $db->query($sql, $searchArticle, $brand);
if(mysqli_num_rows($result) > 0) {
$sql = "UPDATE `dk_prices` SET ?u WHERE searchArticle = ?s and brand = ?s";
$user_data = array(
'description' => $description,
'group_price' => $group_price,
'price' => $price,
'exchange' => $exchange,
'min_value' => $min_value,
'date' => $date,
'status' => 'update'
);
$db->query($sql, $user_data, $searchArticle, $brand);
} else {
/*
* Если такого бренда и артикула нету, то добавляем нововую строку
*/
$sql = "INSERT INTO `dk_prices` SET ?u";
$user_data = array(
'article' => $article,
'searchArticle' => $searchArticle,
'brand' => $brand,
'description' => $description,
'group_price' => $group_price,
'price' => $price,
'exchange' => $exchange,
'min_value' => $min_value,
'date' => $date,
'status' => 'new'
);
$db->query($sql, $user_data);
}
}
}
Но когда файл большой около 60мб тоесть с сотнями тысяч строк, то этот код долго думает а потом пишет Killed, писал в сапорт сказали что он занимает много места.
На сайте бибилотеки
здесь есть код для загрузки по частям
$inputFileType = 'Xls';
$inputFileName = './sampleData/example2.xls';
/** Define a Read Filter class implementing \PhpOffice\PhpSpreadsheet\Reader\IReadFilter */
class ChunkReadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter
{
private $startRow = 0;
private $endRow = 0;
/** Set the list of rows that we want to read */
public function setRows($startRow, $chunkSize) {
$this->startRow = $startRow;
$this->endRow = $startRow + $chunkSize;
}
public function readCell($column, $row, $worksheetName = '') {
// Only read the heading row, and the configured rows
if (($row == 1) || ($row >= $this->startRow && $row < $this->endRow)) {
return true;
}
return false;
}
}
/** Create a new Reader of the type defined in $inputFileType **/
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);
/** Define how many rows we want to read for each "chunk" **/
$chunkSize = 2048;
/** Create a new Instance of our Read Filter **/
$chunkFilter = new ChunkReadFilter();
/** Tell the Reader that we want to use the Read Filter **/
$reader->setReadFilter($chunkFilter);
/** Loop to read our worksheet in "chunk size" blocks **/
for ($startRow = 2; $startRow <= 65536; $startRow += $chunkSize) {
/** Tell the Read Filter which rows we want this iteration **/
$chunkFilter->setRows($startRow,$chunkSize);
/** Load only the rows that match our filter **/
$spreadsheet = $reader->load($inputFileName);
// Do some processing here
}
Вопрос как этот класс по частям внедрить в мой код ?
p.s. Писать про wait_timeout не надо, у меня и так стоит 900, суть в оптимизации памяти.
Вспомнил что я убирал код связаный с инсертом и апдейтом,
тоесть после этого:
$reader = PhpOffice\PhpSpreadsheet\IOFactory::load($filePath);
скрипт сразу падал, нужно как-то внедрить этот класс, а не игратся с базой.