0
0

ExcelUtil.php 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <?php
  2. namespace app\common\util;
  3. use PhpOffice\PhpSpreadsheet\IOFactory;
  4. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  5. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  6. class ExcelUtil
  7. {
  8. static private $error = '';
  9. // 导入获取数据
  10. static public function read($filepath = '', $cols = [],$row = 2){
  11. // $cols = ['id','name','class'];
  12. $e = explode('.',$filepath);
  13. $ext = $e[count($e)-1];
  14. if($ext == 'xls'){
  15. $objread = IOFactory::createReader('Xls');
  16. }else{
  17. $objread = IOFactory::createReader('Xlsx');
  18. }
  19. $newArr=['xls','xlsx'];
  20. if(!in_array($ext,$newArr)){
  21. return false;
  22. }
  23. $objspreadsheet = $objread->load($filepath);
  24. $ret = $objspreadsheet->getActiveSheet()->toArray();
  25. $ret = $ret?$ret:[];
  26. $nret = [];
  27. foreach ($ret as $k=>$v){
  28. if($k + 1 < $row){
  29. continue;
  30. }
  31. if($cols){
  32. foreach ($cols as $kk=>$vv){
  33. $a[$vv] = $v[$kk];
  34. }
  35. $nret[] = $a;
  36. }else{
  37. $nret[] = $v;
  38. }
  39. }
  40. return $nret;
  41. }
  42. // 导出
  43. static public function export($filename,$header = [],$data = [],$savepath = ''){
  44. // $header = [ // header格式,title和name必须存在
  45. // ['title' => '编号', 'name' => 'id','width'=>'20'],
  46. // ['title' => '姓名', 'name' => 'name','width'=>'20'],
  47. // ['title' => '班级', 'name' => 'class','width'=>'20'],
  48. // ];
  49. $spreadsheet = new Spreadsheet();
  50. $worksheet = $spreadsheet->getActiveSheet();
  51. $worksheet->setTitle($filename);
  52. $widths = [];
  53. $titles = [];
  54. $names = [];
  55. foreach ($header as $k=>$v){
  56. $width = isset($v['width'])&&$v['width'] > 0 ?$v['width']:20;
  57. $widths[] = $width;
  58. $titles[] = isset($v['title'])?$v['title']:'';
  59. $names[] = $v['name'];
  60. }
  61. $char = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
  62. $lins = [];
  63. for( $i=0;$i<count($header);$i++ ){
  64. $r1 = $i%26;
  65. $r2 = floor($i/26);
  66. if($r2 == 0){
  67. $lins[] = $char[$r1];
  68. }else if($r2 == 1){
  69. $lins[] = 'A'.$char[$r1];
  70. }else if($r2 == 2){
  71. $lins[] = 'B'.$char[$r1];
  72. }else if($r2 == 3){
  73. $lins[] = 'C'.$char[$r1];
  74. }else if($r2 == 4){
  75. $lins[] = 'D'.$char[$r1];
  76. }else if($r2 == 5){
  77. $lins[] = 'E'.$char[$r1];
  78. }else if($r2 == 6){
  79. $lins[] = 'F'.$char[$r1];
  80. }
  81. }
  82. $lists = self::chunkData($data);
  83. foreach ($lists as $k=>$v){
  84. if($k > 0){
  85. $sheet = $spreadsheet->createSheet($k+1)->setTitle($filename.($k+1));
  86. }else{
  87. $sheet = $worksheet;
  88. }
  89. self::writeSheet($sheet,$v,$titles,$widths,$lins,$names);
  90. }
  91. if(!$lists){
  92. self::writeSheet($worksheet,[],$titles,$widths,$lins,$names);
  93. }
  94. $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
  95. if($savepath){
  96. $res = $writer->save($savepath);
  97. halt($res);
  98. }else{
  99. $path = $filename.'_'.date('YmdHis').'.xlsx';
  100. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  101. header('Content-Disposition: attachment;filename="'.$path.'"');
  102. header('Cache-Control: max-age=0');
  103. $writer->save('php://output');
  104. }
  105. }
  106. // 数据分段
  107. static private function chunkData($data,$length = 50000){
  108. $ret = [];
  109. $arr = [];
  110. foreach ($data as $k=>$v){
  111. $arr[] = $v;
  112. if(count($arr) == $length){
  113. $ret[] = $arr;
  114. $arr = [];
  115. }
  116. }
  117. if($arr){
  118. $ret[] = $arr;
  119. }
  120. return $ret;
  121. }
  122. // 多sheet导出,不用数据分段
  123. static public function exportBySheet($filename,$header = [],$sheets = [],$data = [],$savepath = ''){
  124. // $header = [ // header格式,title和name必须存在
  125. // ['title' => '编号', 'name' => 'id','width'=>'20'],
  126. // ['title' => '姓名', 'name' => 'name','width'=>'20'],
  127. // ['title' => '班级', 'name' => 'class','width'=>'20'],
  128. // ];
  129. // $sheets = ['sheet1','sheet2'];
  130. // $data = [['id'=>1,'name'=>'aaa']]; 二维数组
  131. $spreadsheet = new Spreadsheet();
  132. $worksheet = $spreadsheet->getActiveSheet();
  133. $widths = [];
  134. $titles = [];
  135. $names = [];
  136. foreach ($header as $k=>$v){
  137. $width = isset($v['width'])&&$v['width'] > 0 ?$v['width']:20;
  138. $widths[] = $width;
  139. $titles[] = isset($v['title'])?$v['title']:'';
  140. $names[] = $v['name'];
  141. }
  142. $char = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
  143. $lins = [];
  144. for( $i=0;$i<count($header);$i++ ){
  145. $r1 = $i%26;
  146. $r2 = floor($i/26);
  147. if($r2 == 0){
  148. $lins[] = $char[$r1];
  149. }else if($r2 == 1){
  150. $lins[] = 'A'.$char[$r1];
  151. }else if($r2 == 2){
  152. $lins[] = 'B'.$char[$r1];
  153. }else if($r2 == 3){
  154. $lins[] = 'C'.$char[$r1];
  155. }else if($r2 == 4){
  156. $lins[] = 'D'.$char[$r1];
  157. }else if($r2 == 5){
  158. $lins[] = 'E'.$char[$r1];
  159. }else if($r2 == 6){
  160. $lins[] = 'F'.$char[$r1];
  161. }
  162. }
  163. $lists = $data;
  164. foreach ($lists as $k=>$v){
  165. if($k > 0){
  166. $sheet = $spreadsheet->createSheet($k+1)->setTitle($sheets[$k]);
  167. }else{
  168. $worksheet->setTitle($sheets[$k]);
  169. $sheet = $worksheet;
  170. }
  171. self::writeSheet($sheet,$v,$titles,$widths,$lins,$names);
  172. }
  173. $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
  174. if($savepath){
  175. $res = $writer->save($savepath);
  176. halt($res);
  177. }else{
  178. $path = $filename.'_'.date('YmdHis').'.xlsx';
  179. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  180. header('Content-Disposition: attachment;filename="'.$path.'"');
  181. header('Cache-Control: max-age=0');
  182. $writer->save('php://output');
  183. }
  184. }
  185. // 按sheet写入数据
  186. static private function writeSheet($sheet,$data,$titles,$widths,$lins,$names){
  187. foreach ($titles as $key => $value) {
  188. $sheet->setCellValueByColumnAndRow($key+1, 1, $value);
  189. }
  190. $styleArray = [
  191. 'font' => [
  192. 'bold' => true
  193. ],
  194. 'alignment' => [
  195. 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
  196. ],
  197. ];
  198. $styleArray2 = [
  199. 'alignment' => [
  200. 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
  201. ],
  202. ];
  203. foreach ($lins as $k=>$v){
  204. $sheet->getStyle($v.'1')->applyFromArray($styleArray)->getFont()->setSize(12);
  205. $sheet->getStyle($v)->applyFromArray($styleArray2)->getAlignment()->setWrapText(true);//换行
  206. $sheet->getColumnDimension($v)->setWidth($widths[$k]);
  207. }
  208. foreach ($data as $k=>$v){
  209. foreach ($names as $kk=>$vv){
  210. $sheet->setCellValueByColumnAndRow($kk+1, $k + 2, self::filterEmoji($v[$vv]));
  211. }
  212. }
  213. }
  214. // 过滤表情
  215. static private function filterEmoji($str){
  216. $str = preg_replace_callback('/./u',function ($match){
  217. return strlen($match[0]) >= 4?'':$match[0];
  218. },$str);
  219. return $str;
  220. }
  221. // 导入excel,获取excel数据
  222. static public function importExcel($name,$cols,$row = 2){
  223. $config = config('app.max_upload_excel');
  224. $file = request()->file($name);
  225. if(!$file){
  226. self::$error = '未上传文件';
  227. return false;
  228. }
  229. // $mime = $file->getMime();
  230. $info = $file->validate($config)->move(env('root_path') . 'public' . DIRECTORY_SEPARATOR . 'uploads'. DIRECTORY_SEPARATOR . 'files');
  231. if(!$info){
  232. self::$error = $file->getError();
  233. return false;
  234. }
  235. $img = '/uploads/files/' . $info->getSaveName();
  236. $imgpath = str_replace('\\', '/', $img);
  237. $ret = env('root_path') . 'public'.$imgpath;
  238. if($ret === false){
  239. self::$error = $file->getError();
  240. return false;
  241. }
  242. $data = self::read($ret,$cols,$row);
  243. if($data === false){
  244. self::$error = "后缀类型错误";
  245. return false;
  246. }
  247. @unlink($ret);
  248. return $data;
  249. }
  250. static public function getError(){
  251. return self::$error;
  252. }
  253. }