PHP를 사용하여 디렉토리의 전체 내용을 다른 디렉토리로 복사


146

디렉토리의 전체 내용을 다른 위치로 복사하려고했습니다.

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

그러나 스트림을 찾을 수 없다고 말하면 true를 찾을 수 없습니다 *.*.

다른 방법

고마워 데이브


1
@ 편집자 : 그게 "old_location/."오타일까요?
Felix Kling

Rich Rodecker는 자신의 블로그에 바로 그렇게하는 스크립트를 가지고 있습니다. visible-form.com/blog/copy-directory-in-php
Jon F Hancock

@ 펠릭스 : 나는 같은 것을 궁금해했다. 첫 번째 개정판으로 롤백했지만 "old_location/*.*. 가 포함 된 개정을 찾을 수 없습니다 "old_location/.".
Asaph

@Asaph : 귀하의 롤백, 역사 봐 괜찮다고 ... 나는 의미copy ("old_location/.","new_location/");
펠릭스 클링

3
@dave 언제 받아 들일 수 있습니까 :)?
Nam G VU

답변:


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
별표가 아닌 별표입니다.)
Gordon

6
매력처럼 작동합니다 .. 감사 @FelixKling
Milap

2
@mkdir대신에 mkdir?
Oliboy50

3
Oliboy50 @ : 당신은 5 년 전에 코드를 작성한 사람 요청할 수 있습니다 php.net/manual/en/function.copy.php#91010을 . 아마도 오류 메시지를 억제하는 것이 더 인기가 있었을 것입니다.
Felix Kling

1
@ Oliboy50 : 알겠습니다. 오류 메시지가 표시되지 않습니다. 그래도 실제로는 사용하지 않았습니다. 이것은 문서입니다 : us3.php.net/manual/en/language.operators.errorcontrol.php
Felix Kling

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
mkdirtrue재귀 적으로 디렉토리를 지원하기 위해 마지막 매개 변수로 추가되어야합니다. 그러면이 스크립트는 완벽합니다
ZenithS

이것은 전체 폴더를 복사합니까? 질문에서 알 수 있듯이 부모 폴더없이 폴더 안에 있는 파일 만 복사하려면 어떻게해야 copy ("old_location/*.*","new_location/");합니까? 도트 파일이 있으면 어떻게 일치합니까?
XCS

35

copy ()는 파일에서만 작동합니다.

DOS 카피와 유닉스 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 솔루션에 감사드립니다 ! copy 명령을 조정하는 데 도움이되는 페이지 : UNIX cp DESCRIPTION . 추가 정보 : 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. 제 생각에는 "최고의"솔루션은 거의 없습니다.
Pellmeister

3
그 외에, 누군가가 서버에서 파일을 얻는 방법을 찾을 때 PHP 파일의 명령 줄 컨트롤은 큰 문제가 될 수 있습니다.
Martijn

매력처럼 일했다! CentOS에서는 훌륭하게 작동했습니다. 감사합니다 @bstpierre
Nick Green

1
cpLinux 명령 이기 때문에 Windows에서는 전혀 작동하지 않습니다 . 윈도우 사용을 위해 xcopy dir1 dir2 /e /i, 여기서 /e사본 빈 DIRS 약자 /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 );
    }
}

완벽하게 작동합니다! 고마워 친구
Robin Delaporte

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) 변경을 고려하십시오. 기본 이름 ($ file); 사용 : $ dest = realpath ($ dir). DIRECTORY_SEPARATOR 기본 이름 ($ 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 );
        }
    }
?>

마지막 4 번째 줄부터

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

$destination ='b';

7

필자의 코드에 감사하게 사용 된 탁월한 답변에 대해 Felix Kling에게 전적으로 감사해야합니다. 성공 또는 실패를보고하기 위해 부울 리턴 값을 약간 개선했습니다.

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

closedir ($ dir); 명령문은 if ($ reslut === true) 명령문 외부에 있어야합니다. 즉, 중괄호 하나 더 내려갑니다. 그렇지 않으면 비 사용 리소스가있을 위험이 있습니다.
Dimitar Darazhanski


5

@Kzoty 답변의 정리 된 버전. 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

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

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/'가되어 원하지 않는 것일 수 있습니다. 그래서 원하는 목적지 인 '/home/user/abcde.com/folder/'를 얻기 위해 substr ()을 사용하여 처음 3자를 제거했습니다. 따라서 substr () 함수와 glob () 함수를 개인의 필요에 맞게 조정할 수 있습니다. 도움이 되었기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.