ExcelUtil.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. // 导入获取数据
  9. static public function read($filepath = '', $cols = [],$row = 2){
  10. // $cols = ['id','name','class'];
  11. $e = explode('.',$filepath);
  12. $ext = $e[count($e)-1];
  13. if($ext == 'xls'){
  14. $objread = IOFactory::createReader('Xls');
  15. }else{
  16. $objread = IOFactory::createReader('Xlsx');
  17. }
  18. $newArr=['xls','xlsx'];
  19. if(!in_array($ext,$newArr)){
  20. return false;
  21. }
  22. $objspreadsheet = $objread->load($filepath);
  23. $ret = $objspreadsheet->getActiveSheet()->toArray();
  24. $ret = $ret?$ret:[];
  25. $nret = [];
  26. foreach ($ret as $k=>$v){
  27. if($k + 1 < $row){
  28. continue;
  29. }
  30. if($cols){
  31. foreach ($cols as $kk=>$vv){
  32. $a[$vv] = $v[$kk];
  33. }
  34. $nret[] = $a;
  35. }else{
  36. $nret[] = $v;
  37. }
  38. }
  39. return $nret;
  40. }
  41. // 导出
  42. static public function export($filename,$header = [],$data = [],$savepath = ''){
  43. // $header = [ // header格式,title和name必须存在
  44. // ['title' => '编号', 'name' => 'id','width'=>'20'],
  45. // ['title' => '姓名', 'name' => 'name','width'=>'20'],
  46. // ['title' => '班级', 'name' => 'class','width'=>'20'],
  47. // ];
  48. $spreadsheet = new Spreadsheet();
  49. $worksheet = $spreadsheet->getActiveSheet();
  50. $worksheet->setTitle($filename);
  51. $widths = [];
  52. $titles = [];
  53. $names = [];
  54. foreach ($header as $k=>$v){
  55. $width = isset($v['width'])&&$v['width'] > 0 ?$v['width']:20;
  56. $widths[] = $width;
  57. $titles[] = isset($v['title'])?$v['title']:'';
  58. $names[] = $v['name'];
  59. }
  60. $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'];
  61. $lins = [];
  62. for( $i=0;$i<count($header);$i++ ){
  63. $r1 = $i%26;
  64. $r2 = floor($i/26);
  65. if($r2 == 0){
  66. $lins[] = $char[$r1];
  67. }else if($r2 == 1){
  68. $lins[] = 'A'.$char[$r1];
  69. }else if($r2 == 2){
  70. $lins[] = 'B'.$char[$r1];
  71. }else if($r2 == 3){
  72. $lins[] = 'C'.$char[$r1];
  73. }else if($r2 == 4){
  74. $lins[] = 'D'.$char[$r1];
  75. }else if($r2 == 5){
  76. $lins[] = 'E'.$char[$r1];
  77. }else if($r2 == 6){
  78. $lins[] = 'F'.$char[$r1];
  79. }
  80. }
  81. $lists = self::chunkData($data);
  82. foreach ($lists as $k=>$v){
  83. if($k > 0){
  84. $sheet = $spreadsheet->createSheet($k+1)->setTitle($filename.($k+1));
  85. }else{
  86. $sheet = $worksheet;
  87. }
  88. self::writeSheet($sheet,$v,$titles,$widths,$lins,$names);
  89. }
  90. $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
  91. if($savepath){
  92. $res = $writer->save($savepath);
  93. halt($res);
  94. }else{
  95. $path = $filename.'_'.date('YmdHis').'.xlsx';
  96. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  97. header('Content-Disposition: attachment;filename="'.$path.'"');
  98. header('Cache-Control: max-age=0');
  99. $writer->save('php://output');
  100. }
  101. }
  102. // 数据分段
  103. static private function chunkData($data,$length = 50000){
  104. $ret = [];
  105. $arr = [];
  106. foreach ($data as $k=>$v){
  107. $arr[] = $v;
  108. if(count($arr) == $length){
  109. $ret[] = $arr;
  110. $arr = [];
  111. }
  112. }
  113. if($arr){
  114. $ret[] = $arr;
  115. }
  116. return $ret;
  117. }
  118. // 多sheet导出,不用数据分段
  119. static public function exportBySheet($filename,$header = [],$sheets = [],$data = [],$savepath = ''){
  120. // $header = [ // header格式,title和name必须存在
  121. // ['title' => '编号', 'name' => 'id','width'=>'20'],
  122. // ['title' => '姓名', 'name' => 'name','width'=>'20'],
  123. // ['title' => '班级', 'name' => 'class','width'=>'20'],
  124. // ];
  125. // $sheets = ['sheet1','sheet2'];
  126. // $data = [['id'=>1,'name'=>'aaa']]; 二维数组
  127. $spreadsheet = new Spreadsheet();
  128. $worksheet = $spreadsheet->getActiveSheet();
  129. $widths = [];
  130. $titles = [];
  131. $names = [];
  132. foreach ($header as $k=>$v){
  133. $width = isset($v['width'])&&$v['width'] > 0 ?$v['width']:20;
  134. $widths[] = $width;
  135. $titles[] = isset($v['title'])?$v['title']:'';
  136. $names[] = $v['name'];
  137. }
  138. $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'];
  139. $lins = [];
  140. for( $i=0;$i<count($header);$i++ ){
  141. $r1 = $i%26;
  142. $r2 = floor($i/26);
  143. if($r2 == 0){
  144. $lins[] = $char[$r1];
  145. }else if($r2 == 1){
  146. $lins[] = 'A'.$char[$r1];
  147. }else if($r2 == 2){
  148. $lins[] = 'B'.$char[$r1];
  149. }else if($r2 == 3){
  150. $lins[] = 'C'.$char[$r1];
  151. }else if($r2 == 4){
  152. $lins[] = 'D'.$char[$r1];
  153. }else if($r2 == 5){
  154. $lins[] = 'E'.$char[$r1];
  155. }else if($r2 == 6){
  156. $lins[] = 'F'.$char[$r1];
  157. }
  158. }
  159. $lists = $data;
  160. foreach ($lists as $k=>$v){
  161. if($k > 0){
  162. $sheet = $spreadsheet->createSheet($k+1)->setTitle($sheets[$k]);
  163. }else{
  164. $worksheet->setTitle($sheets[$k]);
  165. $sheet = $worksheet;
  166. }
  167. self::writeSheet($sheet,$v,$titles,$widths,$lins,$names);
  168. }
  169. $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
  170. if($savepath){
  171. $res = $writer->save($savepath);
  172. halt($res);
  173. }else{
  174. $path = $filename.'_'.date('YmdHis').'.xlsx';
  175. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  176. header('Content-Disposition: attachment;filename="'.$path.'"');
  177. header('Cache-Control: max-age=0');
  178. $writer->save('php://output');
  179. }
  180. }
  181. // 按sheet写入数据
  182. static private function writeSheet($sheet,$data,$titles,$widths,$lins,$names){
  183. foreach ($titles as $key => $value) {
  184. $sheet->setCellValueByColumnAndRow($key+1, 1, $value);
  185. }
  186. $styleArray = [
  187. 'font' => [
  188. 'bold' => true
  189. ],
  190. 'alignment' => [
  191. 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
  192. ],
  193. ];
  194. $styleArray2 = [
  195. 'alignment' => [
  196. 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
  197. ],
  198. ];
  199. foreach ($lins as $k=>$v){
  200. $sheet->getStyle($v.'1')->applyFromArray($styleArray)->getFont()->setSize(12);
  201. $sheet->getStyle($v)->applyFromArray($styleArray2)->getAlignment()->setWrapText(true);//换行
  202. $sheet->getColumnDimension($v)->setWidth($widths[$k]);
  203. }
  204. foreach ($data as $k=>$v){
  205. foreach ($names as $kk=>$vv){
  206. $sheet->setCellValueByColumnAndRow($kk+1, $k + 2, self::filterEmoji($v[$vv]));
  207. }
  208. }
  209. }
  210. // 过滤表情
  211. static private function filterEmoji($str){
  212. $str = preg_replace_callback('/./u',function ($match){
  213. return strlen($match[0]) >= 4?'':$match[0];
  214. },$str);
  215. return $str;
  216. }
  217. }