作者 PPPSCN
提交者 Karson

优化导入import方法(废弃phpoffice/phpexcel改用phpoffice/phpspreadsheet)

优化批量更新multi方法
@@ -2,6 +2,11 @@ @@ -2,6 +2,11 @@
2 2
3 namespace app\admin\library\traits; 3 namespace app\admin\library\traits;
4 4
  5 +use app\admin\library\Auth;
  6 +use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
  7 +use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
  8 +use PhpOffice\PhpSpreadsheet\Reader\Xls;
  9 +use PhpOffice\PhpSpreadsheet\Reader\Csv;
5 trait Backend 10 trait Backend
6 { 11 {
7 12
@@ -258,10 +263,8 @@ trait Backend @@ -258,10 +263,8 @@ trait Backend
258 if ($ids) { 263 if ($ids) {
259 if ($this->request->has('params')) { 264 if ($this->request->has('params')) {
260 parse_str($this->request->post("params"), $values); 265 parse_str($this->request->post("params"), $values);
261 - if (!$this->auth->isSuperAdmin()) {  
262 - $values = array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));  
263 - }  
264 - if ($values) { 266 + $values = array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
  267 + if ($values || $this->auth->isSuperAdmin()) {
265 $adminIds = $this->getDataLimitAdminIds(); 268 $adminIds = $this->getDataLimitAdminIds();
266 if (is_array($adminIds)) { 269 if (is_array($adminIds)) {
267 $this->model->where($this->dataLimitField, 'in', $adminIds); 270 $this->model->where($this->dataLimitField, 'in', $adminIds);
@@ -297,15 +300,36 @@ trait Backend @@ -297,15 +300,36 @@ trait Backend
297 if (!is_file($filePath)) { 300 if (!is_file($filePath)) {
298 $this->error(__('No results were found')); 301 $this->error(__('No results were found'));
299 } 302 }
300 - $PHPReader = new \PHPExcel_Reader_Excel2007();  
301 - if (!$PHPReader->canRead($filePath)) {  
302 - $PHPReader = new \PHPExcel_Reader_Excel5();  
303 - if (!$PHPReader->canRead($filePath)) {  
304 - $PHPReader = new \PHPExcel_Reader_CSV();  
305 - if (!$PHPReader->canRead($filePath)) {  
306 - $this->error(__('Unknown data format')); 303 + //实例化reader
  304 + $ext = pathinfo($filePath, PATHINFO_EXTENSION);
  305 + if (!in_array($ext, ['csv', 'xls', 'xlsx'])) {
  306 + $this->error(__('Unknown data format'));
  307 + }
  308 + if ($ext === 'csv') {
  309 + $file = fopen($filePath, 'r');
  310 + $filePath = tempnam(sys_get_temp_dir(), 'import_csv');
  311 + $fp = fopen($filePath, "w");
  312 + $n = 0;
  313 + while ($line = fgets($file)) {
  314 + $line = rtrim($line, "\n\r\0");
  315 + $encoding = mb_detect_encoding($line, ['utf-8', 'gbk', 'latin1', 'big5']);
  316 + if ($encoding != 'utf-8') {
  317 + $line = mb_convert_encoding($line, 'utf-8', $encoding);
  318 + }
  319 + if ($n == 0 || preg_match('/^".*"$/', $line)) {
  320 + fwrite($fp, $line . "\n");
  321 + } else {
  322 + fwrite($fp, '"' . str_replace(['"', ','], ['""', '","'], $line) . "\"\n");
307 } 323 }
  324 + $n++;
308 } 325 }
  326 + fclose($file) || fclose($fp);
  327 +
  328 + $reader = new Csv();
  329 + } elseif ($ext === 'xls') {
  330 + $reader = new Xls();
  331 + } else {
  332 + $reader = new Xlsx();
309 } 333 }
310 334
311 //导入文件首行类型,默认是注释,如果需要使用字段名称请使用name 335 //导入文件首行类型,默认是注释,如果需要使用字段名称请使用name
@@ -323,42 +347,72 @@ trait Backend @@ -323,42 +347,72 @@ trait Backend
323 } 347 }
324 } 348 }
325 349
326 - $PHPExcel = $PHPReader->load($filePath); //加载文件  
327 - $currentSheet = $PHPExcel->getSheet(0); //读取文件中的第一个工作表  
328 - $allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号  
329 - $allRow = $currentSheet->getHighestRow(); //取得一共有多少行  
330 - $maxColumnNumber = \PHPExcel_Cell::columnIndexFromString($allColumn);  
331 - for ($currentRow = 1; $currentRow <= 1; $currentRow++) {  
332 - for ($currentColumn = 0; $currentColumn < $maxColumnNumber; $currentColumn++) {  
333 - $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();  
334 - $fields[] = $val;  
335 - }  
336 - } 350 + //加载文件
337 $insert = []; 351 $insert = [];
338 - for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {  
339 - $values = [];  
340 - for ($currentColumn = 0; $currentColumn < $maxColumnNumber; $currentColumn++) {  
341 - $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();  
342 - $values[] = is_null($val) ? '' : $val; 352 + try {
  353 + if (!$PHPExcel = $reader->load($filePath)) {
  354 + $this->error(__('Unknown data format'));
343 } 355 }
344 - $row = [];  
345 - $temp = array_combine($fields, $values);  
346 - foreach ($temp as $k => $v) {  
347 - if (isset($fieldArr[$k]) && $k !== '') {  
348 - $row[$fieldArr[$k]] = $v; 356 + $currentSheet = $PHPExcel->getSheet(0); //读取文件中的第一个工作表
  357 + $allColumn = $currentSheet->getHighestDataColumn(); //取得最大的列号
  358 + $allRow = $currentSheet->getHighestRow(); //取得一共有多少行
  359 + $maxColumnNumber = Coordinate::columnIndexFromString($allColumn);
  360 + $fields = [];
  361 + for ($currentRow = 1; $currentRow <= 1; $currentRow++) {
  362 + for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
  363 + $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
  364 + $fields[] = $val;
349 } 365 }
350 } 366 }
351 - if ($row) {  
352 - $insert[] = $row; 367 +
  368 + for ($currentRow = 2; $currentRow <= $allRow; $currentRow++) {
  369 + $values = [];
  370 + for ($currentColumn = 1; $currentColumn <= $maxColumnNumber; $currentColumn++) {
  371 + $val = $currentSheet->getCellByColumnAndRow($currentColumn, $currentRow)->getValue();
  372 + $values[] = is_null($val) ? '' : $val;
  373 + }
  374 + $row = [];
  375 + $temp = array_combine($fields, $values);
  376 + foreach ($temp as $k => $v) {
  377 + if (isset($fieldArr[$k]) && $k !== '') {
  378 + $row[$fieldArr[$k]] = $v;
  379 + }
  380 + }
  381 + if ($row) {
  382 + $insert[] = $row;
  383 + }
353 } 384 }
  385 + } catch (Exception $exception) {
  386 + $this->error($exception->getMessage());
354 } 387 }
355 if (!$insert) { 388 if (!$insert) {
356 $this->error(__('No rows were updated')); 389 $this->error(__('No rows were updated'));
357 } 390 }
  391 +
358 try { 392 try {
  393 + //是否包含admin_id字段
  394 + $has_admin_id = false;
  395 + foreach ($fieldArr as $name => $key) {
  396 + if ($key == 'admin_id') {
  397 + $has_admin_id = true;
  398 + break;
  399 + }
  400 + }
  401 + if ($has_admin_id) {
  402 + $auth = Auth::instance();
  403 + foreach ($insert as &$val) {
  404 + if (!isset($val['admin_id']) || empty($val['admin_id'])) {
  405 + $val['admin_id'] = $auth->isLogin() ? $auth->id : 0;
  406 + }
  407 + }
  408 + }
359 $this->model->saveAll($insert); 409 $this->model->saveAll($insert);
360 } catch (\think\exception\PDOException $exception) { 410 } catch (\think\exception\PDOException $exception) {
361 - $this->error($exception->getMessage()); 411 + $msg = $exception->getMessage();
  412 + if (preg_match("/.+Integrity constraint violation: 1062 Duplicate entry '(.+)' for key '(.+)'/is", $msg, $matches)) {
  413 + $msg = "导入失败,包含【{$matches[1]}】的记录已存在";
  414 + };
  415 + $this->error($msg);
362 } catch (\Exception $e) { 416 } catch (\Exception $e) {
363 $this->error($e->getMessage()); 417 $this->error($e->getMessage());
364 } 418 }
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 "phpmailer/phpmailer": "^5.2", 24 "phpmailer/phpmailer": "^5.2",
25 "karsonzhang/fastadmin-addons": "~1.1.4", 25 "karsonzhang/fastadmin-addons": "~1.1.4",
26 "overtrue/pinyin": "~3.0", 26 "overtrue/pinyin": "~3.0",
27 - "phpoffice/phpexcel": "^1.8" 27 + "phpoffice/phpspreadsheet": "^1.2"
28 }, 28 },
29 "config": { 29 "config": {
30 "preferred-install": "dist" 30 "preferred-install": "dist"