PHP实现rar解压读取扩展包小结


Posted in PHP onJune 03, 2021

作为压缩解压方面的扩展学习,两大王牌压缩格式 rar 和 zip 一直是计算机领域的压缩终结者。rar 格式的压缩包是 Windows 系统中有接近统治地位的存在,今天我们学习的 PHP 扩展就是针对于 rar 的压缩包操作,不过,PHP 的 rar 扩展仅能读取和解压 rar 格式的压缩包,并不能进行压缩操作。

php-rar 扩展在 pecl 的安装包已经过时了,无法在 PHP7 中使用,我们需要使用它在 github 上的源码进行编译安装才能够在 PHP7 的环境下安装成功。

https://github.com/cataphract/php-rar

直接 git clone 之后就可以按正常的 PHP 扩展的方式进行安装。

获取压缩包句柄 RarArchive

$arch = RarArchive::open("test.rar");

$archNo = rar_open("test.rar");

echo $arch, PHP_EOL; // RAR Archive "/data/www/blog/test.rar"
echo $archNo, PHP_EOL; // RAR Archive "/data/www/blog/test.rar"

$arch->close();
rar_close($archNo);

echo $arch, PHP_EOL; // RAR Archive "/data/www/blog/test.rar" (closed)
echo $archNo, PHP_EOL; // RAR Archive "/data/www/blog/test.rar" (closed)

php-rar 扩展有两种形式的写法,一种是面向对象的,也就是使用 RarArchive 类来操作压缩包。另一种方式就是直接使用一个函数 rar_open 用来获取一个 rar 文件的句柄。它们都重写了 __toString 方法,所以我们可以直接打印句柄的内容看到当前句柄所操作的具体文件。

当我们关闭句柄时,句柄对象依然能够进行输出,但后面会显示一个 closed 。这时的句柄对象已经不能进行其它操作了。

$arch = RarArchive::open("test.rar");
$archNo = rar_open("test.rar");

echo $arch->getComment(), PHP_EOL;
echo $arch->isBroken(), PHP_EOL;
echo $arch->isSolid(), PHP_EOL;

echo rar_comment_get($archNo), PHP_EOL;
echo rar_broken_is($archNo), PHP_EOL;
echo rar_solid_is($archNo), PHP_EOL;

echo $arch->setAllowBroken(true), PHP_EOL;
echo rar_allow_broken_set($archNo, true), PHP_EOL;

RarArchive 对象的一些方法可以帮我们获取当前压缩包的信息。比如 getComment() 获取压缩包的说明信息,isBroken() 获取当前压缩包是否有损坏,isSolid() 检查当前压缩包是否可用。而 setAllowBroken() 方法是让我们允许对损坏的压缩包进行操作。这里我们给出了面向对象和面向过程的写法。

压缩包内的每个实体文件或目录操作 RarEntry

获得压缩包的句柄之后,我们就需要更进一步地获取压缩包内部的内容。而句柄对象中就已经保存了压缩包内部的各个文件和目录的对象 RarEntry 。

$gameEntry = $arch->getEntry('ldxlcs/ldxlcs/game.htm');
echo $gameEntry->getName(), PHP_EOL; // ldxlcs/ldxlcs/game.htm
echo $gameEntry->getUnpackedSize(), PHP_EOL; // 56063

$gameEntryNo = rar_entry_get($arch, "ldxlcs/ldxlcs/game.htm");
echo $gameEntry->getName(), PHP_EOL; // ldxlcs/ldxlcs/game.htm
echo $gameEntry->getUnpackedSize(), PHP_EOL; // 56063

$fp = $gameEntryNo->getStream();
while (!feof($fp)) {
    $buff = fread($fp, 8192);
    if ($buff !== false) {
        echo $buff;
    } else {
        break;
    }
    //fread error
}
// 输出文件的全部内容
echo PHP_EOL;

echo 'Entry extract: ', $gameEntry->extract("./"), PHP_EOL;

句柄对象的 getEntry() 方法就是用于获取指定的文件或者目录内容的。它获取的是单个文件或目录,所以必须明确地指定需要获取的文件内容。通过这个方法,我们可以拿到一个 RarEntry 对象。接下来,就是这个对象的一些操作。

RarEntry 对象的 getName() 方法用于获取文件名称,这个文件名称是带路径的,这个路径是压缩包内的绝对路径。getUnpackedSize() 方法用于获取文件的大小,getStream() 用于获取文件流,通过 getStream() 方法,我们就可以直接打印输出文件的内容。

