Synchronisation server for use with runsync.php
HotScript @ RoŲnašn index for more scripts and extensions.
Run this script as an example.
<?php
  
/**
  * @author: Arnoud ten Hoedt - Roonaan Webdevelopment
  * This snippet is for public use
  *
  * @date: 2005/10/31
  * @copy: 2005 Arnoud ten Hoedt
  *
  */
  
  /* Set error reporting */
  
error_reporting(E_ALL);

  
/**
   * A mutual "secret" key which should be added
   * to development and live site
   */
  
define('VALID_DOM_KEY''nomennescio');

  
/**
   * @var Boolean $always_update Force all files to be updated
   */
  
$always_update  false;

  
/* You can allow certain ips to have always access */
  
$allow = array();
  
//$allow[] = '127.0.0.1';

  /**
   * Root directory from which we are copying our files
   */
  
define('DIR_BASE'realpath(dirname(__FILE__).'/'));
  
  
/**
   * @var Array $files
   * Files is an associative array:
   * $files[remoteRelativeFile1] = LocalAbsoluteFilePath1;
   * $files[remoteRelativeFile2] = LocalAbsoluteFilePath2;
   *
   * It can be filled using the automated script included
   * which traverses through the DIR_BASE path.
   *
   * You can however also manually include filenames by using
   * $files['config.inc.php']  = './online_config.inc.php';
   *
   * As above you can use this script to also map local files
   * with remote files with another name.
   *
   * Make sure however that you change the filterFile function
   * such that the $files['config.inc.php'] is not overwritten
   * by the script, linking it to './config.inc.php';
   */
  
$files = array();
  
  
/**
   * Determine which files should and should not be
   * added to the synchronisation list
   *
   * When a file should not be synchronised we make
   * sure the $filename variable is emptied.
   *
   * Although the function returns a boolean, the 
   * parameter by reference $filename is checked
   * to actually include or declude a filename
   *
   * @param  String $filename  Holds only filename,
   *                           not relative directory
   * @param  String $fullpath  Holds full absolute
   *                           path to file
   * @return Boolean
   */
  
function filterFiles(&$filename$fullpath '')
  {
    
// Determine the relative path of the file
    
$folder   DIR_BASE;
    
$relative str_replace($folder''$fullpath);

    
// We do not want this script file copied:
    
if($fullpath == __FILE__)     {$filename ''; return false;}
    
    
// We do not want to copy log files and backup files
    
if(strstr($fullpath'.log')) {$filename ''; return false;}
    if(
strstr($fullpath'_bu'))  {$filename ''; return false;}

    
// We allow only .txt, .doc and .pdf files
    
$allowed = array(
      
'\.(txt|doc|pdf)$',
    );

    foreach(
$allowed as $a) {
      if(
preg_match('#'.$a.'#i'$relative))
        return 
true;
    }

    
# We deny all other files
    
$filename '';
  }
  
  
  
/* Additional remote key which changes every hour
   * Changing it to minutes might break your script
   * when it takes several minutes to copy all files
   */
  
$_RKEY md5(__FILE__.date('Ymdh'));


  
/* Prevent from caching */
  
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  
header("Last-Modified: " gmdate("D, d M Y H:i:s") . " GMT");
  
header("Cache-Control: no-store, no-cache, must-revalidate");
  
header("Cache-Control: post-check=0, pre-check=0"false);
  
header("Pragma: no-cache");

  
/**
   * Php opening tag
   */
  
define('PHP_O''<'.'?php ');

  
/**
   * Php closing tag
   */
  
define('PHP_C'' ?'.'>');


  
/**
   * Get all files in the root directory
   */
  
$read_files getFilesInDir(DIR_BASEtrue'filterFiles');

  
/* Construct files array based on $read_files **/
  
foreach($read_files as $f) {
    
$files[$f] = DIR_BASE.'/'.$f;
  }

  
/**
   * Based on the VALID_DOM_KEY we can construct the
   * VALID_REMOTE_KEY which is a md5 of key + remote ip
   */
  
