Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
honningas backup script
<?php
declare(strict_types=1);
require_once('hhb_.inc.php');
const RAR_FILENAME='backup.rar';
const RAR_FILEPATH=__DIR__.DIRECTORY_SEPARATOR.RAR_FILENAME;
const FTP_HOSTNAME="<censored>";
const FTP_USERNAME="<censored>";
const FTP_PASSWORD="<censored>";
const MYSQL_BACKUP_DIR=__DIR__.DIRECTORY_SEPARATOR.'mysql_backup_dir';
const MYSQL_HOST='<censored>';
const MYSQL_USER='<censored>';
const MYSQL_PASSWORD='<censored>'; /// TODO: FIXME!!!!!!!!!!!!!
const FTP_MOUNTPOINT=__DIR__.DIRECTORY_SEPARATOR.'ftp_backup_mountpoint';
const FTP_MOUNTPOINT_BACKUP_MANAGER_DIR=FTP_MOUNTPOINT.DIRECTORY_SEPARATOR.'backup_manager_dir';
init();
if(true){
// now to make the actual backup files
// mariabackup --backup --target-dir=MYSQL_BACKUP_DIR --host=127.0.0.1 --port=3306 --socket=/var/run/mysqld.sock --user=root --password=passwordddd --innodb-flush-method=fdatasync --rsync
$cmd=implode(" ",array(
'mariabackup',
'--backup',
'--target-dir='.escapeshellarg(MYSQL_BACKUP_DIR),
'--backup-encrypted',
'--host='.escapeshellarg(MYSQL_HOST),
'--port=3306',
'--socket='.escapeshellarg('/var/run/mysqld.sock'),
'--user='.escapeshellarg(MYSQL_USER),
'--password='.escapeshellarg(MYSQL_PASSWORD),
//'--innodb-flush-method=fdatasync',
'--rsync'
));
$ret=my_shell_exec($cmd,null,$stdout,$stderr);
if($ret!==0){
throw \RuntimeException("kittens");
}
//passthru("find ".escapeshellarg(MYSQL_BACKUP_DIR)." | xargs cat");
$paths_to_backup=array(
MYSQL_BACKUP_DIR,
'/home/vmail',
'/srv/http',
);
@unlink(RAR_FILEPATH);
$compress=1;
$cmd = implode(" ", array(
'rar',
'a',
($compress ? "-m5 -md1g -s" : "-m0"),
'-mt'.get_available_cpu_cores(),
'-r',
escapeshellarg(RAR_FILEPATH),
));
foreach($paths_to_backup as $tobackup){
$cmd.= " ".escapeshellarg($tobackup);
}
$cmd.=" > /dev/null";
echo "running {$cmd}..";
passthru($cmd,$ret);
if($ret!==0){
throw new \RuntimeException("WINRAR RETURNED NON-ZERO \"{$ret}\"");
//TODO: handle rar error
}else{
echo "done!\n";
mount_ftp_dir();
while(get_backup_dir_size_bytes() >= 90*1024*1024*1024){
echo "backup dir disk space nearly used up, deleting oldest...";
delete_oldest_backup($file,$dirs);
echo "deleted file: ";
var_dump($file);
echo "deleted dirs: ";
var_dump($dirs);
}
while(get_backup_dir_inode_count() >= 900){
echo "backup dir inode limit nearly used up, deleting oldest ...";
delete_oldest_backup($file,$dirs);
echo "deleted file: ";
var_dump($file);
echo "deleted dirs: ";
var_dump($dirs);
}
$abs_dir=FTP_MOUNTPOINT_BACKUP_MANAGER_DIR.DIRECTORY_SEPARATOR.date("Y").DIRECTORY_SEPARATOR.date("m");
passthru("mkdir -v -p ".escapeshellarg($abs_dir));
$i=1;
$backup_loc_filepath=$abs_dir.DIRECTORY_SEPARATOR."{$i}.".RAR_FILENAME;
while(file_exists($backup_loc_filepath)){
++$i;
$backup_loc_filepath=$abs_dir.DIRECTORY_SEPARATOR."{$i}.".RAR_FILENAME;
}
echo "uploading file..\n";
$cmd=implode(" ",array(
"dd",
"bs=10M",
"iflag=fullblock",
"if=".escapeshellarg(RAR_FILEPATH),
"of=".escapeshellarg($backup_loc_filepath)
));
if(!$compress){
$cmd.=" status=progress";
}
echo "executing \"{$cmd}\":\n";
passthru($cmd,$ret);
if($ret!==0){
throw new \RuntimeException("DD RETURNED NON-ZERO {$ret}...");
}
echo "done!\n";
//rename(RAR_FILEPATH,$abs_dir.DIRECTORY_SEPARATOR."{$i}.".RAR_FILENAME);
}
//hhb_var_dump($cmd,$stdout,$stderr);
}
function my_shell_exec(string $cmd, string $stdin=null, string &$stdout=null, string &$stderr=null):int{
echo "executing \"{$cmd}\"...";
// use a tmpfile in case stdout is so large that the pipe gets full before we read it, which would result in a deadlock.
$stdout_handle=tmpfile();
$stderr_handle=tmpfile();
$descriptorspec = array(
// stdin is *inherited* by default, so even if $stdin is empty, we should create a stdin pipe just so we can close it.
0 => array("pipe", "rb"),
1 => $stdout_handle,
2 => $stderr_handle,
);
$proc=proc_open($cmd,$descriptorspec,$pipes);
if(!$proc){
throw \RuntimeException("proc_exec failed!");
}
if(!is_null($stdin) && strlen($stdin)>0){
fwrite($pipes[0],$stdin);
}
fclose($pipes[0]);
$ret=proc_close($proc);
rewind($stdout_handle);// stream_get_contents can seek but it has let me down earlier, https://bugs.php.net/bug.php?id=76268
rewind($stderr_handle);//
$stdout=stream_get_contents($stdout_handle);
fclose($stdout_handle);
$stderr=stream_get_contents($stderr_handle);
fclose($stderr_handle);
//echo "done!\n";
return $ret;
}
function delete_oldest_backup(string &$deleted_file=null, array &$deleted_folders=null){
if(is_null($deleted_folders)){
$deleted_folders=[];
}
$years=glob(FTP_MOUNTPOINT_BACKUP_MANAGER_DIR."/*",GLOB_ONLYDIR);
if(count($years)<=0){
//...
return false;
}
$year=$years[0];
$dir=$year;
$months=glob($dir."/*",GLOB_ONLYDIR);
if(count($months)<=0){
$deleted_folders[]=$dir;
rmdir($dir);
return delete_oldest_backup($deleted_file,$deleted_folders);
}
$month=$months[0];
$dir=$month;
$files=glob($dir."/*");
if(count($files)<=0){
$deleted_folders[]=$dir;
rmdir($dir);
return delete_oldest_backup($deleted_file,$deleted_folders);
}
natsort($files);
$deleted_file=array_values($files)[0];
$ret=unlink($deleted_file);
if($ret && count($files)===1){
$deleted_folders[]=$dir;
rmdir($dir);
if(count(glob($year."/*"))<=0){
$deleted_folders[]=$year;
rmdir($year);
}
}
return $ret;
}
function get_backup_dir_inode_count():int{
$ret=shell_exec('find '.escapeshellarg(FTP_MOUNTPOINT_BACKUP_MANAGER_DIR).' | wc -l');
$ret=(int)$ret;
return $ret;
}
function get_backup_dir_size_bytes():int{
$ret=shell_exec("du -s --bytes ".escapeshellarg(FTP_MOUNTPOINT_BACKUP_MANAGER_DIR));
//var_dump($ret, disk_total_space(FTP_MOUNTPOINT_BACKUP_MANAGER_DIR)) & die();
$ret=(int)$ret;
return $ret;
}
function init(){
require_once('hhb_.inc.php');
hhb_init();
if(php_sapi_name() !== 'cli'){
die("error: this script can only run from cli.");
}
if(posix_geteuid()!==0){
die("error: only root can run this script. (needs curlftpfs mount, only root can do that, i think.)");
}
chdir(__DIR__);
if(is_dir(MYSQL_BACKUP_DIR)){
passthru("rm -rfv ".escapeshellarg(MYSQL_BACKUP_DIR));
}
mkdir(MYSQL_BACKUP_DIR);
register_shutdown_function(function(){
chdir(__DIR__);
if(is_dir(MYSQL_BACKUP_DIR)){
passthru("rm -rf ".escapeshellarg(MYSQL_BACKUP_DIR));
}
});
}
function mount_ftp_dir(){
static $firstrun=true;
if(!$firstrun){
throw new \LogicException("mount_ftp_dir() called twice!");
}
$firstrun=false;
if(is_dir(FTP_MOUNTPOINT)){
@exec("umount ".escapeshellarg(FTP_MOUNTPOINT));
rmdir(FTP_MOUNTPOINT);
}
mkdir(FTP_MOUNTPOINT);
register_shutdown_function(function(){
chdir(__DIR__);
if(is_dir(FTP_MOUNTPOINT)){
passthru("umount ".escapeshellarg(FTP_MOUNTPOINT));
passthru("rm -rfv ".escapeshellarg(FTP_MOUNTPOINT));
}
});
$cmd=implode(" ",array(
'curlftpfs',
'-o ftp_method=singlecwd',
'-o user='.escapeshellarg(FTP_USERNAME.":".FTP_PASSWORD),
// NOT SUPPORTED BY ONLINE.NET FTP: '-o utf8',
// VERY BUGGED IN CURLFTPFS, DO NOT USE: '-o allow_root',
'-o hard_remove',
escapeshellarg(FTP_HOSTNAME),
escapeshellarg(FTP_MOUNTPOINT)
));
echo "executing \"{$cmd}\"...";
passthru($cmd,$ret);
echo "\n";
if($ret!==0){
throw new \RuntimeException("ERROR: UNABLE TO MOUNT, CURLFTPFS RETURNED NON-ZERO \"{$ret}\"\n");
}
if(!is_dir(FTP_MOUNTPOINT_BACKUP_MANAGER_DIR)){
mkdir(FTP_MOUNTPOINT_BACKUP_MANAGER_DIR);
}
}
function get_available_cpu_cores():int{
return (int)(rtrim(shell_exec('nproc')));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.