当前位置: 首页> 最新文章列表> 如何利用php的zip_read函数结合scandir()函数,递归创建目标文件夹结构并实现文件解压?

如何利用php的zip_read函数结合scandir()函数,递归创建目标文件夹结构并实现文件解压?

M66 2025-06-15

在PHP中处理ZIP压缩文件时,zip_read() 函数可以帮助我们逐条读取压缩包内的内容。而配合 scandir() 函数进行递归文件夹操作,我们可以方便地在服务器端实现一个自动解压ZIP文件并保留其目录结构的功能。本文将详细介绍如何通过这两个函数构建这样的脚本。

一、环境准备

确保你的PHP环境已经开启了 zip 扩展。如果没有开启,可以通过编辑 php.ini 文件,找到如下配置行并取消注释:

extension=zip

然后重启你的Web服务器。

二、基本思路

  1. 打开ZIP文件;

  2. 遍历ZIP中的每一个条目;

  3. 判断条目是否为目录或文件;

  4. 使用 scandir() 结合自定义函数递归创建目录结构;

  5. 将ZIP中的文件写入目标路径。

三、代码实现

<?php

function createDirRecursive($path) {
    if (!is_dir($path)) {
        mkdir($path, 0777, true);
    }
}

function unzipWithStructure($zipFilePath, $destination) {
    $zip = zip_open($zipFilePath);

    if (is_resource($zip)) {
        while ($zip_entry = zip_read($zip)) {
            $entryName = zip_entry_name($zip_entry);
            $fullPath = $destination . '/' . $entryName;

            // 如果是目录,则创建
            if (substr($entryName, -1) === '/') {
                createDirRecursive($fullPath);
            } else {
                // 确保文件所在目录存在
                $dirPath = dirname($fullPath);
                createDirRecursive($dirPath);

                if (zip_entry_open($zip, $zip_entry)) {
                    $fileContent = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
                    file_put_contents($fullPath, $fileContent);
                    zip_entry_close($zip_entry);
                }
            }
        }
        zip_close($zip);
    } else {
        echo "无法打开ZIP文件: $zipFilePath";
    }
}

// 使用示例
$zipPath = '/var/www/html/uploads/sample.zip';
$extractTo = '/var/www/html/extracted';

// 调用函数进行解压
unzipWithStructure($zipPath, $extractTo);
?>

四、目录遍历与验证

使用 scandir() 可进一步验证目标目录结构是否被正确创建。例如:

function listAllFiles($dir) {
    $files = scandir($dir);
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        $path = $dir . '/' . $file;
        if (is_dir($path)) {
            echo "目录: $path\n";
            listAllFiles($path);
        } else {
            echo "文件: $path\n";
        }
    }
}

listAllFiles('/var/www/html/extracted');

执行上述代码后,可以输出所有被解压出来的文件和文件夹,方便调试和验证。

五、注意事项

  • 所有路径应使用绝对路径以避免权限或路径错误;

  • 在生产环境中,应注意ZIP文件的来源,防止目录穿越攻击(例如 ZIP 中含有 ../../);

  • 可结合 realpath() 对路径进行规范化处理;

  • 如果文件较大,建议使用流式读取方式处理,防止内存溢出。

六、应用场景

这个脚本适用于上传压缩文件并自动解压的功能,如用户上传一个包含多层目录结构的ZIP文件到 m66.net/upload,后台可直接通过以上脚本在 m66.net/storage 目录下还原完整结构,并进一步处理内容,如生成缩略图、扫描病毒或做备份。

通过这种方式,可以极大简化内容上传及文件初始化的工作流程,提高开发效率。