Recursively copying directories in PHP
Posted on April 5th, 2004 in Code Repository | 30 Comments »
This function allows you to copy an entire directory tree recursively. Symlinks on both operating systems are also accommodated for.
/**
* 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/repos/v/function.copyr.php
* @param string $source Source path
* @param string $dest Destination path
* @return bool Returns TRUE on success, FALSE on failure
*/
function copyr($source, $dest)
{
// 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);
}
// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Deep copy directories
copyr("$source/$entry", "$dest/$entry");
}
// Clean up
$dir->close();
return true;
}
Just to make sure this function works perfectly, we can do some testing:
// Create a directory and file tree
mkdir('testcopy');
mkdir('testcopy/one-a');
touch('testcopy/one-a/testfile');
mkdir('testcopy/one-b');
// Add some hidden files for good measure
touch('testcopy/one-b/.hiddenfile');
mkdir('testcopy/one-c');
touch('testcopy/one-c/.hiddenfile');
// Add some more depth
mkdir('testcopy/one-c/two-a');
touch('testcopy/one-c/two-a/testfile');
mkdir('testcopy/one-d/');
// Test that symlinks are created properly
mkdir('testlink');
touch('testlink/testfile');
symlink(getcwd() . '/testlink/testfile', 'testcopy/one-d/my-symlink');
symlink(getcwd() . '/testlink', 'testcopy/one-d/my-symlink-dir');
symlink('../', 'testcopy/one-d/my-symlink-relative');
$status = copyr('testcopy', 'testcopy-copy');
if (file_exists('testcopy-copy')
&& file_exists('testcopy-copy/one-b/.hiddenfile')
&& file_exists('testcopy-copy/one-c/two-a/testfile')
&& is_link('testcopy-copy/one-d/my-symlink-relative')
&& (readlink('testcopy-copy/one-d/my-symlink-relative') == '../')
&& is_link('testcopy-copy/one-d/my-symlink')) {
echo "TEST PASSED";
} else {
echo "TEST FAILED";
}
If everything works as expected, you should see a “TEST PASSED”.
30 Responses
Thanx for the perfect COPYR func
simple, but nice
THX
Awesome =)
thanks for the function! saved me some brainwaves during a hard programming evening…
Hello,
First Thanks for the nice code. I have something to say on your algorithm.
Here you can do simply this:
if ($dest !== “$source/$entry”) { copyr(”$source/$entry”, “$dest/$entry”); }
If it is a file you do test it in the beginning of your function. If it is the destination you just have to continue.
Hope I am useful!
Regards,
Dimitar Peev
[Editor's note: Good pick up, thanks]
thanks a squillion for this function! I hope you can enjoy the music from my site as a way thanks: futureboogiedotcom
thanks alot for this one. was too lazy to get my brain thinking about a recursive function for it. needed this one quite often. great that someone wrote in down
regards,
chill
Thanks dude! You write beautiful recursive code!
hehello;
good script ! thanks
very nice!
Excellent script, I hate thinking recursively.
This way may allow to copy the permissions over from the source file to the destination:
<?php
// get the current permissions from the source file or directory
$perms = substr(sprintf(’%o’, fileperms(”$source/$entry”)), -4);
?>
Then apply the permissions in $perms to the destination file after its been copied:
<?php
// Change the permissions on the destination file or folder
chmod (”$dest/$entry”, $perms);
?>
I’ve had numerous problems changing permissions in my php scripts. If you’re running PHP on a linux box then try editing the httpd.conf file and changing the user and group apache runs as.
Then make that user a member of the group the files that you want to chmod belongs to. Then restart apache.
Hope this helps.
Thanks for useful example
Good little script Aidan. Strange that there is no native PHP function.
thanks… i was so certain i’d break this thing in a matther of minutes but it seems to work pretty nicely!
Hi and thanx
thanks for the great function. I’ve addapted it to copy only files from certain types, passing an optional array as a third parameter. The result is here, and I hope it will be useful for others:
http://smalltalking.com/wiki/php:copyr
thank’s
Very nice! Thank’s
This is a function that does the same but uses a stack array to make it work faster.
Using recursion is (nearly?) always slower since it takes up extra resources for every instance of the function and all the set variables in the function instances.
Comments are always welcome
http://pastebin.com/775560
The stack array is damned cool. That’s a technique I’ve not seen before.
I spent hours trying to write something similar. thanks.
Thanx,simple but powerful algorithm
Should $source/$entry be $source . DIRECTORY_SEPARATOR . $entry to handle windows paths?
[Editor's Note: No, PHP automatically handles the conversion on Windows.]
thanks
really great. Thank you for all you guys!
Excellent script it works perfectly.
If you are looking to try to make the exec (cp) work, this is easier for real
Wow, This is my FIRST work script !
Thanks very much. I was looking for such a function today and this one is perfect
I have been commissioned to provide a univeral installation system for a company that has several php-based content/database management systems. I have used this copy function (copied asis into it’s own file) without a hitch. Very nice work, and is there somewhere I can send a donation?
Hi Nightmoon,
Glad you liked the function! Your feedback is donation enough, good luck with the project.