The Server Pages
:: TSP Menu
- Home
- Authors
- Glossary
- RSS Feed

:: Servers
- CPanel
- Hosting
- Linux
- Windows

:: Webmaster
- Databases
- Design
- PHP
- Search Engines

:: Scripts
- Scripts

:: Documentation
- PHP Manual

:: Other
- Errors & Solutions
- TechPunt
- Wojjie

search for in the

delete> <clearstatcache
[edit] Last updated: Sat, 12 May 2012

view this page in

copy

(PHP 4, PHP 5)

copyCopies file

Description

bool copy ( string $source , string $dest [, resource $context ] )

Makes a copy of the file source to dest.

If you wish to move a file, use the rename() function.

Parameters

source

Path to the source file.

dest

The destination path. If dest is a URL, the copy operation may fail if the wrapper does not support overwriting of existing files.

Warning

If the destination file already exists, it will be overwritten.

context

A valid context resource created with stream_context_create().

Return Values

Returns TRUE on success or FALSE on failure.

Changelog

Version Description
5.3.0 Added context support.
4.3.0 Both source and dest may now be URLs if the "fopen wrappers" have been enabled. See fopen() for more details.

Examples

Example #1 copy() example

<?php
$file 
'example.txt';
$newfile 'example.txt.bak';

if (!
copy($file$newfile)) {
    echo 
"failed to copy $file...\n";
}
?>

See Also



delete> <clearstatcache
[edit] Last updated: Sat, 12 May 2012
 
add a note add a note User Contributed Notes copy
nikonier 24-Nov-2011 01:22
I tried to copy a file from /tmp to /var/www/html.
But i always get an permission denied (even after a chmod 0777 to the /var/www/html directory)

After spending a lot of hours searching for my error, I found it.
But not where I thought it....It was the turned on SELinux.
(Fedora 15).So i do a echo 0 >/selinux/enforce and everything works perfect. (Look here for disabling SELinux: http://www.crypt.gen.nz/selinux/disable_selinux.html)

regards,
Juergen
ravindersingh dot jal at gmailDELTHIS dot com 08-Jul-2011 04:20
I had to copy a directory but the top level folder name would be different at dest i.e. dirparent/dirchild -> diff/dirchild . I thought I would just copy and rename the destination but you can't rename non empty directories. I wrote this function to work around this:

<?php
function RecursiveCopy($source, $dest, $diffDir = ''){
   
$sourceHandle = opendir($source);
    if(!
$diffDir)
           
$diffDir = $source;
   
   
mkdir($dest . '/' . $diffDir);
   
    while(
$res = readdir($sourceHandle)){
        if(
$res == '.' || $res == '..')
            continue;
       
        if(
is_dir($source . '/' . $res)){
           
RecursiveCopy($source . '/' . $res, $dest, $diffDir . '/' . $res);
        } else {
           
copy($source . '/' . $res, $dest . '/' . $diffDir . '/' . $res);
           
        }
    }
}
?>
promaty at gmail dot com 17-May-2011 11:13
Here is a simple script that I use for removing and copying non-empty directories. Very useful when you are not sure what is the type of a file.

I am using these for managing folders and zip archives for my website plugins.

<?php

// removes files and non-empty directories
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);
}

// copies files and non-empty directories
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);
}
?>

Cheers!
cory at veck dot ca 29-Apr-2011 11:17
My own 'cp -R' written in PHP.

Hopefully it will work for your situation. I'm using it in a web based file manager for my CMS.

<?php

    define
('DS', DIRECTORY_SEPARATOR); // I always use this short form in my code.

   
function copy_r( $path, $dest )
    {
        if(
is_dir($path) )
        {
            @
mkdir( $dest );
           
$objects = scandir($path);
            if(
sizeof($objects) > 0 )
            {
                foreach(
$objects as $file )
                {
                    if(
$file == "." || $file == ".." )
                        continue;
                   
// go on
                   
if( is_dir( $path.DS.$file ) )
                    {
                       
copy_r( $path.DS.$file, $dest.DS.$file );
                    }
                    else
                    {
                       
copy( $path.DS.$file, $dest.DS.$file );
                    }
                }
            }
            return
true;
        }
        elseif(
is_file($path) )
        {
            return
copy($path, $dest);
        }
        else
        {
            return
false;
        }
    }