define('VALID_REMOTE_KEY'md5(VALID_DOM_KEY.$_SERVER['REMOTE_ADDR']));

  
/** Test access **/

  
if(in_array($_SERVER['REMOTE_ADDR'], $allow)) {
    
/* Access allowed based on IP */

  
} elseif(isset($_GET['remote']) && $_GET['remote'] == VALID_REMOTE_KEY) {
    
/* Access allowed */

  
} elseif(empty($_GET['domkey'])) {
    
/* Access key not found */
    
exit('err:You have to provide a valid access key');

  } elseif(
$_GET['domkey'] != VALID_REMOTE_KEY) {
    
/* Access key invalid */
    
exit('err:The provided domkey was invalid');

  }

  
/** Prepare download of a file **/

  
if(!empty($_GET['file'])) {
    
/** @var String $file Requested file */
    
$file $_GET['file'];

    
$valid_remote $_GET['remote'] == VALID_REMOTE_KEY;

    
$fkey = isset($_REQUEST['fkey']) ? $_REQUEST['fkey'] : '';

    if(!
$valid_remote || !$fkey) {
      exit(
'err:file access denied');
    } elseif(!isset(
$files[$file])) {
      exit(
'err:file not available');
    } elseif(!
is_file($files[$file])) {
      exit(
'err:file not found');
    } elseif(
md5($content file_get_contents($files[$file])) != $fkey && !$valid_remote) {
      exit(
'err:invalid request');
    } elseif(
strpos($content'@norootsync')) {
      exit(
'err:file protected from synchronization');
    }
    echo 
$content;
  } else {

    
put_line(PHP_O);
    
put_line('/* list files */');
    
put_line('$always_update = '.($always_update 'true' 'false').';');
    
put_line('$files = array();');
    
$dirs = array();

    
/** All files are checked for md5 keys **/
    
foreach($files as $file => $location)
    {
      if(
is_file($location)) {
        
put_line('$files[] = array(\''.addSlashes($file).'\',\''.md5(file_get_contents($location)).'\');');
        
$dirs[dirname($file)] = true;
      } else {
        
put_line('echo "file no longer supported: '.$file.'<br/>";');
      }
    }

    
/**
     * Make sure all directories exist
     */
    
foreach($dirs as $dir => $dummy) {
      
put_line('testDir(DIR_BASE.\'/'.$dir.'\');');
    }

    
/**
     * Set a basic printf formatted request url for file downloads
     */
    
$script_url '%s?file=%s&remote=%s&fkey=%s';
   
?>
   /**
    * Possibly the download is limited to a certain number
    */
   $limit = isset($limit) ? intval($limit) : -1;

   /**
    * Keeps track of the number of files that are updated
    */
   $updates = 0;

   echo '<p><b>Remote script included succesfully</b>';
   if(!isset($showTotalFiles) || $showTotalFiles) {
     echo '<br/>We need to synchronise '.count($files).' file(s)';
   }
   echo '</p>';
   
   echo '<ol>';
   /**
    * Walk through all files and test wether or not they need
    * updating.
    */
   foreach($files as $file_info) {
     /**
      * @var String $file   holds a relative filename
      * @var String $key    holds a md5 hash for latest file content
      */
     list($file, $key) = $file_info;

     /**
      * Convert relative path to absolute path
      */
     $filepath = DIR_BASE.'/'.$file;

     /**
      * When always update is on, make sure we always copy
      * Otherwise only copy when file does not exists, or is
      * Outdated
      */
     $copy = $always_update;

     if($always_update) {
       $copy = true;
       echo '<li>We need to copy "'.$file.'" because it needs to be updated always.';
       $fkey=md5(file_get_contents($filepath));
     } elseif(!is_file($filepath)) {                                      // File exists?
       $copy = true;
       echo '<li>We need to copy "'.$file.'" because it does not exist.';
       $fkey=md5(file_get_contents($filepath));
     } elseif(($fkey=md5(file_get_contents($filepath))) != $key) {  //File is up to date?
       $copy = true;
       echo '<li>We need to copy "'.$file.'" because it is outdated';
     }
     /**
      * When we need to copy the file, construct a request holding:
      * - $_GET['file']   - required file
      * - $_GET['remote'] - remote key
      * - $_GET['fkey']   - md5 hash as found in $key
      */
     if($copy) {
       $file_request = sprintf('<?=$script_url;?>',
                                SYNC_HOST,
                                urlencode($file),
                                VALID_REMOTE_KEY,
                                $fkey);
       /**
        * Retrieve file using binairy safe file_get_contents
        */
       $file_contents = file_get_contents($file_request);

       /**
        * If the file starts with "err:" show error message
        * and discard file contents.
        */
       if(substr($file_contents,0,4) == 'err:') {
         // Output error message
         echo '<br/>'.htmlspecialchars($file_contents);

       } elseif(false == ($f = fopen($filepath,'w'))) {
         // Local file was not accessible
         echo '<br/>Could not open local file for writing';

       } else {
         // Store filecontents in local file
         fwrite($f, $file_contents);
         fclose($f);
         if(!isset($showBytesCopied) || $showBytesCopied) {
           echo '<br/>File saved: '.strlen($file_contents).' bytes';
         }
         $updates++;
       }
       /**
        * Althoug file copy might fail, we lower the $limit var to
        * make sure we only synchronize the required amount of files
        */
       $limit--;
       
       echo '</li>';

       /**
        * When the limit of files is reached, stop looping
        */
       if($limit == 0) break;

     } else {

      /* Files does not need to be copied. It's up to date
       * You can choose to show a message.
       */
      if(isset($showUpToDate) && $showUpToDate) {
        echo '<li>File "'.$file.'" is up to date</li>';
      }
     }
     flush();
   }
   echo '</ol>';
   /** Show an message telling user the number of updated files */
   echo '<p><b>Remote script completed:</b>';
   echo "<br/>$updates file(s) updated</p>";

   /**
    * Recursive function which makes sure that required
    * directories exist
    *
    * @param String $path  Absolute patg
    *
    * @returns Boolean True when dir exists
    */
   function testDir($path) {
    if(!is_dir($path)) {
      //echo '<div>Directory: '.$path.' will be created.</div>';
      flush();
      $pardir = substr($path, 0, strrpos($path,'/'));
      if(!testDir($pardir))
        return false;
      else
        return mkdir($path, 0777);
    } else {
      //echo '<div>Directory: '.$path.' exists.</div>';
      flush();
    }
    return true;
   }
   <?php

   
/* End PHP generated script */
   
put_line(PHP_C);
  }

  function 
