On my old VPS I was using the following code to copy the files and directories within a directory to a new directory that was created after the user submitted their form.
function copyr($source, $dest)
{
// Simple copy for a file
if (is_file($source)) {
return copy($source, $dest);
}
// Make destination directory
if (!is_dir($dest)) {
mkdir($dest);
$company = ($_POST['company']);
}
// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Deep copy directories
if ($dest !== "$source/$entry") {
copyr("$source/$entry", "$dest/$entry");
}
}
// Clean up
$dir->close();
return true;
}
copyr('Template/MemberPages', "Members/$company")
However now on my new VPS it will only create the main directory, but will not copy any of the files to it. I don't understand what could have changed between the 2 VPS's?
Try something like this:
$source = "dir/dir/dir";
$dest= "dest/dir";
mkdir($dest, 0755);
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());
}
}
Iterator iterate through all folders and subfolders and make copy of files from $source to $dest
Could I suggest that (assuming it's a *nix VPS) that you just do a system call to cp -r and let that do the copy for you.
This function copies folder recursivley very solid. I've copied it from the comments section on copy command of php.net
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);
}
I have changed Joseph's code (below), because it wasn't working for me. This is what works:
function cpy($source, $dest){
if(is_dir($source)) {
$dir_handle=opendir($source);
while($file=readdir($dir_handle)){
if($file!="." && $file!=".."){
if(is_dir($source."/".$file)){
if(!is_dir($dest."/".$file)){
mkdir($dest."/".$file);
}
cpy($source."/".$file, $dest."/".$file);
} else {
copy($source."/".$file, $dest."/".$file);
}
}
}
closedir($dir_handle);
} else {
copy($source, $dest);
}
}
[EDIT] added test before creating a directory (line 7)
The Symfony's FileSystem Component offers a good error handling as well as recursive remove and other useful stuffs. Using #OzzyCzech's great answer, we can do a robust recursive copy this way:
use Symfony\Component\Filesystem\Filesystem;
// ...
$fileSystem = new FileSystem();
if (file_exists($target))
{
$this->fileSystem->remove($target);
}
$this->fileSystem->mkdir($target);
$directoryIterator = new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS);
$iterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $item)
{
if ($item->isDir())
{
$fileSystem->mkdir($target . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
}
else
{
$fileSystem->copy($item, $target . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
}
}
Note: you can use this component as well as all other Symfony2 components standalone.
Here's what we use at our company:
static public function copyr($source, $dest)
{
// recursive function to copy
// all subdirectories and contents:
if(is_dir($source)) {
$dir_handle=opendir($source);
$sourcefolder = basename($source);
mkdir($dest."/".$sourcefolder);
while($file=readdir($dir_handle)){
if($file!="." && $file!=".."){
if(is_dir($source."/".$file)){
self::copyr($source."/".$file, $dest."/".$sourcefolder);
} else {
copy($source."/".$file, $dest."/".$file);
}
}
}
closedir($dir_handle);
} else {
// can also handle simple copy commands
copy($source, $dest);
}
}
function recurse_copy($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
recurse_copy("$source/$entry", "$dest/$entry");
}
// Clean up
$dir->close();
return true;
}
OzzyCheck's is elegant and original, but he forgot the initial mkdir($dest);
See below. No copy command is ever provided with contents only. It must fulfill its entire role.
$source = "dir/dir/dir";
$dest= "dest/dir";
mkdir($dest, 0755);
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());
}
}
Here's a simple recursive function to copy entire directories
source: http://php.net/manual/de/function.copy.php
<?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);
}
?>
Why not just ask the OS to take care of this?
system("cp -r olddir newdir");
Done.
<?php
/**
* code by Nk (nk.have.a#gmail.com)
*/
class filesystem
{
public static function normalizePath($path)
{
return $path.(is_dir($path) && !preg_match('#/$#', $path) ? '/' : '');
}
public static function rscandir($dir, $sort = SCANDIR_SORT_ASCENDING)
{
$results = array();
if(!is_dir($dir))
return $results;
$dir = self::normalizePath($dir);
$objects = scandir($dir, $sort);
foreach($objects as $object)
if($object != '.' && $object != '..')
{
if(is_dir($dir.$object))
$results = array_merge($results, self::rscandir($dir.$object, $sort));
else
array_push($results, $dir.$object);
}
array_push($results, $dir);
return $results;
}
public static function rcopy($source, $dest, $destmode = null)
{
$files = self::rscandir($source);
if(empty($files))
return;
if(!file_exists($dest))
mkdir($dest, is_int($destmode) ? $destmode : fileperms($source), true);
$source = self::normalizePath(realpath($source));
$dest = self::normalizePath(realpath($dest));
foreach($files as $file)
{
$file_dest = str_replace($source, $dest, $file);
if(is_dir($file))
{
if(!file_exists($file_dest))
mkdir($file_dest, is_int($destmode) ? $destmode : fileperms($file), true);
}
else
copy($file, $file_dest);
}
}
}
?>
/var/www/websiteA/backup.php :
<?php /* include.. */ filesystem::rcopy('/var/www/websiteA/', '../websiteB'); ?>
hmm. as that's complicated ))
function mkdir_recursive( $dir ){
$prev = dirname($dir);
if( ! file_exists($prev))
{
mkdir_recursive($prev);
}
if( ! file_exists($dir))
{
mkdir($dir);
}
}
...
$srcDir = "/tmp/from"
$dstDir = "/tmp/to"
mkdir_recursive($dstDir);
foreach( $files as $file){
copy( $srcDir."/".$file, $dstDir."/".$file);
}
$file - somthing like that file.txt
I guess you should check user(group)rights. You should consider chmod for example, depending on how you run (su?)PHP. You could possibly also choose to modify your php configuration.
There were some issues with the functions that I tested in the thread and here is a powerful function that covers everything. Highlights:
No need to have an initial or intermediate source directories. All of the directories up to the source directory and to the copied directories will be handled.
Ability to skip directory or files from an array. (optional) With the global $skip; skipping of files even under sub level directories are handled.
Full recursive support, all the files and directories in multiple depth are supported.
$from = "/path/to/source_dir";
$to = "/path/to/destination_dir";
$skip = array('some_file.php', 'somedir');
copy_r($from, $to, $skip);
function copy_r($from, $to, $skip=false) {
global $skip;
$dir = opendir($from);
if (!file_exists($to)) {mkdir ($to, 0775, true);}
while (false !== ($file = readdir($dir))) {
if ($file == '.' OR $file == '..' OR in_array($file, $skip)) {continue;}
if (is_dir($from . DIRECTORY_SEPARATOR . $file)) {
copy_r($from . DIRECTORY_SEPARATOR . $file, $to . DIRECTORY_SEPARATOR . $file);
}
else {
copy($from . DIRECTORY_SEPARATOR . $file, $to . DIRECTORY_SEPARATOR . $file);
}
}
closedir($dir);
}
Recursively copies files from source to target, with choice of overwriting existing files on the target.
function copyRecursive($sourcePath, $targetPath, $overwriteExisting) {
$dir = opendir($sourcePath);
while (($file = readdir($dir)) !== false) {
if ($file == "." || $file == "..") continue; // ignore these.
$source = $sourcePath . "/" . $file;
$target = $targetPath. "/" . $file;
if (is_dir($source) == true) {
// create the target directory, if it does not exist.
if (file_exists($target) == false) #mkdir($target);
copyRecursive($source, $target, $overwriteExisting);
} else {
if ((file_exists($target) == false) || ($overwriteExisting == true)) {
copy($source, $target);
}
}
}
closedir($dir);
}
Related
I have a directory /main with folders and files inside those folders.
I want to keep directory /main but delete everything in it:
$di = new RecursiveDirectoryIterator('/main');
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
if(!is_dir($filename)){
unlink($filename);
}
};
This is deleting the files inside the folders, leaving /main with a list of empty folders, how do I delete these now?
I know this should be possible to integrate inside the loop, I tried rmdir without success.
Try this code
UPDATED ANSWER:
$dir = '/home/XXXXX/public_html/';
foreach(glob($dir.'*.*') as $v){
echo $v;
// unlink($v);
}
destroy_dir($dir);
function destroy_dir($dir) {
if (!is_dir($dir) || is_link($dir)) return unlink($dir);
foreach (scandir($dir) as $file) {
if ($file == '.' || $file == '..') continue;
if (!destroy_dir($dir . DIRECTORY_SEPARATOR . $file)) {
chmod($dir . DIRECTORY_SEPARATOR . $file, 0777);
if (!destroy_dir($dir . DIRECTORY_SEPARATOR . $file)) return false;
};
}
return rmdir($dir);
}
Here, Code is not tested.
function delete_directory_files($dirname) {
if (is_dir($dirname))
$dir_handle = opendir($dirname);
if (!$dir_handle)
return false;
while($file = readdir($dir_handle)) {
if ($file != "." && $file != "..") {
if (!is_dir($dirname."/".$file))
unlink($dirname."/".$file);
else
delete_directory($dirname.'/'.$file);
}
}
closedir($dir_handle);
return true;
}
I want to move all files and folders inside a folder to another folder. I found a code to copy all files inside a folder to another folder.
move all files in a folder to another
// Get array of all source files
$files = scandir("source");
// Identify directories
$source = "source/";
$destination = "destination/";
// Cycle through all source files
foreach ($files as $file) {
if (in_array($file, array(".",".."))) continue;
// If we copied this successfully, mark it for deletion
if (copy($source.$file, $destination.$file)) {
$delete[] = $source.$file;
}
}
// Delete all successfully-copied files
foreach ($delete as $file) {
unlink($file);
}
How do I change this to move all folders and files inside this folder to another folder.
This is what i use
// Function to remove folders and files
function rrmdir($dir) {
if (is_dir($dir)) {
$files = scandir($dir);
foreach ($files as $file)
if ($file != "." && $file != "..") rrmdir("$dir/$file");
rmdir($dir);
}
else if (file_exists($dir)) unlink($dir);
}
// Function to Copy folders and files
function rcopy($src, $dst) {
if (file_exists ( $dst ))
rrmdir ( $dst );
if (is_dir ( $src )) {
mkdir ( $dst );
$files = scandir ( $src );
foreach ( $files as $file )
if ($file != "." && $file != "..")
rcopy ( "$src/$file", "$dst/$file" );
} else if (file_exists ( $src ))
copy ( $src, $dst );
}
Usage
rcopy($source , $destination );
Another example without deleting destination file or folder
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);
}
Please See: http://php.net/manual/en/function.copy.php for more juicy examples
Thanks
:)
Use rename instead of copy.
Unlike the C function with the same name, rename can move a file from one file system to another (since PHP 4.3.3 on Unix and since PHP 5.3.1 on Windows).
You need the custom function:
Move_Folder_To("./path/old_folder_name", "./path/new_folder_name");
function code:
function Move_Folder_To($source, $target){
if( !is_dir($target) ) mkdir(dirname($target),null,true);
rename( $source, $target);
}
Think this should do the trick:
http://php.net/manual/en/function.shell-exec.php
shell_exec("mv sourcedirectory path_to_destination");
Hope this help.
I think the answers are not complete for me, beacuse DIRECTORY_SEPARATOR are not defined on any answer (thans to Edgar Aivars for remember that!), but I want to write my solution for move (rename), copy and delete directory structures (based on this post info, the credits are for yours!).
defined('DS') ? NULL : define('DS',DIRECTORY_SEPARATOR);
function full_move($src, $dst){
full_copy($src, $dst);
full_remove($src);
}
function full_copy($src, $dst) {
if (is_dir($src)) {
#mkdir( $dst, 0777 ,TRUE);
$files = scandir($src);
foreach($files as $file){
if ($file != "." && $file != ".."){
full_copy("$src".DS."$file", "$dst".DS."$file");
}
}
} else if (file_exists($src)){
copy($src, $dst);
}
}
function full_remove($dir) {
if (is_dir($dir)) {
$files = scandir($dir);
foreach ($files as $file){
if ($file != "." && $file != ".."){
full_remove("$dir".DS."$file");
}
}
rmdir($dir);
}else if (file_exists($dir)){
unlink($dir);
}
}
I hope this hepls anyone! (lile me in the future :D )
EDIT: Spell corrections... :(
My attempt at a recursive move function, after days of research and going through other excellent examples out there.
It provides for an overwriteExisting flag for choice. Consequently, if the overwriteExisting flag is false, the file will not be moved and the folder containing the file would not be removed.
function moveRecursive($sourcePath, $targetPath, $overwriteExisting) {
clearstatcache(); // not sure if this helps, or is even required.
$dir = opendir($sourcePath);
while (($file = readdir($dir)) !== false) {
echo nl2br($file . "\n");
if ($file != "." && $file != "..") {
if (is_dir($sourcePath . "/" . $file) == true) {
if (is_dir($targetPath. "/" . $file) == false) {
// I believe rename would be faster than copying and unlinking.
rename($sourcePath . "/" . $file, $targetPath. "/" . $file);
} else {
moveRecursive($sourcePath . "/" . $file, $targetPath ."/" . $file, $overwriteExisting);
if ($files = glob($sourcePath . "/*")) {
// remove the empty directory.
if (#rmdir($sourcePath . "/" . $file) == false) {
echo nl2br("rmdir has not removed empty directory " . $sourcePath . "/" . $file . "\n");
}
} else {
// when overwriteExisting flag is false, there would be some files leftover.
echo nl2br("cannot remove. not empty, count = " . count(glob($sourcePath . "/*")) . " -> " . $sourcePath . "/" . $file . "\n");
}
}
} else {
if (file_exists($targetPath. "/" . $file)) {
if ($overwriteExisting == true) {
// overwrite the file.
rename($sourcePath . "/" . $file, $targetPath. "/" . $file);
}
} else {
// if the target file does not exist, simply move the file.
rename($sourcePath . "/" . $file, $targetPath. "/" . $file);
}
}
}
}
closedir($dir);
}
I have spent about 3 hours testing this in many different scenarios, and it works most of the time. Although, sometimes, it gives me an Access denied code(5) error on Windows, which I have been unable to figure out. This is why I have put the clearstatcache() function up at the top, after reading up on its documentation. I don't know whether this is its appropriate usage. I can definitely imagine that it would slow down the function.
I can also imagine that this method may be faster than the copy -> unlink cycle, because if a target sub-folder does not exist, the whole folder tree below would be just moved. However, I am not sure and don't have the experience to conduct exhaustive tests, yet.
$src = 'user_data/company_2/T1/';
$dst = 'user_data/company_2/T2/T1/';
rcopy($src, $dst); // Call function
// Function to Copy folders and files
function rcopy($src, $dst) {
if (file_exists ( $dst ))
rrmdir ( $dst );
if (is_dir ( $src )) {
mkdir ( $dst );
$files = scandir ( $src );
foreach ( $files as $file )
if ($file != "." && $file != "..")
rcopy ( "$src/$file", "$dst/$file" );
} else if (file_exists ( $src ))
copy ( $src, $dst );
rrmdir ( $src );
}
// Function to remove folders and files
function rrmdir($dir) {
if (is_dir($dir)) {
$files = scandir($dir);
foreach ($files as $file)
if ($file != "." && $file != "..") rrmdir("$dir/$file");
rmdir($dir);
}
else if (file_exists($dir)) unlink($dir);
}
I use it
// function used to copy full directory structure from source to target
function full_copy( $source, $target )
{
if ( is_dir( $source ) )
{
mkdir( $target, 0777 );
$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 );
}
}
rmdir("./uploads/temp/".$user."/");
I have many files in a directory I wish to remove in my PHP script, however these is no way for me to unlink() the file first. Is there a way I co do
unlink(* FROM (dir=)) // don't downvote the long shot
// delete all files from the dir first
// then delete that dir
Reference a directory has to be empty in order to delete it, see php.net/manual/en/function.rmdir.php
You can use the DirectoryIterator and unlink together.
use this
function delete_directory($dirname) {
if (is_dir($dirname))
$dir_handle = opendir($dirname);
if (!$dir_handle)
return false;
while($file = readdir($dir_handle)) {
if ($file != "." && $file != "..") {
if (!is_dir($dirname."/".$file))
unlink($dirname."/".$file);
else
delete_directory($dirname.'/'.$file);
}
}
closedir($dir_handle);
rmdir($dirname);
return true;
}
This code can easily be improved upon, as it's a quick hack, but it takes a directory as an argument and then uses functional recursion to delete all files and folders within, and then finally removes the directory. Nice and quick, too.
There is no other way except to delete all files first using one way or another and then remove directory.
public static function deleteDir($dirPath) {
if (! is_dir($dirPath)) {
throw new InvalidArgumentException('$dirPath must be a directory');
}
if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
$dirPath .= '/';
}
$files = glob($dirPath . '*', GLOB_MARK);
foreach ($files as $file) {
if (is_dir($file)) {
self::deleteDir($file);
} else {
unlink($file);
}
}
rmdir($dirPath);
}
Try using glob to loop over the files in the directory to delete
foreach (glob('/path/to/directory/*') as $file){
unlink('/path/to/directory/' . $file);
}
Check this http://lixlpixel.org/recursive_function/php/recursive_directory_delete/
function recursive_remove_directory($directory, $empty=FALSE)
{
if(substr($directory,-1) == '/')
{
$directory = substr($directory,0,-1);
}
if(!file_exists($directory) || !is_dir($directory))
{
return FALSE;
}elseif(is_readable($directory))
{
$handle = opendir($directory);
while (FALSE !== ($item = readdir($handle)))
{
if($item != '.' && $item != '..')
{
$path = $directory.'/'.$item;
if(is_dir($path))
{
recursive_remove_directory($path);
}else{
unlink($path);
}
}
}
closedir($handle);
if($empty == FALSE)
{
if(!rmdir($directory))
{
return FALSE;
}
}
}
return TRUE;
}
You can delete it recursively:
public function delete_folder ($path) {
$handle = opendir($path);
while ($file = readdir($handle)) {
if ($file != '..' && $file != '.') {
if (is_file($path . DS . $file))
unlink($path . DS . $file);
else
delete_folder($path . DS . $file);
}
}
closedir($handle);
rmdir($tmp_path);
}
delete_folder('path/to/folder');
I am using windows, Mysql DB, PHP
I am building the Joomla Component whose one of the functionality is to synchronize the folders
I want to sync two folders of different name.. How can I do this? It has to be dne in the same machine, no two different servers are involved in it..
How to sync two folders in PHP?
UPDATED
IN Context of Alex Reply
What if i am editing any .jpg file in one folder and saving it with same name as it has, also this file is already present in other folder. And I want this edited pic to be transfered to the other folder.? also I have Joomla's nested file structured to be compared
UPDATE 2
I have a recursive function which will output me the complete structure of folder... if u can just use it to concat ur solution in...
<?
function getDirectory($path = '.', $ignore = '') {
$dirTree = array ();
$dirTreeTemp = array ();
$ignore[] = '.';
$ignore[] = '..';
$dh = #opendir($path);
while (false !== ($file = readdir($dh))) {
if (!in_array($file, $ignore)) {
if (!is_dir("$path/$file")) {
$stat = stat("$path/$file");
$statdir = stat("$path");
$dirTree["$path"][] = $file. " === ". date('Y-m-d H:i:s', $stat['mtime']) . " Directory == ".$path."===". date('Y-m-d H:i:s', $statdir['mtime']) ;
} else {
$dirTreeTemp = getDirectory("$path/$file", $ignore);
if (is_array($dirTreeTemp))$dirTree = array_merge($dirTree, $dirTreeTemp);
}
}
}
closedir($dh);
return $dirTree;
}
$ignore = array('.htaccess', 'error_log', 'cgi-bin', 'php.ini', '.ftpquota');
$dirTree = getDirectory('.', $ignore);
?>
<pre>
<?
print_r($dirTree);
?>
</pre>
I just ran this, and it seems to work
function sync() {
$files = array();
$folders = func_get_args();
if (empty($folders)) {
return FALSE;
}
// Get all files
foreach($folders as $key => $folder) {
// Normalise folder strings to remove trailing slash
$folders[$key] = rtrim($folder, DIRECTORY_SEPARATOR);
$files += glob($folder . DIRECTORY_SEPARATOR . '*');
}
// Drop same files
$uniqueFiles = array();
foreach($files as $file) {
$hash = md5_file($file);
if ( ! in_array($hash, $uniqueFiles)) {
$uniqueFiles[$file] = $hash;
}
}
// Copy all these unique files into every folder
foreach($folders as $folder) {
foreach($uniqueFiles as $file => $hash) {
copy($file, $folder . DIRECTORY_SEPARATOR . basename($file));
}
}
return TRUE;
}
// usage
sync('sync', 'sync2');
You simply give it a list of folders to sync, and it will sync all files. It will attempt to skip files that appear the same (i.e. of whom their hash collides).
This however does not take into account last modified dates or anything. You will have to modify itself to do that. It should be pretty simple, look into filemtime().
Also, sorry if the code sucks. I had a go at making it recursive, but I failed :(
For a one way copy, try this
$source = '/path/to/source/';
$destination = 'path/to/destination/';
$sourceFiles = glob($source . '*');
foreach($sourceFiles as $file) {
$baseFile = basename($file);
if (file_exists($destination . $baseFile)) {
$originalHash = md5_file($file);
$destinationHash = md5_file($destination . $baseFile);
if ($originalHash === $destinationHash) {
continue;
}
}
copy($file, $destination . $baseFile);
}
It sounds like you just want to copy all files from one folder to another. The second example will do this.
I using this, and it seems to work, also make new dir if not exist .....
//sync the files and folders
function smartCopy($source, $dest, $options=array('folderPermission'=>0755,'filePermission'=>0755))
{
//$result = false;
if (is_file($source)) {
if ($dest[strlen($dest)-1]=='/') {
if (!file_exists($dest)) {
cmfcDirectory::makeAll($dest,$options['folderPermission'],true);
}
$__dest=$dest."/".basename($source);
} else {
$__dest=$dest;
}
$result = copy($source, $__dest);
chmod($__dest,$options['filePermission']);
} elseif(is_dir($source)) {
if ($dest[strlen($dest)-1]=='/') {
if ($source[strlen($source)-1]=='/') {
//Copy only contents
} else {
//Change parent itself and its contents
$dest=$dest.basename($source);
#mkdir($dest);
chmod($dest,$options['filePermission']);
}
} else {
if ($source[strlen($source)-1]=='/') {
//Copy parent directory with new name and all its content
#mkdir($dest,$options['folderPermission']);
chmod($dest,$options['filePermission']);
} else {
//Copy parent directory with new name and all its content
#mkdir($dest,$options['folderPermission']);
chmod($dest,$options['filePermission']);
}
}
$dirHandle=opendir($source);
while($file=readdir($dirHandle))
{
if($file!="." && $file!="..")
{
if(!is_dir($source."/".$file)) {
$__dest=$dest."/".$file;
} else {
$__dest=$dest."/".$file;
}
echo "$source/$file ||| $__dest<br />";
$result=smartCopy($source."/".$file, $__dest, $options);
}
}
closedir($dirHandle);
} else {
$result=false;
}
return $result;
}
//end of function
echo smartCopy('media', 'mobile/images');
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 {
if(md5_file($src . '/' . $file) !== md5_file($dst . '/' . $file))
{
echo 'copying' . $src . '/' . $file; echo '<br/>';
copy($src . '/' . $file, $dst . '/' . $file);
}
}
}
}
closedir($dir);
}
If its on a Linux/Posix system then (depending on what access you have) it may be a lot simpler / faster to:
$chk=`rsync -qrRlpt --delete $src $dest`;
C.
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
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);
}
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));
}
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);
}
}
}
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
?>
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
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 );
}
}
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
<?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';
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;
}
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();
}
}
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");
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.
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.
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 ) );
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));
}
// using exec
function rCopy($directory, $destination)
{
$command = sprintf('cp -r %s/* %s', $directory, $destination);
exec($command);
}
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>';
}
}
}
}
}