使用 php 将目录的全部内容复制到另一个目录

我试图将目录的全部内容复制到另一个位置

copy ("old_location/*.*","new_location/");

但它说它找不到流,真正的 *.*是找不到的。

任何其他方式

谢谢 戴夫

197191 次浏览

对于一个包含多级目录的文件夹,我使用以下代码:

function recurseCopy(
string $sourceDirectory,
string $destinationDirectory,
string $childFolder = ''
): void {
$directory = opendir($sourceDirectory);


if (is_dir($destinationDirectory) === false) {
mkdir($destinationDirectory);
}


if ($childFolder !== '') {
if (is_dir("$destinationDirectory/$childFolder") === false) {
mkdir("$destinationDirectory/$childFolder");
}


while (($file = readdir($directory)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}


if (is_dir("$sourceDirectory/$file") === true) {
recurseCopy("$sourceDirectory/$file", "$destinationDirectory/$childFolder/$file");
} else {
copy("$sourceDirectory/$file", "$destinationDirectory/$childFolder/$file");
}
}


closedir($directory);


return;
}


while (($file = readdir($directory)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}


if (is_dir("$sourceDirectory/$file") === true) {
recurseCopy("$sourceDirectory/$file", "$destinationDirectory/$file");
}
else {
copy("$sourceDirectory/$file", "$destinationDirectory/$file");
}
}


closedir($directory);
}

Copy ()只能处理文件。

DOS copy 和 Unix cp 命令都会递归地进行复制——所以最快的解决方案就是使用 shell。例如:。

`cp -r $src $dest`;

否则,您将需要使用 opendir/readdirscandir来读取目录的内容,迭代结果,如果 is _ dir 对每个目录返回 true,则递归到其中。

例如:。

function xcopy($src, $dest) {
foreach (scandir($src) as $file) {
if (!is_readable($src . '/' . $file)) continue;
if (is_dir($src .'/' . $file) && ($file != '.') && ($file != '..') ) {
mkdir($dest . '/' . $file);
xcopy($src . '/' . $file, $dest . '/' . $file);
} else {
copy($src . '/' . $file, $dest . '/' . $file);
}
}
}

正如其他地方所说,copy只能处理源文件,而不能处理模式。如果要按模式进行复制,请使用 glob确定文件,然后运行复制。但是这不会复制子目录,也不会创建目标目录。

function copyToDir($pattern, $dir)
{
foreach (glob($pattern) as $file) {
if(!is_dir($file) && is_readable($file)) {
$dest = realpath($dir . DIRECTORY_SEPARATOR) . basename($file);
copy($file, $dest);
}
}
}
copyToDir('./test/foo/*.txt', './test/bar'); // copies all txt files

最好的解决办法就是!

<?php
$src = "/home/www/domain-name.com/source/folders/123456";
$dest = "/home/www/domain-name.com/test/123456";


shell_exec("cp -r $src $dest");


echo "<H3>Copy Paste completed!</H3>"; //output when done
?>
function full_copy( $source, $target ) {
if ( is_dir( $source ) ) {
@mkdir( $target );
$d = dir( $source );
while ( FALSE !== ( $entry = $d->read() ) ) {
if ( $entry == '.' || $entry == '..' ) {
continue;
}
$Entry = $source . '/' . $entry;
if ( is_dir( $Entry ) ) {
full_copy( $Entry, $target . '/' . $entry );
continue;
}
copy( $Entry, $target . '/' . $entry );
}


$d->close();
}else {
copy( $source, $target );
}
}

我修剪过的@Kzoty 回答。 谢谢你 Kzoty。

用法

Helper::copy($sourcePath, $targetPath);


class Helper {


static function copy($source, $target) {
if (!is_dir($source)) {//it is a file, do a normal copy
copy($source, $target);
return;
}


//it is a folder, copy its files & sub-folders
@mkdir($target);
$d = dir($source);
$navFolders = array('.', '..');
while (false !== ($fileEntry=$d->read() )) {//copy one by one
//skip if it is navigation folder . or ..
if (in_array($fileEntry, $navFolders) ) {
continue;
}


//do copy
$s = "$source/$fileEntry";
$t = "$target/$fileEntry";
self::copy($s, $t);
}
$d->close();
}


}

作为 这里描述的,这是另一种处理符号链接的方法:

