[TOC] ### 1、composer 安装phpoffice/phpexcel ~~~ composer require phpoffice/phpexcel ~~~ ### 2、通用建议放在common模块 ~~~ php think make:controller common/Import --plain --plain 表示仅仅生成控制器 ~~~ ### 3、该控制器设置了两种通用导出设置 ~~~ 1、commmonImport excel导入通用获取数据--支持多个工作区 2、importBaseVerify excel导入数据基于基础数据校验 ~~~ ### 4、开始代码之前说明 1.1 commmonImport通用导出需要引入 ~~~ use app\common\controller\Files //Files类--参考***Files通用封装*** ~~~ 1.2 importBaseVerify通用导出需要引入 ~~~ use app\common\controller\ImportBaseVerify ImportBaseVerify类--参考***ImportBaseVerify辅助封装*** ~~~ ### 5、开始commmonImport--直接看代码 ~~~ /** * excel导入通用获取数据--支持多个工作区 * * @param array $map 参数值配置 * $map = [ * //每个数组的下标为工作区,确保采用的是正确的索引排序 * [ * 'row' => 2, //从第几行开始读取----行下标为1 * 'col' => 0, //从第几列开始读取----列下标为0 * 'firstHidden' => false //该参数配置的为true的话,表示在excel第一行隐藏了列对应的key值数据,返回的数据将会是以键值对返回 * ], * [], * ]; * * @param string $path 文件路径 如果默认为空,采用文件上传方式 * @return array */ public static function commmonImport(array $map, $path = null) { if (is_null($path)) { $data = (new Files())->upload('default.only_excel'); if (!$data['status']) { return $data; } $path = $data['data']['file_path']; } if (!file_exists($path)) { return [ 'status' => false, 'message' => $path . '文件不存在' ]; } if (empty($map)) { return [ 'status' => false, 'message' => 'map参数不正确' ]; } $suffix = pathinfo($path)['extension']; $loadReader = $suffix == 'xls' ? 'Excel5' : 'Excel2007'; $objReader = \PHPExcel_IOFactory::createReader($loadReader); $objPHPExcel = $objReader->load($path); $jsonData = []; $sheetIndex = 0; foreach ($map as $data) { $row = $data['row'] ?? 2; $col = $data['col'] ?? 0; $firstHidden = $data['firstHidden'] ?? false; $result = self::getCommanData( $objPHPExcel, $sheetIndex, $row, $col, $firstHidden ); if (!$result['status']) { return $result; } else { $jsonData['sheet' . $sheetIndex] = $result['data']; } $sheetIndex++; } return $jsonData; } ~~~ 其中调用了getCommanData方法--方法如下 ~~~ /** * 获取普通excel数据 * * @param object $objPHPExcel * @param integer $sheetIndex * @param integer $rowstart * @param integer $col * @param bool $firstHidden * @return array */ protected static function getCommanData( $objPHPExcel, $sheetIndex, $rowstart, $col, $firstHidden ) { $sheet = $objPHPExcel->getSheet($sheetIndex); $highestRow = $sheet->getHighestRow(); $highestColumm = $sheet->getHighestColumn(); $highestColumm = \PHPExcel_Cell::columnIndexFromString($highestColumm); $fieldKeys = []; if ($firstHidden) { for ($column = $col; $column < $highestColumm; $column++) { $cellData = trim(strval($sheet->getCellByColumnAndRow($column, 1)->getValue())); array_push($fieldKeys, $cellData); } } $excel_data = []; for ($row = $rowstart; $row <= $highestRow; $row++) { $temp = 0; $datatemp = []; for ($column = $col; $column < $highestColumm; $column++) { $cellData = trim(strval($sheet->getCellByColumnAndRow($column, $row)->getValue())); if ($firstHidden) { if (isset($fieldKeys[($column - $col)]) && $fieldKeys[($column - $col)] != '') { $datatemp[$fieldKeys[($column - $col)]] = $cellData; } else { return ['status' => false, 'message' => 'sheet' . $sheetIndex . '工作区key值少于数据值']; } } else { array_push($datatemp, $cellData); } if($temp == ($highestColumm - 1)) break; $temp++; } if (!empty($datatemp)) $excel_data[] = $datatemp; } $jsonData = ['status' => true, 'data' => $excel_data]; return $jsonData; } ~~~ ### 6、开始importBaseVerify--直接上代码 ~~~ /** * excel导入数据基于基础数据校验 * * @param string $key excel配置文件中的import key * @param string $path 文件路径 如果默认为空,采用文件上传方式 */ public static function importBaseVerify($key, $path = null) { if (empty($key)) { return [ 'status' => false, 'message' => 'key值不能为空' ]; } if (is_null($path)) { $data = (new Files())->upload('default.only_excel'); if (!$data['status']) { return $data; } $path = $data['data']['file_path']; } if (!file_exists($path)) { return [ 'status' => false, 'message' => $path . '文件不存在' ]; } $suffix = pathinfo($path)['extension']; $loadReader = $suffix == 'xls' ? 'Excel5' : 'Excel2007'; $objReader = \PHPExcel_IOFactory::createReader($loadReader); $objPHPExcel = $objReader->load($path); $map = Config::get($key); $jsonData = []; $sheetIndex = 0; foreach ($map as $data) { $row = $data['row'] ?? 2; $col = $data['col'] ?? 0; $firstHidden = $data['firstHidden'] ?? false; $verify = $data['verify'] ?? []; $result = self::getBaseVerifyData( $objPHPExcel, $sheetIndex, $row, $col, $firstHidden, $verify ); if (!$result['status']) { return $result; } else { $jsonData['sheet' . $sheetIndex] = $result['data']; } $sheetIndex++; } return $jsonData; } ~~~ 其中调用了getBaseVerifyData方法如下 ~~~ /** * 获取普通excel数据 * * @param object $objPHPExcel * @param integer $sheetIndex * @param integer $rowstart * @param integer $col * @param bool $firstHidden * @param array $verify * @return array */ protected static function getBaseVerifyData( $objPHPExcel, $sheetIndex, $rowstart, $col, $firstHidden, array $verify ) { $sheet = $objPHPExcel->getSheet($sheetIndex); $highestRow = $sheet->getHighestRow(); $highestColumm = $sheet->getHighestColumn(); $highestColumm = \PHPExcel_Cell::columnIndexFromString($highestColumm); $fieldKeys = []; if ($firstHidden) { for ($column = $col; $column < $highestColumm; $column++) { $cellData = trim(strval($sheet->getCellByColumnAndRow($column, 1)->getValue())); array_push($fieldKeys, $cellData); } } $v_flag = !empty($verify) ? true : false; $excel_data = []; $error = 0; $error_msg = ''; for ($row = $rowstart; $row <= $highestRow; $row++) { $temp = 0; $datatemp = []; for ($column = $col; $column < $highestColumm; $column++) { $cellData = trim(strval($sheet->getCellByColumnAndRow($column, $row)->getValue())); //数据校验 if ($v_flag && isset($verify['col' . ($column - $col)]) ) { $verifyResult = ImportBaseVerify::ImportBaseVerifyEnum($verify['col' . ($column - $col)], $cellData); if (!$verifyResult['status']) { $error ++; $error_msg .= 'sheet' . $sheetIndex . '在第' . $row . '行,第' . ($column + 1) . '列' . $verifyResult['message'] . ';'; } } if ($firstHidden) { if (isset($fieldKeys[($column - $col)]) && $fieldKeys[($column - $col)] != '') { $datatemp[$fieldKeys[($column - $col)]] = $cellData; } else { return ['status' => false, 'message' => 'sheet' . $sheetIndex . '工作区key值少于数据值']; } } else { array_push($datatemp, $cellData); } if($temp == ($highestColumm - 1)) break; $temp++; } if (!empty($datatemp)) $excel_data[] = $datatemp; } $jsonData = $error ? [ 'status' => false, 'message' => $error_msg ] : [ 'status' => true, 'data' => $excel_data ]; return $jsonData; } ~~~ 其中的importBaseVerify中的key到底是什么? key是在config目录下excel.php中的配置key如下: ~~~ //代码中调用key通过Config::get('excel.import.test')即可 'import' => [ 'test' => [ [ //从第几行开始读取 'row' => 3, //从第几列开始读取 'col' => 0, //是否有隐藏的第一行字段 'firstHidden' => true, //每一列对应的的校验方法(列下标从0开始) 'verify' => [ 'col2' => 'idcard',//ok 'col3' => 'date_ymd',//ok 'col4' => 'number_2dot',//ok 'col5' => 'number',//ok 'col6' => 'date_y-m-d',//ok 'col7' => 'number_2dot', ], ], [] ], ], ~~~ ### 7、作者有话说 1.说明一下解惑信息 commmonImport中如果传入了文件path,则直接解析 如果是直接文件上传的模式则调用了Files类的上传upload方法 ----其中importBaseVerify一样 2.firstHidden是干什么用的 这个参数是为了有些量非常大,一般提供了模板导出的然后导入 然而一些数据库字段要与该列的值一一对应 如果firstHidden设为false表示excel中第一行没有隐藏的字段 那么返回的已普通数组模式返回即: ``` [ 'sheet0' => [ ['aa','bb','cc'], ['a2a','b2b','c2c'], ], 'sheet1' => [], ] ``` 说明:该方法支持多个sheet工作区导入 如果firstHidden设为true表示excel中第一行有隐藏的字段 那么返回的将会以第一行的字段以键值对返回 ``` [ 'sheet0' => [ [ 'name'=> 'aa', 'addr' => 'bb', 'age' => 20 ], [], ], 'sheet1' => [], ] ``` 3.具体可以参考代码的注释 4.相信这些简单的代码难不倒各位phper 5.如果有一些不明白的直接留言 6.为了该方法的更直接了解,立马写Files类是怎么的 7.再插一句import配置中的verify是什么意思 col2=>idcard col2表示的是第三列 idcard对应的是ImportBaseVerify中需要校验的一个type 该type会在ImportBaseVerify中调用相应的方法