Kopieren Sie den gesamten Inhalt eines Verzeichnisses mit PHP in ein anderes


146

Ich habe versucht, den gesamten Inhalt des Verzeichnisses mit an einen anderen Speicherort zu kopieren

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

aber es heißt, es kann keinen Stream finden, true *.*wird nicht gefunden.

Jeder andere Weg

Danke Dave


1
@ die Redaktion: Bist du sicher, dass "old_location/."das nur ein Tippfehler war?
Felix Kling

Rich Rodecker hat ein Skript in seinem Blog, das genau das zu tun scheint. sichtbare-form.com/blog/copy-directory-in-php
Jon F Hancock

@ Felix: Ich habe mich das gleiche gefragt. Ich bin zur ersten Revision zurückgekehrt, aber es hat "old_location/*.*. Ich kann keine Revision finden, die enthält "old_location/.".
Asaph

@Asaph: Ihr Rollback war in Ordnung, schauen Sie sich die Geschichte an ... Ich meintecopy ("old_location/.","new_location/");
Felix Kling

3
@dave Wann holst du eine akzeptierte ab :)?
Nam G VU

Antworten:


239

Es scheint , dass Kopie nur behandeln einzelne Dateien . Hier ist eine Funktion zum rekursiven Kopieren, die ich in diesem Hinweis auf der Seite zum Kopieren der Dokumentation gefunden habe :

<?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
Es ist ein Sternchen und kein Stern;)
Gordon

6
Funktioniert wie ein Zauber. Danke @FelixKling
Milap

2
Warum @mkdirstatt mkdir?
Oliboy50

3
@ Oliboy50: Sie können die Person fragen, die den Code vor 5 Jahren geschrieben hat: php.net/manual/en/function.copy.php#91010 . Vielleicht war es damals populärer, Fehlermeldungen zu unterdrücken.
Felix Kling

1
@ Oliboy50: Ich verstehe. Ich denke, es unterdrückt jede Fehlermeldung. Ich habe es aber nie wirklich benutzt. Dies ist die Dokumentation: us3.php.net/manual/en/language.operators.errorcontrol.php
Felix Kling

90

Wie hier beschrieben , ist dies ein weiterer Ansatz, der sich auch um Symlinks kümmert:

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

Hat hervorragend funktioniert, um einen Ordner mit 140 Unterordnern und jedem Unterordner mit 21 Bildern zu kopieren. Funktioniert super! Vielen Dank!
Darksaint2014

1
mkdirsollte trueals letzter Parameter hinzugefügt werden, um rekursives Verzeichnis zu unterstützen, dann ist dieses Skript perfekt
ZenithS

Dies kopiert den gesamten Ordner? Was ist, wenn Sie nur die Dateien innerhalb des Ordners ohne den übergeordneten Ordner kopieren möchten , wie in der Frage angegeben: copy ("old_location/*.*","new_location/");Funktioniert das? Was ist, wenn Sie Punktdateien haben, werden diese abgeglichen?
XCS

35

copy () funktioniert nur mit Dateien.

Sowohl der DOS-Kopierbefehl als auch der Unix-cp-Befehl werden rekursiv kopiert. Die schnellste Lösung besteht also darin, diese zu berappen und zu verwenden. z.B

`cp -r $src $dest`;

Andernfalls müssen Sie das opendir/ readdiroder verwenden scandir, um den Inhalt des Verzeichnisses zu lesen, die Ergebnisse zu durchlaufen. Wenn is_dir für jedes Verzeichnis true zurückgibt, können Sie darauf zurückgreifen.

z.B

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
Hier ist eine stabilere und sauberere Version von xcopy (), die den Ordner nicht erstellt, wenn er existiert: 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

Danke für die Backtick-Lösung ! Eine Seite, die mir geholfen hat, den Kopierbefehl zu optimieren: UNIX cp erklärt . Zusätzliche Informationen: PHP> = 5.3 bietet einige nette Iteratoren
maxpower9000

