Question

I want to keep a folder on one machine in sync with a folder on another. This is for a WordPress deployment plugin so I can't rely on rsync or other commands being present on either machine. PHP and a web server will be available on both machines and ideally it would work over HTTP.

My current thinking is that the requesting machine posts the local file list with last modified dates to a script on the other machine. The other machine compares with its files and responds with the modified files - either a list of files to be fetched individually or with the changed files inlined in the response.

I'd rather use an existing solution if one exists, though. Any ideas?

Was it helpful?

Solution

I've created a simple set of classes to implement this: https://github.com/outlandishideas/sync

On the server, e.g. example.com/remote.php:

const SECRET = '5ecR3t'; //make this long and complicated
const PATH = '/path/to/source'; //sync all files and folders below this path

$server = new \Outlandish\Sync\Server(SECRET, PATH);
$server->run(); //process the request

On the client:

const SECRET = '5ecR3t'; //this must match the secret key on the server
const PATH = '/path/to/destination'; //target for files synced from server

$client = new \Outlandish\Sync\Client(SECRET, PATH);
$client->run('http://example.com/remote.php'); //connect to server and start sync

OTHER TIPS

Your best bet is checking when the script was last run and then uploading the folder with ftp_* functions.

<?php
    $username = 'root'; // and this
    $password = 'password'; // this also
    $host     = 'my-remote-server.com'; // and this

    $remote_backup = 'backups/'; // folder on remote server to upload to
    $backup_folder = 'to_backup/'; // folder to backup
    $temp_folder   = 'temp_files/'; // a folder on the local server i can write to

    $last_run = file_get_contents("{$temp_folder}last_run.txt"); // You'll probably want to get this from a database instead

    if($last_run <= strtotime('-1 day'))
    {
        file_put_contents("{$temp_folder}last_run.txt", time()); // Update the last time this was ran

        $file = time() . '_backup.zip'; // what the file will be called both remotely and locally
        $ftp = ftp_connect($host); // connect to the ftp server
        ftp_login($ftp, $username, $password); // login to the ftp server

        $zip = new ZipArchive; // create a new instance of ZipArchive
        $zip->open($temp_folder . $file, ZIPARCHIVE::CREATE); // Create a new archive

        foreach(glob($backup_folder . '*') as $file) // Loop through all files in the local backup directory
        {
            $zip->addFile($file); // add that file
        }

        ftp_chdir($ftp, $remote_backup); // cd into the remote backup folder
        $upload = ftp_nb_put($ftp, $remote_backup . $file, $temp_folder . $file); // non-blocking put, uploads the local backup onto the remote server

        while($upload === FTP_MOREDATA)
        {
            // do something else while we're waiting for the non-blocking upload to finish
        }

        ftp_close($ftp); // closes the connection
    }

It should be non-blocking (well - the upload to the remote server), so if you don't have many files to zip it'll be fine to include on the index page for example. There isn't any error handling so you may want to add that in. It also doesn't delete the local backup, either, you may want to handle that.

In PHP I would not recommend it for a bunch of reasons.

I have exactly what you need as a python app.

This app is built to run as a service, you simply start it and forget about it :)

App: https://gist.github.com/8f62786582c6933395eb

Shell: https://gist.github.com/e08a99937c6f5deac4ab

Note: the shell file should be called fsyncd not fsyncd.sh :)

The PHP version of the above:

https://gist.github.com/3963cbc58793ff7e9773

Note: You need to get it running on both sites and configure each to connect to the other and set them to be executed by crons. Preferably not by WP crons.

I have the path to the directory that will be synced defined here:

define("PATH_DATA", PATH_ROOT . "data" . DIRECTORY_SEPARATOR);

In my case the data folder is in the script folder. You should just set an absolute path or use the WP core to get the WP uploads dir.

The principal is:

  1. find a way to get the two servers capable of talking to each other. I used a socket server/client approach. You could do a HTTP _POST processor (server) and a HTTP _POST maker (client).

  2. Keep a record of last sync time.

  3. At certain intervals read folder for and record any files modified from the last sync time.

  4. Send list of files to be updated with their modified timestamp to the other server.

  5. It should compare your list to his records and tell you which of the files he does not have.

  6. Send those files.

  7. The receiver will write the files and set modified date to the one on the other server. (this is important, to avoid infinite loops)

Good luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top