当然,最最重要的是,我们可以通过 extract() 方法来直接解压一个文件到指定的目录。php-rar 扩展并没有提供一个能够完全地解压整个压缩包的方法,所以如果我们需要对整个压缩包进行解压的话,就需要通过循环遍历压缩包内部的全部内容来对这些文件一个一个地进行解压。

最后,我们就来看看如何遍历压缩包内的全部内容。

$entries = $arch->getEntries();

foreach ($entries as $en) {
    echo $en, PHP_EOL;
    echo $en->getName(), PHP_EOL;
    echo $en->getUnpackedSize(), PHP_EOL;
    echo $en->getAttr(), PHP_EOL;
    echo $en->getCrc(), PHP_EOL;
    echo $en->getFileTime(), PHP_EOL;
    echo $en->getHostOs(), PHP_EOL;
    echo $en->getMethod(), PHP_EOL;
    echo $en->getPackedSize(), PHP_EOL;
    echo $en->getVersion(), PHP_EOL;
    echo $en->isDirectory(), PHP_EOL;
    echo $en->isEncrypted(), PHP_EOL;

}

// 压缩包中所有文件的内容
// RarEntry for file "ldxlcs/ldxlcs/game.htm" (3c19abf6)
// ldxlcs/ldxlcs/game.htm
// 56063
// 32
// 3c19abf6
// 2017-09-10 13:25:04
// 2
// 51
// 7049
// 200
// ……

$entriesNo = rar_list($archNo);
foreach ($entriesNo as $en) {
    echo $en->getName(), PHP_EOL;
}

直接使用的是 RarArchive 对象的 getEntries() 方法,我们通过这个方法可以获得一个 RarEntry 对象的数组,里面包含的就是这个 rar 压缩包里面的全部内容。在这段代码中,我们还打印了 RarEntry 对象的其它一些属性方法,根据名称也能大概了解这些方法都是获取关于文件的各种信息的,大家可以自行测试。

异常处理

最后,如果打开错了文件或者获取压缩包内部没有的文件时,php-rar 扩展会以 PHP 错误的形式报错。但既然提供了完整的面向对象写法,那么它也必然提供了一套面向对象的异常处理机制。

// 不打开 UsingExceptions 全部错误会走 PHP 错误机制,打开后走 PHP 的异常机制
RarException::setUsingExceptions(true);
var_dump(RarException::isUsingExceptions()); // bool(true)
try {
    $arch = RarArchive::open("test1.rar");
    $arch->getEntry('ttt.txt');
} catch (RarException $e) {
    var_dump($e);
    // object(RarException)#35 (7) {
    //     ["message":protected]=>
    //     string(91) "unRAR internal error: Failed to open /data/www/blog/test1.rar: ERAR_EOPEN (file open error)"
    //     ["string":"Exception":private]=>
    //     string(0) ""
    //     ["code":protected]=>
    //     int(15)
    //     ["file":protected]=>
    //     string(22) "/data/www/blog/rar.php"
    //     ["line":protected]=>
    //     int(93)
    //     ["trace":"Exception":private]=>
    //     array(1) {
    //       [0]=>
    //       array(6) {
    //         ["file"]=>
    //         string(22) "/data/www/blog/rar.php"
    //         ["line"]=>
    //         int(93)
    //         ["function"]=>
    //         string(4) "open"
    //         ["class"]=>
    //         string(10) "RarArchive"
    //         ["type"]=>
    //         string(2) "::"
    //         ["args"]=>
    //         array(1) {
    //           [0]=>
    //           string(9) "test1.rar"
    //         }
    //       }
    //     }
    //     ["previous":"Exception":private]=>
    //     NULL
    //   }
}

只要将 RarException::setUsingExceptions() 设置为 true ,就能够开启 php-rar 扩展的异常处理机制,这时,我们打开一个错误的文件,或者去获取压缩包内的一个错误文件路径,那么,错误信息就会以异常的形式进行抛出。

总结

这套扩展是不是感觉很人性化?即提供了面向对象的方式,也提供了以函数操作为主的面向过程的方式。但是,这样做其实并没有太多的好处,因为又要兼顾老代码,又要兼顾新思想,本身扩展的内部实现相必也会复杂很多。我们自己写代码的时候就尽量不要这么写了,在重构的时候一步步的向最新的形式迁移即可。

关于 rar 的压缩操作并没有找到太多有用的资料。当然,我们在生产环境中如果要生成压缩包的话大部分情况下都会直接去生成 zip 格式的提供给用户,毕竟大部分的客户端软件都是能够同时支持 rar 和 zip 格式文件的解压的,如果一定要指定生成 rar 的话,也可以多多和产品经理或者客户商量。有的时候,技术的难点是可以通过业务的变通来解决的,最重要的其实还是在于沟通。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/PHP%E7%9A%84rar%E8%A7%A3%E5%8E%8B%E8%AF%BB%E5%8F%96%E6%89%A9%E5%B1%95%E5%8C%85%E5%AD%A6%E4%B9%A0.php

