美文网首页
PHP压缩目录成ZIP

PHP压缩目录成ZIP

作者: Zed_790e | 来源:发表于2019-06-13 14:48 被阅读0次

    前言

    最近需要压缩整个目录为ZIP,网上找到的代码测试了几份都有存在的BUG,最终找到一份强大的博文
    博文地址:https://blog.csdn.net/qq_29238009/article/details/77982145
    博文整理版:https://blog.csdn.net/qq_29238009/article/details/79063894
    在linux奔跑时,发现几处异常

    • 抛出rename()方法报错,仔细一看发现转换时候用到了\\,而linux下应该为/,兼容两种环境于是直接改写为DIRECTORY_SEPARATOR,并将四个方法改写为类,贴出来以便以后使用。
    • 在处理目录和文件的时候将GBK转为UTF-8,还原的时候将UTF-8转为GBK,当目录或者文件编码不为GBK的时候会导致异常,因此修改了转码时候的代码:记住原文件或目录的字符编码,在压缩结束后还原最初的编码。
      再次感谢原博主power124932811的贡献。

    不多BB,上代码

    <?php
    
    class MakeZip
    {
    
        public function zip($dir_path, $zipName)
        {
            try {
                $relationArr = [$dir_path => [
                    'originName' => $dir_path,
                    'is_dir' => true,
                    'encode' => '',
                    'children' => []
                ]];
                $this->modifiyFileName($dir_path, $relationArr[$dir_path]['children']);
                $zip = new \ZipArchive();
                $zip->open($zipName, \ZipArchive::CREATE);
                $this->zipDir(array_keys($relationArr)[0], '', $zip, array_values($relationArr)[0]['children']);
                $zip->close();
                $this->restoreFileName(array_keys($relationArr)[0], array_values($relationArr)[0]['children']);
                return true;
            } catch (\Exception $exception) {
                return false;
            }
        }
    
        private function zipDir($real_path, $zip_path, &$zip, $relationArr)
        {
            $sub_zip_path = empty($zip_path) ? '' : $zip_path . DIRECTORY_SEPARATOR;
            if (is_dir($real_path)) {
                foreach ($relationArr as $k => $v) {
                    if ($v['is_dir']) {
                        $zip->addEmptyDir($sub_zip_path . $v['originName']);
                        $this->zipDir($real_path . DIRECTORY_SEPARATOR . $k, $sub_zip_path . $v['originName'], $zip, $v['children']);
                    } else {
                        $zip->addFile($real_path . DIRECTORY_SEPARATOR . $k, $sub_zip_path . $k);
                        $zip->deleteName($sub_zip_path . $v['originName']);
                        $zip->renameName($sub_zip_path . $k, $sub_zip_path . $v['originName']);
                    }
                }
            }
        }
    
        private function modifiyFileName($path, &$relationArr)
        {
            if (!is_dir($path) || !is_array($relationArr)) {
                return false;
            }
            if ($dh = opendir($path)) {
                $count = 0;
                while (($file = readdir($dh)) !== false) {
                    if (in_array($file, ['.', '..', null])) continue; //无效文件,重来
                    $encode = mb_detect_encoding($file, array("ASCII", "UTF-8", "GB2312", "GBK", "BIG5"));
                    if (is_dir($path . DIRECTORY_SEPARATOR . $file)) {
                        $newName = md5(rand(0, 99999) . rand(0, 99999) . rand(0, 99999) . microtime() . 'dir' . $count);
                        $relationArr[$newName] = [
                            'originName' => iconv($encode, 'UTF-8', $file),
                            'is_dir' => true,
                            'encode' => $encode,
                            'children' => []
                        ];
                        rename($path . DIRECTORY_SEPARATOR . $file, $path . DIRECTORY_SEPARATOR . $newName);
                        $this->modifiyFileName($path . DIRECTORY_SEPARATOR . $newName, $relationArr[$newName]['children']);
                        $count++;
                    } else {
                        $extension = strchr($file, '.');
                        $newName = md5(rand(0, 99999) . rand(0, 99999) . rand(0, 99999) . microtime() . 'file' . $count);
                        $relationArr[$newName . $extension] = [
                            'originName' => iconv($encode, 'UTF-8', $file),
                            'is_dir' => false,
                            'encode' => $encode,
                            'children' => []
                        ];
                        rename($path . DIRECTORY_SEPARATOR . $file, $path . DIRECTORY_SEPARATOR . $newName . $extension);
                        $count++;
                    }
                }
            }
        }
    
        private function restoreFileName($path, $relationArr)
        {
            foreach ($relationArr as $k => $v) {
                if (!empty($v['children'])) {
                    $this->restoreFileName($path . DIRECTORY_SEPARATOR . $k, $v['children']);
                    rename($path . DIRECTORY_SEPARATOR . $k, iconv('UTF-8', $v['encode'], $path . DIRECTORY_SEPARATOR . $v['originName']));
                } else {
                    rename($path . DIRECTORY_SEPARATOR . $k, iconv('UTF-8', $v['encode'], $path . DIRECTORY_SEPARATOR . $v['originName']));
                }
            }
        }
    }
    

    错误食用方法:裹上面包糠,在油里...
    正确食用

    (new MakeZip())->zip('目录绝对地址','生成的文件名绝对地址') #成功返回true,有报错返回false,异常捕获在$e中自行测试
    

    相关文章

      网友评论

          本文标题:PHP压缩目录成ZIP

          本文链接:https://www.haomeiwen.com/subject/tahsfctx.html