Table Of Contents

骑驴找蚂蚁

全干工程师

PHP不使用扩展及类库解压zip文件

在不使用扩展、类库的情况下,只用原生PHP来解压zip文件该如何实现呢,下面就通过一个简单的代码来实现这一功能.

文件头描述

在编写之前我们需要了解zip文件格式的头信息才能完成此功能.

OffsetBytes描述
04文件头标识,值固定(0x04034b50)
42解压文件所需 pkware最低 版本 
62通用位标记
82压缩方法
102文件最后修改时间
122文件最后修改日期
144说明采用的算法。
184压缩后的大小。
224非压缩的大小。
262文件名长度
282扩展区长度
30n文件名
30+nm扩展区

根据上面的头信息下面实现了一版非常简单的解压版本.

完整实现

<?php
function unzip_simple($zipFile, $destDir) {
    $fp = fopen($zipFile, 'rb');
    if (!$fp) return false;
    while (!feof($fp)) {
        $sig = fread($fp, 4);
        if ($sig === "\x50\x4b\x03\x04") { // 本地文件头
            $ver = fread($fp, 2);
            $flag = fread($fp, 2);
            $method = fread($fp, 2);
            $time = fread($fp, 2);
            $date = fread($fp, 2);
            $crc32 = fread($fp, 4);
            $comp_size = unpack('V', fread($fp, 4))[1];
            $uncomp_size = unpack('V', fread($fp, 4))[1];
            $name_len = unpack('v', fread($fp, 2))[1];
            $extra_len = unpack('v', fread($fp, 2))[1];
            $filename = fread($fp, $name_len);
            fseek($fp, $extra_len, SEEK_CUR);
            // 只支持存储模式(无压缩)
            if (unpack('v', $method)[1] == 0) {
                $data = fread($fp, $uncomp_size);
                $outPath = rtrim($destDir, '/').'/'.$filename;
                if (!is_dir(dirname($outPath))) {
                    mkdir(dirname($outPath), 0777, true);
                }
                echo "提取出文件:",$filename, "\n";
                file_put_contents($outPath, $data);
            } else {
                // 跳过压缩文件
                fseek($fp, $comp_size, SEEK_CUR);
            }
        } else {
            break;
        }
    }
    fclose($fp);
}
unzip_simple(__DIR__ . '/example.zip', __DIR__);

上述的代码未实现压缩算法的解压只支持存储模式.

# 生成一个不压缩的zip文件, 将上面的代码保存在`unzip.php`中.
[#] zip example.zip 1.txt 2.txt 3.txt -0   
[#] rm 1.txt 2.txt 3.txt
# 解压文件
[#] php unzip.php
提取出文件:1.txt
提取出文件:2.txt
提取出文件:3.txt

此代码只是为学习zip文件的格式解析,不适合在生产环境中使用。线上环境建议使用扩展形式来处理zip文件。

$zip = new ZipArchive();
if ($zip->open('example.zip') === TRUE) {
    $zip->extractTo('output_dir'); // 解压到 output_dir 目录
    $zip->close();
    echo '解压成功';
} else {
    echo '解压失败';
}

说明:ZipArchive 是 PHP 内置扩展,支持绝大多数 ZIP 文件的解压和压缩。 output_dir目录需提前存在或确保有写权限。

留言