PHP操作ZIP文件

wen PHP项目 3

本文目录导读:

PHP操作ZIP文件

  1. 环境检查
  2. 基础操作
  3. 高级操作
  4. 实用工具函数
  5. 错误处理
  6. 流式上传处理
  7. 压缩方式设置

在PHP中操作ZIP文件,主要使用内置的 ZipArchive 类,以下是全面的操作指南:

环境检查

// 检查ZIP扩展是否可用
if (!extension_loaded('zip')) {
    echo "ZIP扩展未启用";
    exit;
}
// 查看ZipArchive版本
echo ZipArchive::LIBZIP_VERSION;  // 输出libzip版本

基础操作

创建ZIP文件

$zip = new ZipArchive();
$zipPath = 'my_archive.zip';
if ($zip->open($zipPath, ZipArchive::CREATE) === TRUE) {
    // 添加文件
    $zip->addFile('file.txt', 'file.txt');  // 添加现有文件
    $zip->addFile('path/to/file.jpg', 'images/photo.jpg');  // 添加并重命名
    // 添加空目录
    $zip->addEmptyDir('empty_folder');
    // 直接添加字符串内容(不创建物理文件)
    $zip->addFromString('readme.txt', "Hello world");
    // 关闭ZIP
    $zip->close();
    echo "ZIP文件创建成功";
} else {
    echo "无法创建ZIP文件";
}

解压ZIP文件

$zip = new ZipArchive();
if ($zip->open('my_archive.zip') === TRUE) {
    // 解压到目录
    $zip->extractTo('/destination/path/');
    // 只解压特定文件
    $zip->extractTo('/destination/path/', ['file.txt', 'images/photo.jpg']);
    $zip->close();
    echo "解压成功";
} else {
    echo "无法打开ZIP文件";
}

高级操作

遍历ZIP内容

$zip = new ZipArchive();
if ($zip->open('my_archive.zip') === TRUE) {
    for ($i = 0; $i < $zip->numFiles; $i++) {
        $fileInfo = $zip->statIndex($i);
        echo "文件名: " . $fileInfo['name'] . "<br>";
        echo "大小: " . $fileInfo['size'] . " bytes<br>";
        echo "压缩方式: " . $fileInfo['comp_method'] . "<br>";
        echo "压缩后大小: " . $fileInfo['comp_size'] . " bytes<br>";
        echo "时间戳: " . date('Y-m-d H:i:s', $fileInfo['mtime']) . "<br>";
        echo "---<br>";
    }
    $zip->close();
}
$zip = new ZipArchive();
if ($zip->open('my_archive.zip') === TRUE) {
    // 获取文件内容
    $content = $zip->getFromName('readme.txt');
    // 通过索引获取内容
    $content2 = $zip->getFromIndex(0);
    // 流式读取大文件(节省内存)
    $fp = $zip->getStream('large_file.bin');
    if ($fp) {
        while (!feof($fp)) {
            $chunk = fread($fp, 8192); // 8KB chunks
            // 处理数据
        }
        fclose($fp);
    }
    $zip->close();
}

删除和重命名

$zip = new ZipArchive();
if ($zip->open('my_archive.zip') === TRUE) {
    // 删除文件
    $zip->deleteName('file.txt');
    // 通过索引删除
    $zip->deleteIndex(0);
    // 重命名文件
    $zip->renameName('old.txt', 'new.txt');
    // 重命名目录
    $zip->renameName('old_folder', 'new_folder');
    $zip->close();
}

实用工具函数

完整目录压缩

function zipDirectory($sourceDir, $zipFile) {
    // 递归删除前先检查目录
    if (!is_dir($sourceDir)) {
        return false;
    }
    $zip = new ZipArchive();
    if ($zip->open($zipFile, ZipArchive::CREATE) !== TRUE) {
        return false;
    }
    // 递归添加目录的方法
    $dir = rtrim($sourceDir, '/');
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );
    foreach ($iterator as $file) {
        $filePath = $file->getPathname();
        $relativePath = substr($filePath, strlen($dir) + 1);
        if ($file->isDir()) {
            $zip->addEmptyDir($relativePath);
        } else {
            $zip->addFile($filePath, $relativePath);
        }
    }
    return $zip->close();
}
// 使用
zipDirectory('/path/to/source', '/path/to/output.zip');

带进度显示的解压

function extractWithProgress($zipFile, $destination) {
    $zip = new ZipArchive();
    if ($zip->open($zipFile) !== TRUE) {
        return false;
    }
    $totalFiles = $zip->numFiles;
    $processed = 0;
    for ($i = 0; $i < $totalFiles; $i++) {
        // 提取单个文件(保持目录结构)
        $zip->extractTo($destination, [$zip->getNameIndex($i)]);
        $processed++;
        $progress = ($processed / $totalFiles) * 100;
        echo sprintf("进度: %.1f%%\n", $progress);
        flush();
    }
    $zip->close();
    return true;
}

错误处理

try {
    $zip = new ZipArchive();
    // 使用异常处理
    if (@$zip->open('file.zip') !== TRUE) {
        throw new Exception('无法打开ZIP文件');
    }
    if (!$zip->addFile('non_existent.txt')) {
        throw new Exception('文件添加失败');
    }
    // 其他操作...
    if (!$zip->close()) {
        throw new Exception('ZIP关闭失败');
    }
} catch (Exception $e) {
    error_log('ZIP操作错误: ' . $e->getMessage());
    if (isset($zip)) {
        $zip->close(); // 确保关闭
    }
}

流式上传处理

// 处理上传的ZIP文件
if ($_FILES['zipfile']['error'] === UPLOAD_ERR_OK) {
    $tmpFile = $_FILES['zipfile']['tmp_name'];
    $zip = new ZipArchive();
    if ($zip->open($tmpFile) === TRUE) {
        // 安全解压(防止路径遍历攻击)
        $extractPath = '/safe/directory/';
        array_map(function($entry) use ($extractPath) {
            // 安全检查:防止 '../' 等路径
            if (strpos($entry, '..') !== false || strpos($entry, '/') === 0) {
                throw new Exception('不安全的文件路径');
            }
        }, array_column(range(0, $zip->numFiles - 1), 0));
        $zip->extractTo($extractPath);
        $zip->close();
    }
}

压缩方式设置

$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
// 设置压缩级别
$zip->setCompressionName('file.txt', ZipArchive::CM_DEFLATE, 9); // 最高压缩
// 对整个压缩包设置压缩
$zip->setArchiveComment('This is an archive comment');
$zip->setCompressionIndex(0, ZipArchive::CM_STORE); // 无压缩
// 添加加密文件(libzip >= 1.2.0)
$zip->setPassword('secret_password');
$zip->addFile('file.txt', 'encrypted.txt');
$zip->close();

这些操作覆盖了PHP处理ZIP文件的主要场景,在生产环境中,还需要注意:

  • 内存限制和上传大小限制
  • 文件权限和安全性检查
  • 大文件的流式处理
  • 编码问题(UTF-8文件名)

抱歉,评论功能暂时关闭!