Copy entire contents of a directory to another using php

Php

Php Problem Overview


I tried to copy the entire contents of the directory to another location using

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

but it says it cannot find stream, true *.* is not found.

Any other way

Thanks Dave

Php Solutions


Solution 1 - Php

that worked for a one level directory. for a folder with multi-level directories I used this:

function recurseCopy(
    string $sourceDirectory,
    string $destinationDirectory,
    string $childFolder = ''
): void {
    $directory = opendir($sourceDirectory);

    if (is_dir($destinationDirectory) === false) {
        mkdir($destinationDirectory);
    }

    if ($childFolder !== '') {
        if (is_dir("$destinationDirectory/$childFolder") === false) {
            mkdir("$destinationDirectory/$childFolder");
        }

        while (($file = readdir($directory)) !== false) {
            if ($file === '.' || $file === '..') {
                continue;
            }

            if (is_dir("$sourceDirectory/$file") === true) {
                recurseCopy("$sourceDirectory/$file", "$destinationDirectory/$childFolder/$file");
            } else {
                copy("$sourceDirectory/$file", "$destinationDirectory/$childFolder/$file");
            }
        }

        closedir($directory);

        return;
    }

    while (($file = readdir($directory)) !== false) {
        if ($file === '.' || $file === '..') {
            continue;
        }

        if (is_dir("$sourceDirectory/$file") === true) {
            recurseCopy("$sourceDirectory/$file", "$destinationDirectory/$file");
        }
        else {
            copy("$sourceDirectory/$file", "$destinationDirectory/$file");
        }
    }

    closedir($directory);
}

Solution 2 - Php

As described here, this is another approach that takes care of symlinks too:

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

Solution 3 - Php

copy() only works with files.

Both the DOS copy and Unix cp commands will copy recursively - so the quickest solution is just to shell out and use these. e.g.

`cp -r $src $dest`;

Otherwise you'll need to use the opendir/readdir or scandir to read the contents of the directory, iterate through the results and if is_dir returns true for each one, recurse into it.

e.g.

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

Solution 4 - Php

The best solution is!

<?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
?>

Solution 5 - Php

With Symfony this is very easy to accomplish:

$fileSystem = new Symfony\Component\Filesystem\Filesystem();
$fileSystem->mirror($from, $to);

See https://symfony.com/doc/current/components/filesystem.html

Solution 6 - Php

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

Solution 7 - Php

Like said elsewhere, copy only works with a single file for source and not a pattern. If you want to copy by pattern, use glob to determine the files, then run copy. This will not copy subdirectories though, nor will it create the destination directory.

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

Solution 8 - Php

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

from the last 4th line , make this

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

and

$destination ='b';

Solution 9 - Php

Full thanks must go to Felix Kling for his excellent answer which I have gratefully used in my code. I offer a small enhancement of a boolean return value to report success or failure:

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

Solution 10 - Php

My pruned version of @Kzoty answer. Thank you Kzoty.

Usage

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

}

Solution 11 - Php

I clone entire directory by 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");

Solution 12 - Php

For Linux servers you just need one line of code to copy recursively while preserving permission:

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

Another way of doing it is:

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

but it's slower and does not preserve permissions.

Solution 13 - Php

I had a similar situation where I needed to copy from one domain to another on the same server, Here is exactly what worked in my case, you can as well adjust to suit yours:

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

Notice the use of "substr()", without it, the destination becomes '/home/user/abcde.com/../folder/', which might be something you don't want. So, I used substr() to eliminate the first 3 characters(../) in order to get the desired destination which is '/home/user/abcde.com/folder/'. So, you can adjust the substr() function and also the glob() function until it fits your personal needs. Hope this helps.

Solution 14 - Php

Long-winded, commented example with return logging, based on parts of most of the answers here:

It is presented as a static class method, but could work as a simple function also:

/**
 * Recursive copy directories and content
 * 
 * @link		https://stackoverflow.com/a/2050909/591486
 * @since		4.7.2
*/
public static function copy_recursive( $source = null, $destination = null, &$log = [] ) {

	// is directory ##
	if ( is_dir( $source ) ) {

		$log[] = 'is_dir: '.$source;

		// log results of mkdir call ##
		$log[] = '@mkdir( "'.$destination.'" ): '.@mkdir( $destination );

		// get source directory contents ##
		$source_directory = dir( $source );

		// loop over items in source directory ##
		while ( FALSE !== ( $entry = $source_directory->read() ) ) {
			
			// skip hidden ##
			if ( $entry == '.' || $entry == '..' ) {

				$log[] = 'skip hidden entry: '.$entry;

				continue;

			}

			// get full source "entry" path ##
			$source_entry = $source . '/' . $entry; 

			// recurse for directories ##
			if ( is_dir( $source_entry ) ) {

				$log[] = 'is_dir: '.$source_entry;

				// return to self, with new arguments ##
				self::copy_recursive( $source_entry, $destination.'/'.$entry, $log );

				// break out of loop, to stop processing ##
				continue;

			}

			$log[] = 'copy: "'.$source_entry.'" --> "'.$destination.'/'.$entry.'"';

			// copy single files ##
			copy( $source_entry, $destination.'/'.$entry );

		}

		// close connection ##
		$source_directory->close();

	} else {

		$log[] = 'copy: "'.$source.'" --> "'.$destination.'"';

		// plain copy, as $destination is a file ##
		copy( $source, $destination );

	}

	// clean up log ##
	$log = array_unique( $log );

	// kick back log for debugging ##
	return $log;

}

Call like:

// call method ##
$log = \namespace\to\method::copy_recursive( $source, $destination );

// write log to error file - you can also just dump it on the screen ##
error_log( var_export( $log, true ) );

Solution 15 - Php

// using exec

function rCopy($directory, $destination)
{

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

Solution 16 - Php

For copy entire contents from a directory to another, first you should sure about transfer files that they were transfer correctly. for this reason, we use copy files one by one! in correct directories. we copy a file and check it if true go to next file and continue...

1- I check the safe process of transferring each file with this function:


function checksum($src,$dest)
{
    if(file_exists($src) and file_exists($dest)){
        return md5_file($src) == md5_file($dest) ? true : false;
    }else{
        return false;
    }
}

2- Now i copy files one by one from src into dest, check it and then continue. (For separate the folders that i don't want to copy them, use exclude array)

$src  = __DIR__ . '/src';
$dest = __DIR__ . '/dest';
$exclude = ['.', '..'];

function copyDir($src, $dest, $exclude)
{

    !is_dir($dest) ? mkdir($dest) : '';

    foreach (scandir($src) as $item) {

        $srcPath = $src . '/' . $item;
        $destPath = $dest . '/' . $item;

        if (!in_array($item, $exclude)) {

            if (is_dir($srcPath)) {

                copyDir($srcPath, $destPath, $exclude);

            } else {

                copy($srcPath, $destPath);

                if (checksum($srcPath, $destPath)) {
                    echo 'Success transfer for:' . $srcPath . '<br>';
                }else{
                    echo 'Failed transfer for:' . $srcPath . '<br>';
                }
            }
        }
    }

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondaveView Question on Stackoverflow
Solution 1 - PhpFelix KlingView Answer on Stackoverflow
Solution 2 - PhpitsjaviView Answer on Stackoverflow
Solution 3 - PhpsymcbeanView Answer on Stackoverflow
Solution 4 - PhpblackView Answer on Stackoverflow
Solution 5 - PhpchickenchilliView Answer on Stackoverflow
Solution 6 - PhpkzotyView Answer on Stackoverflow
Solution 7 - PhpGordonView Answer on Stackoverflow
Solution 8 - PhpHemanta NandiView Answer on Stackoverflow
Solution 9 - PhpgonzoView Answer on Stackoverflow
Solution 10 - PhpNam G VUView Answer on Stackoverflow
Solution 11 - PhpTuhin BepariView Answer on Stackoverflow
Solution 12 - PhpDan BrayView Answer on Stackoverflow
Solution 13 - PhpChimdiView Answer on Stackoverflow
Solution 14 - PhpQ StudioView Answer on Stackoverflow
Solution 15 - PhpƁukasz SzpakView Answer on Stackoverflow
Solution 16 - PhpSaeed.ModarresiView Answer on Stackoverflow