Sao chép toàn bộ nội dung của một thư mục sang thư mục khác bằng php


146

Tôi đã cố gắng sao chép toàn bộ nội dung của thư mục sang một vị trí khác bằng cách sử dụng

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

nhưng nó nói nó không thể tìm thấy luồng, đúng *.*là không tìm thấy.

Bất kỳ cách nào khác

Cảm ơn Dave


1
@ các biên tập viên: Bạn có chắc chắn đó "old_location/."chỉ là một lỗi đánh máy?
Felix Kling

Rich Rodecker có một kịch bản trên blog của mình dường như làm điều đó. nhìn thấy
Jon F Hancock

@Felix: Tôi đã tự hỏi điều tương tự. Tôi quay trở lại phiên bản đầu tiên nhưng nó có "old_location/*.*. Tôi không thể tìm thấy bản sửa đổi có chứa "old_location/.".
Asaph

@Asaph: Rollback của bạn đã ổn, hãy nhìn vào lịch sử ... Ý tôi làcopy ("old_location/.","new_location/");
Felix Kling

3
@dave Khi nào bạn sẽ nhận một chấp nhận :)?
Nam G VU

Câu trả lời:


239

Có vẻ như sao chép chỉ xử lý các tập tin duy nhất . Đây là một chức năng để sao chép đệ quy tôi tìm thấy trong ghi chú này trên trang tài liệu sao chép :

<?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
Đó là một dấu sao và không phải là một ngôi sao;)
Gordon

6
Hoạt động như một bùa mê .. Cảm ơn @FelixKling
Milap

2
Tại sao @mkdirthay vì mkdir?
Oliboy50

3
@ Oliboy50: Bạn có thể hỏi người đã viết mã 5 năm trước: php.net/manual/en/feft.copy.php#91010 . Có lẽ nó đã trở nên phổ biến hơn sau đó để chặn các thông báo lỗi.
Felix Kling

1
@ Oliboy50: Tôi hiểu rồi. Tôi nghĩ rằng nó ngăn chặn bất kỳ thông báo lỗi. Tôi chưa bao giờ thực sự sử dụng nó mặc dù. Đây là tài liệu: us3.php.net/manual/en/lingu.operators.errorcontrol.php
Felix Kling

90

Như được mô tả ở đây , đây là một cách tiếp cận khác cũng quan tâm đến các liên kết tượng trưng:

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

Làm việc tuyệt vời để sao chép một thư mục với 140 thư mục con và mỗi thư mục con chứa 21 hình ảnh. Hoạt động tuyệt vời! Cảm ơn!
Darksaint2014

1
mkdirnên được thêm truelàm tham số cuối cùng để hỗ trợ thư mục đệ quy thì tập lệnh này là hoàn hảo
ZenithS

Điều này sao chép toàn bộ thư mục? Điều gì sẽ xảy ra nếu bạn chỉ muốn sao chép các tệp trong thư mục mà không có thư mục mẹ như câu hỏi cho biết: Nó copy ("old_location/*.*","new_location/");có hoạt động không? Điều gì nếu bạn có tập tin dấu chấm, chúng sẽ được khớp?
XCS

35

copy () chỉ hoạt động với các tập tin.

Cả hai lệnh sao chép DOS và Unix cp sẽ sao chép đệ quy - vì vậy giải pháp nhanh nhất là bỏ ra và sử dụng chúng. ví dụ

`cp -r $src $dest`;

Nếu không, bạn sẽ cần sử dụng opendir/ readdirhoặc scandirđể đọc nội dung của thư mục, lặp qua các kết quả và nếu is_dir trả về true cho từng mục, hãy lặp lại vào đó.

ví dụ

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
Đây là phiên bản xcopy () ổn định và gọn gàng hơn, không tạo thư mục nếu nó tồn tại: 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

Cảm ơn các giải pháp backtick ! Một trang giúp tôi điều chỉnh lệnh sao chép: UNIX cp giải thích . Thông tin bổ sung: PHP> = 5.3 cung cấp một số trình vòng lặp
maxpower9000

21

Giải pháp tốt nhất là!