?>
Yoga Wibowo Aji 08-Feb-2011 09:22
you can try this code if you don't having permission to access the shell
this code is alternative for file copy

<?php
$source
= 'myfile.doc';
$destination = 'clonefile.doc';

$data = file_get_contents($source);

$handle = fopen($destination, "w");
fwrite($handle, $data);
fclose($handle);
?>
tomas at slax dot org 21-Jan-2011 04:09
Very important to note is that copy() handles url wrappers, but sometimes incorrectly. For example, you can copy a file like

<?php
   copy
("http://example.net/file.dat","./local_file.dat");
?>

However, it doesn't work with spaces in filename (as of PHP 5.2.13, please test in newer versions).

<?php
   copy
("http://example.net/file with space.dat","./local_file.dat");
?>

To fix this, you need to replace spaces with %20.
eng-ayman at aymax dot net 30-Aug-2009 05:48
some hosts disable copy() function and say its for security

and for some copy is important so this is and simple function that do same as copy function effect

how smart php can help us l like php

<?php
   
function copyemz($file1,$file2){
         
$contentx =@file_get_contents($file1);
                  
$openedfile = fopen($file2, "w");
                  
fwrite($openedfile, $contentx);
                  
fclose($openedfile);
                    if (
$contentx === FALSE) {
                   
$status=false;
                    }else
$status=true;
                   
                    return
$status;
    }
?>
Sina Salek 02-Jun-2009 05:02
Thanks for all the comments, i wrote this function for fully supporting file and directory copy.
As you may have noticed there are feature that didn't have time to implement , but if you have time to implement them or even add more cool features, please notify me as well :). you can find me here http://sina.salek.ws/en/contact

PS : It was very useful for me, hope you find it useful as well.

<?php
   
/**
     * Copy file or folder from source to destination, it can do
     * recursive copy as well and is very smart
     * It recursively creates the dest file or directory path if there weren't exists
     * Situtaions :
     * - Src:/home/test/file.txt ,Dst:/home/test/b ,Result:/home/test/b -> If source was file copy file.txt name with b as name to destination
     * - Src:/home/test/file.txt ,Dst:/home/test/b/ ,Result:/home/test/b/file.txt -> If source was file Creates b directory if does not exsits and copy file.txt into it
     * - Src:/home/test ,Dst:/home/ ,Result:/home/test/** -> If source was directory copy test directory and all of its content into dest     
     * - Src:/home/test/ ,Dst:/home/ ,Result:/home/**-> if source was direcotry copy its content to dest
     * - Src:/home/test ,Dst:/home/test2 ,Result:/home/test2/** -> if source was directoy copy it and its content to dest with test2 as name
     * - Src:/home/test/ ,Dst:/home/test2 ,Result:->/home/test2/** if source was directoy copy it and its content to dest with test2 as name
     * @todo
     *     - Should have rollback technique so it can undo the copy when it wasn't successful
     *  - Auto destination technique should be possible to turn off
     *  - Supporting callback function
     *  - May prevent some issues on shared enviroments : http://us3.php.net/umask
     * @param $source //file or folder
     * @param $dest ///file or folder
     * @param $options //folderPermission,filePermission
     * @return boolean
     */
   
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;
    }
?>
gimmicklessgpt at gmail dot com 20-May-2009 04:04
Here's a simple recursive function to copy entire directories

Note to do your own check to make sure the directory exists that you first call it on.

<?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);
}
?>
nensa at zeec dot biz 27-Jan-2009 11:44
When I recently had to copy a few millions of small files (< 1kb) from one NAS to another and for some reasons had to do that file by file I compared the following function with copy($src, $dest) and shell_exec("cp -r $src $dest").

