Skip to content

Instantly share code, notes, and snippets.

@MattLoyeD
Last active January 29, 2016 18:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MattLoyeD/fd1e4341f11e64d8c1f0 to your computer and use it in GitHub Desktop.
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).
<?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