<?php
/**
* This file contains a function library for both the backup module and
*	the backup script.
*
*/


/**
* This function backs up our database.
*
* @param string $db_file This is set to the name of the file which holds
*	the database.
*
* @param string $prefix_dir The directory name to prefix to the backup.
* 
* @return mixed NULL is returned on success.  Otherwise an error is returned.
*/
function backup_database(&$db_file, $prefix_dir = "") {

	//
	// Parse our database URL into credentials and remove the leading
	// slash from the path as well.
	//
	$db_data = parse_url($GLOBALS["db_url"]);
	$db_data["path"][0] = " ";

	//
	// Create our database temp file
	//
	$db_file_tmp = tempnam("/tmp", "drupal-backup-db-");

	//
	// Create our date string for filenames
	//
	$date_string = date("YmdHis");

	//
	// The name of our final db file.
	// This includes a random number to keep attackers from guessing 
	// the filename.
	//
	$db_file = "drupal-backup-db-" . $date_string 
		. "-" . mt_rand(0, 999999999) . ".tgz";

	//
	// Pre-pend our prefix if it's present.
	//
	if (!empty($prefix_dir)) {
		$db_file = $prefix_dir . "/" . $db_file;
	}

	if (empty($db_file_tmp)) {
		$error = "Call to tempnam() failed";
		return($error);
	}

	//
	// Now dump our database to the temp file
	//
	$cmd = "mysqldump -u " . $db_data["user"]
		. " -h "  . $db_data["host"]
		. " -p"  . $db_data["pass"]
		. " "  . $db_data["path"]
		. " |gzip >$db_file_tmp "
		;

	$fp = popen($cmd, "r");

	if (empty($fp)) {
		$error = "Unable to run command '$cmd'";
		return($error);
	}

	$retval = pclose($fp);

	if ($retval != 0) {
		$error = "Command '$cmd' returned value: $retval";
		return($error);
	}

	//
	// Move the temp file into the current directory (with a new name)
	// so that it can be included in the tarball.
	//
	if (!rename($db_file_tmp, $db_file)) {
		$error = "Renaming file '$db_file_tmp' to '$db_file' failed";
		return($error);
	}

	// Assume success
	return(null);

} // End of backup_database() 


/**
* This function gets a list of files to back up.  Any files that are 
*	already backups are excluded.
*
* @param array $files This is set to a list of filenames to be backed up.
*
* @return mixed NULL is returned on success.  Otherwise an error is returned.
*/
function backup_get_files(&$file_list) {

	//
	// Get a list of all files in the current directory, filter out the 
	// current and parent directories, and any existing backup files.
	// Trying to make GNU tar's --exclude switch actually work for me
	// was like trying to herd housecats that were hopped up on crack.
	// It just wasn't going to happen. :-)  Plus, this approach is
	// more portable.
	//
	$file_list = "";

	$fp = opendir(".");

	while ($file = readdir($fp)) {
		//
		// Skip the current and parent directory
		//
		if ($file == "." || $file == "..") {
			continue;
		}

		//
		// Skip any backup files
		//
		if (strstr($file, "backup-")) {
			continue;
		}

		$file_list .= $file . " ";

	}

	if (!$fp) {
		$error = "Unable to open current directory";
		return($error);
	}

	closedir($fp);

	// Assume success
	return(null);

} // End of backup_get_files()


/**
* This function backs up our file system under DOCUMENT_ROOT, which also
*	includes the database dump.
*
* @param string $db_file The name of our database dump
*
* @param string $backup_file This is set to the name of the main backup
*	file which is created.
*
* @param string $prefix_dir The directory name to prefix to the backup.
* 
* @return mixed NULL is returned on success.  Otherwise an error is returned.
*/
function backup_files($db_file, &$backup_file, $prefix_dir = "") {

	$error = backup_get_files($file_list);
	if (!empty($error)) {
		$error = "backup_get_files(): " . $error;
		return($error);
	}

	//
	// Finally, add in our database backup.  It's excluded since it's
	// a backup file just in case there's multiple database dumps lying 
	// around from previous backups that were aborted.  But we want to
	// explicitly add in the dump from *this* run of backup.
	//
	$file_list .= $db_file;

	//
	// Now tar up the contents of this directory
	//
	$backup_tmp = tempnam("/tmp", "backup-htdocs-");

	//
	// This includes a random number to keep attackers from guessing 
	// the filename.
	//
	$date_string = date("YmdHis");
	$backup_file = "drupal-backup-" . $date_string 
		. "-" . mt_rand(0, 999999999) . ".tgz";

	//
	// Pre-pend our prefix if it's present.
	//
	if (!empty($prefix_dir)) {
		$backup_file = $prefix_dir . "/" . $backup_file;
	}

	$cmd = "tar cfz $backup_tmp $file_list 2>&1";

	$fp = popen($cmd, "r");

	if (empty($fp)) {
		$error = "Unable to run command '$cmd'";
		return($error);
	}

	while ($line = fgets($fp)) {
		print "tar output: $line";
	}

	$retval = pclose($fp);

	if ($retval != 0) {
		$error = "Command '$cmd' returned value: $retval";
		return($error);
	}

	//
	// Now remove the database file, we don't need it anymore.
	//
	if (!unlink($db_file)) {
		$error = "Unable to delete file '$db_file'";
		return($error);
	}

	//
	// Finally, move the tarball into this directory so the user can grab it
	//
	if (!rename($backup_tmp, $backup_file)) {
		$error = "Renaming file '$backup_tmp' to '$backup_file' failed";
		return($error);
	}

	//
	// Make our backup file world-readable.
	//
	if (!chmod($backup_file, 0644)) {
		$error = "chmod() failed";
		return($error);
	}
  
	// Assume success
	return(null);

} // End of backup_files()


/**
* This is the main function which does all of our work.
*
* @return mixed NULL is returned on success, otherwise an error is returned.
* 	This allows us to "catch" errors and let them bubble up the call stack,
*	not unlike exceptions in PHP 5.
*/
function main() {


} // End of main()


/*
if ($error = main()) {
	print $argv[0] . ": Error: $error\n";
	exit (1);
}
*/


?>
