I created this script to keep my external hard drive synchronized with my different PCs. I needed it to work both by pulling from PC to external, and reverse because sometimes I change things on the external hard drive with one PC and need to sync back to the other. If a file / folder exists in the same location on both it doesn't check which is newer / last modified it only makes sure the same files and folders are present in both locations.
So the usage is something like this (.bat):
@ECHO off
echo Synchonizing D:\Documents with P:\Documents
php C:\syncDirs.php -- D:\Documents P:\Documents
PAUSE
And the script itself:
<?php
set_time_limit(0);
// Get directories specified by command line arguments
$dir1 = isset($argv[2]) ? $argv[2] : NULL;
$dir2 = isset($argv[3]) ? $argv[3] : NULL;
// If 2 directories weren't specified, exit the script
if( is_null($dir1) || is_null($dir2) ) die('Invalid or missing arguments.');
synchronizeDirs($dir1,$dir2);
synchronizeDirs($dir2,$dir1);
synchronizeDirs();
function synchronizeDirs($source = '',$dest = '') {
static $newDirs = 0;
static $newFiles = 0;
// If called without arguments, echo number of directories and files this function created
if( empty($source) && empty($dest) ) {
echo "\nTotal Directories created: $newDirs\nTotal Files Copies: $newFiles\n\n";
return;
}
// Trim trailing slash(es)
$source = rtrim($source,'/\\');
$dest = rtrim($dest,'/\\');
// Verify the arguments passed
if( !is_dir($source) || !is_readable($source) ) {
trigger_error('Source is not a valid directory or is not readable',E_USER_ERROR);
}
if( !is_dir($dest) ) {
if( !mkdir($dest,777) ) {
trigger_error('Unable to create destination directory',E_USER_ERROR);
}
} elseif( !is_writeable($dest) ) {
if( !chmod($dest,777) ) {
trigger_error('Unable to write to destination directory',E_USER_ERROR);
}
}
// Fix file / folder names with brackets for glob usage
$tSource = preg_replace('/(\*|\?|\[)/', '[$1]', $source).DIRECTORY_SEPARATOR.'*';
$tDest = preg_replace('/(\*|\?|\[)/', '[$1]', $dest).DIRECTORY_SEPARATOR.'*';
$globSource = glob($tSource);
if( $globSource === FALSE ) {
trigger_error('Unable to get contents of '.$source,E_USER_ERROR);
}
$globDest = glob($tDest);
if( $globDest === FALSE ) {
trigger_error('Unable to get contents of '.$dest,E_USER_ERROR);
}
foreach( $globSource as $file ) {
// Skip all .ini files
if( pathinfo($file,PATHINFO_EXTENSION) == 'ini' ) continue;
// Target location to go with current file/folder from source
$targ = $dest.DIRECTORY_SEPARATOR.basename($file);
if( is_file($file) ) {
if( !file_exists($targ) ) {
echo "\tCopying to $targ...\n";
copy($file,$dest.DIRECTORY_SEPARATOR.basename($file));
$newFiles++;
}
} elseif( is_dir($file) ) {
if( !is_dir($targ) ) {
echo "\tCreating $targ...\n";
mkdir($targ,777);
$newDirs++;
}
synchronizeDirs($file,$targ);
}
}
}
Thoughts? Any ways to improve it? Thanks for looking =D