#!/usr/local/bin/php 'B', 1 => 'KB', 2 => 'MB', 3 => 'GB', 4 => 'TB'); $factor = 0; while($size >= 1024) { $size /= 1024; $factor++; } return ((0 == $factor) ? $size : sprintf("%4.2f", $size)).$factorLookup[$factor]; } ob_end_flush(); define('REMOTE_HOST', 'your_host'); define('REMOTE_USER', 'your_ssh_user'); define('REMOTE_PATH', '/backup'); define('LOCAL_PATH', '/backup/remote'); define('IDENTITY_FILE', '/path/to/private/ssh/key'); define('SCREEN_WIDTH', 80); function fitString($string, $width=40, $prefix=' ', $suffix='') { if(!strlen($string)) { die('Empty string passed to fitString()'); } $paddingSize = strlen($prefix) + strlen($suffix); $maxStringSize = $width - $paddingSize; if(strlen($string)+strlen($prefix)+strlen($suffix) <= $width) { return $prefix.str_pad($string, $maxStringSize); } else { return $prefix.substr($string, 0, $maxStringSize - 3).'...'.$suffix; } } function printMultiColumn($input, $cols=1, $prefix=' ', $suffix='') { $return = ''; $line = ''; $colWidth = floor(SCREEN_WIDTH / $cols); for($i = 0; $i < count($input); $i++) { $line .= fitString($input[$i], $colWidth, $prefix, $suffix); if($i % $cols == 0) { $return .= $line.PHP_EOL; $line = ''; } } return $return; } $return = null; $remoteFiles = array(); $localFiles = array(); $newFiles = array(); $oldFiles = array(); $changedFiles = array(); $recentFiles = array(); exec('ssh -i '.IDENTITY_FILE.' '.REMOTE_USER.'@'.REMOTE_HOST.' stat -t '.REMOTE_PATH.'/\*.tar.gz', $remoteFiles, $return); if(false === $return) { die("Couldn't list remote files"); } foreach($remoteFiles as $index => $data) { $data = explode(' ', $data); $remoteFiles[basename($data[0])] = array($data[13], $data[1]); unset($remoteFiles[$index]); } exec('stat -f "%N %a %z" /backup/remote/*.tar.gz', $localFiles, $return); if(false === $return) { die("Couldn't list local files"); } foreach($localFiles as $index => $data) { $data = explode(' ', $data); $localFiles[basename($data[0])] = array($data[1], $data[2]); unset($localFiles[$index]); } foreach($remoteFiles as $file => $info) { $file = trim($file); if(!in_array($file, array_keys($localFiles))) { $newFiles[] = $file; } } foreach($localFiles as $file => $info) { $file = trim($file); if(!in_array($file, array_keys($remoteFiles))) { $oldFiles[] = $file; } else if($info[1] != $remoteFiles[$file][1]) { $changedFiles[] = $file; } else { $recentFiles[] = $file; } } echo 'New files: '.PHP_EOL .printMultiColumn($newFiles, 3).PHP_EOL .'Changed files: '.PHP_EOL .printMultiColumn($changedFiles, 3).PHP_EOL .'Old files: '.PHP_EOL .printMultiColumn($oldFiles, 3).PHP_EOL .'Recent files: '.PHP_EOL .printMultiColumn($recentFiles, 3).PHP_EOL .PHP_EOL; $filesToFetch = array_unique($newFiles + $changedFiles); echo 'Files that need to be fetched: '.PHP_EOL .printMultiColumn($filesToFetch, 3).PHP_EOL .PHP_EOL; echo 'Fetching files . . .'.PHP_EOL; foreach($filesToFetch as $file) { echo ' Fetching '.$file.' ('.prettyFilesize($remoteFiles[$file][1]).') . . . '; ob_flush(); flush(); exec('scp -BCpq -i '.IDENTITY_FILE.' '.REMOTE_USER.'@'.REMOTE_HOST.':'.REMOTE_PATH.'/'.$file.' '.LOCAL_PATH, $output, $return); if(false === $return) { die("failed".PHP_EOL); } else { echo 'done'.PHP_EOL; } ob_flush(); flush(); } echo PHP_EOL; echo 'Done fetching files'.PHP_EOL; echo PHP_EOL; echo 'Removing files . . .'.PHP_EOL; foreach($oldFiles as $file) { echo ' Removing '.$file.' . . . '; ob_flush(); flush(); unlink(LOCAL_PATH.'/'.$file); echo 'done'.PHP_EOL; ob_flush(); flush(); } echo PHP_EOL; echo 'Remote backup is complete!'.PHP_EOL; ?>