/**
* Copy a file, or recursively copy a folder and its contents
* @author      Aidan Lister <aidan@php.net>
* @version     1.0.1
* @link        http://aidanlister.com/2004/04/recursively-copying-directories-in-php/
* @param       string   $source    Source path
* @param       string   $dest      Destination path
* @param       int      $permissions New folder creation permissions
* @return      bool     Returns true on success, false on failure
*/
function xcopy($source, $dest, $permissions = 0755)
{
$sourceHash = hashDirectory($source);
// Check for symlinks
if (is_link($source)) {
return symlink(readlink($source), $dest);
}


// Simple copy for a file
if (is_file($source)) {
return copy($source, $dest);
}


// Make destination directory
if (!is_dir($dest)) {
mkdir($dest, $permissions);
}


// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}


// Deep copy directories
if($sourceHash != hashDirectory($source."/".$entry)){
xcopy("$source/$entry", "$dest/$entry", $permissions);
}
}


// Clean up
$dir->close();
return true;
}


// In case of coping a directory inside itself, there is a need to hash check the directory otherwise and infinite loop of coping is generated


function hashDirectory($directory){
if (! is_dir($directory)){ return false; }


$files = array();
$dir = dir($directory);


while (false !== ($file = $dir->read())){
if ($file != '.' and $file != '..') {
if (is_dir($directory . '/' . $file)) { $files[] = hashDirectory($directory . '/' . $file); }
else { $files[] = md5_file($directory . '/' . $file); }
}
}


$dir->close();


return md5(implode('', $files));
}

非常感谢 Felix Kling 的精彩回答,我很感激他在我的代码中使用了这个回答。我提供了一个布尔返回值的小增强,用于报告成功或失败:

function recurse_copy($src, $dst) {


$dir = opendir($src);
$result = ($dir === false ? false : true);


if ($result !== false) {
$result = @mkdir($dst);


if ($result === true) {
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' ) && $result) {
if ( is_dir($src . '/' . $file) ) {
$result = recurse_copy($src . '/' . $file,$dst . '/' . $file);
}     else {
$result = copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
}


return $result;
}
<?php
function copy_directory( $source, $destination ) {
if ( is_dir( $source ) ) {
@mkdir( $destination );
$directory = dir( $source );
while ( FALSE !== ( $readdirectory = $directory->read() ) ) {
if ( $readdirectory == '.' || $readdirectory == '..' ) {
continue;
}
$PathDir = $source . '/' . $readdirectory;
if ( is_dir( $PathDir ) ) {
copy_directory( $PathDir, $destination . '/' . $readdirectory );
continue;
}
copy( $PathDir, $destination . '/' . $readdirectory );
}


$directory->close();
}else {
copy( $source, $destination );
}
}
?>

从最后一行开始,做这个

$source = 'wordpress';//i.e. your source path

还有

$destination ='b';

我通过 SPL 目录迭代器克隆了整个目录。

function recursiveCopy($source, $destination)
{
if (!file_exists($destination)) {
mkdir($destination);
}


$splFileInfoArr = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);


foreach ($splFileInfoArr as $fullPath => $splFileinfo) {
//skip . ..
if (in_array($splFileinfo->getBasename(), [".", ".."])) {
continue;
}
//get relative path of source file or folder
$path = str_replace($source, "", $splFileinfo->getPathname());


if ($splFileinfo->isDir()) {
mkdir($destination . "/" . $path);
} else {
copy($fullPath, $destination . "/" . $path);
}
}
}
#calling the function
recursiveCopy(__DIR__ . "/source", __DIR__ . "/destination");
// using exec


function rCopy($directory, $destination)
{


$command = sprintf('cp -r %s/* %s', $directory, $destination);


exec($command);


}

使用 Symfony,这是非常容易实现的:

$fileSystem = new Symfony\Component\Filesystem\Filesystem();
$fileSystem->mirror($from, $to);

参见 https://symfony.com/doc/current/components/filesystem.html

对于 Linux 服务器,您只需要一行代码就可以在保留权限的同时递归地进行复制:

exec('cp -a '.$source.' '.$dest);

另一种方法是:

mkdir($dest);
foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item)
{
if ($item->isDir())
mkdir($dest.DIRECTORY_SEPARATOR.$iterator->getSubPathName());
else
copy($item, $dest.DIRECTORY_SEPARATOR.$iterator->getSubPathName());
}

