Salin seluruh isi direktori ke yang lain menggunakan php

146

Saya mencoba menyalin seluruh isi direktori ke lokasi lain menggunakan

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

tetapi dikatakan tidak dapat menemukan aliran, benar *.*tidak ditemukan.

Cara lain

Terima kasih Dave

dave
sumber
1
@ editor: Apakah Anda yakin "old_location/."itu hanya kesalahan ketik?
Felix Kling
Rich Rodecker memiliki skrip di blognya yang tampaknya melakukan hal itu. visible-form.com/blog/copy-directory-in-php
Jon F Hancock
@ Feliks: Saya bertanya-tanya hal yang sama. Saya kembali ke revisi pertama tetapi sudah "old_location/*.*. Saya tidak dapat menemukan revisi yang mengandung "old_location/.".
Asaf
@ Asaf: Kembalikan Anda baik-baik saja, lihat sejarah ... Maksud sayacopy ("old_location/.","new_location/");
Felix Kling
3
@dave Kapan Anda akan menerima yang diterima :)?
Nam G VU

Jawaban:

239

Tampaknya salinan hanya menangani file tunggal . Berikut adalah fungsi untuk menyalin secara rekursif yang saya temukan dalam catatan ini di halaman dokumentasi salinan :

<?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); 
} 
?>
Felix Kling
sumber
2
Ini tanda bintang dan bukan bintang;)
Gordon
6
Bekerja seperti pesona .. Terima kasih @ Felkling
Milap
2
Kenapa @mkdirbukannya mkdir?
Oliboy50
3
@ Oliboy50: Anda dapat bertanya kepada orang yang menulis kode 5 tahun yang lalu: php.net/manual/en/function.copy.php#91010 . Mungkin saat itu lebih populer untuk menekan pesan kesalahan.
Felix Kling
1
@ Oliboy50: Begitu. Saya pikir itu menekan pesan kesalahan. Saya tidak pernah benar-benar menggunakannya. Ini dokumentasinya: us3.php.net/manual/en/language.operators.errorcontrol.php
Felix Kling
90

Seperti dijelaskan di sini , ini adalah pendekatan lain yang menangani symlink juga:

