Скопіюйте весь вміст каталогу в інший за допомогою php


146

Я спробував скопіювати весь вміст каталогу в інше місце за допомогою

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

але він говорить, що не може знайти потік, правда *.*не знайдена.

Будь-який інший спосіб

Дякую, Дейв


1
@the редактори: Ви впевнені, що це "old_location/."був просто друкарський помилок?
Фелікс Клінг

Багатий Родекер має у своєму блозі сценарій, який, здається, робить саме це. visible-form.com/blog/copy-directory-in-php
Jon F Hancock

@Felix: Мені було цікаво те саме. Я відкотився до першої редакції, але вона має "old_location/*.*. Я не можу знайти версію, що містить "old_location/.".
Асаф

@Asaph: Ваш відкат був нормальний, подивіться на історію ... Я мав на увазіcopy ("old_location/.","new_location/");
Фелікс Клінг

3
@dave Коли ви підберете прийняте :)?
Нам Г ВУ

Відповіді:


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
Мілап

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
Фелікс Клінг

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як останній параметр для підтримки рекурсивно каталогу, тоді цей сценарій ідеальний
ZenithS

Це копіює всю папку? Що робити, якщо ви хочете скопіювати лише файли всередині папки, без батьківської папки, як сказано в питанні: copy ("old_location/*.*","new_location/");чи працює це? Що робити, якщо у вас є крапкові файли, чи вони будуть відповідні?
XCS

35

copy () працює лише з файлами.

Як DOS copy, так і Unix cp команди копіюватимуться рекурсивно - тому найшвидшим рішенням є просто викласти їх і використовувати їх. напр

`cp -r $src $dest`;

Інакше вам потрібно буде скористатися opendir/ readdirабоscandir для читання вмісту каталогу, повторити результати, і якщо 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

Дякуємо за рішення "backtick" ! Сторінка, яка допомогла мені налаштувати команду копіювання: пояснив 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_execабо cp. Це робить - на мою думку - навряд чи «найкращим» рішенням.
The Pellmeister

3
Крім того, управління командним рядком з файлу PHP може бути великою проблемою, коли хтось знайде спосіб отримати файл на вашому сервері.
Мартійн

Працював як шарм! На CentOS і він працював чудово. Спасибі @bstpierre
Нік Грін

1
Це взагалі не буде працювати в Windows, оскільки cpце команда Linux. Для використання в Windows xcopy dir1 dir2 /e /i, де /eстоїть копія порожніх панів та /iігнорування запитань щодо файлів чи каталогів
Мішель

Так, це найкраще рішення, якщо ваш сервер підтримує цю команду і у вас є необхідні дозволи. Це дуже швидко. На жаль, працює не в усіх середовищах.
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). базове ім'я ($ файл); з: $ dest = realpath ($ dir). DIRECTORY_SEPARATOR базове ім'я ($ файл);
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 );
        }
    }
?>

з останнього 4-го рядка зробіть це

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

і

$destination ='b';

7

Повна подяка повинна віддячити Феліксу Клінгу за його чудову відповідь, яку я з вдячністю використовував у своєму коді. Я пропоную невелике збільшення булевого значення повернення, щоб повідомити про успіх чи провал:

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

Закритий ($ dir); Оператор повинен бути поза оператором if ($ reslut === true), тобто однією фігурною дужкою далі вниз. В іншому випадку ви ризикуєте отримати невивільнені ресурси.
Димитър Даражанський


5

Моя обрізана версія відповіді @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

Я клоную весь каталог за допомогою Iterator каталогу 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 (), щоб усунути перші 3 символи (../), щоб отримати бажане місце призначення, яке є "/home/user/abcde.com/folder/". Отже, ви можете налаштувати функцію substr (), а також функцію glob (), поки вона не відповідає вашим особистим потребам. Сподіваюся, це допомагає.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.