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
Asaph
155k25 gold badges190 silver badges194 bronze badges
asked Jan 12, 2010 at 17:17
5
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];
}
Max
3451 gold badge3 silver badges10 bronze badges
answered Jan 12, 2010 at 17:23
Felix KlingFelix Kling
767k171 gold badges1068 silver badges1114 bronze badges
9
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
* @version 1.0.1
* @link //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]];
}
answered Oct 6, 2012 at 21:17
itsjaviitsjavi
2,5762 gold badges20 silver badges24 bronze badges
3
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];
}
}
}
answered Jan 12, 2010 at 17:32
symcbeansymcbean
46.9k6 gold badges56 silver badges89 bronze badges
2
The best solution is!
bstpierre
28.9k14 gold badges67 silver badges101 bronze badges
answered Apr 21, 2011 at 0:28
blackblack
3453 silver badges2 bronze badges
7
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 ];
}
}
Mr.Wizard
24k5 gold badges42 silver badges119 bronze badges
answered Apr 29, 2011 at 15:47
kzotykzoty
1511 silver badge2 bronze badges
1
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
answered Jan 12, 2010 at 18:10
GordonGordon
307k72 gold badges525 silver badges549 bronze badges
1
from the last 4th line , make this
$source = 'wordpress';//i.e. your source path
and
$destination ='b';
Guern
1,1891 gold badge11 silver badges30 bronze badges
answered Mar 6, 2013 at 20:40
0
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;
}
answered Jan 4, 2013 at 11:23
gonzogonzo
5186 silver badges6 bronze badges
2
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[];
}
}
answered Dec 10, 2011 at 19:59
Nam G VUNam G VU
31.4k67 gold badges218 silver badges355 bronze badges
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"];
answered Jan 11, 2018 at 12:36
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.
answered Oct 24, 2018 at 19:00
Dan BrayDan Bray
6,7403 gold badges49 silver badges63 bronze badges
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.
answered Apr 27, 2020 at 23:52
ChimdiChimdi
1571 silver badge7 bronze badges
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 //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 ] ];
answered Sep 10, 2020 at 8:49
Q StudioQ Studio
1,7763 gold badges15 silver badges17 bronze badges
// using exec
function rCopy[$directory, $destination]
{
$command = sprintf['cp -r %s/* %s', $directory, $destination];
exec[$command];
}
answered Jul 11, 2018 at 7:56
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 . '
';
}else{
echo 'Failed transfer for:' . $srcPath . '
';
}
}
}
}
}
answered Jun 20, 2021 at 5:46
1
I find this to be way simpler, more easily customizable, and to not require any dependency:
foreach[glob["old_location/*"] as $file] {
copy[$file, "new_location/" . basename[$file]];
}
answered Aug 18 at 18:19
Vic SeedoubleyewVic Seedoubleyew
9,8916 gold badges50 silver badges71 bronze badges