<?php 

/**
 * 名称：数据库管理控制器
 * 作者：荷塘月色
 * 邮箱：kujiw@qq.com
 * 说明：
 */

namespace Admin\Controller;
class DatabaseController extends CommonController {

	public function index(){
		if (IS_GET) {
			$this -> display();
		}elseif (IS_POST) {
			// 返回备份的数据包
			$path  = realpath(C('DATA_BACKUP_PATH')) . DIRECTORY_SEPARATOR . '201*-*-*.sql*';
			$files = glob($path);
			$list = array();
			foreach($files as $name){
				$basename = basename($name);
				$size = filesize($name);
				$ext = pathinfo($basename, PATHINFO_EXTENSION);
				$match	= sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
				$filetime = $match[0].$match[1].$match[2].'-'.$match[3].$match[4].$match[5];
				$list[$filetime]['time'] = $filetime;
				$list[$filetime]['parts'] += 1;
				$list[$filetime]['size'] += $size;
				$list[$filetime]['ext'] = $ext;
				$list[$filetime]['files'][$match[6]] = array('file' => $basename,'size' => intval($size/1024)?intval($size/1024):1);
			}
			$count = count($list);
			$rows = array();
			for ($i=0; $i < $count; $i++) { 
				$rows[$i] = array_shift($list);
				$rows[$i]['id'] = $i+1;
				$rows[$i]['size'] = intval($rows[$i]['size']/1024)?intval($rows[$i]['size']/1024):1;
			}
			$rows = array_reverse($rows);
			$result = array(
				'rows'  =>  $rows,
				'total' =>  $count,
				);
			$this -> ajaxReturn($result);
		}
	}

	public function showsql(){
		if (IS_POST) {
			$filename = I('filename');
			$file  = realpath(C('DATA_BACKUP_PATH')) . DIRECTORY_SEPARATOR . $filename;
			if (!is_file($file)) {
				$this -> error('文件不存在！');
			}
			$ext = pathinfo($file, PATHINFO_EXTENSION);
			if($ext == 'gz'){
				$gz   = gzopen($file, 'r');
			} else {
				$gz   = fopen($file, 'r');
			}
			$sql  = '';
			for($i = 0; $i < 1000; $i++){
				$sql .= ($ext == 'gz') ? gzgets($gz) : fgets($gz); 
				if (($ext == 'gz') ? gzeof($gz) : feof($gz)) {
					break;
				}
			}
			if (($ext == 'gz') ? !gzeof($gz) : !feof($gz)) {
				$sql .='<a href="'.str_replace(array('./','//'), array('/','/'), __ROOT__.C('DATA_BACKUP_PATH').'/'.basename($file)).'" style="color:red" target="_blank">后面还有更多内容，请下载到电脑上查看！</a>';
			}
			$this -> success($sql);
		}
	}

	// 还原数据库
	public function import(){
		if (IS_GET) {
			$path  = realpath(C('DATA_BACKUP_PATH')) . DIRECTORY_SEPARATOR . I('filetime').'-*.sql*';
			$files = glob($path);
			$list = array();
			foreach($files as $name){
				$basename = basename($name);
				$match	= sscanf($basename, '%4s%2s%2s-%2s%2s%2s-%d');
				$list[$match[6]] = $basename;
			}
			ksort($list);
			$count = count($list);
			end($list);
			if (!$count || $count != key($list)) {
				session('backup_list',null);
				echo '备份文件可能已经损坏，请检查！';die;
			}else{
				session('backup_list', $list);
				$this -> backup_list = $list;
				$this ->display();
			}
		}elseif (IS_POST) {
			$list  = session('backup_list');
			if (!$list) {
				$this -> error('数据提交错误！');
			}
			$part = I('part');
			$start = I('start');
			$config = array(
				'path'	 => realpath(C('DATA_BACKUP_PATH')) . DIRECTORY_SEPARATOR,
				'compress' => (pathinfo($list[$part], PATHINFO_EXTENSION)=='sql')?0:1
			);
			$db = new \Common\Vendor\Database($list[$part], $config);
			$start = $db->import($start);
			if(false === $start){
				$this->error('还原数据出错！');
			} elseif(0 === $start) { //下一卷
				$part = $part+1;
				if(isset($list[$part])){
					$data = array('part' => $part, 'start' => 0, 'rate'=>0);
					$this->success($data);
				} else {
					session('backup_list', null);
					$data = array('part' => $part, 'start' => -1, 'rate'=>0);
					$this->success($data);
				}
			} else {
				if($start[1]){
					$data = array('part' => $part, 'start' => $start[0],'rate'=>floor(100 * ($start[0] / $start[1])));
					$this->success($data);
				} else {
					$data = array('part' => $part, 'start' => $start[0],'rate'=>0);
					$this->success($data);
				}
			}
		}
	}

	// 删除备份数据
	public function delete(){
		if (IS_POST) {
			$pattern = realpath(C('DATA_BACKUP_PATH')) . DIRECTORY_SEPARATOR . I('time') . '-*.'.I('ext');
			$list = glob($pattern);
			if (count($list) != I('parts')) {
				$this -> error('数据校验失败！');
			}
			foreach ($list as $key => $value) {
				@unlink($value);
			}
			$this -> success('删除成功！');
		}
	}

	// 返回数据库中的表
	public function table(){
		if (IS_POST) {
			$Db = \Think\Db::getInstance();
			// $list  = $Db->query('SHOW TABLE STATUS');
			$list  = $Db->query("SHOW TABLE STATUS from ".C('DB_NAME')." LIKE '".C('DB_PREFIX')."%'");
			$list  = array_map('array_change_key_case', $list);
			$count = count($list);
			for ($i=0; $i < $count; $i++) { 
				$list[$i]['id'] = $i+1;
			}
			$result = array(
				'rows'  =>  $list,
				'total' =>  $count,
				);
			$this -> ajaxReturn($result);
		}
	}

	// 优化表
	public function optimize(){
		if (IS_POST) {
			$tables = I('table');
			if($tables) {
				$Db   = \Think\Db::getInstance();
				if(is_array($tables)){
					$tables = implode('`,`', $tables);
					$list = $Db->query('OPTIMIZE TABLE '.$tables);
					if($list){
						$this->success('数据表优化完成！');
					} else {
						$this->error('数据表优化出错请重试！');
					}
				} else {
					$list = $Db->query('OPTIMIZE TABLE '.$tables);
					if($list){
						$this->success('数据表'.$tables.'优化完成！');
					} else {
						$this->error('数据表'.$tables.'优化出错请重试！');
					}
				}
			} else {
				$this->error('请指定要优化的表！');
			}
		}
	}

	// 修复表
	public function repair(){
		if (IS_POST) {
			$tables = I('table');
			if($tables) {
				$Db   = \Think\Db::getInstance();
				if(is_array($tables)){
					$tables = implode('`,`', $tables);
					$list = $Db->query('REPAIR TABLE '.$tables);
					if($list){
						$this->success('数据表修复完成！');
					} else {
						$this->error('数据表修复出错请重试！');
					}
				} else {
					$list = $Db->query('REPAIR TABLE '.$tables);
					if($list){
						$this->success('数据表'.$tables.'修复完成！');
					} else {
						$this->error('数据表'.$tables.'修复出错请重试！');
					}
				}
			} else {
				$this->error('请指定要修复的表！');
			}
		}
	}

	// 查看创建信息
	public function showcreate(){
		if (IS_POST) {
			$table = I('table');
			$Db   = \Think\Db::getInstance();
			$result = $Db->query("SHOW CREATE TABLE `{$table}`");
			$this -> success($result[0]['Create Table']);
		}
	}

	// 备份数据库
	public function export(){
		if (IS_GET) {
			$tables = I('tables');
			$backup_path = C('DATA_BACKUP_PATH');
			if(!is_dir($backup_path)){
				mkdir($backup_path, 0755, true);
			}
			if (!is_writeable($backup_path)) {
				echo '备份目录不存在或不可写，请检查后重试！';die();
			}
			if (is_array($tables)) {
				$this -> tables = $tables;
				session('backup_tables',$tables);
				$this -> display();
			}else{
				echo '参数错误！';die();
			}
		}elseif (IS_POST) {
			$step = I('step',0,'intval');
			$backup_path = C('DATA_BACKUP_PATH');
			$backup_config = array(
				'path'	 => realpath($backup_path) . DIRECTORY_SEPARATOR,
				'part'	 => C('DATA_BACKUP_PART_SIZE'),
				'compress' => C('DATA_BACKUP_COMPRESS'),
				'level'	=> C('DATA_BACKUP_COMPRESS_LEVEL'),
			);

			switch ($step) {
				//检查是否有正在执行的备份任务
				case 0:
					if (!session('backup_tables')) {
						$this->error(array('step'=>$step,'msg'=>'没有检测到需要备份的数据库表！请从新提交！'));
					}
					$lock = $backup_config['path'].'backup.lock';
					if(is_file($lock)){
						$this->error(array('step'=>$step,'msg'=>'检测到有一个备份任务正在执行，请稍后再试！'));
					} else {
						//创建锁文件
						file_put_contents($lock, NOW_TIME);
						session('backup_step',$step+1);
						$this -> success(array('step'=>$step+1));
					}
					break;

				// 创建备份文件
				case 1:
					if (session('backup_step') != $step) {
						session('backup_step',null);
						$this->error(array('step'=>$step,'msg'=>'步骤错误！'));
					}
					//生成备份文件信息
					$file = array(
						'name' => date('Ymd-His', NOW_TIME),
						'part' => 1,
					);
					session('backup_file', $file);

					//创建备份文件
					$Database = new \Common\Vendor\Database($file, $backup_config);
					if(false !== $Database->create()){
						session('backup_step',$step+1);
						$tables = session('backup_tables');
						$table = array_shift($tables);
						session('backup_tables',$tables);
						$this->success(array('step'=>$step+1,'table'=>$table,'start'=>0,'rate'=>0));
					} else {
						$this->error(array('step'=>$step,'msg'=>'初始化失败，备份文件创建失败！'));
					}
					break;

				case 2:
					if (session('backup_step') != $step) {
						session('backup_step',null);
						$this->error(array('step'=>$step,'msg'=>'步骤错误！'));
					}
					$table = I('table');
					$start = I('start');
					$Database = new \Common\Vendor\Database(session('backup_file'), $backup_config);
					$start  = $Database->backup($table, $start);
					if(false === $start){ //出错
						$this->error(array('step'=>$step,'msg'=>'备份出错！'));
					} elseif (0 === $start) { //下一表
						if(session('backup_tables')){
							$tables = session('backup_tables');
							$pretable = $table;
							$table = array_shift($tables);
							session('backup_tables',$tables);
							$data = array(
								'step'=>$step,
								'pretable' => $pretable,
								'table'=>$table,
								'start'=>0,
								'rate'=>0,
								);
							$this->success($data);
						} else { //备份完成，清空缓存
							unlink($backup_config['path'] . 'backup.lock');
							session('backup_tables', null);
							session('backup_step', null);
							session('backup_file', null);
							session('backup_config', null);
							$this->success(array('step'=>$step+1,'table'=>$table,'rate'=>100));
						}
					} else {
						$data = array(
							'step'=>$step,
							'table'=>$table,
							'start'=>$start[0],
							'rate'=>floor(100 * ($start[0] / $start[1])),
							);
						$this->success($data);
					}

					break;
				
				default:
					# code...
					break;
			}
		}
	}
}