ThinkPHP5.1框架下PhpSpreadsheet操作Excel表的导⼊导出■☞背景
最近在后台业务需求中⼜涉及到了 Excel 表的导⼊导出
正要参考以前整理的⽂章 ——
但是发现,好多道友早就提⽰了 "PHPExcel" ⼏年前就不再维护了
所以,觉得有必要整理⼀份 "PhpSpreadsheet " 的使⽤指导
希望能帮到有需求的道友,欢迎指摘 …
参考⽂档
1. 官⽅⽂档 ——(英⽂不好的直接⾕歌右键翻译就好呗)
2. 如果觉得有帮助,也可参考参考鄙⼈获取的⼀份⼊门⼿册
链接:pan.baidu/s/1NEIH-yO-c9okPxhD2bkShA 提取码:8ssr
操作环境
> 框架:ThinkPHP5.1.40
> 类库:PhpSpreadsheet
> 技能:Composer, MySql
> PHP: php7.2.9 (建议 7.2 版本以上哦!)
■☞前期准备
提⽰: 本⼈整理的⽂章,⽬前只是针对于 拓展名为 ".xls"和".xlsx" 的 excel 规范⽂件
▶ PhpSpreadsheet 安装
建议使⽤ composer ,执⾏命令如下:
composer require phpoffice/phpspreadsheet
▶操作参考表 "tp5_xop_excel" 的创建
为了⽅便测试,在此可以创建⼀个数据表,如果想节约时间,可以跳过 …
CREATE TABLE`tp5_xop_excel`(
`goods_id`int(11)NOT NULL AUTO_INCREMENT COMMENT'商品ID',
`goods_name`varchar(50)NOT NULL DEFAULT''COMMENT'商品名称',
`thumbnail`varchar(200)NOT NULL DEFAULT''COMMENT'缩略图,⼀般⽤于订单页的商品展⽰',
`place`varchar(50)CHARACTER SET utf8 NOT NULL DEFAULT'1'COMMENT'产地,国家:美国、澳⼤利亚等',
`list_order`int(11)NOT NULL DEFAULT'0'COMMENT'排序,越⼤越靠前',
`reference_price`decimal(11,2)NOT NULL DEFAULT'0.00'COMMENT'商品参考价',
`updated_at`timestamp NOT NULL DEFAULT'1970-01-01 10:00:00'COMMENT'商品更新时间',
`status`tinyint(2)NOT NULL DEFAULT'0'COMMENT'状态 -1:删除 0:待上架 1:已上架 2:预售 ',
PRIMARY KEY(`goods_id`)
视频xml格式)
ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COMMENT='商品表. 注意:status 的规定,app 上只显⽰上架的产品哦';
▶集成操作类 "SpreadsheetService.php" 的下载
可下载 【附录】中提供的源码⽂件 "SpreadsheetService.php"
■☞读取 excel 中的数据
⼀般读取到 excel 表中的数据,就可以做后续的操作(,备忘数据等);此处以我导⼊数据库(mySQL)为例讲解▷前端操作
jquery下载的文件怎么使用⼀般是需要⼀个⽂件上传按钮的,以鄙⼈使⽤ LayUI 框架为例,核⼼代码如下:
layui.use('upload',function(){
const upload = layui.upload;
//普通图⽚上传
elem:'.btn_upload_excel'
, url:"{:url('cms/expand/opExcel')}"
, accept:'file'//上传⽂件类型
,done:function(res){
//如果上传成功
layer.ssage);
}
,error:function(){
//演⽰失败状态,并实现重传
return layer.msg('上传失败,请重新上传');
}
});
});
▷服务端接⼝操作
此处即为服务端的处理接⼝,在此介绍⼀下鄙⼈的思路:
⾸先,将对象⽂件拷贝到项⽬的 "public/upload" ⽬录下
然后,需要获取其 【绝对路径】(⽹上总说 Linux/windows 下的相对路径操作有区别)
接着,就是读取 excel ⽂件中的内容,并将其插⼊到数据库 mySQL 的表中
最后,考虑到上传的⽂件没必要留着,进⾏删除操作 【注意删除前要释放空间,即⽂中的代码 "unset($info); "】
如下,便是鄙⼈的服务端接⼝核⼼源码:
public function opExcel(Request $request){
$file=$request->file('file');
$info=$file->move('upload');
if($info){
//绝对路径,把反斜杠(\)替换成斜杠(/) 因为在 windows下上传路是反斜杠径
$file_real_path=str_replace("\\","/",$info->getRealPath());
unset($info);//释放空间,也可使⽤ $info = null;(写在这⾥最好,后⾯总是不执⾏!!)
$opRes=(new Xmozxx())->importExcelData($file_real_path);
//TODO 操作完成后,删除⽂件
deleteServerFile($file_real_path);
}else{
$opRes['status']=0;
$opRes['message']="⽂件上传失败 ".$file->getError();
}
return showMsg($opRes['status'],$opRes['message']);
}
上⾯代码中提到的 "(new Xmozxx())->importExcelData($file_real_path);",⼀般是要提取到 Model 操作类 中的,核⼼代码如下:
/**
* 导⼊ excel 表中的数据
* @param $file_real_path
* @return array
*/
public function importExcelData($file_real_path){
$opRes=(new SpreadsheetService())->readExcelFileToArray($file_real_path,"A2");
//TODO 根据返回来到数据数组,进⾏数据向数据库的插⼊或其他操作 ...
if(isset($opRes['data'])){
$resultArr=[];
foreach($opRes['data']as$key=>$value){
$resultArr[$key]['goods_name']=isset($value[0])?$value[0]:'';
$resultArr[$key]['thumbnail']=isset($value[1])?$value[1]:'';
$resultArr[$key]['place']=isset($value[2])?$value[2]:'';
$resultArr[$key]['reference_price']=isset($value[3])?$value[3]:'';
$resultArr[$key]['updated_at']=date("Y-m-d H:i:s",time());
}
/**
* TODO 此时进⾏数据表记录的遍历插⼊操作即可
* 因为数据量较⼤,建议使⽤批量插⼊的⽅式,以我的业务需求,代码举例如下:
*/
Db::name('xop_excel')->data($resultArr)->limit(10)->insertAll();
}
return['status'=>$opRes['status'],'message'=>$opRes['message']];
}
}
▶【重要提⽰】
其中最重要的就是集成类 "SpreadsheetService" 的调⽤ ,建议详细阅读鄙⼈的注释信息
(new SpreadsheetService())->readExcelFileToArray()
附录⽂件夹中的 "small.xlsx" ,可作为导⼊操作的⽬标⽂件
【注意】:
第⼀点:上传的⽂件要标准
⽐如:直接将原⽂⽂件的扩展名 ".xlsx" 改为了 ".xls",这是不允许的(可以打开后点击 “另存为”)第⼆点:操作的⽂件数据不要太⼤
鄙⼈测试,⼀万条的 excel 表还是没出问题的
如果出现溢出内存的问题,第⼀可考虑 在 php.ini 中 增加 memory_limit 的限制
如果是百万数据的 excel ⽂件,⽬测还是需要优化代码的
⽬前,鄙⼈没有这个需求,毕竟⼩⽹站业务量有限 …
xml运行显示效果■☞将数据导出到 excel ⽂件
业务需求中经常遇到这个,当前整合的⽅法适合 excel 表样式不复杂的导出操作;
实际业务如果要求严格的话,那是需要根据开发⽂档,设置表格内容样式(⽂字颜⾊,⼤⼩等…)的哦 !▷前端操作
鄙⼈发现,多数的业务适合将 excle ⽂件下载到客户端【为例】,极少数要求保存到服务器指定位置的!
前端核⼼参考代码如下:
<form class="form-download"action="{url('cms/expand/opExcel')}"method="post">
sharepoint client components<input type="hidden"name="op_tag"value="down">
</form>
<button type="button"onclick="downloadExcel()"class="layui-btn layui-btn-danger">下载Excel表格</button>
<script>
function downloadExcel(){
$(".form-download").submit();
layer.msg('数据下载中...',{timer:3500})
}
</script>
【提⽰】:
以鄙⼈的开发经验,有的项⽬中使⽤ form 表单提交⽅式下载会在浏览器中出现乱码
分析原因,很可能是项⽬框架使⽤的 jquery 库不兼造成的
javaajax请求我的解决⽅案就是转化为 GET 页⾯提交,最简单的⽅式即为:window.location = toUrl+query;
多样的实际测试,需要多做经验积累,建议多做尝试即可 …
▷服务端接⼝操作
相对来说,这个需求是简单的,在此讲解⼀下鄙⼈的操作思路:
⾸先,设置⼀个 ⼀维的 "头部标题数组"
然后,获取获得要导出的 ⼆维数组形式的 "⽬标数据",以 ThinkPHP5 框架为例:
Db::name('xop_excel')
->field('goods_name,thumbnail,place,reference_price,status')
->limit(6)
->select();
再者,便是对⼯作簿标题、⽂件名称等的设置
最后,便是对集成类的调⽤了:" (new SpreadsheetService())->outputDataToExcelFile() "
$header=['商品名称','缩略图','产地','售价','状态'];
$opData=(new Xmozxx())->getExcelTestLoginData();
//此时去下载 Excel⽂件
(new SpreadsheetService())->outputDataToExcelFile($header,$opData,"哎呦喂-数据表");
▶【提⽰】
此处展⽰⼀下对操作⽅法 "outputDataToExcelFile()" 的注释信息,保证阅读后才能正确使⽤
【提⽰】
如果业务上需要保存⽂件到指定位置,那就请参考⽅法 "public static function saveExcelFileToLocal()"
鄙⼈也是建议不要下载太⼤的数据量
当前测试,满⾜个⼀两万条数据 (700KB左右) 的下载
如果要求⼤数据量,还是需要进⾏代码优化的哦 !【可见附录…】
■□☞附录
☞☛
☛代码中涉及到的公共⽅法
/
**
* 公⽤的⽅法返回json数据,进⾏信息的提⽰
* @param int $status 状态
* @param string $message 提⽰信息
* @param array $data 返回数据
*/
function showMsg($status=1,$message='',$data=array()){
$result=array(
'status'=>$status,
'message'=>$message,
'data'=>$data
)
;
exit(json_encode($result,JSON_UNESCAPED_UNICODE));
}
/**
* 删除本地⽂件,Linux 上⽐较适⽤
* 有时不能⽣效,需要注意释放⽂件变量的内存,例:unset($info)
* @param string $file_real_path ⼀般来说为绝对路径
* @return bool
*/
function deleteServerFile($file_real_path="")
{
/
/检查⽂件是否存在
if(file_exists($file_real_path)){
@unlink($file_real_path);
return true;
}else{
return false;
}
}
☹☞开发过程中,遇到的奇葩问题
都说是 "PHPExcel" 的升级维护版本,怎么感觉⽐当初开发旧版都⿇烦恁 ?
①. "The filename xxxxx is not recognised as an OLE file"
这个保存信息提⽰,基本的解释就是:上传的⽂件 【不标准】
⽐如:直接将原⽂⽂件的扩展名 ".xlsx" 改为了 ".xls"
或者,⽂件是⾃⼰代码操作所下载的,⽣成过程不标准
该问题可以考虑打开⽂件,另存为 excel 其他类型的⽂件
②. "ZipArchive::getFromName(): Invalid or uninitialized Zip object"
这出现在⽂件上传操作过程,值得⼀提的是,鄙⼈觉得这个问题最奇葩
⽹上对于这个问题:componentsseparatedbystring
多数的⾔论都是说 —— 操作⽂件的格式没有区分好("Xls/Xlsx");
另有部分⾔论认为 —— 没有对该⽂件的操作权限(我整了没⽤,建议可以多试试!)
然后,鄙⼈发现了神奇的⼀幕:
只要将⽂件打开后,再保存⼀下(啥也没动也可以)就能正常读取操作了;
好在鄙⼈认为,我们多数正常的操作都是会对 excel ⽂件进⾏编辑保存的,出现错的情况也不多;
暂时没到好的⽅案,
可以提醒操作⼈员,如果报错就再保存⼀下好了,只能当做曲线救国吧 ...
③. "⽂件删除时会有报错:unlink xxx Resource temporarily unavailable
⼀般来说, 我们都是⽤ "unlink()" 进⾏⽂件的删除操作
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论