创意电子

标题: PHP支持多格式的解压缩工具类 [打印本页]

作者: 博读代码    时间: 2021-9-24 11:46
标题: PHP支持多格式的解压缩工具类
一、引语

本人在做一个企业云盘项目当中,碰到一个文件在线解压缩的需求,查了网上很多资料,但都是只支持单一格式或部分格式。因此创建了本工具类,对市面上主流的压缩格式举行集成支持,并且简单易用。


                               
登录/注册后可看大图

二、功能

1.支持zip、rar、phar、tar、gz、bz2、7z格式的解压;

2.支持对单文件、多文件、文件夹举行压缩成zip文件格式数据库连接池。


三、前置条件

1. 安装php_zip插件:用于解压缩zip格式文件

2. 安装php_rar插件:用于解压缩rar格式文件

3. 安装php_phar插件:用于解压缩phar、tar、gz、bz2格式文件

4. 安装p7zip p7zip-full软件:用于解压缩7z格式文件



四、实现

class ZipUtil{    /**     * 解压     * @param string $zipFilePath 压缩文件路径     * @param string $toDirPath 解压目次路径     * @return string     * @throws \Exception     */    public static function extract(string $zipFilePath, string $toDirPath)    {        $toDirPath = rtrim($toDirPath, &#39;/&#39;);        self::deleteDir($toDirPath, false);        if (!is_file($zipFilePath)) throw new \Exception(&#39;文件不存在。&#39;);        if (!is_dir($toDirPath)) {            mkdir($toDirPath, 0777, true);        }        $zipFilePathInfo = pathinfo($zipFilePath);        $zipExt = pathinfo($zipFilePath, PATHINFO_EXTENSION);          switch ($zipExt) {            case &#39;zip&#39;:                if (!class_exists(&#39;\ZipArchive&#39;)) throw new \Exception(&#39;未安装Zip插件。&#39;);                $zipArch = new \ZipArchive();                if ($zipArch->open($zipFilePath) !== true) throw new \Exception(&#39;解压失败。&#39;);                //$zipArch->extractTo($toDirPath); //这个中文会乱码                //解决中文会乱码                $fileNum = $zipArch->numFiles;                for ($i = 0; $i < $fileNum; ++$i) {                    $statInfo = $zipArch->statIndex($i, \ZipArchive::FL_ENC_RAW);                    $statInfo[&#39;name&#39;] = self::convertToUtf8($statInfo[&#39;name&#39;]);                    //print_r($statInfo);                    if ($statInfo[&#39;crc&#39;] === 0 && $statInfo[&#39;name&#39;][strlen($statInfo[&#39;name&#39;]) - 1] === &#39;/&#39;) {                        $dirPath = $toDirPath . &#39;/&#39; . $statInfo[&#39;name&#39;];                        if (!is_dir($dirPath)) {                            mkdir($dirPath, 0777, true);                        }                    } else {                        copy(&#39;zip://&#39; . $zipFilePath . &#39;#&#39; . $zipArch->getNameIndex($i), $toDirPath . &#39;/&#39; . $statInfo[&#39;name&#39;]);                    }                }                $zipArch->close();                break;            case &#39;rar&#39;:                if (!class_exists(&#39;\RarArchive&#39;)) throw new \Exception(&#39;未安装Rar插件。&#39;);                $rarArch = \RarArchive::open($zipFilePath);                if ($rarArch === false) throw new \Exception(&#39;解压失败。&#39;);                $entries = $rarArch->getEntries();                if ($entries === false) throw new \Exception(&#39;解压失败。&#39;);                foreach ($entries as $entry) {                    $entry->extract($toDirPath);                }                $rarArch->close();                break;            case &#39;phar&#39;:                if (!class_exists(&#39;\Phar&#39;)) throw new \Exception(&#39;未安装Phar插件。&#39;);                $phar = new \Phar($zipFilePath, null, null);                $extract = $phar->extractTo($toDirPath, null, true);                if (!isset($zipFilePathInfo[&#39;extension&#39;])) {                    unlink($zipFilePath);                }                if ($extract === false) throw new \Exception(&#39;解压失败。&#39;);                break;            case &#39;tar&#39;:            case &#39;gz&#39;:            case &#39;bz2&#39;:                if (!class_exists(&#39;\PharData&#39;)) throw new \Exception(&#39;未安装Phar插件。&#39;);                $formats = [                    &#39;tar&#39; => \Phar::TAR,                    &#39;gz&#39; => \Phar::GZ,                    &#39;bz2&#39; => \Phar::BZ2,                ];                $format = $formats[$zipExt];                $phar = new \PharData($zipFilePath, null, null, $format);                $extract = $phar->extractTo($toDirPath, null, true);                if (!isset($zipFilePathInfo[&#39;extension&#39;])) {                    unlink($zipFilePath);                }                if ($extract === false) throw new \Exception(&#39;解压失败。&#39;);                break;            case &#39;7z&#39;:                if(shell_exec(&#39;type 7z&#39;) === null) throw new \Exception(&#39;未安装p7zip软件。&#39;);                $cmd = &#39;7z x &#39; . $zipFilePath . &#39; -r -o&#39; . $toDirPath;                $result = shell_exec($cmd);                break;            default:                throw new \Exception(&#39;不支持的解压格式。&#39;);        }        return $toDirPath;    }    /**     * 压缩多个文件     * @param array $files 文件列表,格式:[[&#39;file_type&#39;=>&#39;file|folder&#39;, &#39;file_path&#39;=>&#39;/a/b/test.txt&#39;, &#39;local_name&#39;=>&#39;b/test.txt&#39;]]     * @param string $toFilePath 压缩文件路径     * @return string     * @throws \Exception     */    public static function package(array $files, string $toFilePath)    {        $toFilePathInfo = pathinfo($toFilePath);        if (!is_dir($toFilePathInfo[&#39;dirname&#39;])) {            mkdir($toFilePathInfo[&#39;dirname&#39;], 0777, true);        }        $zipArch = new \ZipArchive();        if ($zipArch->open($toFilePath, \ZipArchive::CREATE) !== true) throw new \Exception(&#39;压缩失败。&#39;);        foreach ($files as $file) {            if ($file[&#39;file_type&#39;] === &#39;folder&#39;) {                $zipArch->addEmptyDir(ltrim($file[&#39;local_name&#39;], &#39;/&#39;));            } else if ($file[&#39;file_type&#39;] === &#39;file&#39;) {                if (is_file($file[&#39;file_path&#39;])) {                    $zipArch->addFile($file[&#39;file_path&#39;], $file[&#39;local_name&#39;]);                }            }        }        $zipArch->close();        return $toFilePath;    }    /**     * 压缩文件夹     * @param string $dirPath 要压缩的文件夹路径     * @param string $toFilePath 压缩文件路径     * @param bool $includeSelf 是否包罗自身     * @return string     * @throws \Exception     */    public static function packageDir(string $dirPath, string $toFilePath, bool $includeSelf = true)    {        if (!is_dir($dirPath)) throw new \Exception(&#39;文件夹不存在。&#39;);        $toFilePathInfo = pathinfo($toFilePath);        if (!is_dir($toFilePathInfo[&#39;dirname&#39;])) {            mkdir($toFilePathInfo[&#39;dirname&#39;], 0777, true);        }        $dirPathInfo = pathinfo($dirPath);        //print_r($dirPathInfo);        $zipArch = new \ZipArchive();        if ($zipArch->open($toFilePath, \ZipArchive::CREATE) !== tre) throw new \Exception(&#39;压缩失败。&#39;);        $dirPath = rtrim($dirPath, &#39;/&#39;) . &#39;/&#39;;        $filePaths = self::scanDir($dirPath);        if ($includeSelf) {            array_unshift($filePaths, $dirPath);        }        //print_r($filePaths);        foreach ($filePaths as $filePath) {            $localName = mb_substr($filePath, mb_strlen($dirPath) - ($includeSelf ? mb_strlen($dirPathInfo[&#39;basename&#39;]) + 1 : 0));            //echo $localName . PHP_EOL;            if (is_dir($filePath)) {                $zipArch->addEmptyDir($localName);            } else if (is_file($filePath)) {                $zipArch->addFile($filePath, $localName);            }        }        $zipArch->close();        return $toFilePath;    }    /**     * 压缩单个文件     * @param string $filePath 要压缩的文件路径     * @param string $toFilePath 压缩文件路径     * @return string     * @throws \Exception     */    public static function packageFile(string $filePath, string $toFilePath)    {        if (!is_file($filePath)) throw new \Exception(&#39;文件不存在。&#39;);        $toFilePathInfo = pathinfo($toFilePath);        if (!is_dir($toFilePathInfo[&#39;dirname&#39;])) {            mkdir($toFilePathInfo[&#39;dirname&#39;], 0777, true);        }        $filePathInfo = pathinfo($filePath);        $zipArch = new \ZipArchive();        if ($zipArch->open($toFilePath, \ZipArchive::CREATE) !== true) throw new \Exception(&#39;压缩失败。&#39;);        $zipArch->addFile($filePath, $filePathInfo[&#39;basename&#39;]);        $zipArch->close();        return $toFilePath;    }    /**     * 字符串转为UTF8字符集     * @param string $str     * @return false|string     */    private static function convertToUtf8(string $str)    {        $charset = mb_detect_encoding($str, [&#39;UTF-8&#39;, &#39;GBK&#39;, &#39;BIG5&#39;, &#39;CP936&#39;]);        if ($charset !== &#39;UTF-8&#39;) {            $str = iconv($charset, &#39;UTF-8&#39;, $str);        }        return $str;    } /**     * 删除目次以及子目次等所有文件     *     * - 请注意不要删除紧张目次!     *     * @param string $path 需要删除目次路径     * @param bool $delSelf 是否删除自身     */    private static function deleteDir(string $path, bool $delSelf = true)    {        if (!is_dir($path)) {            return;        }        $dir = opendir($path);        while (false !== ($file = readdir($dir))) {            if (($file != &#39;.&#39;) && ($file != &#39;..&#39;)) {                $full = $path . &#39;/&#39; . $file;                if (is_dir($full)) {                    self::deleteDir($full, true);                } else {                    unlink($full);                }            }        }        closedir($dir);        if ($delSelf) {            rmdir($path);        }    }    /**     * 遍历文件夹,返回文件路径列表     * @param string $path     * @param string $fileType all|file|folder     * @param bool $traversalChildren 是否遍历下级目次     * @return array     */    private static function scanDir(string $path, string $fileType = &#39;all&#39;, bool $traversalChildren = true)    {        if (!is_dir($path) || !in_array($fileType, [&#39;all&#39;, &#39;file&#39;, &#39;folder&#39;])) {            return [];        }        $path = rtrim($path, &#39;/&#39;);        $list = [];        $files = scandir($path);        foreach ($files as $file) {            if ($file != &#39;.&#39; && $file != &#39;..&#39;) {                $p = $path . &#39;/&#39; . $file;                $isDir = is_dir($p);                if ($isDir) {                    $p .= &#39;/&#39;;                }                if ($fileType === &#39;all&#39; || ($fileType === &#39;file&#39; && !$isDir) || ($fileType === &#39;folder&#39; && $isDir)) {                    $list[] = $p;                }                if ($traversalChildren && $isDir) {                    $list = array_merge($list, self::scanDir($p, $fileType, $traversalChildren));                }            }        }        return $list;    }}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.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.141.142.143.144.145.146.147.148.149.150.151.152.153.154.155.156.157.158.159.160.161.162.163.164.165.166.167.168.169.170.171.172.173.174.175.176.177.178.179.180.181.182.183.184.185.186.187.188.189.190.191.192.193.194.195.196.197.198.199.200.201.202.203.204.205.206.207.208.209.210.211.212.213.214.215.216.217.218.219.220.221.222.223.224.225.226.227.228.229.230.231.232.233.234.235.236.237.238.239.240.241.242.243.244.245.246.247.248.249.250.251.252.253.254.255.256.257.258.259.260.261.262.263.264.265.266.267.268.269.270.271.272.273.274.275.276.277.278.279.280.281.282.283.284.285.286.287.288.289.290.291.292.293.294.295.296.297.298.299.300.301.302.303.304.305.306.307.308.309.310.311.312.313.314.315.316.317.318.319.320.321.322.323.324.325.326.327.328.329.330.331.332.333.334.335.336.337.338.339.340.341.342.343.344.345.346.347.348.349.350.351.352.353.354.355.356.357.358.359.360.361.362.363.364.365.366.367.368.369.370.371.372.373.374.375.376.377.378.379.380.381.382.383.384.385.386.387.388.389.390.391.392.393.394.395.396.397.398.399.400.401.402.403.404.405.406.407.408.409.410.411.412.413.414.415.416.417.418.419.420.421.422.423.424.425.426.427.428.429.430.431.432.433.434.435.436.437.438.439.440.441.442.443.444.445.446.447.448.449.450.451.452.453.454.455.456.457.458.459.460.461.462.463.464.465.466.467.468.469.470.471.472.473.474.475.476.477.478.479.480.481.482.483.484.485.486.487.488.489.490.491.492.493.494.495.496.497.498.499.500.501.502.503.504.505.506.507.508.509.510.511.512.513.514.515.516.517.518.519.520.521.522.523.524.525.526.527.528.529.530.531.532.533.534.535.536.537.538.539.540.541.542.543.544.545.546.547.548.549.550.551.552.553.554.555.556.557.558.559.560.561.562.563.564.565.


调用:

//示例1:解压zip文件到/test/test1/目次下ZipUtil::extract(&#39;/test/test1.zip&#39;, &#39;/test/test1/&#39;);//示例2:解压rar文件到/test/test2/目次下ZipUtil::extract(&#39;/test/test2.rar&#39;, &#39;/test/test2/&#39;);//示例3:解压phar文件到/test/test3/目次下ZipUtil::extract(&#39;/test/test3.phar&#39;, &#39;/test/test3/&#39;);//示例4:解压tar文件到/test/test4/目次下ZipUtil::extract(&#39;/test/test4.tar&#39;, &#39;/test/test4/&#39;);//示例5:解压gz文件到/test/test5/目次下ZipUtil::extract(&#39;/test/test5.tar.gz&#39;, &#39;/test/test5/&#39;);//示例6:解压bz2文件到/test/test6/目次下ZipUtil::extract(&#39;/test/test6.tar.bz2&#39;, &#39;/test/test6/&#39;);//示例7:解压7z文件到/test/test7/目次下ZipUtil::extract(&#39;/test/test7.7z&#39;, &#39;/test/test7/&#39;);//示例8:压缩单个文件ZipUtil::packageFile(&#39;/test/test8/1.txt&#39;, &#39;/test/test8.zip&#39;);//示例9:压缩多个文件ZipUtil::package([ [&#39;file_type&#39;=>&#39;file&#39;, &#39;file_path&#39;=>&#39;/test/test9/1.txt&#39;, &#39;local_name&#39;=>&#39;1.txt&#39;], [&#39;file_type&#39;=>&#39;file&#39;, &#39;file_path&#39;=>&#39;/test/test9/2.txt&#39;, &#39;local_name&#39;=>&#39;2.txt&#39;], [&#39;file_type&#39;=>&#39;folder&#39;, &#39;local_name&#39;=>&#39;1/&#39;], [&#39;file_type&#39;=>&#39;folder&#39;, &#39;local_name&#39;=>&#39;2/&#39;],], &#39;/test/test9.zip&#39;);//示例10:压缩文件夹ZipUtil::packageDir(&#39;/test/test10/&#39;, &#39;/test/test10.zip&#39;);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.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.


五、结语

在刚开始使用这个工具类的过程中,发现在了个坑,就是在window压缩的zip文件放到linux举行解压会发生文件名乱码的情况,所以不能直接使用extractTo方法举行解压,需要对zip解压出来的文件名举行转码。

以上是本期分享的全部内容,主要讲解通过PHP对主流的压缩格式举行集成支持,简单易用。
下期会分享应用配置管理演变及apollo概念拆解哦,敬请等待~
欢迎各位关注、留言,大家的支持就是我的动力!




欢迎光临 创意电子 (https://wxcydz.cc/) Powered by Discuz! X3.4