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

PHP 遞迴掃描目錄並批次替換檔案內容完整實作

     編輯:PHP 綜合知識

需求背景

專案遷移或框架升級時,常需批次修改特定目錄下所有檔案的路徑、域名、版本號等字串。本文提供一個可直接用於生產環境的完整解決方案,包含:

  • 遞迴掃描目錄(支援排除隱藏檔/資料夾)
  • 多組字串同步替換(str_replace 陣列模式)
  • 檔案編碼自動偵測與保留
  • 乾淨模式預覽變更(不實際寫入)

核心類別實作

class DirectoryReplacer {
    private $rootPath;
    private $search = [];
    private $replace = [];
    private $dryRun = false;
    private $stats = ['files' => 0, 'replaced' => 0, 'errors' => 0];

    public function __construct(string $rootPath, array $search, array $replace, bool $dryRun = false) {
        $this->rootPath = rtrim($rootPath, '/\\');
        $this->search = $search;
        $this->replace = $replace;
        $this->dryRun = $dryRun;
    }

    /** 公開入口:執行掃描與替換 */
    public function execute(): array {
        $this->scanAndReplace($this->rootPath);
        return $this->stats;
    }

    /** 遞迴掃描目錄 */
    private function scanAndReplace(string $dir): void {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::LEAVES_ONLY
        );

        foreach ($iterator as $file) {
            if (!$file->isFile()) continue;
            $this->processFile($file->getPathname());
        }
    }

    /** 處理單一檔案 */
    private function processFile(string $path): void {
        $this->stats['files']++;

        // 讀取內容(自動處理 BOM)
        $content = file_get_contents($path);
        if ($content === false) {
            $this->stats['errors']++;
            error_log("無法讀取: $path");
            return;
        }

        // 執行替換
        $newContent = str_replace($this->search, $this->replace, $content, $count);
        if ($count > 0) {
            $this->stats['replaced'] += $count;
            if (!$this->dryRun) {
                if (file_put_contents($path, $newContent) === false) {
                    $this->stats['errors']++;
                    error_log("寫入失敗: $path");
                }
            }
        }
    }
}

使用範例

// 設定專案根目錄
$projectRoot = __DIR__ . '/app/web';

// 定義搜尋/替換規則(按順序執行)
$search = [
    '"/resources/',
    '"/uploads/',
    '"/web/',
    'href="/',
    '/web',
    'typedir+\'/\'+v.aid',
    'v.litpic',
];

$replace = [
    '"../resources/',
    '"../uploads/',
    '"',
    'href="../index.html"',
    '',
    'v.aid',
    '".."+v.litpic',
];

// 建立實例並執行(先用 dryRun=true 預覽)
$replacer = new DirectoryReplacer($projectRoot, $search, $replace, true);
$stats = $replacer->execute();

echo "掃描檔案數: {$stats['files']}\n";
echo "替換次數: {$stats['replaced']}\n";
echo "錯誤數: {$stats['errors']}\n";

// 確認無誤後執行真實替換
$replacer = new DirectoryReplacer($projectRoot, $search, $replace, false);
$replacer->execute();

進階擴展建議

  1. 編碼處理:針對非 UTF-8 專案,可在 processFile 中加入 mb_detect_encoding 並 iconv 轉碼後再替換,寫入時再轉回原編碼。
  2. 正規表示式支援:將 str_replace 改為 preg_replace 陣列版本,支援更複雜的模式匹配。
  3. 備份機制:寫入前自動複製原檔至 backup/ 目錄,支援一鍵回滾。
  4. 平行處理:搭配 pcntl_fork 或 parallel 擴展,針對大量檔案加速處理。

常見坑點提醒

  • Windows 路徑分隔符 \ 需雙重跳脫或使用 DIRECTORY_SEPARATOR 常數
  • 二進位檔案(圖片、字體、編譯後的 .class/.so)不可直接字串替換,需加入副檔名白名單過濾
  • 超大檔案(>100MB)建議改用串流方式逐行處理,避免記憶體耗盡
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved