<?php
######################################################################
## MySQL Backup Script v2.1 - May 3, 2007
######################################################################
## For more documentation and new versions, please visit:
## http://www.dagondesign.com/articles/automatic-mysql-backup-script/
## -------------------------------------------------------------------
## Created by Aleister (www.dagondesign.com).
## Much credit goes to Oliver Mueller ([email protected])
## for contributing additional features, fixes, and testing.
######################################################################
######################################################################
## Usage Instructions
######################################################################
## This script requires two files to run:
## backup_dbs.php - Main script file
## backup_dbs_config.php - Configuration file
## Be sure they are in the same directory.
## -------------------------------------------------------------------
## Do not edit the variables in the main file. Use the configuration
## file to change your settings. The settings are explained there.
## -------------------------------------------------------------------
## A few methods to run this script:
## - php /PATH/backup_dbs.php
## - BROWSER: http://domain/PATH/backup_dbs.php
## - ApacheBench: ab "http://domain/PATH/backup_dbs.php"
## - lynx http://domain/PATH/backup_dbs.php
## - wget http://domain/PATH/backup_dbs.php
## - crontab: 0 3 * * * root php /PATH/backup_dbs.php
## -------------------------------------------------------------------
## For more information, visit the website given above.
######################################################################
error_reporting( E_ALL );
// Initialize default settings
$MYSQL_PATH = '/usr/bin';
$MYSQL_HOST = 'localhost';
$MYSQL_USER = 'root';
$MYSQL_PASSWD = 'password';
$BACKUP_DEST = '/db_backups';
$BACKUP_TEMP = '/tmp/backup_temp';
$VERBOSE = true;
$BACKUP_NAME = 'mysql_backup_' . date('Y-m-d');
$LOG_FILE = $BACKUP_NAME . '.log';
$ERR_FILE = $BACKUP_NAME . '.err';
$COMPRESSOR = 'bzip2';
$EMAIL_BACKUP = false;
$DEL_AFTER = false;
$EMAIL_FROM = 'Backup Script';
$EMAIL_SUBJECT = 'SQL Backup for ' . date('Y-m-d') . ' at ' . date('H:i');
$EMAIL_ADDR = '[email protected]';
$ERROR_EMAIL = '[email protected]';
$ERROR_SUBJECT = 'ERROR: ' . $EMAIL_SUBJECT;
$EXCLUDE_DB = 'information_schema';
$MAX_EXECUTION_TIME = 18000;
$USE_NICE = 'nice -n 19';
$FLUSH = false;
$OPTIMIZE = false;
// Load configuration file
$current_path = dirname(__FILE__);
if( file_exists( $current_path.'/backup_dbs_config.php' ) ) {
require( $current_path.'/backup_dbs_config.php' );
} else {
echo 'No configuration file [backup_dbs_config.php] found. Please check your installation.';
exit;
}
################################
# functions
################################
/**
* Write normal/error log to a file and output if $VERBOSE is active
* @param string $msg
* @param boolean $error
*/
function writeLog( $msg, $error = false ) {
// add current time and linebreak to message
$fileMsg = date( 'Y-m-d H:i:s: ') . trim($msg) . "\n";
// switch between normal or error log
$log = ($error) ? $GLOBALS['f_err'] : $GLOBALS['f_log'];
if ( !empty( $log ) ) {
// write message to log
fwrite($log, $fileMsg);
}
if ( $GLOBALS['VERBOSE'] ) {
// output to screen
echo $msg . "\n";
flush();
}
} // function
/**
* Checks the $error and writes output to normal and error log.
* If critical flag is set, execution will be terminated immediately
* on error.
* @param boolean $error
* @param string $msg
* @param boolean $critical
*/
function error( $error, $msg, $critical = false ) {
if ( $error ) {
// write error to both log files
writeLog( $msg );
writeLog( $msg, true );
// terminate script if this error is critical
if ( $critical ) {
die( $msg );
}
$GLOBALS['error'] = true;
}
} // function
################################
# main
################################
// set header to text/plain in order to see result correctly in a browser
header( 'Content-Type: text/plain; charset="UTF-8"' );
header( 'Content-disposition: inline' );
// set execution time limit
if( ini_get( 'max_execution_time' ) < $MAX_EXECUTION_TIME ) {
set_time_limit( $MAX_EXECUTION_TIME );
}
// initialize error control
$error = false;
// guess and set host operating system
if( strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' ) {
$os = 'unix';
$backup_mime = 'application/x-tar';
$BACKUP_NAME .= '.tar';
} else {
$os = 'windows';
$backup_mime = 'application/zip';
$BACKUP_NAME .= '.zip';
}
// create directories if they do not exist
if( !is_dir( $BACKUP_DEST ) ) {
$success = mkdir( $BACKUP_DEST );
error( !$success, 'Backup directory could not be created in ' . $BACKUP_DEST, true );
}
if( !is_dir( $BACKUP_TEMP ) ) {
$success = mkdir( $BACKUP_TEMP );
error( !$success, 'Backup temp directory could not be created in ' . $BACKUP_TEMP, true );
}
// prepare standard log file
$log_path = $BACKUP_DEST . '/' . $LOG_FILE;
($f_log = fopen($log_path, 'w')) || error( true, 'Cannot create log file: ' . $log_path, true );
// prepare error log file
$err_path = $BACKUP_DEST . '/' . $ERR_FILE;
($f_err = fopen($err_path, 'w')) || error( true, 'Cannot create error log file: ' . $err_path, true );
// Start logging
writeLog( "Executing MySQL Backup Script v1.4" );
writeLog( "Processing Databases.." );
################################
# DB dumps
################################
$excludes = array();
if( trim($EXCLUDE_DB) != '' ) {
$excludes = array_map( 'trim', explode( ',', $EXCLUDE_DB ) );
}
// Loop through databases
$db_conn = @mysql_connect( $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWD ) or error( true, mysql_error(), true );
$db_result = mysql_list_dbs($db_conn);
$db_auth = " --host=\"$MYSQL_HOST\" --user=\"$MYSQL_USER\" --password=\"$MYSQL_PASSWD\"";
while ($db_row = mysql_fetch_object($db_result)) {
$db = $db_row->Database;
if( in_array( $db, $excludes ) ) {
// excluded DB, go to next one
continue;
}
// dump db
unset( $output );
exec( "$MYSQL_PATH/mysqldump $db_auth --opt $db 2>&1 >$BACKUP_TEMP/$db.sql", $output, $res);
if( $res > 0 ) {
error( true, "DUMP FAILED\n".implode( "\n", $output) );
} else {
writeLog( "Dumped DB: " . $db );
if( $OPTIMIZE ) {
unset( $output );
exec( "$MYSQL_PATH/mysqlcheck $db_auth --optimize $db 2>&1", $output, $res);
if( $res > 0 ) {
error( true, "OPTIMIZATION FAILED\n".implode( "\n", $output) );
} else {
writeLog( "Optimized DB: " . $db );
}
} // if
} // if
// compress db
unset( $output );
if( $os == 'unix' ) {
exec( "$USE_NICE $COMPRESSOR $BACKUP_TEMP/$db.sql 2>&1" , $output, $res );
} else {
exec( "zip -mj $BACKUP_TEMP/$db.sql.zip $BACKUP_TEMP/$db.sql 2>&1" , $output, $res );
}
if( $res > 0 ) {
error( true, "COMPRESSION FAILED\n".implode( "\n", $output) );
} else {
writeLog( "Compressed DB: " . $db );
}
if( $FLUSH ) {
unset( $output );
exec("$MYSQL_PATH/mysqladmin $db_auth flush-tables 2>&1", $output, $res );
if( $res > 0 ) {
error( true, "Flushing tables failed\n".implode( "\n", $output) );
} else {
writeLog( "Flushed Tables" );
}
} // if
} // while
mysql_free_result($db_result);
mysql_close($db_conn);
################################
# Archiving
################################
// TAR the files
writeLog( "Archiving files.. " );
chdir( $BACKUP_TEMP );
unset( $output );
if( $os == 'unix' ) {
exec("cd $BACKUP_TEMP ; $USE_NICE tar cf $BACKUP_DEST/$BACKUP_NAME * 2>&1", $output, $res);
} else {
exec("zip -j -0 $BACKUP_DEST/$BACKUP_NAME * 2>&1", $output, $res);
}
if ( $res > 0 ) {
error( true, "FAILED\n".implode( "\n", $output) );
} else {
writeLog( "Backup complete!" );
}
// first error check, so we can add a message to the backup email in case of error
if ( $error ) {
$msg = "\n*** ERRORS DETECTED! ***";
if( $ERROR_EMAIL ) {
$msg .= "\nCheck your email account $ERROR_EMAIL for more information!\n\n";
} else {
$msg .= "\nCheck the error log {$err_path} for more information!\n\n";
}
writeLog( $msg );
}
################################
# post processing
################################
// do we email the backup file?
if ($EMAIL_BACKUP) {
writeLog( "Emailing backup to " . $EMAIL_ADDR . " .. " );
$headers = "From: " . $EMAIL_FROM . " <root@localhost>";
// Generate a boundary string
$rnd_str = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$rnd_str}x";
// Add headers for file attachment
$headers .= "\nMIME-Version: 1.0\n" .
"Content-Type: multipart/mixed;\n" .
" boundary=\"{$mime_boundary}\"";
// Add a multipart boundary above the plain message
$body = "This is a multi-part message in MIME format.\n\n" .
"--{$mime_boundary}\n" .
"Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
file_get_contents($log_path) . "\n\n";
// make Base64 encoding for file data
$data = chunk_split(base64_encode(file_get_contents($BACKUP_DEST.'/'.$BACKUP_NAME)));
// Add file attachment to the message
$body .= "--{$mime_boundary}\n" .
"Content-Type: {$backup_mime};\n" .
" name=\"{$BACKUP_NAME}\"\n" .
"Content-Disposition: attachment;\n" .
" filename=\"{$BACKUP_NAME}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" .
"--{$mime_boundary}--\n";
$res = mail( $EMAIL_ADDR, $EMAIL_SUBJECT, $body, $headers );
if ( !$res ) {
error( true, 'FAILED to email mysql dumps.' );
}
}
// do we delete the backup file?
if ( $DEL_AFTER && $EMAIL_BACKUP ) {
writeLog( "Deleting file.. " );
if ( file_exists( $BACKUP_DEST.'/'.$BACKUP_NAME ) ) {
$success = unlink( $BACKUP_DEST.'/'.$BACKUP_NAME );
error( !$success, "FAILED\nUnable to delete backup file" );
}
}
// see if there were any errors to email
if ( ($ERROR_EMAIL) && ($error) ) {
writeLog( "\nThere were errors!" );
writeLog( "Emailing error log to " . $ERROR_EMAIL . " .. " );
$headers = "From: " . $EMAIL_FROM . " <root@localhost>";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: text/plain; charset=\"iso-8859-1\";\n";
$body = "\n".file_get_contents($err_path)."\n";
$res = mail( $ERROR_EMAIL, $ERROR_SUBJECT, $body, $headers );
if( !$res ) {
error( true, 'FAILED to email error log.' );
}
}
################################
# cleanup / mr proper
################################
// close log files
fclose($f_log);
fclose($f_err);
// if error log is empty, delete it
if( !$error ) {
unlink( $err_path );
}
// delete the log files if they have been emailed (and del_after is on)
if ( $DEL_AFTER && $EMAIL_BACKUP ) {
if ( file_exists( $log_path ) ) {
$success = unlink( $log_path );
error( !$success, "FAILED\nUnable to delete log file: ".$log_path );
}
if ( file_exists( $err_path ) ) {
$success = unlink( $err_path );
error( !$success, "FAILED\nUnable to delete error log file: ".$err_path );
}
}
// remove files in temp dir
if ($dir = @opendir($BACKUP_TEMP)) {
while (($file = readdir($dir)) !== false) {
if (!is_dir($file)) {
unlink($BACKUP_TEMP.'/'.$file);
}
}
}
closedir($dir);
// remove temp dir
rmdir($BACKUP_TEMP);
?>
<?php
######################################################################
## MySQL Backup Script Configuration File
##
## Use this file to configure your settings for the script.
######################################################################
## For more documentation and new versions, please visit:
## http://www.dagondesign.com/articles/automatic-mysql-backup-script/
## -------------------------------------------------------------------
## Created by Aleister (www.dagondesign.com).
## Much credit goes to Oliver Mueller ([email protected])
## for contributing additional features, fixes, and testing.
######################################################################
######################################################################
## General Options
######################################################################
// Remember to always use absolute paths without trailing slashes!
// On Windows Systems: Don't forget volume character (e.g. C:).
// Path to the mysql commands (mysqldump, mysqladmin, etc..)
$MYSQL_PATH = '/usr/bin';
// Mysql connection settings (must have root access to get all DBs)
$MYSQL_HOST = 'localhost';
$MYSQL_USER = 'root';
$MYSQL_PASSWD = 'password';
// Backup destination (will be created if not already existing)
$BACKUP_DEST = '/db_backups';
// Temporary location (will be created if not already existing)
$BACKUP_TEMP = '/tmp/backup_temp';
// Show script status on screen while processing
// (Does not effect log file creation)
$VERBOSE = true;
// Name of the created backup file (you can use PHP's date function)
// Omit file suffixes like .tar or .zip (will be set automatically)
$BACKUP_NAME = 'mysql_backup_' . date('Y-m-d');
// Name of the standard log file
$LOG_FILE = $BACKUP_NAME . '.log';
// Name of the error log file
$ERR_FILE = $BACKUP_NAME . '.err';
// Which compression program to use
// Only relevant on unix based systems. Windows system will use zip command.
$COMPRESSOR = 'bzip2';
######################################################################
## Email Options
######################################################################
// Email the backup file when finished?
$EMAIL_BACKUP = false;
// If using email backup, delete from server afterwards?
$DEL_AFTER = false;
// The backup email's 'FROM' field
$EMAIL_FROM = 'Backup Script';
// The backup email's subject line
$EMAIL_SUBJECT = 'SQL Backup for ' . date('Y-m-d') . ' at ' . date('H:i');
// The destination address for the backup email
$EMAIL_ADDR = '[email protected]';
######################################################################
## Error Options
######################################################################
// Email error log to specified email address
// (Will only send if an email address is given)
$ERROR_EMAIL = $EMAIL_ADDR;
// Subject line for error email
$ERROR_SUBJECT = 'ERROR: ' . $EMAIL_SUBJECT;
######################################################################
## Advanced Options
## Be sure you know what you are doing before making changes here!
######################################################################
// A comma separated list of databases, which should be excluded
// from backup
// information_schema is a default exclude, because it is a read-only DB anyway
$EXCLUDE_DB = 'information_schema';
// Defines the maximum number of seconds this script shall run before terminating
// This may need to be adjusted depending on how large your DBs are
// Default: 18000
$MAX_EXECUTION_TIME = 18000;
// Low CPU usage while compressing (recommended) (empty string to disable).
// Only relevant on unix based systems
// Default: 'nice -n 19'
$USE_NICE = 'nice -n 19';
// Flush tables between mysqldumps (recommended, if it runs during non-peak time)
// Default: false
$FLUSH = false;
// Optimize databases between mysqldumps.
// (For detailed information look at
// http://dev.mysql.com/doc/mysql/en/mysqlcheck.html)
// Default: false
$OPTIMIZE = false;
######################################################################
## End of Options
######################################################################
?>
<?php
/**
* Generates a backup of the database and sends it in an email
*
* @author Elijah Lofgren < elijahlofgren [at] elijahlofgren.com>
* @version $Id: backup-database-cron.php 2135 2005-08-07 13:43:29Z elijahlofgren $
*/
require_once dirname(__FILE__).'/../config.php';
$output = 'Creating Database backup.';
$email = '[email protected]';
$output .= backup($config, $email);
echo $output;
// $output .= $Page->showFooter();
// echo $output;
/* Database Backup Utility 1.0 By Eric Rosebrock, [url]http://www.phpfreaks.com[/url]
Written: July 7th, 2002 12:59 AM
If running from shell, put this above the <?php "#! /usr/bin/php -q" without the quotes!!!
This script is dedicated to "Salk". You know who you are :)
This script runs a backup of your database that you define below. It then gzips the .sql file
and emails it to you or ftp's the file to a location of your choice.
It is highly recommended that you leave gzip on to reduce the file size.
You must chown the directory this script resides in to the same user or group your webserver runs
in, or CHMOD it to writable. I do not recommend chmod 777 but it's a quick solution. If you can setup
a cron, you can probably chown your directory!
IMPORTANT!!! I recommend that you run this outside of your
web directory, unless you manually want to run this script. If you do upload it inside your web
directory source Tree($settings), I would at least apply Apache access control on that directory. You don't
want people downloading your raw databases!
This script is meant to be setup on a crontab and run on a weekly basis
You will have to contact your system administrator to setup a cron tab for this script
Here's an example crontab:
0 0-23 * * * php /path/to/thisdirectory/dbsender.php > /dev/null
*/
function backup($config, $email)
{
// Optional Options You May Optionally Configure
$use_gzip = TRUE; // Set to FALSE if you don't want the files sent in .gz format
$remove_sql_file = TRUE; // Set this to TRUE if you want to remove the .sql file after gzipping. Yes is recommended.
$remove_gzip_file = TRUE; // Set this to TRUE if you want to delete the gzip file also. I recommend leaving it to "no"
// Full path to the backup directory. Do not use trailing slash!
$savepath = dirname(__FILE__);
$send_email = TRUE; // Do you want this database backup sent to your email? Fill out the next 2 lines
// $senddate = date("j F Y");
$senddate = date('Y-m-d-Hi');
// Subject in the email to be sent.
$subject = 'MySQL DB: '.$config['db_name'].' Backup - '.$senddate;
$message = 'Your MySQL database has been backed up and is attached to this email'; // Brief Message.
/*
$use_ftp = "no"; // Do you want this database backup uploaded to an ftp server? Fill out the next 4 lines
$ftp_server = ""; // FTP hostname
$ftp_user_name = ""; // FTP username
$ftp_user_pass = ""; // FTP password
$ftp_path = "/public_html/backups/"; // This is the path to upload on your ftp server!
*/
// Do not Modify below this line! It will void your warranty!
$date = date('Y-m-d-Hi');
$filename = $savepath.'/'.$config['db_name'].'-'.$date.'.sql';
// passthru("mysqldump --opt -h$dbhost -u$dbuser -p$dbpass $dbname >$filename");
// passthru("mysqldump --opt -h$dbhost -u$dbuser -p$dbpass $dbname >$filename");
// $passthru = "mysqldump -h $server -u $username -p$password --add-drop-table --all --quick --lock-tables --disable-keys --extended-insert -d $database >$filename";
$passthru = 'mysqldump --opt'
.' -h '.$config['db_hostname']
.' -u '.$config['db_username']
// There must not be a space between -p and the password
.' -p'.$config['db_password']
// There MUST be a space between the password and DB name
.' '.$config['db_name'].' > '.$filename;
// echo $passthru;
// $passthru = "mysqldump -h $server -u $username -p$password --opt --tables -d $database >$filename";
// echo $passthru;
passthru($passthru);
if (FALSE != $use_gzip) {
$real_path = realpath($savepath);
// echo '<br />df '.$real_path.'</br>';
$zipline = "tar -czf ".$real_path.'/'.$config['db_name'].'-'.$date.'_sql.tar.gz '.$real_path.'/'.$config['db_name'].'-'.$date.'.sql';
// $zipline = "tar -czf --directory=".$real_path.' '.$database."-".$date."_sql.tar.gz "."$database-$date.sql";
// echo '<br />'.$zipline.'<br />';
shell_exec($zipline);
}
// Remove the SQL file if needed
if (FALSE != $remove_sql_file) {
exec('rm -r -f '.$filename);
}
// If supposed to gzip the file
if (FALSE != $use_gzip) {
$filename2 = $savepath.'/'.$config['db_name'].'-'.$date.'_sql.tar.gz';
} else {
$filename2 = $savepath.'/'.$config['db_name'].'-'.$date.'.sql';
}
// If backing up to email address
if (FALSE != $send_email) {
$fileatt_type = filetype($filename2);
// echo $filename2;
$fileatt_name = "".$config['db_name']."-".$date."_sql.tar.gz";
$headers = 'From: '.$email;
// Read the file to be attached ('rb' = read binary)
$file = fopen($filename2, 'rb');
$data = fread($file, filesize($filename2));
fclose($file);
// Generate a boundary string
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
// Add the headers for a file attachment
$headers .= "\nMIME-Version: 1.0\n" ."Content-Type: multipart/mixed;\n" ." boundary=\"{$mime_boundary}\"";
// Add a multipart boundary above the plain message
$message = "This is a multi-part message in MIME format.\n\n" ."--{$mime_boundary}\n" ."Content-Type: text/plain; charset=\"iso-8859-1\"\n" ."Content-Transfer-Encoding: 7bit\n\n" .
$message . "\n\n";
// Base64 encode the file data
$data = chunk_split(base64_encode($data));
// Add file attachment to the message
$message .= "--{$mime_boundary}\n" ."Content-Type: {$fileatt_type};\n" ." name=\"{$fileatt_name}\"\n" ."Content-Disposition: attachment;\n" ." filename=\"{$fileatt_name}\"\n" ."Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" ."--{$mime_boundary}--\n";
// Send the message
$ok = mail($email, $subject, $message, $headers);
if (FALSE != $ok) {
$output = '<p>Database backup created and sent! ';
$output .= 'File name '.$filename2.'</p>';
} else {
$output = '<p>Mail could not be sent. Sorry!</p>';
}
}
/*
if($use_ftp == "yes"){
$ftpconnect = "ncftpput -u $ftp_user_name -p $ftp_user_pass -d debsender_ftplog.log -e dbsender_ftplog2.log -a -E -V $ftp_server $ftp_path $filename2";
shell_exec($ftpconnect);
echo "<h4><center>$filename2 Was created and uploaded to your FTP server!</center></h4>";
}
*/
if ('yes' == $remove_gzip_file) {
exec("rm -r -f $filename2");
}
return $output;
}
?>