Unix like smart recursive file/folder copy function for PHP

Blog

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 :). It's also shared here

Update : Thiago has written a different version of this function

Several sites considered this function the best solutions for copying files!

 

    /**
    * Create a new directory, and the whole path.
    *
    * If  the  parent  directory  does  not exists, we will create it,
    * etc.
    * @todo
    *     - PHP5 mkdir functoin supports recursive, it should be used
    * @author baldurien at club-internet dot fr 
    * @param string the directory to create
    * @param int the mode to apply on the directory
    * @return bool return true on success, false else
    * @previousNames mkdirs
    */

    function makeAll($dir, $mode = 0777, $recursive = true) {
        if( is_null($dir) || $dir === "" ){
            return FALSE;
        }
        
        if( is_dir($dir) || $dir === "/" ){
            return TRUE;
        }
        if( makeAll(dirname($dir), $mode, $recursive) ){
            return mkdir($dir, $mode);
        }
        return FALSE;
    }

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

No votes yet

Comments

Very good post, thanks a lot.

Very good post, thanks a lot.

Hello, I was trying to use

Hello,

I was trying to use your smartCopy function that I found on php.net
(http://ca.php.net/copy). I noticed that when trying to run the function
it fails because the variable $dirsource has not been defined ($dirsource
is used in the last while loop of your function). Would you be able to
help me out?

Thanks again for the great function :)

- Justin

Hi justin , Sorry about that

Hi justin ,
Sorry about that i renamed $dirsource parameter to $source but i missed that one :),
so It should be fixed by replacing it with $source.

ah perfect thank you!! I

ah perfect thank you!! I thought that might work but I was thinking if the $source was pointing to a file, then it might break because it's not a "directory". I probably should have just tried it out to see what would happen. Thanks a lot! :D

Hello again, I did some more

Hello again,

I did some more testing and realized that the problem with the missing
cmfcDirectory class has nothing to do with trying to copy accross two
domains. It's just plain missing because it seems to be a custom class that
you built and omitted to include on php.net.

Is there any chance you could email me the class please? Your smartcopy
function is not very useful without this important missing piece. It works
fine if the destination folder already exists but if not then it calls on
the class and fails right there...

Please correct me if I'm wrong... and I do apoligize if I am.. but after a
bit of googling it seems like cmfcDirectory is a custom user class and I'd
really like to have it. Thanks for your time!

Hi, You guessed correctly,

Hi,
You guessed correctly, this function is part of my own framework. i simply missed that function :).
I attached the most recent version, hope it helps

Sweet! Thanks a lot man you

Sweet! Thanks a lot man you rock!