嗯,不同的项目,同样的问题,又找到了我自己的问题!这是我这次所做的(cp/rsync 并不总是可用):
// php xcopy, assumes /s /q /c /y /r switches
// /exclude switch via skipfiles and skipfolders (appended to in-built defaults)
// /u switch via $ifindest
public static function xcopy($source, $dest, $skipfiles = [], $skipfolders = [], $ifindest = false) {
// ensure source and destination end in one directory separator
$source = rtrim($source,DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
$dest = rtrim($dest,DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
// normalise skip arrays and apply defaults
$skipfolders = array_unique(array_merge(['.git','.ssh','editor'], array_map('rtrim', $skipfolders, array_fill(0, count($skipfolders), DIRECTORY_SEPARATOR))));
$skipfiles = array_unique(array_merge(['.ds_store','.htaccess','thumbs.db','about.txt','readme.md'], array_map('strtolower', $skipfiles)));
// examine folders and files using an iterator to avoid exposing functional recursion
foreach ($iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST) as $item) {
$name = strtolower($iterator->getFilename());
$path = $iterator->getSubPathName();
$folders = explode(DIRECTORY_SEPARATOR, empty($iterator->getSubPath()) ? $iterator->getSubPathName() : $iterator->getSubPath()); // subpath is empty at source root folder
$skip = count(array_intersect($folders,$skipfolders))>0;
// skip this iteration due to a folder match?
if ($skip) continue;
// skip this iteration due to a file match?
if ($item->isFile() && in_array($name, $skipfiles)) continue;
if ($item->isDir()) {
if (!file_exists("{$dest}{$path}")) {
// create destination folder structure
mkdir($dest.$path,0775,true);
}
} else {
if ($ifindest) {
if (!file_exists("{$dest}{$path}")) continue; // copy only if file exists in destination already
}
// finally we can copy the file
copy($path,$dest.$path);
}
}
}
这里有一些值得注意的漏洞,特别是没有异常处理,但这次它让我摆脱了麻烦。