最近遇到一个项目需求, 要求把服务器上的一堆不按命名规则的图片文件压缩出来, 每个文件都要在压缩包里重新命名。
下面记录一下这个问题的解决:
———————————————————————————————————————
一、 服务器扩展ZipArchive
参考安装
在liunxde XSEHLL中输入
wget http://pecl.php.net/get/zip-1.8.3.tgz
自动下载到/root文件下了,也可移到etc文件下同一规范
然后执行在所在目录执行
tar -zxvf zip-1.8.3.tgz
cd zip-1.8.3
此时需要去寻找php-config 文件所在位置
可以输入find / -name php-config 寻找
输入,生成./configure 信息
phpize
注意
我的服务器上有phprize但是提示找不到,故可能是环境变量没配好
故输入export PATH=$PATH:/usr/local/php/bin
注意,最重要的一部,查看这个扩展的安装方式(一般不能通过下面这种方式安装的有readme.txt):
如果输入
./configure --with-php-config=/opt/remi/php56/root/usr/bin/php-config
不通过则不能使用./configure && make && make install安装,阅读readme.txt查看,如果是可执行文件则直接配置可执行文件到环境变量PATH
注意,./configure可能会提示找不到ZLIB, 不能成功编译
因为使用了函数 zlib 来支持数据压缩,因此需要安装 Zlib 模块
解决:本人是centos通过yum :yum install zlib zlib-devel
如果是ubuntu 则:通过sudo库
Complete!
接下来make 和make install还是出现问题,炸了,
注意,编译出现make: *** [php_zip.lo] Error
网上查了,要换个版本,emmmm
换成
wget http://pecl.php.net/get/zip-1.12.4.tg
以上操作再来一遍。
最后,终于成功
make install之后会出现一个zip.so保存的路径,这个路径要添加到php.ini里。
ok, 打开php.ini在“extension=”下面添加如下一段
extension=/opt/remi/php56/root/usr/lib64/php/modules/zip.so
zlib.output_compression = Off 改为 zlib.output_compression = On
zlib.output_compression_level 建议参数值是1~5
修改过后需要重启[php-fpm],如果你是编译安装的那么就用[绝对路径]去启动,如果是直接安装的可以用 service restart
重启apache。
二、PHP扩展类ZipArchive实现压缩解压Zip文件和文件打包下载
关于ZipArchive几点需要注意的地方:
1、打开的模式在linux下不可使用ZipArchive::OVERWRITE来自动创建ZIP包
2、如果要压缩的文件名包含中文,则不能识别,要通过iconv进行编码转化,并用file_exists检测
3、不能对压缩包进行二次压缩
4、PHP的readdir扫描要压缩的文件夹是不按顺序的,但都会扫描一次
5、估计有一个压缩处理池, 如果不close掉,那么这个处理池满了就压缩异常, 一个压缩对象最多处理压缩600个左右文件, 超过不报任何异常,不生成压缩包, 所以遇到大型的压缩项目, 分包压缩吧, 并在扫描文件时检测这个文件时第几个, 每600个文件close掉当前压缩包对象生成文件, 开始往新对象放入文件。
创建对象打开文件
//创建压缩包对象
$zip = new \ZipArchive();
$zipName = iconv("utf-8", "GB2312//IGNORE", C('UPLOAD_PATH').'/所有商品相册'.date('m-d', time()).'('.$i.').zip');
//这里打开的模式在linux下不可使用ZipArchive::OVERWRITE来自动创建ZIP包
$zip->open($zipName, \ZipArchive::CREATE);
批量对某个目录进行压缩
/** 一次压缩
* 将文件夹打包成zip文件
* add by guo 2018年6月3日
* 循环的读取文件夹下的所有文件和文件夹
* 其中$filename = readdir($handler)是每次循环的时候将读取的文件名赋值给$filename,
* 为了不陷于死循环,所以还要让$filename !== false。
* 定要用!==,因为如果某个文件名如果叫'0',或者某些被系统认为是代表false,用!=就会停止循环
*/
function addFileToZip($path, $zip , $goods_mod, $supplier ,$pre_dir , $goods_num) {
//$zip为传入总共需要分包的压缩对象列表
$handler = opendir($path); //打开当前文件夹由$path指定。
while (($filename = readdir($handler)) !== false) {
if ($filename != "." && $filename != "..") {//文件夹文件名字为'.'和‘..’,不要对他们进行操作
if (is_dir($path . "/" . $filename)&&is_numeric($filename)) {// 如果读取的某个对象是文件夹,则递归
//遇到商品id的文件夹把它替换成商品名,查找不到该商品则不递归该文件夹
$where['goods_id'] = $filename;
$where['supplier'] = $supplier;
$goods_name = $goods_mod
->where($where)
->getField('goods_name',true);
if(!empty($goods_name[0])){
$goods_num++;
//
addFileToZip($path . "/" . $filename, $zip, $goods_mod ,$supplier, $goods_name[0], $goods_num);//动态规划递归算法
}
} else { //将文件加入zip对象
//对商品名中带/的进行转义
//70个商品左右(500左右图片)达到可压缩最大值
$pre_dir=str_replace("/","",$pre_dir);
$package_div = ($goods_num/70);
if (is_int($package_div)) {
//估计有一个压缩处理池, 如果不close掉,那么这个处理池满了就压缩异常
$zip[(int)$package_div-1]->close();
}
//$pre_dir用于命名这个文件存储的上级目录名字
$zip[(int)$package_div]->addFile($path . "/" . $filename, $pre_dir.'/'.$filename);
}
}
}
closedir($path);
———————————————————————————————————————
由于不能二次压缩,所以以上的批量压缩算法会生成多个压缩包供前端下载。