PHP 5: Recursively move or copy files

July 15, 2011

I was looking for a quick code example on recursively moving files with PHP and I only saw code snippets using PHP 5. I like using the new and powerful features of PHP 5 when doing file system interactions so I wrote two quick PHP 5 functions that will move or copy directories and files recursively. That means your entire file tree will be moved or copied. The following is the code you can use for reference with your own recursive move or copy functions.

Move

/**
 * Recursively move files from one directory to another
 * 
 * @param String $src - Source of files being moved
 * @param String $dest - Destination of files being moved
 */
function rmove($src, $dest){

    // If source is not a directory stop processing
    if(!is_dir($src)) return false;

    // If the destination directory does not exist create it
    if(!is_dir($dest)) { 
        if(!mkdir($dest)) {
            // If the destination directory could not be created stop processing
            return false;
        }    
    }

    // Open the source directory to read in files
    $i = new DirectoryIterator($src);
    foreach($i as $f) {
        if($f->isFile()) {
            rename($f->getRealPath(), "$dest/" . $f->getFilename());
        } else if(!$f->isDot() && $f->isDir()) {
            rmove($f->getRealPath(), "$dest/$f");
            unlink($f->getRealPath());
        }
    }
    unlink($src);
}

Copy

/**
 * Recursively copy files from one directory to another
 * 
 * @param String $src - Source of files being moved
 * @param String $dest - Destination of files being moved
 */
function rcopy($src, $dest){

    // If source is not a directory stop processing
    if(!is_dir($src)) return false;

    // If the destination directory does not exist create it
    if(!is_dir($dest)) { 
        if(!mkdir($dest)) {
            // If the destination directory could not be created stop processing
            return false;
        }    
    }

    // Open the source directory to read in files
    $i = new DirectoryIterator($src);
    foreach($i as $f) {
        if($f->isFile()) {
            copy($f->getRealPath(), "$dest/" . $f->getFilename());
        } else if(!$f->isDot() && $f->isDir()) {
            rcopy($f->getRealPath(), "$dest/$f");
        }
    }
}

Deploying with the Cloud 9 IDE

(Updated: Nov 2, 2012)

Stephen Owens wrote up a great intro to using the Cloud 9 IDE to build on a development environment and utilize a modified version of the above code to then migrate to the production server. See his comment below for details.

6 thoughts on “PHP 5: Recursively move or copy files

  1. Stephen Owens (November 2, 2012)

    A PHP recursive copy, with few slight mods, works well as deploy script when working with Cloud9 IDE (https://c9.io/). Actually it works well with any cloud based IDE that uses a (S)FTP connection to a server for development.

    I still prefer my local LAMP stack for development, with a staging server for testing, and a production server for deployment, with a GIT or SVN repo for code management. That being said, the rise of the cloud based IDE looks very promising. So back to the original comment…

    Cloud9 does support GIT, but the other cloud based IDEs are all taking an FTP or Dropbox or some other kind of shared file space approach.

    My work flow for an FTP based cloud IDE is to setup a sub-domain on the production server to use as the cloud IDE’s development testing and staging environment. Complete with it’s own isolated directories and database. This allows me to edit and test on the actual development enviro, without touching what my visitors will see.

    When I’m satisfied with the latest iteration in the dev-test-stage sub-domain. I then use a recursive copy script to deploy the changed files over to the production directory. I also skip any special files & directories. Such as, configs, .htaccess, .htpassw, or anything else that is specific to the dev-test-stage sub-domain that the cloud IDE is directly connecting to.

    The modifications to the recursive copy script Ben posted above are:
    * a function to compare the file name to the ignored files list; which can be as simple as a: strpos(), switch(), in_array(), or preg_match()
    * a function that uses filemtime() to compare the make dates of the development copy to the production copy

    1. blobaugh (November 2, 2012)

      Thanks for the great info Stephen! I have updated the article to point other Cloud 9 users to your comment

  2. Stephen Owens (November 2, 2012)

    Here are two more Cloud IDEs that support FTP based projects.

    ShiftEdit http://shiftedit.net

    CodeAnywhere https://codeanywhere.net

  3. Danilo Carrabino (March 23, 2015)

    Hello Ben, here are a couple of fixed to your rmove function:

    function rmove($src, $dest) {

    // If source is not a directory stop processing
    if(!is_dir($src)) return false;

    // If the destination directory does not exist create it
    if(!is_dir($dest)) {
    if(!mkdir($dest)) {
    // If the destination directory could not be created stop processing
    return false;
    }
    }

    // Open the source directory to read in files
    $i = new DirectoryIterator($src);
    foreach($i as $f) {
    if($f->isFile()) {
    rename($f->getRealPath(), “$dest/” . $f->getFilename());
    } else if(!$f->isDot() && $f->isDir()) {
    rmove($f->getRealPath(), “$dest/$f”);
    }
    }
    rmdir($src);

    return true;
    }

  4. Geraldo (July 17, 2015)

    With some corrections:

    /**
    * Recursively move files from one directory to another
    *
    * @param String $src – Source of files being moved
    * @param String $dest – Destination of files being moved
    */
    function rmove($src, $dest){

    // If source is not a directory stop processing
    if(!is_dir($src)) return false;

    // If the destination directory does not exist create it
    if(!is_dir($dest)) {
    if(!mkdir($dest)) {
    // If the destination directory could not be created stop processing
    return false;
    }
    }

    // Open the source directory to read in files
    $i = new DirectoryIterator($src);
    foreach($i as $f) {
    if($f->isFile()) {
    rename($f->getRealPath(), “$dest/” . $f->getFilename());
    } else if(!$f->isDot() && $f->isDir()) {
    rmove($f->getRealPath(), “$dest/$f”);
    rmdir($f->getRealPath());

    }
    }
    unlink($src);
    }

  5. sameer (May 12, 2016)

    Thanks. It helps.