專案遷移或框架升級時,常需批次修改特定目錄下所有檔案的路徑、域名、版本號等字串。本文提供一個可直接用於生產環境的完整解決方案,包含:
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();
processFile 中加入 mb_detect_encoding 並 iconv 轉碼後再替換,寫入時再轉回原編碼。str_replace 改為 preg_replace 陣列版本,支援更複雜的模式匹配。backup/ 目錄,支援一鍵回滾。pcntl_fork 或 parallel 擴展,針對大量檔案加速處理。\ 需雙重跳脫或使用 DIRECTORY_SEPARATOR 常數