部署發布、模板複製、備份同步等場景常需將整個目錄結構(含子目錄、文件)完整複製到新位置。PHP 原生無單一函數實現,需自行封裝遞歸邏輯。
copyFile($src, $dst) 入口;CreateFolder() 兼容深層路徑一次性創建;@mkdir 避免已存在時拋出警告。CreateFolder($toFile);
$handle = opendir($fromFile);
if (!$handle) return false;
while (($item = readdir($handle)) !== false) {
if ($item === '.' || $item === '..') continue;
$srcPath = $fromFile . DIRECTORY_SEPARATOR . $item;
$dstPath = $toFile . DIRECTORY_SEPARATOR . $item;
if (is_file($srcPath)) {
// 文件直接複製
if (!copy($srcPath, $dstPath)) {
closedir($handle);
return false;
}
} elseif (is_dir($srcPath)) {
// 目錄遞歸
if (!$this->copyFile($srcPath, $dstPath)) {
closedir($handle);
return false;
}
}
}
closedir($handle);
return true;
}
/** 遞歸創建多級目錄
* @param string $dir 目錄路徑
* @param int $mode 權限,默認 0777
* @return bool
*/
public function CreateFolder($dir, $mode = 0777) {
if (is_dir($dir) || @mkdir($dir, $mode, true)) {
return true;
}
// 理論上 mkdir($dir, $mode, true) 已支持遞歸創建(PHP 5.0.0+)
// 此處保留遞歸邏輯兼容極舊版本
return $this->CreateFolder(dirname($dir), $mode) && @mkdir($dir, $mode);
}
}
// 使用示例
$copier = new CopyFile();
$success = $copier->copyFile('/var/www/project_a', '/var/www/backup/project_a_20240115');
if ($success) {
echo "複製完成";
} else {
echo "複製失敗,請檢查權限或路徑";
}
DIRECTORY_SEPARATOR 跨平台兼容(Windows \,Linux /);mkdir($path, $mode, true) 第三參數 true 即為遞歸創建,PHP 5.0.0+ 內置支持,手動遞歸僅為教學或極舊環境;readlink() + symlink();exec('cp -r ...') 或 rsync 系統命令,性能更優;function($current, $total) 實現進度條。use RecursiveIteratorIterator;
use RecursiveDirectoryIterator;
use FilesystemIterator;
function copyDirSpl($src, $dst) {
$src = realpath($src);
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($src, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $item) {
$relative = substr($item->getPathname(), strlen($src) + 1);
$target = $dst . DIRECTORY_SEPARATOR . $relative;
if ($item->isDir()) {
@mkdir($target, 0777, true);
} else {
copy($item->getPathname(), $target);
}
}
}
SPL 迭代器代碼更簡潔、性能更好,推薦 PHP 5.3+ 環境使用。