首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 遞歸實現無限級目錄完整復制 (保留結構與權限)

     編輯:PHP 相關知識

需求背景

項目部署、備份、模板複製等場景常需完整復制目錄樹 (包含子目錄、文件、權限)。PHP 無內置一鍵復制目錄函數,需自行實現遞歸遍歷。

核心類實現

<?php
class CopyPath {
    // 遞歸復制目錄
    function wm_chief_copypath($o_path, $n_path) {
        $handle = opendir($o_path);
        if (!file_exists($n_path)) {
            $this->wm_chief_createpath($n_path); // 創建目標目錄
        }
        $i = 0;
        while ($file = readdir($handle)) {
            $i++;
            if ($i == 1 || $i == 2) continue; // 跳過 . 和 ..
            
            $o_item = $o_path . "/" . $file;
            $n_item = $n_path . "/" . $file;
            
            if (is_dir($o_item)) { // 判斷是否目錄 (原代碼 strchr 判斷有無 '.' 有缺陷)
                $this->wm_chief_copypath($o_item, $n_item); // 遞歸
            } else {
                $this->wm_chief_copyfile($o_item, $n_item); // 復制文件
            }
        }
        closedir($handle);
        return true;
    }

    function wm_chief_copyfile($o_file, $n_file) {
        return copy($o_file, $n_file); // 可增強:檢查返回值、保留權限 chmod
    }

    function wm_chief_createpath($n_path) {
        return mkdir($n_path, 0777, true); // 遞歸創建,權限受 umask 影響
    }
}

// 使用示例
$wm_chief = new CopyPath();
$ok = $wm_chief->wm_chief_copypath("admin", "n_admin");
if ($ok) echo "復制完畢";
?>

代碼改進點 (關鍵)

  • 目錄判斷:原代碼 !(strchr($file, ".")) 錯誤地以“文件名含點”區分文件/目錄。**正確用 is_dir()**。
  • 錯誤處理:應檢查 opendir, mkdir, copy 返回值,拋出異常或記錄日誌。
  • 權限保留:復制後可用 chmod($n_file, fileperms($o_file) & 0777) 保留原權限。
  • 符號鏈接:copy() 會複製鏈接指向的文件內容,若需保留鏈接需用 readlink() + symlink()。
  • 大文件/深目錄:遞歸可能導致棧溢出,極深目錄建議用迭代器 (RecursiveIteratorIterator)。

現代標準庫寫法 (PHP 5.3+)

function copy_dir_recursive(string $src, string $dst): bool {
    $dir = new RecursiveDirectoryIterator($src, RecursiveDirectoryIterator::SKIP_DOTS);
    $iter = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST);
    foreach ($iter as $item) {
        $target = $dst . DIRECTORY_SEPARATOR . $iter->getSubPathName();
        if ($item->isDir()) {
            if (!file_exists($target)) mkdir($target, 0777, true);
        } else {
            copy($item->getPathname(), $target);
        }
    }
    return true;
}

推薦使用成熟庫 (如 Symfony Filesystem, Laravel File) 處理邊界情況。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved