由于做后台的很多时候都会用到PHPExcel这款插件实现统计数据的导出功能,每个地方都引入这款插件和实例化当然是可以的,只是感觉有点麻烦,项目一旦多了就发现每次都要复制一份插件到新的网站去,而有些只是某个小功能需要下载而已,这样有点浪费资源!
所以我想能不能在一个地方写一次,以后每次只是调用接口即可呢?百度了一下居然没有找到,找来的都是直接输出文件流下载的。。。。
好吧,趁着周末,自己东西实现一下这种小功能。
1.首先在一个服务器上面新增一个接口,以方便其他地方调用实现下载导出文件。
(我在自己写的一个收集日志的系统上面直接加一个接口)。
2.构造数据,调整数据和定义规则。
3.测试效果
4.优化传入
5.实现远程方式
6.完成
7.总结
这里先写总结再上代码:
实现这个下功能还是遇到了一些问题,首先就是输出文件的问题,正常情况下我们是直接输出文件流的形式,然后设置header和清理缓存等,实现即时下载功能。这次发现这个文件流在curl中很难捕获,用php://input 和php://ouput 都试过,效果让人抓头!!!
直接打印curl的结果当然是文件流了,所以就要想办法保存这个文件流作为临时文件,然后远程下载即可(直接流强制转化下载失败了,所以放弃了)。
写好规范后即可实现远程curl调用下载功能,会返回一个临时文件链接,点击即可下载。
待完善:
1.设置更细节的属性,比如高度、字体属性、对齐方式等。
2.安全过滤
3.检测数据的可靠性
4.其他
效果图:
下面贴上代码:
define('LOG_URL','http://服务器地址已经马赛克/'); define('LOG_APP_ID','07授权马赛克8'); define('LOG_APP_SECRET','gF秘钥口令马赛克zJtFDsetxDxl'); //下载数据Excel function getExcel($file_name) { $array = array( 'mod'=>'api', 'route'=>'data_private', 'class'=>'down', 'method'=>'ExcelDownload', 'font_size'=>12, 'app_id'=>LOG_APP_ID ); $data = array( array('a'=>1,'b'=>'数据1','c'=>'哈哈哈','d'=>53,'e'=>'345sdf','f'=>'d','e1'=>'2522242'), array('a'=>3,'b'=>'数据3','c'=>'a','d'=>'adfasdfadsf','e'=>'a','f'=>'32rsdf','e1'=>'s'), array('a'=>4,'b'=>'数据4','c'=>'dowfj','d'=>3242,'e'=>'d','f'=>'3423','e1'=>'3'), array('a'=>5,'b'=>'数据5','c'=>'we','d'=>222,'e'=>'11111','f'=>'aa','e1'=>'e'), array('a'=>555,'b'=>'测试成功','c'=>'晚安','d'=>'待完善很多啊','e'=>'慢慢来','f'=>'好的','e1'=>'么么哒') ); $data = json_encode_cn($data); $column =json_encode_cn( array([10,'标题1','a'],[12,'标题2','b'],[10,'标题3','c'],[35,'名称xx','d'],[10,'标题5','e'],[15,'标题6','f'],[15,'e1字段','e1']) );//[宽度,标题,字段名称] $array['data'] = $data; $array['column'] = $column; $array['file_name'] = $file_name; $array['sign'] = getSign($array); $file = json_decode(sendPost(LOG_URL,$array,10),true); header('location:'.$file['url']); } getExcel('测试下载');//下载测试 //生成当前请求的签名 function getSign($param) { $secret = LOG_APP_SECRET;//平台secret秘钥 $str=''; ksort($param);//key用ascii从小到大排序 foreach ($param as $k=>$v) { //排除sign后拼接字符串 $str .=$k.$v; } $end_str = $secret.$str.$secret;//对称拼接 $sign = strtoupper(md5($end_str));//将字符串用MD5加密后转换大写 return $sign; } /** * 发送post请求 */ function sendPost($url,$post_data=array(),$timeout=10) { if($url == "" || $post_data == array() || $timeout <= 0){ return false; } //初始化 $con = curl_init(); //设置抓取的url curl_setopt($con, CURLOPT_URL, $url); //设置头文件的信息作为数据流输出 curl_setopt($con, CURLOPT_HEADER, 0); //设置获取的信息以文件流的形式返回,而不是直接输出。 curl_setopt($con, CURLOPT_RETURNTRANSFER, 1); //设置post方式提交 curl_setopt($con, CURLOPT_POST, 1); //设置post数据 curl_setopt($con, CURLOPT_POSTFIELDS, $post_data); //请求时间 curl_setopt($con, CURLOPT_TIMEOUT, (int)$timeout); //执行命令 curl_setopt($con, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查 curl_setopt($con, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在 $data = curl_exec($con); //关闭URL请求 curl_close($con); //显示获得的数据 return $data; } //兼容低版本json中文乱码问题 function json_encode_cn($value) { if (version_compare(PHP_VERSION,'5.4.0','<')) { $str = json_encode($value); $str = preg_replace_callback( "#\\\u([0-9a-f]{4})#i", function($matchs) { return iconv('UCS-2BE', 'UTF-8', pack('H4', $matchs[1])); }, $str ); $res = $str; } else { $res= json_encode($value, JSON_UNESCAPED_UNICODE); } return $res; } //下面是下载接口里面的方法,只是复制了方法出来哦,其他验证的全部忽略了!下面的保护的方法,使用请先该属性为public //下载excel//todo 定时清理临时文件 protected function newExcelDownload() { //实例化Excel类 $objPHPExcel = new PHPExcel(); // 设置基本属性 $objPHPExcel->getProperties()->setCreator("ctos") ->setLastModifiedBy("ctos") ->setTitle("Office 2007 XLSX Test Document") ->setSubject("Office 2007 XLSX Test Document") ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.") ->setKeywords("office 2007 openxml php") ->setCategory("Test result file"); $column = json_decode($_POST['column'],true); if (empty($column) || !is_array($column)) { return ReturnError('column非json格式,目前只支持json格式'); } if (count($column[0]) < 3) { return ReturnError('column单元格式应为【宽度,列标题,字段名称】'); } $data = json_decode($_POST['data'],true); if (empty($data) || !is_array($data)) { return ReturnError('data非json格式,目前只支持json格式'); } if (count($data[0]) < count($column)) { return ReturnError('每个data单元数量应该不少于column的数组单元数,且有key对应column单元的‘字段名称’'); } $file_name = !empty($this->data['file_name'])?trim($this->data['file_name']):'测试名称'; $int = 65;//65字母开始位置,91是最后一个字母z的位置 $end = $int + count($column); $last_col = strtoupper(chr($end-1)); if ($end >91 ) { return ReturnError('column列数不能超过26,系统按A~Z安排'); } for($i= $int;$i< $end ;$i++) { $objPHPExcel->getActiveSheet()->getColumnDimension(strtoupper(chr($i)))->setWidth($column[($i-$int)][0]);//设置宽度 } //设置文字大小 $objPHPExcel->getActiveSheet()->getDefaultStyle()->getFont()->setSize(!empty($this->data['font_size'])?intval($this->data['font_size']):12); //设置文字对齐方式 $objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_LEFT); //合并单元格 $objPHPExcel->getActiveSheet()->mergeCells('A1:'.$last_col.'1'); //设置水平居中 for($i= $int;$i< $end ;$i++) { $objPHPExcel->getActiveSheet()->getStyle(strtoupper(chr($i)))->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER); } //设置加粗 $objPHPExcel->getActiveSheet()->getStyle('A1:'.$last_col.'1')->getFont()->setBold(true); $objPHPExcel->getActiveSheet()->getStyle('A1:'.$last_col.'1')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER); $objPHPExcel->getActiveSheet()->getStyle('A1:'.$last_col.'1')->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN); $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A1', $file_name.date('Y-m-d H:i:s'));//默认首行作为名称描述 //设置表格头名称 for($i= $int;$i< $end ;$i++) { $objPHPExcel->setActiveSheetIndex(0)->setCellValue(strtoupper(chr($i)).'2', $column[($i-$int)][1]);//设置标题 } // Miscellaneous glyphs, 编码:UTF-8 //写入数据 foreach ($data as $k => $item) { for($i= $int;$i< $end ;$i++) { $objPHPExcel->getActiveSheet()->setCellValue(strtoupper(chr($i)) . ($k + 3), $item[$column[$i-$int][2]]); } $objPHPExcel->getActiveSheet()->getStyle('A' . ($k + 3) . ':' .$last_col. ($k + 2))->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER); $objPHPExcel->getActiveSheet()->getStyle('A' . ($k + 3) . ':' .$last_col. ($k + 2))->getBorders()->getAllBorders()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN); } // 重命名表 $objPHPExcel->getActiveSheet()->setTitle($file_name); // 打开Excel后默认选中的单元格 $objPHPExcel->setActiveSheetIndex(0); $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5'); $objWriter->save(ROOT_DIR.'/public/upload/file'.$_REQUEST['app_id'].'.xls');//临时文件存放位置,请及时清理 return array('url'=>WEBURL.'upload/file'.$_REQUEST['app_id'].'.xls','code'=>0); }