<?php
/*
* This class backups folders from your local filesystem.
* It saves them on a selected ftp server or on your local filesystem.
* Old backups are deleted (see $max_age) but you can ensure that there will be always a certain number of backups (see $min_backup_num)
* Author: Mark Simkin, Germany;
* mail: hide@address.com;
* version: 1.0 /31.07.2006
*
*/
class backupclass {
// This is an array containing all paths to the Folders and Files, which will be archived
var $backup_dirs;
//This Variable shows the max age of the archives in days, every archiv older then this variable is going to be deleted!
var $max_age = 5;
// With this Variable you can secure, that you will have at least $min_backup_num of archivs, even though the are older then $max_age
var $min_backup_num = 1;
// This is the path where tar is installed, eventually you have to change it.
var $tar_path = '/bin/';
// This array is saving all error_messages
var $log = array();
//This is the data needed to connect to the ftp server
var $host;
var $user;
var $pass;
//This is the stream to the ftp server. Use the config_ftp function to open a stream.
var $ftphandler;
/*
* backupclass
* This is the Constructor.
* param $backup_dirs array paths to the folders which will be archived.
*
* return bool Return true on success, false on failure
*/
function backupclass($backup_dirs) {
if(!is_array($backup_dirs)) {
$this->log [] = '$backup_dirs isn“t an array!';
return false;
}
foreach($backup_dirs as $current_dir)
{
if(!$this->add_backup_dir($current_dir)) return false;
}
return true;
}
/*
* add_backup_dir
* With this function one can add dirs
* param $dir string the path of the folder which is going to be achived.
*
* return bool Return true on success, false on failure
*/
function add_backup_dir($dir) {
if(!$this->check_dir($dir))return false;
$this->backup_dirs[] = realpath($dir);
return true;
}
/*
* config ftp
* This function is trying to connect to the ftp server.
* param $host string Host of the ftp server
* param $user string user of the ftp server
* param $password string password of ftp server
*
* return bool Return true on success, false on failure
*/
function config_ftp($host,$user,$password) {
$this->host = $host;
$this->user = $user;
$this->pass = $password;
/*
If there is already an other ftp stream, then the old stream will be shut down and the new one will be created
*/
if(!empty($this->ftphandler)) {
ftp_quit($this->ftphandler);
unset($this->ftphandler);
}
/*
If the connection fails, then an error message will be written into the log array $log
*/
if(@!$this->ftphandler = ftp_connect ($this->host)) {
$this->log[] = "not able to connect to '" . $this->host . "'";
return false;
}
/*
When the password or the username is wrong, then there will be written an errormessage into the log array $log
*/
if(@!ftp_login ( $this->ftphandler , $this->user, $this->pass)) {
$this->log[] = "Login or password incorrect";
return false;
}
return true;
}
/*
* set_max_age
* This is the setter function for $max_age. The max age shows how old an archiv can be.
* param $days int maximum age in days of an archive.
*
* return bool Return true on success, false on failure
*/
function set_max_age($days) {
$this->max_age = intval($days);
if($this->max_age > 0) {
return true;
}
else {
$this->log[] = '$max_age can not be smaller then 1';
return false;
}
}
/*
* set_min_backup_number
* This is the setter function for $min_backup_num. The min_backup_num shows how much archivs of one folder must be at least kept
* param $number int min number of archivs
*/
function set_min_backup_number($number) {
$this->min_backup_num = intval($number);
}
/*
* set_tar_path
* Here you can change the tar path.
* param $path string the path to tar
*
* return bool Return true on success, false on failure
*/
function set_tar_path($path) {
if(!$this->check_dir($path)){
$this->log[] = 'Wrong tar path "' . $path . '"';
return false;
}
}
/*
* check_archives
* This function is checking the max_age and is deleting every overaged archiv if there are more then $min_backup_num
* param $mode string setting the mode (ftp or filesystem)
* param $path string string the path to the archives
*
* return bool Return true on success, false on failure
*/
function check_archives($mode,$path = '.') {
if($mode == 'ftp') {
@ftp_mkdir ($this->ftphandler, $path . "/");
$tmp = ftp_nlist ( $this->ftphandler, $path); //getting a array with the content of $path from ftp
for($c = 0;$c < count($tmp);$c++) {
$tmp_r = explode('/', $tmp[$c]);
$dir[] = $tmp_r[count($tmp_r)-1];
}
}
else if($mode == 'filesys') { //getting a array with the content of $path from filesystem
if(!is_dir($path)){
mkdir ($path);
chmod ($path, 0777);
}
$handle=opendir($path);
while ($file = readdir ($handle)) {
if ($file != "." && $file != "..") {
$dir[] = $file;
}
}
closedir($handle);
}
else {
$this->log[] = "Unkown mode '" . $mode . "'. Failed to check.";
return false;
}
foreach($dir as $current_file) {
//searching for archives visible by the class-specific filename
if(preg_match("/^(\d{6}_){2}.+\.tgz$/", $current_file)) {
$today = mktime(0, 0, 0, date("m") , date("d"), date("Y"));
$old_time = mktime(0, 0, 0, substr($current_file,2,2) , substr($current_file,4,2)+$this->max_age, substr($current_file,0,2));
//if the old timestamp + the max age is smaller then the timestamp from today, then the file is overaged
if(($today - $old_time) > 0) {
$counter = 0; //counting the number of backups for this file(s)
for($z = 0;$z < count($dir);$z++) {
if(substr($dir[$z],14,strlen($dir[$z])) == substr($current_file,14,strlen($dir[$z]))) {
$counter++;
}
}
//if there are more then min_backup_num backups then the current file will be deleted
if($counter > $this->min_backup_num) {
if($mode == 'ftp') {
$bool = ftp_delete ( $this->ftphandler, $path . "/" . $current_file);
}
if($mode == 'filesys') {
$bool = unlink($path . "/" . $current_file);
}
if($bool == false) {
$this->log[] = 'Could not delete ' . $current_file . ' from filesystem';
return false;
}
}
}
}
}
return true;
}
/*
* check_dir
* Checking $dir.Can I find it? Is it readable?
*
* param string $dir Directory to check
* return bool Return true on success, false on failure
*/
function check_dir($dir) {
if(!is_dir($dir)) {
$this->log[] = 'could not found ' . $dir;
return false;
}
if(!is_readable($dir)) {
$this->log[] = 'permission for ' . $dir . ' denied';
return false;
}
return true;
}
/*
* backup
* This Function is creating the backups on the filesystem or on an ftp server.
* If $path is not given, then the backups will be saved in the current folder
*
* param $mode string setting the mode (ftp or filesystem)
* param $path string string the path where the archives are going to be saved
*
* return bool Return true on success, false on failure
*/
function backup($mode,$path = '.') {
if($mode != 'ftp' && $mode != 'filesys') {
$this->log[] = 'could not create backup. Unkown mode :' . $mode;
return false;
}
foreach($this->backup_dirs as $current) {
if($path == $current) { //backup folder and target folder can not be the same
$this->log[] = 'Target Folder can not be the backup folder';
return false;
}
if(substr($current,-1) == '/') {
$current = substr($current,0,-1);
}
$tmp_r = explode('/', $current); //detecting the folder
$dir_name = $tmp_r[count($tmp_r)-1];
$archiv_name = date('ymd_his') . "_" . $dir_name . ".tgz";
$archiv_name = str_replace('"', "''", $archiv_name);
$current = str_replace('"', "'", $current);
if($mode == 'filesys') { //Creating folder if need be
if(!is_dir($path)){
mkdir ($path);
chmod ($path, 0777);
}
/*
this is the command which will be send to the shell.
*/
$command = $this->tar_path . "tar cvzf " . escapeshellarg($path . "/" . $archiv_name) . " " . escapeshellarg($current);
passthru ($command, $return);
}
else if($mode == 'ftp') {
@ftp_mkdir ($this->ftphandler, $path . "/");
$command = $this->tar_path . "tar cvzf " . escapeshellarg($archiv_name) . " " . escapeshellarg($current);
passthru ($command, $return);
if(ftp_put ($this->ftphandler, $path . "/" . $archiv_name, $archiv_name, FTP_BINARY) === false) {
$this->log[] = 'could not write on ftp';
return false;
}
unlink($archiv_name);
}
}
}
}
?>