Last active
January 29, 2016 18:11
-
-
Save MattLoyeD/fd1e4341f11e64d8c1f0 to your computer and use it in GitHub Desktop.
Local to ftp backup (sql & files, limited by local or ftp timestamp or folder/file sizes).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$conf = array( | |
"backup_prefix" => "bc-", | |
"backup_dir" => dirname(__FILE__).'/backups/', | |
"backup_files" => true, | |
"backup_target_dir" => '/folder', | |
"keep_local_files" => true, | |
"local_backup_size_limit" => "80GB", // in what you want, like 1GB or 2MB | |
"local_backup_time_limit" => 7, // in days, 0 for no limit | |
"ftp_backup_size_limit" => "95GB", // in what you want, like 10GB | |
"ftp_backup_time_limit" => 3, // in days, 0 for no limit | |
"sql_backup" => true, | |
"sql_host" => 'localhost', | |
"sql_login" => 'root', | |
"sql_pass" => '', | |
"sql_tables" => 'all', // separated by space or "all" for everything | |
"ftp_host" => '', | |
"ftp_login" => '', | |
"ftp_pass" => '', | |
/* "ftp_dir" => '', // leave empty for home | |
"ftp_secure_mode" => false, //ftps ? | |
"tmp_sql_file" => $this->backup_prefix.date('Y-m-d-H-i-s').'.sql', | |
"tmp_backup_file" => $this->backup_prefix.date('Y-m-d-H-i-s').'.zip',*/ | |
); | |
$need_backup = new SuperBackup($conf); | |
/** | |
* Super easy backup, based on what you need/have/want. | |
*/ | |
class SuperBackup | |
{ | |
public function __construct($array_conf = array()) | |
{ | |
$this->backup_prefix = "bc-"; | |
$this->backup_dir = dirname(__FILE__).'/backups/'; | |
$this->backup_files = true; | |
$this->backup_target_dir = '/var/www/'; | |
$this->keep_local_files = true; | |
$this->local_backup_size_limit = "200MB"; // in MB, 100000 ~= 100 GB, 0 for no limit | |
$this->local_backup_time_limit = 30; // in days, 0 for no limit | |
$this->ftp_backup_size_limit = "1GB"; // in MB, 100000 ~= 100 GB, 0 for no limit | |
$this->ftp_backup_time_limit = 3; // in days, 0 for no limit | |
$this->sql_backup = true; | |
$this->sql_host = 'localhost'; | |
$this->sql_login = ''; | |
$this->sql_pass = ''; | |
$this->sql_tables = 'all'; // separated by space or "all" for everything | |
$this->ftp_host = ''; | |
$this->ftp_login = ''; | |
$this->ftp_pass = ''; | |
$this->ftp_dir = ''; // leave empty for home | |
$this->ftp_secure_mode = false; //ftps ? | |
$this->tmp_sql_file = $this->backup_prefix.date('Y-m-d-H-i-s').'.sql'; | |
$this->tmp_backup_file = $this->backup_prefix.date('Y-m-d-H-i-s').'.zip'; | |
if(!empty($array_conf)){ | |
foreach ($array_conf as $key => $value) { | |
// Replacing default values | |
if(isset($this->$key) && !empty($value)){ | |
if(is_bool($this->$key)){ | |
$this->$key = (bool)$value; | |
} | |
elseif(is_float($this->$key)){ | |
$this->$key = (float)$value; | |
} | |
elseif(is_int($this->$key)){ | |
$this->$key = (int)$value; | |
} | |
elseif(is_array($this->$key)){ | |
$this->$key = (array)$value; | |
}else{ | |
// Str | |
$this->$key = $value; | |
} | |
} | |
} | |
} | |
if(!file_exists($this->backup_dir)){ | |
if(!mkdir($this->backup_dir) || !is_writable($this->backup_dir)){ | |
$this->dieJson('Cannot write backup files locally'); | |
} | |
} | |
// Whatever happens, we go to the right folder | |
shell_exec('cd '.$this->backup_dir); | |
$this->run(); | |
} | |
private function toByteSize($p_sFormatted) { | |
$aUnits = array('B'=>0, 'KB'=>1, 'MB'=>2, 'GB'=>3, 'TB'=>4, 'PB'=>5, 'EB'=>6, 'ZB'=>7, 'YB'=>8); | |
$sUnit = strtoupper(trim(substr($p_sFormatted, -2))); | |
if (intval($sUnit) !== 0) { | |
$sUnit = 'B'; | |
} | |
if (!in_array($sUnit, array_keys($aUnits))) { | |
return false; | |
} | |
$iUnits = trim(substr($p_sFormatted, 0, strlen($p_sFormatted) - 2)); | |
if (!intval($iUnits) == $iUnits) { | |
return false; | |
} | |
return $iUnits * pow(1024, $aUnits[$sUnit]); | |
} | |
private function run(){ | |
// PSR-2 Nazis :p | |
$files_to_push = array(); | |
if($this->sql_backup === true){ | |
$files_to_push[] = $this->run_sql_backup(); | |
} | |
if($this->backup_files === true){ | |
$files_to_push[] = $this->run_files_backup(); | |
} | |
if(!empty($files_to_push)){ | |
$this->push_to_ftp($files_to_push); | |
if($this->clean_local_dir($files_to_push) === false){ | |
$this->dieJson('Something wen\'t wrong when manipulating local files'); | |
} | |
}else{ | |
$this->dieJson('Nothing to backup ?'); | |
} | |
$this->dieJson('Backup done without problem !',true); | |
} | |
private function run_sql_backup(){ | |
if($this->sql_tables === 'all'){ | |
$db_tabls = "--all-databases"; | |
}else{ | |
$db_tabls = "--databases ".implode(' ',explode(' ',$this->sql_tables)); | |
} | |
$cmd = "mysqldump -h ".$this->sql_host." --user=".$this->sql_login." --password=".$this->sql_pass." ".$db_tabls." > ".$this->backup_dir."/".$this->tmp_sql_file.""; | |
shell_exec($cmd); | |
// Verify success | |
return file_exists($this->backup_dir.'/'.$this->tmp_sql_file) ? $this->backup_dir.'/'.$this->tmp_sql_file : false; | |
} | |
private function run_files_backup(){ | |
$cmd = "zip -y -0 -r ".$this->backup_dir."/".$this->tmp_backup_file." ".$this->backup_target_dir.""; | |
shell_exec($cmd); | |
// Verify success | |
return file_exists($this->backup_dir.'/'.$this->tmp_backup_file) ? $this->backup_dir.'/'.$this->tmp_backup_file : false; | |
} | |
private function push_to_ftp($files_to_push){ | |
if(!empty($this->ftp_backup_time_limit)){ | |
$datetime = new Datetime('now - '.$this->ftp_backup_time_limit.' days'); | |
$timestamp_limit = abs($datetime->format("U")); | |
} | |
if(!empty($this->ftp_backup_size_limit)){ | |
$size_limit = (int)$this->toByteSize($this->ftp_backup_size_limit); | |
// prevent ftp folder limit by removing new files to be pushed | |
$fsize = 0; | |
foreach ($files_to_push as $file) { | |
$fsize += filesize($file); | |
} | |
if($size_limit < $fsize){ | |
$this->dieJson('Not enough space on FTP (space limit ('.$this->human_filesize($size_limit).') < file sizes to upload('.$this->human_filesize($fsize).').'); | |
} else { | |
$size_limit = $size_limit - $fsize; | |
} | |
// setup ftp size limit | |
$ftp_filesizes = 0; | |
} | |
// set up basic connection | |
if($this->ftp_secure_mode === true){ | |
$conn_id = ftp_ssl_connect($this->ftp_host); | |
}else{ | |
$conn_id = ftp_connect($this->ftp_host); | |
} | |
// login with username and password | |
$login_result = ftp_login($conn_id, $this->ftp_login, $this->ftp_pass); | |
// get contents of the current directory | |
$contents = ftp_nlist($conn_id, "-t .".$this->ftp_dir); | |
foreach ($contents as $file) { | |
$target = ".".$this->ftp_dir."/".$file; | |
if($this->ftp_is_dir($target) === true){ | |
// This is not a recursive script ;) | |
continue; | |
} | |
if(!empty($this->ftp_backup_time_limit)){ | |
$buff = ftp_mdtm($conn_id, $target); | |
if ($buff > $timestamp_limit) { | |
ftp_delete($conn_id, $target); | |
continue; | |
} | |
} | |
if(!empty($this->ftp_backup_size_limit)){ | |
$ftp_filesizes += ftp_size($conn_id, $target); | |
if($ftp_filesizes > $size_limit){ | |
// lets kill all the unecessary folks ! | |
ftp_delete($conn_id, $target); | |
continue; | |
} | |
} | |
} | |
// now that folder is clean, we can upload OKLM | |
foreach ($files_to_push as $file) { | |
$target = ".".$this->ftp_dir."/".basename($file); | |
if (!ftp_put($conn_id, $target, $file, FTP_ASCII)) { | |
$this->dieJson("Error uploading $file on FTP."); | |
} | |
} | |
// close connection | |
ftp_close($conn_id); | |
} | |
private function clean_local_dir($files_to_push){ | |
$r = array(); | |
if((bool)$this->keep_local_files == false){ | |
foreach ($files_to_push as $file) { | |
$r[] = unlink($file); | |
} | |
return !in_array(false,$r); | |
} | |
if(!empty($this->local_backup_time_limit)){ | |
$datetime = new Datetime('now - '.$this->local_backup_time_limit.' days'); | |
$timestamp_limit = abs($datetime->format("U")); | |
} | |
if(!empty($this->local_backup_size_limit)){ | |
$size_limit = (int)$this->toByteSize($this->local_backup_size_limit); | |
// prevent ftp folder limit by removing new files to be pushed | |
$fsize = 0; | |
foreach ($files_to_push as $file) { | |
$fsize += filesize($file); | |
} | |
if($size_limit < $fsize){ | |
// Remove everything new, not enough space allowed to keep dir | |
foreach ($files_to_push as $file) { | |
$r[] = unlink($file); | |
} | |
} else { | |
$size_limit = $size_limit - $fsize; | |
} | |
// setup ftp size limit | |
$local_filesizes = 0; | |
} | |
$files = glob($this->backup_dir."/*.*"); | |
usort($files, function ($a, $b) { | |
return filemtime($b) - filemtime($a); | |
}); | |
foreach ($files as $file) { | |
if((bool)is_dir($file) == true){ | |
// This is not a recursive script ;) | |
continue; | |
} | |
if(!empty($this->local_backup_time_limit)){ | |
$buff = filemtime($file); | |
if ($buff > $timestamp_limit) { | |
$r[] = unlink($file); | |
continue; | |
} | |
} | |
if(!empty($this->local_backup_size_limit)){ | |
$local_filesizes += filesize($file); | |
if($local_filesizes > $size_limit){ | |
// lets kill all the unecessary folks ! | |
$r[] = unlink($file); | |
continue; | |
} | |
} | |
} | |
return !in_array(false,$r); | |
} | |
/** | |
* Copyright : http://nl.php.net/manual/en/function.ftp-chdir.php | |
*/ | |
private function ftp_is_dir( $conn_id, $dir ) { | |
$original_directory = ftp_pwd( $conn_id ); | |
if ( @ftp_chdir( $conn_id, $dir ) ) { | |
ftp_chdir( $conn_id, $original_directory ); | |
return true; | |
} | |
else { | |
return false; | |
} | |
} | |
/** | |
* Copyright : http://jeffreysambells.com/2012/10/25/human-readable-filesize-php | |
*/ | |
public function human_filesize($bytes, $decimals = 2) { | |
$size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); | |
$factor = floor((strlen($bytes) - 1) / 3); | |
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor]; | |
} | |
private function dieJson($msg,$result = false){ | |
die(json_encode(array('result'=>(bool)$result,'message'=>(string)$msg))); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment