<?php
class mysqlbackup{
	private $config;
	private $content;
	private $dbName = array();
	const DIR_SEP = DIRECTORY_SEPARATOR;
	public function __construct($config){
		$config['charset'] = 'utf8';
		$config['isCompress'] = 0; 
		$config['isDownload'] = 0; 
		$this->config = $config;
		header ( "Content-type: text/html;charset=utf-8" );
		$this->connect();
	}
	private function connect() {
		if (mysql_connect($this->config['host'], $this->config['userName'], $this->config['userPassword'])) {
			mysql_query("SET NAMES '{$this->config['charset']}'");
			mysql_query("set interactive_timeout=24*3600");
		} else {
			$this->throwException('无法连接到数据库!');
		}
	}
	public function setDBName($dbName = '*') {
		if ($dbName == '*') {
			$rs = mysql_list_dbs();
			$rows = mysql_num_rows($rs);
			if($rows){
				for($i=0;$i<$rows;$i++){
					$dbName = mysql_tablename($rs,$i);
					$block = array('information_schema', 'mysql');
					if (!in_array($dbName, $block)) {
						$this->dbName[] = $dbName;
					}
				}
			} else {
				$this->throwException('没有任何数据库!');
			}
		} else {
			$this->dbName = func_get_args();
		}
	}
	private function getFile($fileName) {
		$this->content = '';
		$fileName = $this->trimPath($this->config['path'] . self::DIR_SEP .$fileName);
		if (is_file($fileName)) {
			$ext = strrchr($fileName, '.');
			if ($ext == '.sql') {
				$this->content = @file_get_contents($fileName);
			} elseif ($ext == '.gz') {
				$this->content = implode('', gzfile($fileName));
			} else {
				$this->throwException('无法识别的文件格式!');
			}
		} else {
			$this->throwException('文件不存在!');
		}
	}
	private function setFile() {
		$recognize = '';
		$recognize = implode('_', $this->dbName);
		$fileName = $this->trimPath($this->config['path'] . self::DIR_SEP . $this->config['newFileName']);
		if ($this->config['isCompress'] == 0) {
			if (!file_put_contents($fileName, $this->content, LOCK_EX)) {
				$this->throwException('写入文件失败,请检查磁盘空间或者权限!');
			}
		} else {
			if (function_exists('gzwrite')) {
				$fileName .= '.gz';
				if ($gz = gzopen($fileName, 'wb')) {
					gzwrite($gz, $this->content);
					gzclose($gz);
				} else {
					$this->throwException('写入文件失败,请检查磁盘空间或者权限!');
				}
			} else {
				$this->throwException('没有开启gzip扩展!');
			}
		}
		if ($this->config['isDownload']) {
			$this->downloadFile($fileName);
		}
	}
	private function trimPath($path) {
		return str_replace(array('/', '\\', '//', '\\\\'), self::DIR_SEP, $path);
	}
	private function downloadFile($fileName) {
		ob_end_clean();
		header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		header('Content-Description: File Transfer');
		header('Content-Type: application/octet-stream');
		header('Content-Length: ' . filesize($fileName));
		header('Content-Disposition: attachment; filename=' . basename($fileName));
		readfile($fileName);
	}
	private function backquote($str) {
		return "`{$str}`";
	}
	private function getTables($dbName){
		@$rs = mysql_list_tables($dbName);
		$rows = mysql_num_rows($rs);
		$dbprefix = $this->config['dbprefix'];
		for ($i=0; $i<$rows; $i++) {
			$tbName = mysql_tablename($rs,$i);
			if(substr($tbName,0,strlen($dbprefix)) == $dbprefix){ 
				$tables[] = $tbName;
			}
		}
		return $tables;
	}
	private function chunkArrayByByte($array, $byte = 5120) {
		$i=0;
		$sum=0;
		foreach ($array as $v) {
			$sum += strlen($v);
			if ($sum < $byte) {
				$return[$i][] = $v;
			} elseif ($sum == $byte) {
				$return[++$i][] = $v;
				$sum = 0;
			} else {
				$return[++$i][] = $v;
				$i++;
				$sum = 0;
			}
		}
		return $return;
	}
	public function backup() {
		$this->content = '/* This file is created by MySQLReback ' . date('Y-m-d H:i:s') . ' */';
		foreach ($this->dbName as $dbName) {
			$qDbName = $this->backquote($dbName);
			$rs = mysql_query("SHOW CREATE DATABASE {$qDbName}");
			if ($row = mysql_fetch_row($rs)) {
				mysql_select_db($dbName);
				$tables = $this->getTables($dbName);
				foreach ($tables as $table) {
					$table = $this->backquote($table);
					$tableRs = mysql_query("SHOW CREATE TABLE {$table}");
					if ($tableRow = mysql_fetch_row($tableRs)) {
						$this->content .= "\r\n /* 创建表结构 {$table}  */";
						$this->content .= "\r\n DROP TABLE IF EXISTS {$table};/* MySQLReback Separation */ {$tableRow[1]};/* MySQLReback Separation */";
						$tableDateRs = mysql_query("SELECT * FROM {$table}");
						$valuesArr = array();
						$values = '';
						while ($tableDateRow = mysql_fetch_row($tableDateRs)) {
							foreach ($tableDateRow as &$v) {
								$v = "'" . addslashes($v) . "'"; 
							}
							$valuesArr[] = '(' . implode(',', $tableDateRow) . ')';
						}
						$temp = $this->chunkArrayByByte($valuesArr);
						if (is_array($temp)) {
							foreach ($temp as $v) {
								$values = implode(',', $v) . ';/* MySQLReback Separation */';
								if ($values != ';/* MySQLReback Separation */') {
									$this->content .= "\r\n /* 插入数据 {$table} */";
									$this->content .= "\r\n INSERT INTO {$table} VALUES {$values}";
								}
							}
						}
					}
				}
			} else {
				$this->throwException('未能找到数据库!');
			}
		}
		if (!empty($this->content)) {
			$this->setFile();
		}
		return true;
	}
	public function recover($fileName) {
		$this->getFile($fileName);
		if (!empty($this->content)) {
			$content = explode(';/* MySQLReback Separation */', $this->content);
			foreach ($content as $i => $sql) {
				$sql = trim($sql);
				if (!empty($sql)) {
					$dbName = $this->dbName[0];
					if(!mysql_select_db($dbName)) $this->throwException('不存在的数据库!' . mysql_error());
					$rs = mysql_query($sql);
					if ($rs) {
						if (strstr($sql, 'CREATE DATABASE')) {
							$dbNameArr = sscanf($sql, 'CREATE DATABASE %s');
							$dbName = trim($dbNameArr[0], '`');
							mysql_select_db($dbName);
						}
					} else {
						$this->throwException('备份文件被损坏!' . mysql_error());
					}
				}
			}
		} else {
			$this->throwException('无法读取备份文件!');
		}
		return true;
	}
	private function throwException($error) {
		throw new Exception($error);
	}
}