put_line($line) {
    if(
$line == PHP_C) return print($line);
    echo 
$line."\n";
  }

  
/**
  * @author: Arnoud ten Hoedt - Roonaan Webdevelopment
  * This snippet is for public use
  *
  * @date: 2005/07/22
  * @copy: 2005 Arnoud ten Hoedt
  *
  * This function provides functionality to read files from a
  * folder and apply a filtering function to the found filenames
  *
  */

  /**
   * @param String $dir         Initial start dir
   * @param Boolean $recursive  Set to true to read subdirs
   * @param String $filter      Empty or a callable functionname.
   *                            the called filter function should take 1 argument
   *                            ($filename) by reference
   * @param String $subdir      is prepended to filenames used when $recursive is
   *                            set to true
   * @return Array list of files
   */
  
function getFilesInDir($dir$recursive false$filter ''$subdir '')
  {
    
# Test the $dir parameter
    
if(!is_dir($dir))
      return 
false;

    
# Create a directory handle
    
$handle opendir($dir);

    
# Test the created handle
    
if(!is_resource($handle))
      return 
false;

    
# Initialize an array to hold the file names
    
$files = array();

    
# Read files from the directory handle
    
while(false !== ($file readdir($handle)))
    {
      
# Exclude the '..' and '.' which readdir always returns
      
if($file != '.' && $file != '..')
      {

        
# Temporary variable holding the fullpath to $file
        
$fullpath $dir.'/'.$file;

        
# Check for directories
        
if(is_dir($fullpath) && $recursive)
        {
          
$files array_merge($filesgetFilesInDir($fullpathtrue$filter$subdir.$file.'/'));
        }
        elseif(
is_file($fullpath))
        {
          
# When set, filter
          
if(is_callable($filter))
            
$filter($file$fullpath);

          if(!empty(
$file))
            
$files[] = $subdir.$file;
        }
      }
    }

    return 
$files;
  }
?>