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

Dave
quelle
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); 
} 
?>
Felix Kling
quelle
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 <[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
quelle
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);
        }
    }
}
Symcbean
quelle
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
?>
schwarz
quelle
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 );
    }
}
kzoty
quelle
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
Gordon
quelle
Ü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';
Hemanta Nandi
quelle
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;
}
Gonzo
quelle
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();
    }

}
Nam G VU
quelle
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");
Tuhin Bepari
quelle
0
// using exec

function rCopy($directory, $destination)
{

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

    exec($command);

}
Łukasz Szpak
quelle
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.

Dan Bray
quelle
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.

Chimdi
quelle