<?php
class db_back{
	var $ver;
	var $charset;
	var $maxsize = 1024;
	var $backdir = '';

	function db_back($dir, $maxsize = 0){
		global $_SET;
		$this->ver = qdb::version();
		$this->charset = str_replace('-', '', $_SET['def_charset']);
		$this->maxsize = $maxsize ? $maxsize : 1024 * 1024 * 2;
		$this->backdir = $dir . qbase::formatTime('Y-m-d', time()) . "/";
	}

	function clear(){
		qbase::deletedir($this->backdir);
		clearstatcache();
		qbase::createdir($this->backdir);
	}

	function dump($table, $page = 1, $limit = 0){
		if(!in_array($table, $this->get_table())) return array('status'=>404);
		qdb::query("lock tables {$table} write");
		$info = $this->_get_field_info($table);
		$status = $this->_get_status($table);
		$insert_field = $this->get_insert_field($table);
		$index = $this->_get_file_index($table);
		if($limit == 0)	$limit = $status['Data_length'] ? intval( $this->maxsize / $status['Data_length'] / 2  *  $status['Rows']) : 100;
		if($index == 0) $index = 1;
		$dumpsql = ($index == 1 && $page == 1) ? $this->get_dump_create_sql($table) : '';
		$total = $status['Rows'];
		$offset = ($page - 1) * $limit;
		if($info['auto']){
			$sql = "select * from {$table} order by {$info['auto']} asc limit {$offset}, {$limit}";
		}else{
			$sql = "select * from {$table} limit {$offset}, {$limit}";
		}
		$query = qdb::query($sql);
		$count = 0;
		$len = 0;
		$insert_pre = "QE(\"insert into `{$table}` ({$insert_field}) values ";
		$insert_array = array();
		while($item = qdb::fetchArray($query, MYSQL_NUM)){
			$count++;
			$item_sql = '';
			for($i=0; $i<$info['num']; $i++){
				$item_sql .= ",'".$this->_escape_str($item[$i])."'";
			}
			$len += strlen($item_sql);
			$insert_array[] = "(" . substr($item_sql, 1) . ")";
			if($count % 100 == 0 ){
				//flush data to disk
				$file = $this->_get_file($table, $index);
				if(is_file($file)){
					$size = filesize($file);
					if($size + $len > $this->maxsize){
						$index++;
						$file = $this->_get_file($table, $index);
					}
				}
				if(count($insert_array) > 0) $dumpsql .= $insert_pre . implode(',', $insert_array) . "\");\r\n";
				$fp = fopen($file, 'a+');
				fwrite($fp, $dumpsql);
				fclose($fp);
				$len = 0;
				$insert_array = array();
				$dumpsql = '';
			}
		}

		$file = $this->_get_file($table, $index);
		if(is_file($file)){
			$size = filesize($file);
			if($size + strlen($dumpsql) > $this->maxsize){
				$index++;
				$file = $this->_get_file($table, $index);
			}
		}
		if(count($insert_array) > 0) $dumpsql .= $insert_pre . implode(',', $insert_array) . "\");\r\n";
		$fp = fopen($file, 'a+');
		fwrite($fp, $dumpsql);
		fclose($fp);
		$data = array(
			'status'=> 200,
			'table'=> $table,
			'total'=> 	$total ,
			'pages'=> $limit ? ceil($total / $limit) : 1,
			'page'=> $page,
			'limit'=> $limit,
		);
		if($data['page'] >= $data['pages']) qdb::query("unlock tables ");
		return $data;
	}

	function get_table(){
		$temp = qdb::fetchAll("show tables");
		$data = array();
		foreach($temp as $val){
			$data[] = array_shift($val);
		}
		return $data;
	}


	function optimize($table){
		return qdb::query("OPTIMIZE TABLE {$table}");
	}

	function repair($table){
		return qdb::query("REPAIR TABLE {$table}");
	}

	function get_dump_create_sql($table){
		global $_SET;
		$dumpsql = "<?php\r\nif(!defined('R_P'))  die('access die');\r\n";
		$dumpsql .= "QE(\"DROP TABLE IF EXISTS `".$table."`;\");\r\n";
		$temp = qdb::queryFirst("show  create table {$table};");
		$sql = $this->_add_charset($temp['Create Table']);
		$sql =  str_replace("\"","\\\"",$sql);
		$dumpsql .="QC(\"".$sql."\");\r\n";
		return $dumpsql;
	}

	function get_status(){
		global $_SET;
		return qdb::fetchAll("SHOW TABLE STATUS FROM {$_SET['dbname']} " );
	}

	/*
	* 返回插入字段
	*/
	function get_insert_field($table){
		$temp = qdb::fetchAll("show fields from {$table}");
		$s= '';
		foreach($temp as $val){
			$s .= ',`'.$val['Field'].'`';
		}
		return substr($s,1);
	}


	/*
	* 返回表字段信息
	*/
	function _get_field_info($table){
		$temp = qdb::fetchAll("SHOW FIELDS FROM `".$table."`");
		$data = array();
		$auto = '';
		foreach($temp as $val){
			if($val['Extra']=='auto_increment'){
				$auto= $val['Field'];
				break;
			}
		}
		$data['num'] = count($temp);
		$data['auto'] = $auto;
		return $data;
	}

	function _add_charset($sql){
		if($this->ver >= '4.1' && !strstr($sql,'ENGINE=')){
			$sql = $this->_create_table($sql);
		}elseif($this->ver == '4.0' && strstr($sql,'ENGINE=')){
			$sql = $this->_change_mysql4($sql);
		}
		$sql = $this->_replace_field_charset($sql);
		return $sql;
	}

	/*
	* 创建数据表
	*/
	function _create_table($sql){
		$type = strtoupper(preg_replace("/^\s*CREATE TABLE\s+.+\s+\(.+?\).*(ENGINE|TYPE)\s*=\s*([a-z]+?).*$/isU","\\2",$sql));
		$type = in_array($type,array('MYISAM','HEAP')) ? $type : 'MYISAM';
		return preg_replace("/^\s*(CREATE TABLE\s+.+\s+\(.+?\)).*$/isU", "\\1", $sql ) . ( $this->ver>='4.1' ? " ENGINE=$type DEFAULT CHARSET={$this->charset} " : " TYPE=$type");
	}

	/*
	* 装换成mysql4.0格式
	*/
	function _change_mysql4($query){
		$exp = "ENGINE=";
		if(!strstr($query,$exp)){
			return $query;
		}
		$exp1 = " ";
		$r = explode($exp,$query);
		$r1 = explode($exp1,$r[1]);
		$returnquery = $r[0]."TYPE=".$r1[0];
		return $returnquery;
	}

	/*
	*去除字段中的编码
	*/
	function _replace_field_charset($sql){
		if($this->ver == '4.0' && strstr($sql, ' character set ')){
			$preg_str="/ character set (.+?) collate (.+?) /is";
			$sql=preg_replace($preg_str,' ',$sql);
		}
		return $sql;
	}

	function _get_status($table){
		return qdb::queryFirst("show  table  status like '{$table}';");
	}

	function _get_file_index($table){
		qbase::createdir($this->backdir);
		if (!is_dir($this->backdir)) die("make dir {$this->backdir} failed");
		$handle = @opendir($this->backdir);
		$temp = array(0);
		while (false !== ($filename = @readdir($handle)))
		{
			if (false !== ($index = $this->_is_table_file($this->backdir , $filename, $table))){
				$temp[] = $index;
			}
		}
		@closedir($handle);
		return max($temp);
	}

	function _get_file($table, $index){
		$dir = $this->backdir;
		qbase::createdir($dir);
		return $dir . $index . "_" . $table . ".php";
	}

	function _is_table_file($dir, $file, $table){
		if(!is_file($dir . $file)) return false;
		$r = preg_match("/([0-9]{1,5})_". preg_quote($table) .".php/", $file, $data);
		if($r) return intval($data[1]) ? intval($data[1]) : false;
		else return false;
	}

	function _escape_str($str){
		$str=mysql_escape_string($str);
		$str=str_replace('\\\'','\'\'',$str);
		$str=str_replace("\\\\","\\\\\\\\",$str);
		$str=str_replace('$','\$',$str);
		return $str;
	}
}
?>