Surprisingly stream_copy seamed to be slightly faster (at least in this specific context).

<?php
   
function stream_copy($src, $dest)
    {
       
$fsrc = fopen($src,'r');
       
$fdest = fopen($dest,'w+');
       
$len = stream_copy_to_stream($fsrc,$fdest);
       
fclose($fsrc);
       
fclose($fdest);
        return
$len;
    }
?>
allasso residing at signalmesa dot com 28-Nov-2008 03:15
As far as recursive copy, something like this seems to work fine for me:

<?php
$output
= shell_exec( " cp -r -a dir_source/* dir_dest 2>&1 " )
echo
$output
?>

Of course you need to get all your permissions clear.  You can do the necessary stuff to use variables.

You could also do this to create the destination directory:

<?php
shell_exec
( " cp -r -a dir_source dir_dest 2>&1 " )
?>

This will create a new directory called "dir_dest" if it does not already exist. This is a bit risky though if your situation is ambiguous, and you want to continue to make backups etc, 'cause if you do it twice you end up with:

dir_destination/dir_source

to avoid that one could do something like:

<?php
shell_exec
( " mkdir dir_dest;  cp -r -a dir_source/* dir_dest 2>&1 " )
?>

Maybe someone can tell me when or why it would be better to use all that PHP code I see here.
jim dot mcgowen at cox dot net 14-Jul-2008 10:50
On Windows (not sure about Linux) copy will overwrite an existing file but will not change the case of the existing filename.

In other words if I have a file named "Myfile.txt" and I overwrite it using copy with a file named "MyFile.txt" it will overwrite it but the filename will remain "Myfile.txt".

If this is a problem (as it was for me) use unlink to delete the existing file first.
steve a h 20-Jun-2008 02:44
Don't forget; you can use copy on remote files, rather than doing messy fopen stuff.  e.g.

<?php
if(!@copy('http://someserver.com/somefile.zip','./somefile.zip'))
{
   
$errors= error_get_last();
    echo
"COPY ERROR: ".$errors['type'];
    echo
"<br />\n".$errors['message'];
} else {
    echo
"File copied from remote!";
}
?>
tom at r dot je 18-Jun-2008 08:30
It's worth noting that copy() sets the destination file's last modified time/date.
jtaylor -at- ashevillenc -dot- com 13-Feb-2007 12:48
It seems as though you can only use move_uploaded_file() once on a temporary file that has been uploaded through a form. Most likely the action this function takes destroys the temporary file after it has been moved, assuming permanent placement on a file system.

Attempting to use the function again in the same PHP script will return false and not move the file.

I ran into this when an image that was uploaded did not need resizing (smaller than a size threshold) and after moving the temporary upload to the "originals" directory, an attempt was made to again move the temporary file to another folder.

This behavior is understandable, but be careful - in this instance, I simply used copy() on the file that was already uploaded.
mspreij 27-Jan-2007 08:20
This function creates a new filename to use for a copy of the given filename, its behaviour was mostly sto^Wborrowed from how the OS X Finder (*1) does it.
Note it *doesn't* actually copy the file, it just returns the new name. I needed it to work regardless of data source (filesystem, ftp, etc).

It also tries to match the current name as neatly as possible:
foo.txt -> foo copy.txt -> foo copy 1.txt -> foo copy 2.txt [etc]
foo.bar.baz.jpg -> foo.bar.baz copy.jpg
foobar -> foobar copy -> foobar copy 1 [etc]
".txt" -> .txt copy, and "txt." -> txt. copy
file.longextension -> file.longextension copy

It keeps trying until it finds a name that is not yet taken in $list, or until it looped 500 times (change as needed).

If the renamed file becomes longer than max filename length, it starts chopping away at the end of the part before where it adds " copy": reallylong...filename.txt -> reallylong...filena copy.txt

<?php

