
PHP不使用扩展及类库解压zip文件
在不使用扩展、类库的情况下,只用原生PHP
来解压zip
文件该如何实现呢,下面就通过一个简单的代码来实现这一功能.
文件头描述
在编写之前我们需要了解zip
文件格式的头信息才能完成此功能.
Offset | Bytes | 描述 |
---|---|---|
0 | 4 | 文件头标识,值固定(0x04034b50) |
4 | 2 | 解压文件所需 pkware最低 版本 |
6 | 2 | 通用位标记 |
8 | 2 | 压缩方法 |
10 | 2 | 文件最后修改时间 |
12 | 2 | 文件最后修改日期 |
14 | 4 | 说明采用的算法。 |
18 | 4 | 压缩后的大小。 |
22 | 4 | 非压缩的大小。 |
26 | 2 | 文件名长度 |
28 | 2 | 扩展区长度 |
30 | n | 文件名 |
30+n | m | 扩展区 |
根据上面的头信息下面实现了一版非常简单的解压版本.
完整实现
<?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
目录需提前存在或确保有写权限。