21

Die beste Lösung ist!

<?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
Funktioniert nicht auf Windows-Servern oder anderen Umgebungen, auf die Sie entweder keinen Zugriff haben shell_execoder cp. Das macht es meiner Meinung nach kaum zur "besten" Lösung.
Der Pellmeister

3
Abgesehen davon können Befehlszeilensteuerelemente aus einer PHP-Datei ein großes Problem sein, wenn jemand einen Weg findet, eine Datei auf Ihrem Server abzurufen.
Martijn

Lief wie am Schnürchen! Auf CentOS und es hat super funktioniert. Danke @bstpierre
Nick Green

1
Dies funktioniert unter Windows überhaupt nicht, da cpes sich um einen Linux-Befehl handelt. Für Windows xcopy dir1 dir2 /e /i, wo /efür das Kopieren leerer Verzeichnisse und /ifür das Ignorieren von Fragen zu Dateien oder Verzeichnissen steht
Michel

Ja, es ist die beste Lösung, wenn Ihr Server diesen Befehl unterstützt und Sie über erforderliche Berechtigungen verfügen. Es ist sehr schnell. Leider funktionieren nicht alle Umgebungen.
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 );
    }
}

Funktioniert perfekt! Vielen Dank Bruder
Robin Delaporte

8

Wie an anderer Stelle gesagt, copyfunktioniert nur mit einer einzigen Datei als Quelle und nicht mit einem Muster. Wenn Sie nach Muster kopieren möchten, globbestimmen Sie die Dateien und führen Sie die Kopie aus. Dadurch werden jedoch weder Unterverzeichnisse kopiert noch das Zielverzeichnis erstellt.

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

Überlegen Sie, ob Sie Folgendes ändern möchten: $ dest = realpath ($ dir. DIRECTORY_SEPARATOR). Basisname ($ file); mit: $ dest = realpath ($ dir). DIRECTORY_SEPARATOR. Basisname ($ 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 );
        }
    }
?>

Machen Sie dies aus der letzten 4. Zeile

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

und

$destination ='b';

7

Ein voller Dank geht an Felix Kling für seine hervorragende Antwort, die ich dankbar in meinem Code verwendet habe. Ich biete eine kleine Verbesserung eines booleschen Rückgabewerts an, um Erfolg oder Misserfolg zu melden:

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
Wenn Sie recurse_copy () und recurseCopy () als Funktionsnamen verwenden, aktualisieren Sie diese.
AgelessEssence

Das Closedir ($ dir); Die Anweisung muss außerhalb der if ($ reslut === true) -Anweisung liegen, dh eine geschweifte Klammer weiter unten. Andernfalls riskieren Sie nicht freigegebene Ressourcen.
Dimitar Darazhanski


5

Meine beschnittene Version der @ Kzoty-Antwort. Vielen Dank, Kzoty.

Verwendung

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

Ich klone das gesamte Verzeichnis mit 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

Für Linux-Server benötigen Sie nur eine Codezeile, um rekursiv zu kopieren und dabei die Berechtigung beizubehalten:

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

Eine andere Möglichkeit ist:

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

Es ist jedoch langsamer und behält keine Berechtigungen bei.


0

Ich hatte eine ähnliche Situation, in der ich auf demselben Server von einer Domain auf eine andere kopieren musste. Genau das hat in meinem Fall funktioniert. Sie können es auch an Ihre anpassen:

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

Beachten Sie die Verwendung von "substr ()". Ohne diese Option wird das Ziel zu "/home/user/abcde.com/../folder/", was Sie möglicherweise nicht möchten. Also habe ich substr () verwendet, um die ersten 3 Zeichen (../) zu entfernen, um das gewünschte Ziel zu erhalten, nämlich '/home/user/abcde.com/folder/'. So können Sie die Funktion substr () und auch die Funktion glob () anpassen, bis sie Ihren persönlichen Anforderungen entspricht. Hoffe das hilft.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.