zoukankan      html  css  js  c++  java
  • PHP扩展类ZipArchive实现压缩解压Zip文件和文件打包下载 && Linux下的ZipArchive配置开启压缩 &&搞个鸡巴毛,写少了个‘/’号,浪费了一天

    PHP ZipArchive 是PHP自带的扩展类,可以轻松实现ZIP文件的压缩和解压,使用前首先要确保PHP ZIP 扩展已经开启,具体开启方法就不说了,不同的平台开启PHP扩增的方法网上都有,如有疑问欢迎交流。这里整理一下常用的示例供参考。

    一、解压缩zip文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $zip = new ZipArchive;//新建一个ZipArchive的对象
    /*
    通过ZipArchive的对象处理zip文件
    $zip->open这个方法的参数表示处理的zip文件名。
    如果对zip文件对象操作成功,$zip->open这个方法会返回TRUE
    */
    if ($zip->open('test.zip') === TRUE)
    {
    $zip->extractTo('images');//假设解压缩到在当前路径下images文件夹的子文件夹php
    $zip->close();//关闭处理的zip文件
    }

    二、将文件压缩成zip文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $zip = new ZipArchive;
    /*
    $zip->open这个方法第一个参数表示处理的zip文件名。
    第二个参数表示处理模式,ZipArchive::OVERWRITE表示如果zip文件存在,就覆盖掉原来的zip文件。
    如果参数使用ZIPARCHIVE::CREATE,系统就会往原来的zip文件里添加内容。
    如果不是为了多次添加内容到zip文件,建议使用ZipArchive::OVERWRITE。
    使用这两个参数,如果zip文件不存在,系统都会自动新建。
    如果对zip文件对象操作成功,$zip->open这个方法会返回TRUE
    */
    if ($zip->open('test.zip', ZipArchive::OVERWRITE) === TRUE)
    {
    $zip->addFile('image.txt');//假设加入的文件名是image.txt,在当前路径下
    $zip->close();
    }

    三、文件追加内容添加到zip文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $zip = new ZipArchive;
    $res = $zip->open('test.zip', ZipArchive::CREATE);
    if ($res === TRUE) {
    $zip->addFromString('test.txt', 'file content goes here');
    $zip->close();
    echo 'ok';
    } else {
    echo 'failed';
    }

    四、将文件夹打包成zip文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function addFileToZip($path, $zip) {
    $handler = opendir($path); //打开当前文件夹由$path指定。
    /*
    循环的读取文件夹下的所有文件和文件夹
    其中$filename = readdir($handler)是每次循环的时候将读取的文件名赋值给$filename,
    为了不陷于死循环,所以还要让$filename !== false。
    一定要用!==,因为如果某个文件名如果叫'0',或者某些被系统认为是代表false,用!=就会停止循环
    */
    while (($filename = readdir($handler)) !== false) {
    if ($filename != "." && $filename != "..") {//文件夹文件名字为'.'和‘..’,不要对他们进行操作
    if (is_dir($path . "/" . $filename)) {// 如果读取的某个对象是文件夹,则递归
    addFileToZip($path . "/" . $filename, $zip);
    } else { //将文件加入zip对象
    $zip->addFile($path . "/" . $filename);
    }
    }
    }
    @closedir($path);
    }
     
    $zip = new ZipArchive();
    if ($zip->open('images.zip', ZipArchive::OVERWRITE) === TRUE) {
    addFileToZip('images/', $zip); //调用方法,对要打包的根目录进行操作,并将ZipArchive的对象传递给方法
    $zip->close(); //关闭处理的zip文件
    }

    五、ZipArchive方法如下:


    另附一:几行代码实现PHP文件打包下载zip


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <?php  
    /**    
     * 没有写成class 或者 function ,需要的朋友自己写,就这么几行。。    
     */ 
    $filename = "./test/test.zip"; //最终生成的文件名(含路径)  
    if(!file_exists($filename)){  
    //重新生成文件  
        $zip = new ZipArchive();//使用本类,linux需开启zlib,windows需取消php_zip.dll前的注释  
        if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {  
            exit('无法打开文件,或者文件创建失败');
        }  
        foreach( $datalist as $val){  
            $attachfile = $attachmentDir . $val['filepath']; //获取原始文件路径  
            if(file_exists($attachfile)){  
                $zip->addFile( $attachfile , basename($attachfile));//第二个参数是放在压缩包中的文件名称,如果文件可能会有重复,就需要注意一下  
            }  
        }  
        $zip->close();//关闭  
    }  
    if(!file_exists($filename)){  
        exit("无法找到文件"); //即使创建,仍有可能失败。。。。  
    }  
    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header('Content-disposition: attachment; filename='.basename($filename)); //文件名  
    header("Content-Type: application/zip"); //zip格式的  
    header("Content-Transfer-Encoding: binary"); //告诉浏览器,这是二进制文件   
    header('Content-Length: '. filesize($filename)); //告诉浏览器,文件大小  
    @readfile($filename);
    ?>



    另附二:文件打包,下载之使用PHP自带的ZipArchive压缩文件并下载打包好的文件


    总结:                                                              

    1. 使用PHP下载文件的操作需要给出四个header(),可参考:PHP下载文件名中文乱码解决方法和PHP下载流程分析
    2. 计算文件的大小的时候,并不需要先打开文件,通过filesize($filename)就可以看出,如果需要先打开文件的话,filesize可能就会是这样的形式了filesize($filehandle)
    3. 向客户端回送数据的是,记得要设置一个buffer,用来指定每次向客户端输出多少数据,如:$buffer=1023。如果不指定的话,就会将整个文件全部写入内存当中,再一次性的讲数据传送给客户端
    4. 通过feof()函数,可以判断要读取的文件是否读完,如果还没读完,继续读取文件($file_data=fread()),并将数据回送给客户端(echo $file_data)
    5. 每次下载完成后,在客户端都会刷新下,说明了,其实每次都将数据写入到一个临时文件中,等全部下载完成后,再将所有的数据重新整合在一起
    6. 这里我使用的是绝对路径,绝对路径有个好处,就是适应性比较强,而且相对于相对路径,效率更高(免去了查找文件的过程)

    分析下技术要点:                            

    1. 将文件打包成zip格式
    2. 下载文件的功能

    要点解析:

    1. 这里我采用的是php自带的ZipArchive类

        a) 我们只需要new一个ZipArchive对象,然后使用open方法创建一个zip文件,接着使用addFile方法,将要打包的文件写入刚刚创建的zip文件中,最好还得记得关闭该对象。

        b) 注意点:使用open方法的时候,第二个参数$flags是可选的,$flags用来指定对打开的zip文件的处理方式,共有四种情况

                        i.     ZIPARCHIVE::OVERWRITE总是创建一个新的文件,如果指定的zip文件存在,则会覆盖掉

                          ii.    ZIPARCHIVE::CREATE     如果指定的zip文件不存在,则新建一个

                  iii.  ZIPARCHIVE::EXCL      如果指定的zip文件存在,则会报错   

                   iv.  ZIPARCHIVE::CHECKCONS

     

    下载文件的流程:                        

    服务器端的工作:
    -------------------------------------------
    客户端的浏览器发送一个请求到处理下载的php文件。
    注意:任何一个操作都首先需要写入到内存当中,不管是视频、音频还是文本文件,都需要先写入到内存当中。
    换句话说,将“服务器”上的文件读入到“服务器”的内存当中的这个操作时必不可少的(注意:这里我将服务器三个字加上双引号,主要是说明这一系类的操作时在服务器上完成的)。<br>
    既然要将文件写入到内存当中,就必然要先将文件打开
    所以这里就需要三个文件操作的函数了:
    一:fopen($filename ,$mode)
    二:fread ( int $handle , int $length )
    三:fclose ( resource $handle )

    ---------------------------------------
    客户端端的工作:
    ---------------------------------------
    那么,如何将已经存在于服务器端内存当中的文件信息流,传给客户端呢?
    答案是通过header()函数,客户端就知道该如何处理文件,是保存还是打开等等


     

    最终的效果如下图所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    <?php
    require'./download.php';
    /**
     * 遍历目录,打包成zip格式
     */
        class traverseDir{
            public $currentdir;//当前目录
            public $filename;//文件名
            public $fileinfo;//用于保存当前目录下的所有文件名和目录名以及文件大小
            public function __construct(){
                $this->currentdir=getcwd();//返回当前目录
            }       
            //遍历目录
            public function scandir($filepath){
                if (is_dir($filepath)){
                        $arr=scandir($filepath);
                        foreach ($arr as $k=>$v){
                            $this->fileinfo[$v][]=$this->getfilesize($v);
                        }
                    }else {
                        echo "<script>alert('当前目录不是有效目录');</script>";
                    }
            }
            /**
             * 返回文件的大小
             *
             * @param string $filename 文件名
             * @return 文件大小(KB)
             */
            public function getfilesize($fname){
                return filesize($fname)/1024;
            }
             
            /**
             * 压缩文件(zip格式)
             */
            public function tozip($items){
                $zip=new ZipArchive();
                $zipname=date('YmdHis',time());
                if (!file_exists($zipname)){
                    $zip->open($zipname.'.zip',ZipArchive::OVERWRITE);//创建一个空的zip文件
                    for ($i=0;$i<count($items);$i++){
                        $zip->addFile($this->currentdir.'/'.$items[$i],$items[$i]);
                    }
                    $zip->close();
                    $dw=new download($zipname.'.zip'); //下载文件
                    $dw->getfiles();
                    unlink($zipname.'.zip'); //下载完成后要进行删除   
                }
            }
        }
    ?>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    <?php
    /**
     * 下载文件
     *
     */
        class download{
            protected $_filename;
            protected $_filepath;
            protected $_filesize;//文件大小
            public function __construct($filename){
                $this->_filename=$filename;
                $this->_filepath=dirname(__FILE__).'/'.$filename;
            }
            //获取文件名
            public function getfilename(){
                return $this->_filename;
            }
             
            //获取文件路径(包含文件名)
            public function getfilepath(){
                return $this->_filepath;
            }
             
            //获取文件大小
            public function getfilesize(){
                return $this->_filesize=number_format(filesize($this->_filepath)/(1024*1024),2);//去小数点后两位
            }
            //下载文件的功能
            public function getfiles(){
                //检查文件是否存在
                if (file_exists($this->_filepath)){
                    //打开文件
                    $file = fopen($this->_filepath,"r");
                    //返回的文件类型
                    Header("Content-type: application/octet-stream");
                    //按照字节大小返回
                    Header("Accept-Ranges: bytes");
                    //返回文件的大小
                    Header("Accept-Length: ".filesize($this->_filepath));
                    //这里对客户端的弹出对话框,对应的文件名
                    Header("Content-Disposition: attachment; filename=".$this->_filename);
                    //修改之前,一次性将数据传输给客户端
                    echo fread($file, filesize($this->_filepath));
                    //修改之后,一次只传输1024个字节的数据给客户端
                    //向客户端回送数据
                    $buffer=1024;//
                    //判断文件是否读完
                    while (!feof($file)) {
                        //将文件读入内存
                        $file_data=fread($file,$buffer);
                        //每次向客户端回送1024个字节的数据
                        echo $file_data;
                    }
                     
                    fclose($file);
                }else {
                    echo "<script>alert('对不起,您要下载的文件不存在');</script>";
                }
            }
        }
    ?>

    页面显示的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    <script type="text/javascript" src="jquery-1.7.2.js"></script>
    <script type="text/javascript" src="ajax.js"></script>
    <?php
        header("Content-type:text/html;charset=utf8");
        require('./getfile.php');
        $scandir=new traverseDir();
        $scandir->scandir($scandir->currentdir);
        $scandir->currentdir;
         
        if (isset($_POST['down_load'])){
            $items=$_POST['items'];
            $scandir->tozip($items);//将文件压缩成zip格式
        }
        echo "当前的工作目录:".$scandir->currentdir;
        echo "<br>当前目录下的所有文件";
    ?>
     
    <form action="list.php" method="POST">
    <table>
        <tr>
            <td></td>
            <td>名称</td>
            <td>大小(KB)</td>
        </tr>
    <?php
        $res=$scandir->fileinfo;
        foreach ($res as $k=>$v){
            if (!($k=='.' || $k=='..'))    {//过滤掉.和..
    ?>
        <tr>
            <td><input type="checkbox" name="items[]" class="filename" value="<?php echo $k;?>"></td>
            <td><?php echo $k; ?></td>
            <td><?php echo number_format($v[0],0); ?></td>
        </tr>
    <?php
            }
        }
    ?>
        <tr>
            <td><input type="checkbox" id="selall"><label for="selall">全选</label></td>
            <td><input type="submit" name="down_load" value="打包并下载" id="tozip_tetttt"></td>
        </tr>
    </table>
    </form>

    Linux下的ZipArchive配置

     
    今天在Linux底下上传Excel文件时,抛出“ZipArchive library is not enabled” 的异常。而我在本地的windows下的代码则是运行正常的。
     
     原因是:在Linux下没有php_zip.dll这个文件(有也不会起作用的),所以需要重新编译一下php的zip模块。
         
         在Unix/Linux下的解决办法 :
         www.2cto.com  
          1、依次运行如下命令:
     
          cd /usr/src 
          wget http://pecl.php.net/get/zip   (默认会在线下载最新版本的)
          tar zxvf zip-1.x.x.tgz   (所下载的包名)
          cd zip-1.x.x 
          /usr/bin/phpize    (对应的phpize路径 find / -name phpize 出来结果/usr/bin/phpize)
          ./configure --with-php-config=/usr/bin/php-config (对应的php-config路径)
          make 
          make instal
     
    2、查看生成的模块路径(安装完之后,屏幕上会提示zip.so的位置):
    cd /usr/lib/php/modules/ (对应的extensions路径 /usr/lib/php/modules/)
     
    3、修改php.ini
          增加 extension=zip.so
        然后同样在php.ini文件中,将zlib.output_compression = Off 改为 zlib.output_compression = On ;
     
          4、最后再重启一下Apache:./apachectl restart ;
          www.2cto.com  
          这个针对php的zip模块就安装完成了,能够在php中使用ZipArchive类了。
     
          附:在Windows下的解决办法就比较简单了 :
     
         1、在php.ini文件中,将extension=php_zip.dll前面的分号“;”去除
      然后同样在php.ini文件中,将 zlib.output_compression = Off 改为 zlib.output_compression = On ;
     
         2、重启Apache服务器。
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    在linux 系统上使用php 代码解压,中文的文件解压不出来,其他的可以,求解答

    2014-07-24 21:00 hemmoe | 浏览 191 次
    2014-07-25 09:46 提问者采纳
     
    文件名用中文那就别拉着别人一起恶心了。服务器的基本原则就是绝对不能出现中文文件名。

    因为 Linux 下面普遍的文件名默认编码都是 UTF-8 。但是很多情况下,压缩包里面的文件名都是当前系统的 IO 用字符编码。而且解压缩写入文件时,很多软件也都没有提供文件名编码转换的问题。
    结果就是出现问题。

    现在,你要不然就是用你当前编码去重新压缩文件,当然,Windows 的编码肯定不是 UTF8 ,只能是 Linux ,或者尝试用英文版(不能是用语言包换成英文,必须是纯英文版)。要不然就去用支持文件名编码设置的压缩协议去重新压缩,不过具体有哪些支持我不清楚。

    最后的一个办法,那就是你自己写解压缩代码,代码里获取文件名后自己转换。
    追问:
    关键是中文不是我要求的,对我来说也很重要,不然也不可能费力不讨好
    追答:
    那没办法。编码问题一直就是这么XXOO。

    现在你遇到的主要问题是,压缩时编码、解压缩编码、系统文件名编码,这三个只要有一个不同,就会出问题。

    你最直接的办法,就是在 Linux 里面先解压缩一下,之后重新压缩。
    用和服务器系统版本一样的 Linux ,而且 locale 设置也要一样的。当然不一定非得是中文,但是最好是 UTF8 的。en_US.UTF-8 和 zh_CN.UTF-8 这种。你的服务器也要用 UTF8 (不过我记得现在服务器基本都是这个,除非有人手欠,或者系统太老)。

    如果是乱码的,你在你自己的 Linux 上面要么解压失败,要么就是文件名乱码,这个时候你可以临时 export LANG=XXX 来设置,之后再尝试解压。还有文件系统也有自己的 IO 编码,export 并不一定管用,可能还需要你单独弄一个大文件,格式化成 ext3 之后 -o loop 方式挂载,加上 charset=xxx 参数来使用,让文件能解压缩出来到这个文件里(当然对于系统来说,类似一个新的分区)。之后再给你这个解压缩出来的文件夹转换文件目录的编码(抱歉命令忘了)。之后用 UTF8 重新压缩,服务器上就能正常解压缩了。

    最好是去要求,给你的文件,就必须在某个环境下压缩的让他可以在服务器上解压缩。
    另外,我记得好像 7zip 的文件名是有编码信息的。这个压缩方式,文件名可以跨编码正确识别。当然有前提,那就是,如果我没记错。
    zip 是铁定不行的,tar 好像也依赖于当前系统状况。不过 tar 有个好处是,Linux 现在都是 utf8 ,他在 Linux 里没问题,但是 Windows 下面过来的数据无法保证。另外 rar 也有编码问题,这东西在纯中文版的 Windows 和纯英文版的里面就互相不能文件名兼容。其他的就真想不起来了。
    追问:

    代码是在linux运行的,要解压到linux一个指定目录,只有图片是中文反而丢失了,

    刚你说的那么多,能不能给点实用的具体该怎么:(临时写)export LANG=XXX 

    ,这个可以么具体是怎么实现的

    追答:
    你可以试试解压缩改用命令 LANG=XXXXX unzip xxxxxx 。
    LANG 后面的 XXXXX 你可以是是 zh_CN.GB2312 ,zh_CN.GB18030 ,后面的 xxxxx 是压缩包的名字。
    php 调用命令的函数我记得是 system() 吧?
    不过有些服务器设置是禁止 php 调用系统命令的。

    不过你这么做就算能解压,那么解压缩出来也是乱码,你还是无法调用和提供访问。
    而且这么做可能反而更糟,导致服务器上面文件名混乱。

    所以,这种情况下,要么你自己实现解压缩的代码,自己读取文件名后转换,而不是调用 php 的 zip 模块。不然就在你自己的计算机上解压缩重新压缩,自己先解决一下编码问题。
    zip 的文件名是不含编码信息的,而且你这个肯定是 Windows 下面拿到的 zip ,Windows 自己用的不是 UTF8 ,你这么弄,肯定有编码问题。
  • 相关阅读:
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第一题
    fiddler模拟发送post请求
  • 原文地址:https://www.cnblogs.com/caicaizi/p/5290098.html
Copyright © 2011-2022 走看看