但是速度较慢,而且不能保留权限。

我也有过类似的情况,我需要在同一台服务器上从一个域名复制到另一个域名,以下就是我的情况,你也可以根据自己的情况进行调整:

foreach(glob('../folder/*.php') as $file) {
$adjust = substr($file,3);
copy($file, '/home/user/abcde.com/'.$adjust);

注意,使用了“ subr ()”,如果没有它,目标就变成了“/home/user/ abcde.com/../folder/”,这可能是您不想要的。因此,我使用 subr ()来消除前3个字符(。./) ,以便得到所需的目的地,即“/home/user/ abcde.com/folder/”。因此,您可以调整 subr ()函数和 globb ()函数,直到它满足您的个人需求。希望这个能帮上忙。

冗长的,带有评论的返回日志示例,基于这里大多数答案的一部分:

它表示为一个静态类方法,但也可以作为一个简单的函数:

/**
* Recursive copy directories and content
*
* @link        https://stackoverflow.com/a/2050909/591486
* @since       4.7.2
*/
public static function copy_recursive( $source = null, $destination = null, &$log = [] ) {


// is directory ##
if ( is_dir( $source ) ) {


$log[] = 'is_dir: '.$source;


// log results of mkdir call ##
$log[] = '@mkdir( "'.$destination.'" ): '.@mkdir( $destination );


// get source directory contents ##
$source_directory = dir( $source );


// loop over items in source directory ##
while ( FALSE !== ( $entry = $source_directory->read() ) ) {
            

// skip hidden ##
if ( $entry == '.' || $entry == '..' ) {


$log[] = 'skip hidden entry: '.$entry;


continue;


}


// get full source "entry" path ##
$source_entry = $source . '/' . $entry;


// recurse for directories ##
if ( is_dir( $source_entry ) ) {


$log[] = 'is_dir: '.$source_entry;


// return to self, with new arguments ##
self::copy_recursive( $source_entry, $destination.'/'.$entry, $log );


// break out of loop, to stop processing ##
continue;


}


$log[] = 'copy: "'.$source_entry.'" --> "'.$destination.'/'.$entry.'"';


// copy single files ##
copy( $source_entry, $destination.'/'.$entry );


}


// close connection ##
$source_directory->close();


} else {


$log[] = 'copy: "'.$source.'" --> "'.$destination.'"';


// plain copy, as $destination is a file ##
copy( $source, $destination );


}


// clean up log ##
$log = array_unique( $log );


// kick back log for debugging ##
return $log;


}

打电话给我:

// call method ##
$log = \namespace\to\method::copy_recursive( $source, $destination );


// write log to error file - you can also just dump it on the screen ##
error_log( var_export( $log, true ) );

要将整个内容从一个目录复制到另一个目录,首先应确保正确地传输了文件。因此,我们使用复制文件一个接一个!在正确的目录中。我们复制一个文件并检查它是否为真转到下一个文件并继续..。

我用这个函数检查传输每个文件的安全过程:


function checksum($src,$dest)
{
if(file_exists($src) and file_exists($dest)){
return md5_file($src) == md5_file($dest) ? true : false;
}else{
return false;
}
}


现在我将文件一个一个地从 src 复制到 est,检查它,然后继续。(如果要分隔不想复制的文件夹,请使用排除数组)

$src  = __DIR__ . '/src';
$dest = __DIR__ . '/dest';
$exclude = ['.', '..'];


function copyDir($src, $dest, $exclude)
{


!is_dir($dest) ? mkdir($dest) : '';


foreach (scandir($src) as $item) {


$srcPath = $src . '/' . $item;
$destPath = $dest . '/' . $item;


if (!in_array($item, $exclude)) {


if (is_dir($srcPath)) {


copyDir($srcPath, $destPath, $exclude);


} else {


copy($srcPath, $destPath);


if (checksum($srcPath, $destPath)) {
echo 'Success transfer for:' . $srcPath . '<br>';
}else{
echo 'Failed transfer for:' . $srcPath . '<br>';
}
}
}
}


}

我发现这样更简单,更容易定制,而且不需要任何依赖性:

foreach(glob("old_location/*") as $file) {
copy($file, "new_location/" . basename($file));
}