由于做后台的很多时候都会用到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);
}