// $orig = current name, of course
// $list = array of filenames in the target directory (if none given, it will still return a new name)
// $max = max length of filename
function duplicate_name($orig, $list = array(), $max = 64) {
 
$ext = '';
 
$counter = 0;
 
$list = (array) $list;
 
$max = (int) $max;
 
$newname = $orig;
  do {
   
$name = $newname; # name in, newname out
   
if (preg_match('/ copy$| copy \d+$/', $name, $matches)) {
     
// don't even check for extension, name ends with " copy[ digits]"
    // preg hereunder matches anything with at least one period in the middle and an extension of 1-5 characters
   
}elseif (preg_match('/(.+)\.([^.]{1,5})$/', $name, $parts)) {
     
// split to name & extension
     
list($name, $ext) = array($parts[1], $parts[2]);
    }
    if (
preg_match('/ copy (\d+)$/', $name, $digits)) {
     
$newname = substr($name, 0, - strlen($digits[1])) . ($digits[1] + 1);
     
# $cutlen is only used for the bit at the end where it checks on max filename length
     
$cutlen = 6 + strlen($digits[1]+1); // ' copy ' + digits
   
}elseif(preg_match('/ copy$/', $name, $digits)) {
     
$newname = $name . ' 1';
     
$cutlen = 7; // ' copy' + ' 1'
   
}else{
     
$newname = $name . ' copy';
     
$cutlen = 5; // ' copy'
   
}
    if (
$ext) {
     
$newname .= '.' . $ext;
     
$cutlen += strlen($ext) + 1;
    }
    if (
$max > 0) {
      if (
strlen($newname) > $max) {
       
$newname = substr($newname, 0, max($max - $cutlen, 0)) . substr($newname, -$cutlen);
        if (
strlen($newname) > $max) {echo "duplicate_name() error: Can't keep the new name under given max length.\n"; return false;}
      }
    }
    if (
$counter++ > 500) {echo "duplicate_name() error: Too many similarly named files or infinite while loop.\n"; return false;}
  } while (
in_array($newname, $list));
  return
$newname;
}

?>

*1) The Finder seems to check the extension vs a list of known extensions, this function considers it valid if it's 5 or fewer characters long.

ps. sorry for taking up so much space! :-)
fred dot haab at gmail dot com 18-Aug-2006 05:49
Just some caveats for people to consider when working with this copy function.  Like everyone else, I needed a recursive copy function, so I wrote one.

It worked great until I hit a file greater than 2GB, at which point I got a File Size Exceeded error.  I've read that you can recompile PHP with larger file support, but I'm not able to do this on my system.

So I used exec to copy one file at a time (I need to do other things to the file, so can't just do an exec with "cp -r").  Then I ran into problems with spaces in the names.  The escapeshellcmd and escapeshellargs functions don't seem to cleanup spaces, so I wrote my own function to do that.
cooper at asu dot ntu-kpi dot kiev dot ua 09-Mar-2006 04:32
It take me a long time to find out what the problem is when i've got an error on copy(). It DOESN'T create any directories. It only copies to existing path. So create directories before. Hope i'll help,
info at sameprecision dot org 28-Jan-2005 03:54
When using copy on win32 (don't know about anywhere else),  copy sets the 'last modified time' of the the new copy to the current time instead of that of the source (win32 copy preserves last modified time).  If you are tracking backups by last modified time, use:

<?php

copy
($src, $dest); touch($dest, filemtime($src));

?>
simonr_at_orangutan_dot_co_dot_uk 03-Sep-2004 01:54
Having spent hours tacking down a copy() error: Permission denied , (and duly worrying about chmod on winXP) , its worth pointing out that the 'destination' needs to contain the actual file name ! --- NOT just the path to the folder you wish to copy into.......
DOH !
hope this saves somebody hours of fruitless debugging
kadnan at yahoo dot com 29-Aug-2004 10:30
you can also try xcopy command by using Shell to move/copy files/folders from one place to another
here is the code:

<?php
exec
('xcopy c:\\myfolder d:\\myfolder /e/i', $a, $a1);
?>

by executing this command, it will move folder along with all contents to destination.

-adnan

 
show source | credits | sitemap | contact | advertising | mirror sites