参考文档:
https://www.php.net/manual/zh/book.rar.php

以上就是PHP的rar解压读取扩展包学习的详细内容,更多关于PHP rar解压读取的资料请关注三水点靠木其它相关文章!

PHP 相关文章推荐
PHP 和 MySQL 开发的 8 个技巧
Oct 09 PHP
PHP+MYSQL的文章管理系统(二)
Oct 09 PHP
一个简单的PHP&MYSQL留言板源码
Jul 19 PHP
PHP执行批量mysql语句的解决方法
May 02 PHP
基于PHP开发中的安全防范知识详解
Jun 06 PHP
CodeIgniter表单验证方法实例详解
Mar 03 PHP
php 防止表单重复提交两种实现方法
Nov 03 PHP
php实现留言板功能(会话控制)
May 23 PHP
php递归函数怎么用才有效
Feb 24 PHP
php两点地理坐标距离的计算方法
Dec 29 PHP
ThinkPHP框架实现的微信支付接口开发完整示例
Apr 10 PHP
php curl操作API接口类完整示例
May 21 PHP
详解Laravel制作API接口
May 31 #PHP
浅谈PHP7中的一些小技巧
May 29 #PHP
详解Laravel服务容器的优势
May 29 #PHP
如何用RabbitMQ和Swoole实现一个异步任务系统
浅谈Laravel中使用Slack进行异常通知
May 29 #PHP
详解Go与PHP的语法对比
May 29 #PHP
详解php中流行的rpc框架
You might like
使用Xdebug调试和优化PHP程序之[1]
2007/04/17 PHP
php5中类的学习
2008/03/28 PHP
php echo, print, print_r, sprintf, var_dump, var_expor的使用区别
2013/06/20 PHP
php实现websocket实时消息推送
2018/03/30 PHP
PHP单元测试配置与使用方法详解
2019/12/27 PHP
jscript之Read an Excel Spreadsheet
2007/06/13 Javascript
niceTitle 基于jquery的超链接提示插件
2010/05/31 Javascript
Jquery 点击按钮显示和隐藏层的代码
2011/07/25 Javascript
修复IE9&safari 的sort方法
2011/10/21 Javascript
jQuery-Easyui 1.2 实现多层菜单效果的代码
2012/01/13 Javascript
基于jQuery实现左右div自适应高度完全相同的代码
2012/08/09 Javascript
angular中实现控制器之间传递参数的方式
2017/04/24 Javascript
layer弹窗插件操作方法详解
2017/05/19 Javascript
Angular学习教程之RouterLink花式跳转
2018/05/03 Javascript
Jquery和CSS实现选择框重置按钮功能
2018/11/08 jQuery
vue 内置过滤器的使用总结(附加自定义过滤器)
2018/12/11 Javascript
js屏蔽退格键(backspace或者叫后退键与F5)
2019/02/10 Javascript
对vue中的事件穿透与禁止穿透实例详解
2019/10/28 Javascript
Vue 一键清空表单的实现方法
2020/02/07 Javascript
通过高德地图API获得某条道路上的所有坐标用于描绘道路的方法
2020/08/24 Javascript
Python使用turtule画五角星的方法
2015/07/09 Python
python+mongodb数据抓取详细介绍
2017/10/25 Python
Python实现图片滑动式验证识别方法
2017/11/09 Python
Django框架多表查询实例分析
2018/07/04 Python
Python之字典对象的几种创建方法
2020/09/30 Python
html5应用缓存_动力节点Java学院整理
2017/07/13 HTML / CSS
HTML5实现WebSocket协议原理浅析
2014/07/07 HTML / CSS
详解移动端h5页面根据屏幕适配的四种方案
2020/04/15 HTML / CSS
俄罗斯马克西多姆家居用品网上商店:Максидом
2020/02/06 全球购物
数组越界问题
2015/10/21 面试题
酒吧创业计划书
2014/01/18 职场文书
教师求职信范文
2014/05/24 职场文书
高校师德师风自我剖析材料
2014/09/29 职场文书
大学生见习报告范文
2014/11/03 职场文书
2015年语言文字工作总结
2015/07/23 职场文书
Windows 11要来了?微软文档揭示Win11太阳谷 / Win10有两个不同版本
2021/11/21 数码科技