<?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
Không hoạt động trên các máy chủ Windows hoặc các môi trường khác mà bạn không có quyền truy cập vào shell_exechoặc cp. Điều đó làm cho nó - theo tôi - hầu như không phải là giải pháp "tốt nhất".
Pellmeister

3
Ngoài ra, các điều khiển dòng lệnh từ tệp PHP có thể là một vấn đề lớn khi ai đó tìm cách lấy tệp trên máy chủ của bạn.
Martijn

Làm việc như người ở! Trên CentOS và nó hoạt động rất tốt. Cảm ơn @bstpierre
Nick Green

1
Điều này sẽ không hoạt động trên Windows, bởi vì đó cplà một lệnh Linux. Để sử dụng Windows xcopy dir1 dir2 /e /i, nơi /eviết tắt của các bản sao trống rỗng và /ibỏ qua các câu hỏi về tệp hoặc thư mục
Michel

Có, đó là giải pháp tốt nhất nếu máy chủ của bạn hỗ trợ lệnh này và bạn có quyền yêu cầu. Nó rất nhanh. Thật không may, không làm việc tất cả các môi trường.
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 );
    }
}

Hoạt động hoàn hảo! Cảm ơn người anh em
Robin Delaporte

8

Giống như đã nói ở nơi khác, copychỉ hoạt động với một tệp duy nhất cho nguồn chứ không phải mẫu. Nếu bạn muốn sao chép theo mẫu, sử dụng globđể xác định các tệp, sau đó chạy sao chép. Điều này sẽ không sao chép thư mục con mặc dù, nó cũng sẽ không tạo thư mục đích.

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

xem xét thay đổi: $ Dest = realpath ($ dir. DIRECTORY_SEPARATOR). tên cơ sở (tập tin $); với: $ mệnh = realpath ($ dir). GIÁM ĐỐC_SEPARATOR. tên cơ sở (tập tin $);
dawez

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

từ dòng thứ 4 cuối cùng, thực hiện điều này

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

$destination ='b';

7

Cảm ơn đầy đủ phải đến Felix Kling vì câu trả lời tuyệt vời của anh ấy mà tôi đã biết ơn sử dụng trong mã của mình. Tôi cung cấp một sự nâng cao nhỏ của giá trị trả về boolean để báo cáo thành công hay thất bại:

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
bạn đang sử dụng recurse_copy () và recurseCopy () làm tên hàm, cập nhật nó.
AglessEssence

Các đóng cửa ($ dir); câu lệnh cần nằm ngoài câu lệnh if ($ reslut === true), tức là một dấu ngoặc nhọn tiếp tục đi xuống. Nếu không, bạn có nguy cơ có tài nguyên không được giải phóng.
Dimitar Darazhanski


5

Phiên bản cắt tỉa của câu trả lời @Kzoty của tôi. Cảm ơn bạn Kzoty.

Sử dụng

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

Tôi sao chép toàn bộ thư mục bằng SPL Directory Iterator.

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

Đối với máy chủ Linux, bạn chỉ cần một dòng mã để sao chép đệ quy trong khi vẫn giữ quyền:

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

Một cách khác để làm điều đó là:

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

nhưng nó chậm hơn và không bảo vệ quyền.


0

Tôi đã có một tình huống tương tự khi tôi cần sao chép từ tên miền này sang tên miền khác trên cùng một máy chủ, Đây chính xác là những gì đã hoạt động trong trường hợp của tôi, bạn cũng có thể điều chỉnh cho phù hợp với tên miền của mình:

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

Lưu ý việc sử dụng "chất nền ()", nếu không có nó, đích sẽ trở thành '/home/user/abcde.com/../folder/', đây có thể là điều bạn không muốn. Vì vậy, tôi đã sử dụng chất nền () để loại bỏ 3 ký tự đầu tiên (../) để có được đích đến mong muốn đó là '/home/user/abcde.com/folder/'. Vì vậy, bạn có thể điều chỉnh hàm struct () và cả hàm global () cho đến khi phù hợp với nhu cầu cá nhân của bạn. Hi vọng điêu nay co ich.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.