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


146

我尝试使用以下命令将目录的全部内容复制到另一个位置

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

但是它说找不到流,没有找到true *.*

任何其他方式

谢谢戴夫


1
@编辑:您确定那"old_location/."只是一个错字?
菲利克斯·克林

Rich Rodecker在他的博客上有一个脚本似乎可以做到这一点。visible-form.com/blog/copy-directory-in-php
Jon F Hancock 2010年

@Felix:我在想同样的事情。我回滚到第一个修订版,但已经修订了"old_location/*.*。我找不到包含的修订"old_location/."
Asaph 2010年

@Asaph:您的回滚还不错,看看历史……我的意思是copy ("old_location/.","new_location/");
Felix Kling 2010年

3
@dave您什么时候会拿起被接受的:)?
Nam G VU

Answers:


239

看来复制处理单个文件。这是我在复制文档页面上的本说明中找到的用于递归复制的功能:

<?php 
function recurse_copy($src,$dst) { 
    $dir = opendir($src); 
    @mkdir($dst); 
    while(false !== ( $file = readdir($dir)) ) { 
        if (( $file != '.' ) && ( $file != '..' )) { 
            if ( is_dir($src . '/' . $file) ) { 
                recurse_copy($src . '/' . $file,$dst . '/' . $file); 
            } 
            else { 
                copy($src . '/' . $file,$dst . '/' . $file); 
            } 
        } 
    } 
    closedir($dir); 
} 
?>

2
这是一个星号,而不是星星;)
戈登

6
像魅力一样工作..谢谢@FelixKling
Milap 2012年

2
为什么要@mkdir代替mkdir
Oliboy50

3
@ Oliboy50:您可以问问5年前编写代码的人:php.net/manual/en/function.copy.php#91010。也许在那时,抑制错误消息更为流行。
菲利克斯·克林

1
@ Oliboy50:我明白了。我认为它可以抑制任何错误消息。我从来没有真正使用过它。这是文档:us3.php.net/manual/en/language.operators.errorcontrol.php
Felix Kling

90

如此处所述,这是另一种也处理符号链接的方法:

/**
 * 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));
}

复制一个包含140个子文件夹的文件夹非常有用,每个子文件夹包含21张图像。很棒!谢谢!
Darksaint2014年

1
mkdir应该添加true为最后一个参数以支持递归目录,那么此脚本非常完美
ZenithS18年

这会复制整个文件夹吗?如果只想将文件复制什么里面的文件夹,没有父文件夹,因为这个问题说:copy ("old_location/*.*","new_location/");运作的?如果您有点文件,该怎么办?
XCS

35

copy()仅适用于文件。

DOS复制和Unix cp命令都将以递归方式复制-因此最快的解决方案是将它们打包并使用。例如

`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);
        }
    }
}

1
这是xcopy()的更稳定和更清洁的版本,如果存在该文件夹,则不会创建该文件夹: function xcopy($src, $dest) { foreach (scandir($src) as $file) { $srcfile = rtrim($src, '/') .'/'. $file; $destfile = rtrim($dest, '/') .'/'. $file; if (!is_readable($srcfile)) { continue; } if ($file != '.' && $file != '..') { if (is_dir($srcfile)) { if (!file_exists($destfile)) { mkdir($destfile); } xcopy($srcfile, $destfile); } else { copy($srcfile, $destfile); } } } }
TheStoryCoder

感谢您提出的解决方案!一个帮助我调整复制命令的页面:UNIX cp解释了。附加信息:PHP> = 5.3提供了一些不错的迭代器
maxpower9000

21

最好的解决方案是!

<?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
?>

31
无法在Windows服务器或其他环境中工作,你要么必须要么无法访问shell_execcp。我认为,这几乎不是“最佳”解决方案。
Pellmeister,2012年

3
除此之外,当有人找到在您的服务器上获取文件的方法时,PHP文件的命令行控件可能是一个大问题。
马丁2014年

像魅力一样工作!在CentOS上,效果很好。感谢@bstpierre
Nick Green

1
这根本无法在Windows上运行,因为这cp是Linux命令。对于Windows使用xcopy dir1 dir2 /e /i,其中/e代表复制空目录,/i而忽略有关文件或目录的问题
Michel

是的,如果您的服务器支持此命令并且您具有必需的权限,则这是最佳解决方案。非常快。不幸的是不能在所有环境下工作。
mdikici

13
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 );
    }
}

完美的作品!谢谢兄弟
罗宾·德拉波特

8

就像在其他地方说过的那样,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

考虑更改:$ dest = realpath($ dir。DIRECTORY_SEPARATOR)。basename($ file); 使用:$ dest = realpath($ dir)。DIRECTORY_SEPARATOR。basename($ file);
dawez 2013年

8
<?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 );
        }
    }
?>

从第4行开始

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

$destination ='b';

7

非常感谢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;
}

1
您正在使用recurse_copy()和recurseCopy()作为函数名称,请对其进行更新。
AgelessEssence

closeirir($ dir); 语句需要在if($ reslut === true)语句之外,即,将大括号向下。否则,您将面临拥有未释放资源的风险。
Dimitar Darazhanski


5

我修剪的@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();
    }

}

1

我通过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");

0
// using exec

function rCopy($directory, $destination)
{

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

    exec($command);

}

0

对于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());
}

但速度较慢,并且不会保留权限。


0

我遇到过类似的情况,我需要从一个域复制到同一服务器上的另一个域,这正是我的情况,您可以根据自己的需要进行调整:

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

注意使用了“ substr()”,如果没有它,目标将变成“ /home/user/abcde.com/../folder/”,这可能是您不想要的。因此,我使用substr()消除了前三个字符(../),以获得所需的目标位置,即“ /home/user/abcde.com/folder/”。因此,您可以调整substr()函数以及glob()函数,直到满足您的个人需求为止。希望这可以帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.