/**
 * Copy a file, or recursively copy a folder and its contents
 * @author      Aidan Lister <[email protected]>
 * @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));
}
itsjavi
sumber
Berfungsi bagus untuk menyalin folder dengan 140 sub folder dan setiap subfolder berisi 21 gambar. Bagus sekali! Terima kasih!
Darksaint2014
1
mkdirharus ditambahkan truesebagai parameter terakhir untuk mendukung direktori rekursif maka skrip ini sempurna
ZenithS
Ini menyalin seluruh folder? Bagaimana jika Anda hanya ingin menyalin file di dalam folder, tanpa folder induk, seperti pertanyaan mengatakan: copy ("old_location/*.*","new_location/");Apakah itu berhasil? Bagaimana jika Anda memiliki file dot, apakah mereka akan cocok?
XCS
35

copy () hanya berfungsi dengan file.

Baik perintah salin DOS dan Unix cp akan menyalin secara rekursif - jadi solusi tercepat adalah dengan keluar dan menggunakannya. misalnya

`cp -r $src $dest`;

Kalau tidak, Anda harus menggunakan opendir/readdir atau scandiruntuk membaca isi direktori, beralih melalui hasilnya dan jika is_dir mengembalikan true untuk masing-masing, kembalilah ke dalamnya.

misalnya

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);
        }
    }
}
symcbean
sumber
1
Berikut ini adalah versi xcopy () yang lebih stabil dan lebih bersih yang tidak membuat folder jika ada: 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
Terima kasih atas solusi backtick ! Halaman yang membantu saya mengubah perintah copy: UNIX cp menjelaskan . Info tambahan: PHP> = 5.3 menawarkan beberapa iterator yang
maxpower9000
21

Solusi terbaik adalah!

<?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
?>
hitam
sumber
31
Tidak akan bekerja di server Windows atau lingkungan lain di mana Anda tidak memiliki akses ke salah satu shell_execatau cp. Itu membuatnya - menurut saya - bukan solusi "terbaik".
The Pellmeister
3
Selain itu, kontrol commandline dari file PHP bisa menjadi masalah besar ketika seseorang menemukan cara untuk mendapatkan file di server Anda.
Martijn
Bekerja seperti pesona! Di CentOS dan itu bekerja dengan baik. Terima kasih @ bstpierre
Nick Green
1
Ini tidak akan bekerja pada Windows sama sekali, karena cpini adalah perintah Linux. Untuk penggunaan Windows xcopy dir1 dir2 /e /i, di mana /ekepanjangan dari salinan direktori kosong dan /iuntuk mengabaikan pertanyaan tentang file atau direktori
Michel
Ya, ini adalah solusi terbaik jika server Anda mendukung perintah ini dan Anda telah meminta izin. Ini sangat cepat. Sayangnya tidak bekerja di semua lingkungan.
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 );
    }
}
kzoty
sumber
Bekerja dengan sempurna! Terima kasih kawan
Robin Delaporte
8

Seperti yang dikatakan di tempat lain, copyhanya bekerja dengan satu file untuk sumber dan bukan pola. Jika Anda ingin menyalin berdasarkan pola, gunakan globuntuk menentukan file, kemudian jalankan salin. Ini tidak akan menyalin subdirektori, juga tidak akan membuat direktori tujuan.

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
Gordon
sumber
pertimbangkan untuk mengubah: $ dest = realpath ($ dir. DIRECTORY_SEPARATOR). basename ($ file); dengan: $ dest = realpath ($ dir). DIRECTORY_SEPARATOR. basename ($ file);
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 );
        }
    }
?>

dari baris 4 terakhir, buat ini

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

dan

$destination ='b';
Hemanta Nandi
sumber
7

Terima kasih penuh harus ditujukan kepada Felix Kling untuk jawaban luar biasa yang telah saya gunakan dengan penuh syukur dalam kode saya. Saya menawarkan peningkatan kecil dari nilai pengembalian boolean untuk melaporkan keberhasilan atau kegagalan:

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;
}
gonzo
sumber
1
Anda menggunakan recurse_copy () dan recurseCopy () sebagai nama fungsi, perbarui.
AgelessEssence
The closedir ($ dir); pernyataan harus di luar pernyataan if ($ reslut === true), yaitu satu kurung kurawal lebih jauh ke bawah. Kalau tidak, Anda berisiko memiliki sumber daya yang tidak dibebaskan.
Dimitar Darazhanski
5

Versi @Kzoty saya yang sudah dipangkas. Terima kasih, Kzoty.

Pemakaian

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

}
Nam G VU
sumber
1

Saya mengkloning seluruh direktori dengan 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");
Tuhin Bepari
sumber
0
// using exec

function rCopy($directory, $destination)
{

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

    exec($command);

}
Łukasz Szpak
sumber
0

Untuk server Linux, Anda hanya perlu satu baris kode untuk menyalin secara rekursif sambil mempertahankan izin:

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

Cara lain untuk melakukannya adalah:

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

tapi lebih lambat dan tidak mempertahankan izin.

Dan Bray
sumber
0

Saya memiliki situasi yang serupa di mana saya perlu menyalin dari satu domain ke domain lain di server yang sama, Inilah yang berhasil dalam kasus saya, Anda juga dapat menyesuaikan sesuai keinginan Anda:

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

Perhatikan penggunaan "substr ()", tanpa itu, tujuan menjadi '/ home / pengguna / abcde.com/../folder/', yang mungkin sesuatu yang tidak Anda inginkan. Jadi, saya menggunakan substr () untuk menghilangkan 3 karakter pertama (../) untuk mendapatkan tujuan yang diinginkan yaitu '/home/user/abcde.com/folder/'. Jadi, Anda dapat menyesuaikan fungsi substr () dan juga fungsi glob () hingga sesuai dengan kebutuhan pribadi Anda. Semoga ini membantu.

Chimdi
sumber