开发过程中经常用到导入导出excel的功能,自己写了段代码记录一下。
- 引入phpspreadsheet
解释一下为什么不用PHPExcel,PHPExcel已被维护为一个用于处理电子表格文件多年的库,并且因为保留对旧版PHP的支持而受到束缚,这使得前进和改进非常困难.它是一个稳定的库,但不会再进一步开发。
而PHPSpreadsheet是PHPExcel的最新版本,其中大部分内容已经过重写,所以我们选择它。composer require phpoffice/phpspreadsheet
-
app目录下 创建excel.php,封装了两个方法,导入和导出,一会在控制器里调用。
个人没做压力测试,导出1W-6W的表应该是没什么问题的,需要的人可以自测一下。
注释写的比较全面,不懂的或者出现什么bug可以私信问我。<?php //根据自己的文件位置更改命名空间 namespace app; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Spreadsheet; use think\exception\ValidateException; use think\facade\Filesystem; class Excel { /** * @param string $filename * @return array|string * @throws \PhpOffice\PhpSpreadsheet\Exception * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception */ public static function import($filename = "") { $file[] = $filename; try { // 验证文件大小,名称等是否正确 validate(['file' => 'filesize:51200|fileExt:xls,xlsx'])->check($file); // 把上传的excel文件下载到本地一份 $savename = \think\facade\Filesystem::disk('public')->putFile('file', $file[0]); // 读取本地的excel文件 $spreadsheet = IOFactory::load('storage/' . $savename); // 获取excel中的第一张sheet $sheet = $spreadsheet->getSheet(0); // 取得总行数(例如: 3) $highestRow = $sheet->getHighestRow(); // 取得总列数(例如:F) $highestColumn = $sheet->getHighestColumn(); Coordinate::columnIndexFromString($highestColumn); // 去除表头后的总行数 $lines = $highestRow - 1; if ($lines <= 0) { return "数据为空数组"; } // 直接取出excel中的数据 // toArray() 具体参数参考官方文档 $sheetData = $spreadsheet->getActiveSheet()->toArray(null, true, true, true); // 删除第一个元素(表头) array_shift($sheetData); // 删除本地下载的文件 unlink('storage/' . $savename); // 返回结果 return $sheetData; } catch (ValidateException $e) { return $e->getMessage(); } } /** * 数据导出Excel(csv文件) * @param string $file_name 文件名称 * @param array $tile 标题 * @param array $data 数据源 */ public static function export($file_name, $tile = [], $data = []) { ini_set('memory_limit', '512M'); ini_set('max_execution_time', 0); ob_end_clean(); ob_start(); header("Content-Type: text/csv"); header("Content-Disposition:filename=" . $file_name); $fp = fopen('php://output', 'w'); // 转码 防止乱码(比如微信昵称) fwrite($fp, chr(0xEF) . chr(0xBB) . chr(0xBF)); fputcsv($fp, $tile); $index = 0; foreach ($data as $item) { if ($index == 1000) { $index = 0; ob_flush(); flush(); } $index++; fputcsv($fp, $item); } ob_flush(); flush(); ob_end_clean(); } }
-
导入:控制器调用上面的封装好的方法
/** * 导入 * * @return array|Json */ public function import(Request $request) { // 接收文件上传信息 $files = $request->file("file"); // 调用封装类方法,读取excel中的内容 $data = Excel::import($files); // 重构数组,因为id为主键自增,所以这个字段不需要存在于sql语句内 $newData = []; foreach ($data as $val){ //存储到数据库中的字段名 和 表格里的列名要一一对应 $newData[] = [ 'name'=>$val['B'], 'pwd'=>$val['C'], 'phone'=>$val['D'], 'lastOpTime'=>$val['E'], 'regTime'=>$val['F'], ]; } // 入库 // 启动事务 Db::startTrans(); try { $result = Db::name('jason_user')->insertAll($newData); if (!$result) { throw new \Exception('插入数据失败!'); } // 提交事务 Db::commit(); return json(['msg'=>'文件上传成功,已经导入'.$result.'条数据','status'=>200]); } catch (\Exception $e) { // 回滚事务 Db::rollback(); return json(['msg'=>'导入数据失败,'.$e->getMessage(),'status'=>400]); } }
-
导出:控制器调用上面的封装好的方法
/** * 导出 * */ public function export() { $data=Db::table('jason_user')->select()->toArray(); //此处说明:解决数字太长尾数变000的问题 //由于数字超过15位,会被显示成0或者加小数点处理。造成这种情况是由于Excel内置的数值有效范围是15位。超过15位,如果要显示的话,就需要转换成非数字格式。比如文本格式。 foreach ($data as $key => $value) { $data[$key]['uid'] = "\t".$value['uid']."\t"; $data[$key]['name'] = "\t".$value['name']."\t"; $data[$key]['pwd'] = "\t".$value['pwd']."\t"; $data[$key]['phone'] = "\t".$value['phone']."\t"; $data[$key]['lastOpTime'] = "\t".$value['lastOpTime']."\t"; $data[$key]['regTime'] = "\t".$value['regTime']."\t"; } //这里规定列名 return Excel::export('用户_'.time().'.xlsx',['id','用户名','密码','手机号','上次登陆时间戳','注册时间戳'],$data); }
TP6实现导入导出,至此结束