Hi folks. I was here a while ago, trying to figure out how to keep deployment instances of my common code, running on more than 1 site, in sync with eachother. I've looked at rsync which was recommended here, but didn't like it much, nor could I find a good windows version of it. So yesterday, I decided to try a pure PHP solution. My thinking was: run a PHP sync script once on each physical machine that holds possibly multiple copies of my common code, and FTP the common code only 1 time because I use only 1 shared hosting account besides my windows development machine. I've gotten it so far that it creates an imo good list of what to copy where. The only problem I can foresee is that the copy command will take more than 30 seconds, which makes it hard to run at the shared hoster. And obviously, it's going to need some good input checking to prevent abuse. I've put up a demo at http://skatescene.biz/sites/mediabeez.ws/sync_secret_cndj593n2/ , you can "execute" the "code" job to see it in action. I'll also post the working copy of my sync library at the bottom of this post. The only thing missing is the actual copy($source,$dest), I think. But, I'm wondering if this is a good approach to code deployment. It certainly seems easier and more convenient to me than using rsync. Maybe i'm an amateur indeed ;) Anyways, all criticism is welcome here. Thanks for your time! :) <?php function sync_echo_jobs ($path) { $jobs = sync_read_jobs ($path); echo '<div id="rajmvSync_jobs_json"><!-- '.json_encode($jobs).' --></div>'; echo '<ul class="rajmvSync_jobs">'; foreach ($jobs['jobs'] as $jobName => $job) { echo '<li>'.$jobName.' (<a href="javascript:rscg.executeJob(\''.$jobName.'\');">execute</a>) (<a href="javascript:rscg.showEditJobForm(\''.$jobName.'\');">edit</a>)</li>'; } echo '</ul>'; ?> <?php } function sync_read_jobs ($path) { $filepath = $path.'/rajmvSync_jobs.json'; if (file_exists($filepath)) { $r = json_decode (file_get_contents($filepath), true); } else { $r = array ( 'jobs' => array() ); } return $r; } function sync_write_jobs ($path, $jobs) { $filepath = $path.'/rajmvSync_jobs.json'; file_put_contents ($filepath, json_encode($jobs)); } function sync_addOrEditJob ($path, $name, $paths) { $jobs = sync_read_jobs ($path); $jobs['jobs'][$name] = array ( 'paths' => $paths ); sync_write_jobs ($path, $jobs); } function sync_executeJob ($path, $name) { $jobs = sync_read_jobs ($path); if (array_key_exists($name, $jobs['jobs'])) { $job = $jobs['jobs'][$name]; $paths = explode ("\n", $job['paths']); // work only on approved paths; $pathsApproved = array(); foreach ($paths as $idx=>$pathToSync) { $drive = strtolower(substr($pathToSync,0,2)); if ($drive=='m:') $pathsApproved[]=$pathToSync; } $paths = $pathsApproved; // get a list of files for each path to sync with the other paths in the same list/var $fileLists = array(); foreach ($paths as $idx => $pathToSync) { $fileLists[$pathToSync] = getFilePathList ($pathToSync, true, "/(.*)/", array('file')); } // get all the last modified timestamps for each of the found files $fileList = array(); foreach ($paths as $idx => $pathToSync) { foreach ($fileLists[$pathToSync] as $idx2 => $filepathToSync) { $fileRelativePath = str_replace ($pathToSync, '', $filepathToSync); if (!array_key_exists($fileRelativePath, $fileList)) $fileList[$fileRelativePath] = array(); $fileList[$fileRelativePath][$pathToSync] = filemtime($filepathToSync); } } // $copyList will hold all the copy commands, initialize; $copyList = array(); foreach ($fileList as $fileRelativePath => $locationResults) { foreach ($locationResults as $pathToSync => $filemtime) { if (!array_key_exists($fileRelativePath, $copyList)) $copyList[$fileRelativePath] = array( 'latest' => null, 'source' => null, 'destinations' => array() ); if (is_null($copyList[$fileRelativePath]['latest']) || $filemtime > $copyList[$fileRelativePath]['latest']) { $copyList[$fileRelativePath]['source'] = $pathToSync; $copyList[$fileRelativePath]['latest'] = $filemtime; } } } // schedule copy command for all files with older filemtime() than the latest copy foreach ($fileList as $fileRelativePath => $locationResults) { foreach ($locationResults as $pathToSync => $filemtime) { if ($filemtime < $copyList[$fileRelativePath]['latest']) { $copyList[$fileRelativePath]['destinations'][] = $pathToSync; } } } // schedule copy command for all new files that must go to all $pathToSync where it is not present yet: foreach ($copyList as $fileRelativePath => $fileRec) { if (count($fileList[$fileRelativePath])!=count($paths)) { foreach ($paths as $idx=>$pathToSync) { if (!array_key_exists($pathToSync, $fileList[$fileRelativePath])) $copyList[$fileRelativePath]['destinations'][] = $pathToSync; } } } // debug output of actual copy commands foreach ($copyList as $fileRelativePath => $fileRec) { if (count($fileRec['destinations'])>0) { echo $fileRec['source'].$fileRelativePath.' : '; var_dump ($fileRec['destinations']); } } } } ?>