PHP处理文件压缩和解压主要依赖ZipArchive类操作ZIP格式,支持递归遍历目录并保留结构,可通过路径计算和排除模式过滤文件;同时提供GZIP、BZ2等函数处理字符串或文件流的压缩,适用于不同场景如传输优化或归档;性能上需关注内存与执行时间限制,合理设置压缩级别,并通过检查返回值、权限等方式进行错误处理。

PHP处理文件压缩和解压,主要依赖内置的
ZipArchive
ZipArchive是PHP处理ZIP文件的核心,它能让你像操作文件系统一样,把文件或目录打包成一个ZIP文件,或者将ZIP文件里的内容解压出来。
<?php
// --- 文件压缩示例 ---
function compressFilesToZip(array $filesToCompress, string $outputZipPath, string $baseDir = '') {
$zip = new ZipArchive();
if ($zip->open($outputZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) {
foreach ($filesToCompress as $filePath) {
// 确保文件存在且可读
if (!file_exists($filePath) || !is_readable($filePath)) {
error_log("Warning: File not found or not readable: " . $filePath);
continue;
}
// 计算在ZIP文件中的路径
// 如果提供了baseDir,则相对baseDir计算路径
$inZipPath = $filePath;
if (!empty($baseDir) && strpos($filePath, $baseDir) === 0) {
$inZipPath = ltrim(substr($filePath, strlen($baseDir)), '/\');
} else {
// 否则直接使用文件名或完整路径
$inZipPath = basename($filePath);
}
if ($zip->addFile($filePath, $inZipPath)) {
echo "Added '{$filePath}' as '{$inZipPath}' to zip.
";
} else {
error_log("Error adding file '{$filePath}' to zip.");
}
}
$zip->close();
echo "Files compressed successfully to '{$outputZipPath}'
";
return true;
} else {
error_log("Error: Could not create zip archive at '{$outputZipPath}'");
return false;
}
}
// --- 文件解压示例 ---
function decompressZipFile(string $zipFilePath, string $extractPath) {
$zip = new ZipArchive();
if ($zip->open($zipFilePath) === TRUE) {
// 确保解压目录存在且可写
if (!is_dir($extractPath)) {
mkdir($extractPath, 0777, true); // 递归创建目录
}
if (!is_writable($extractPath)) {
error_log("Error: Extraction path '{$extractPath}' is not writable.");
$zip->close();
return false;
}
if ($zip->extractTo($extractPath)) {
echo "Files extracted successfully to '{$extractPath}'
";
$zip->close();
return true;
} else {
error_log("Error: Could not extract files from '{$zipFilePath}' to '{$extractPath}'");
$zip->close();
return false;
}
} else {
error_log("Error: Could not open zip archive at '{$zipFilePath}'");
return false;
}
}
// 示例用法:
// 创建一些测试文件
file_put_contents('test_file1.txt', 'This is content for file 1.');
file_put_contents('test_file2.log', 'Log entry 1
Log entry 2.');
mkdir('sub_dir', 0777, true);
file_put_contents('sub_dir/test_file3.txt', 'This is content for file 3 in a subdirectory.');
$filesToZip = [
'test_file1.txt',
'test_file2.log',
'sub_dir/test_file3.txt'
];
$outputZip = 'my_archive.zip';
$extractDir = 'extracted_files';
// 压缩
compressFilesToZip($filesToZip, $outputZip);
// 解压
if (file_exists($outputZip)) {
decompressZipFile($outputZip, $extractDir);
}
// 清理测试文件
unlink('test_file1.txt');
unlink('test_file2.log');
unlink('sub_dir/test_file3.txt');
rmdir('sub_dir');
if (file_exists($outputZip)) {
unlink($outputZip);
}
// 递归删除解压目录
if (is_dir($extractDir)) {
array_map('unlink', glob("$extractDir/*.*"));
rmdir($extractDir);
}
?>在PHP中使用
ZipArchive
最直接的方式是利用
ZipArchive::addFile()
/var/www/html/project/data/image.jpg
data/image.jpg
addFile()
立即学习“PHP免费学习笔记(深入)”;
对于整个目录的递归压缩,通常会结合
RecursiveIteratorIterator
RecursiveDirectoryIterator
一个简单的实现思路是:
$zip->addFile($realPath, $relativePathInZip);
$zip->addEmptyDir($relativePathInZip);
addFile
.git
node_modules
.env
.log
<?php
// 假设这是你的项目根目录
$sourceDir = '/path/to/your/project';
$outputZip = 'project_backup.zip';
// 要排除的文件或目录模式
$excludePatterns = [
'/.git/',
'/node_modules/',
'/.env',
'/*.log',
'/vendor/', // 排除composer依赖
'/cache/', // 排除缓存目录
];
$zip = new ZipArchive();
if ($zip->open($outputZip, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) {
// 确保sourceDir存在
if (!is_dir($sourceDir)) {
echo "Source directory does not exist: {$sourceDir}
";
$zip->close();
exit;
}
// 规范化sourceDir,确保以斜杠结尾
$sourceDir = rtrim($sourceDir, '/\') . DIRECTORY_SEPARATOR;
$len = strlen($sourceDir);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($files as $file) {
$realPath = $file->getRealPath();
$relativePath = substr($realPath, $len); // 获取文件相对于sourceDir的路径
// 检查是否需要排除
$skip = false;
foreach ($excludePatterns as $pattern) {
if (preg_match($pattern, $relativePath)) {
$skip = true;
break;
}
}
if ($skip) {
echo "Skipping excluded item: {$relativePath}
";
continue;
}
if ($file->isDir()) {
// 如果是目录,且不是根目录本身,则添加空目录
if ($relativePath !== '') {
$zip->addEmptyDir($relativePath);
echo "Added empty directory: {$relativePath}
";
}
} else if ($file->isFile()) {
$zip->addFile($realPath, $relativePath);
echo "Added file: {$relativePath}
";
}
}
$zip->close();
echo "Project compressed successfully to '{$outputZip}'
";
} else {
echo "Error: Could not create zip archive.
";
}
?>上面的代码片段展示了如何递归遍历目录并根据模式排除文件或目录。这种方式灵活且强大,能够满足大部分复杂的压缩需求。
PHP除了对ZIP格式有强大的支持(通过
ZipArchive
我个人在处理一些API响应或者需要快速压缩/解压小块数据时,会优先考虑GZIP或BZ2,因为它们操作起来更直接,不需要像
ZipArchive
GZIP (GNU Zip)
gzcompress()
gzuncompress()
gzencode()
gzdecode()
gzcompress
gzuncompress
gzencode
gzfile()
readgzfile()
gzopen()
gzread()
gzwrit()
<?php
$data = 'This is a string that will be compressed using GZIP. It can be quite long.';
// 使用 gzencode 压缩字符串 (更适合网络传输)
$compressed_gz = gzencode($data, 9); // 9 是最高压缩级别
echo "GZIP Compressed (gzencode): " . strlen($compressed_gz) . " bytes
";
$uncompressed_gz = gzdecode($compressed_gz);
echo "GZIP Uncompressed (gzdecode): " . $uncompressed_gz . "
";
// 使用 gzcompress 压缩字符串 (不带GZIP头尾)
$compressed_raw_gz = gzcompress($data, 9);
echo "Raw GZIP Compressed (gzcompress): " . strlen($compressed_raw_gz) . " bytes
";
$uncompressed_raw_gz = gzuncompress($compressed_raw_gz);
echo "Raw GZIP Uncompressed (gzuncompress): " . $uncompressed_raw_gz . "
";
// 写入GZIP文件并读取
$gz_file = 'test.txt.gz';
file_put_contents($gz_file, $compressed_gz); // 直接写入gzencode的结果
$read_data = implode('', gzfile($gz_file)); // gzfile直接读取GZIP文件并解压
echo "Read from GZIP file: " . $read_data . "
";
unlink($gz_file);
?>BZIP2
bzcompress()
bzdecompress()
bzopen()
bzread()
bzwrite()
bzclose()
<?php
$data = 'This is a string that will be compressed using BZIP2. It typically achieves better compression than GZIP but is slower.';
$compressed_bz2 = bzcompress($data, 9); // 9 是最高压缩级别
echo "BZIP2 Compressed: " . strlen($compressed_bz2) . " bytes
";
$uncompressed_bz2 = bzdecompress($compressed_bz2);
echo "BZIP2 Uncompressed: " . $uncompressed_bz2 . "
";
// 写入BZIP2文件并读取
$bz2_file = 'test.txt.bz2';
$fp = bzopen($bz2_file, 'w');
bzwrite($fp, $data);
bzclose($fp);
$fp = bzopen($bz2_file, 'r');
$read_data = '';
while (!feof($fp)) {
$read_data .= bzread($fp, 4096);
}
bzclose($fp);
echo "Read from BZIP2 file: " . $read_data . "
";
unlink($bz2_file);
?>TAR (Tape Archive) / TAR.GZ / TAR.BZ2
.tar.gz
.tar.bz2
PharData
gzcompress
Phar
PharData
Phar
ZipArchive
选择哪种格式,真的要看具体场景。如果是多文件打包且要保持目录结构,
ZipArchive
在处理文件压缩和解压时,尤其是在生产环境中,性能和错误处理是不可忽视的环节。我遇到过不少因为没有充分考虑这些而导致脚本超时、内存溢出甚至文件损坏的问题。
性能优化策略:
内存限制(memory_limit
ZipArchive
file_get_contents
memory_limit
ZipArchive
执行时间限制(max_execution_time
set_time_limit(0);
exec
选择合适的压缩级别
ZipArchive::setCompressionName()
ZipArchive::setCompressionIndex()
避免不必要的文件操作
错误处理策略:
检查函数返回值
ZipArchive
false
ZipArchive::open()
addFile()
extractTo()
close()
ZipArchive::open()
ZipArchive::getStatusString()
if ($zip->open($outputZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
// $zip->status 包含了错误码
error_log("Failed to open zip archive: " . $zip->getStatusString());
return false;
}文件权限检查
is_writable()
is_readable()
mkdir($path, 0777, true)
以上就是php怎么压缩和解压文件_php实现文件压缩和解压的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号