参照了网上一些文档,最后自己总结写出了两个类,我试了,可以实现数据库备份与上传功能
<?php
/**
file: dbbackup.class.php
数据库备份类文件,备份文件放在/backup 目录下
package: sql
*/
date_default_timezone_set('PRC'); //设置时区
class Dbbackup {
private $path = "sql/backup/"; //SQL文件保存路径,默认为/backup
private $database; //所要备份的数据库的名称
private $size; //分卷分件大小
private $fileName; //SQL文件名
private $ds = "\n"; //换行符
private $sqlEnd = ";"; //每条SQL语句的结尾符号
/**
*构造方法,用来实例化备份类对象
*@param string $database 数据库名称,默认值为‘lighting’
*@param int $size 分卷文件大小,默认值为2048
*/
function __construct($size = 2048, $database = 'lighting') {
$this->database = $database; //设置所要备份的数据库,默认为 lighting
$this->size = $size; //分卷文件大小,默认为2MB
$this->fileName = date('YmdHis')."_all";
ob_end_flush(); //清除所有缓存
}
/**
*公用方法,进行数据库备份
*@return bool 是否备份成功
*/
public function backup() {
$sqlFile = ''; //准备写入数据库的信息
$this->showMess("正在备份");
/*备份指定数据库中所有的数据表*/
if ($tables = mysql_query( "SHOW TABLE STATUS FROM ".$this->database)) {
$this->showMess("读取数据库结构成功!");
}
else {
$this->showMess("读取数据库结构失败!", true);
exit(0);
}
$sqlFile .= $this->retrieve(); //写入头部dump信息
$tables = mysql_query("SHOW TABLES"); //查询数据库中所有的表
$paper = 1; //分卷标示
while($table = mysql_fetch_array($tables)) {
$tableName = $table[0]; //获取表名
$sqlFile .= $this->insertTableStructure($tableName); //获取表结构
$data = mysql_query("SELECT * FROM ".$tableName); //获取表中数据
$num_fields = mysql_num_fields($data);
/*遍历表中所有数据记录*/
while($record = mysql_fetch_array($data)) {
$sqlFile .= $this->insertRecord($tableName, $num_fields, $record); //单条数据记录
/*如果大于分卷大小,则写入文件*/
if($sqlFile >= $this->size*1000) {
$file = $this->fileName."_v".$paper.".sql"; //SQL文件名
/*将SQL数据写入文件*/
if($this->writeFile($sqlFile,$file)) {
$this->showMess("-卷-<b>".$paper."</b>-数据备份完成,备份文件 [ <span>".$this->path.$file."</span> ]");
}
else {
$this->showMess("卷-<b>".$paper."</b>-备份失败",true);
return false;
}
/*下一个分卷*/
$paper ++;
/*重置$sqlFile变量为空,重新计算该变量大小*/
$sqlFile = "";
}
else {
/*如果SQL文件没有超过分卷大小,直接写入文件*/
$file = $this->fileName.".sql"; //SQL文件名
if($this->writeFile($sqlFile,$file)) {
$this->showMess("-卷-<b>".$paper."</b>-数据备份完成,备份文件 [ <span>".$this->path.$file."</span> ]");
}
else {
$this->showMess("卷-<b>".$paper."</b>-备份失败",true);
return false;
}
}
$this->showMess("恭喜您! <span>备份成功</span>");
}
}
}
/**
*类内部调用的私有方法,进行提示信息输出
*@param string $mess 提示信息
*@param bool $err 错误信息标示符,默认为false,true为输出错误信息
*/
private function showMess($mess, $err = false) {
if($err)
$err = "<span>ERROR:</span>";
else
$err = '';
echo "<p>".$err.$mess."</p>";
}
/**
*类内部调用的私有方法,添加数据库备份文件头部基础信息
*@return string $value 头部基础信息
*/
private function retrieve() {
$value = '';
$value .= '--'.$this->ds;
$value .= '-- MySQL database dump'.$this->ds;
$value .= '--' . $this->ds;
$value .= '-- 主机: '.$_SERVER['SERVER_NAME'].$this->ds;
$value .= '-- 生成日期: '.date('Y').'年 '.date('m').'月'.date('d').'日'.date('H:i').$this->ds;
$value .= '-- MySQL版本: '.mysql_get_server_info().$this->ds;
$value .= '-- PHP 版本: '.phpversion().$this->ds;
$value .= $this->ds;
$value .= '--'.$this->ds;
$value .= '-- 数据库:`'.$this->database.'`'.$this->ds;
$value .= '--'.$this->ds.$this->ds;
$value .= '-- -------------------------------------------------------';
$value .= $this->ds.$this->ds;
return $value;
}
/**
*类内部调用的私有方法,将表结构信息插入
*@param string $tableName 提示信息
*@return string $sqlFileTable 返回表结构
*/
private function insertTableStructure($tableName) {
$sqlFileTable = '';
$sqlFileTable .= "--".$this->ds;
$sqlFileTable .= "-- 表的结构".$tableName.$this->ds;
$sqlFileTable .= "--".$this->ds.$this->ds;
/*如果数据库中存在此表,进行删除(用户数据库文件导入时)*/
$sqlFileTable .= "DROP TABLE IF EXISTS `".$tableName.'`'.$this->sqlEnd.$this->ds;
/*获取详细表信息*/
$res = mysql_query('SHOW CREATE TABLE `'.$tableName.'`');
$row = mysql_fetch_array($res);
$sqlFileTable .= $row[1];
$sqlFileTable .= $this->sqlEnd.$this->ds;
/*加上表数据提示*/
$sqlFileTable .= $this->ds;
$sqlFileTable .= "--".$this->ds;
$sqlFileTable .= "-- 转存表中的数据 ".$tableName.$this->ds;
$sqlFileTable .= "--".$this->ds;
$sqlFileTable .= $this->ds;
return $sqlFileTable;
}
/**
*类内部调用的私有方法,将表中的数据插入
*@param string $tableName 表名
*@param int $num_fields 表中数据条数
*@param array $record 表中的数据
*@return string $insert 表中该条数据中所有字段中的数据组成的字符串
*/
private function insertRecord($tableName, $num_fields, $record) {
$insert = ''; // sql字段逗号分割
$comma = "";
$insert .= "INSERT INTO `".$tableName."` VALUES(";
/*循环每个子段下面的内容*/
for($i = 0; $i < $num_fields; $i++) {
$insert .= ($comma."'".mysql_real_escape_string($record[$i])."'");
$comma = ",";
}
$insert .= ");".$this->ds;
return $insert;
}
/**
*@param string $sqlFile 所要写入的SQL数据
*@param string $filename SQL备份文件名
*@return bool $re 返回是否成功写入SQL文件
*/
private function writeFile($sqlFile, $filename) {
$re = true;
if (!$fp =fopen($this->path.$filename, "x")) {
$re = false;
$this->showMess("打开sql文件失败!", true);
}
if (!fwrite($fp,$sqlFile)) {
$re = false;
$this->showMess("写入sql文件失败,请文件是否可写", true);
}
if (!fclose($fp)) {
$re = false;
$this->showMess("关闭sql文件失败!", true);
}
return $re;
}
/*析构函数*/
function __destruct() {
echo "再见<br />";
}
}
?>
<?php
/**
file: dbupdata.class.php
数据库更新类文件,将放在/backup 文件下的对应SQL文件更新到数据库
package: sql
*/
class Dbupdata {
private $fileName; //需要上传的文件的名称
private $path = "sql/backup/"; //SQL文件所在路径,默认为/backup
private $database; //所要上传到的数据库
/**
*构造方法,用来实例化备份类对象
*@param string $fileName SQL文件名称
*/
function __construct($fileName) {
$this->database = "lighting"; //操作数据库名,默认为lighting
$this->fileName = $fileName;
}
/*公共函数,用于进行数据文件上传*/
public function restore() {
if(!file_exists($this->path.$this->fileName)) {
$this->showMess("SQL文件不存在! 请检查", true);
exit ();
}
/*检测是否包含分卷,将类似20120516211738_all_v1.sql从_v分开,有则说明有分卷*/
$volume = explode("_v", $this->fileName);
$volume_path = $volume[0];
$this->showMess("请勿刷新及关闭浏览器以防止程序被中止,如有不慎!将导致数据库结构受损");
$this->showMess("正在导入备份数据,请稍候!");
/*无分卷sql文件导入*/
if(count($volume) == 1) {
$this->showMess("正在导入sql:<span>".$this->fileName.'</span>');
if($this->importInto($this->fileName)) {
$this->showMess("数据库导入成功! ");
}
else {
$this->showMess("数据库导入失败!", true);
exit();
}
}
/*有分卷导入*/
else {
/*获取当前是第几分卷,循环执行余下分卷*/
$volume_id = explode(".sq", $volume[1]);
/*当前分卷为$volume_id*/
$volume_id = intval($volume_id[0]); //将string强制转换为int型
while($volume_id) {
$tmpfile = $volume_path."_v".$volume_id.".sql"; //构造当前分卷文件名
/*如果存在分卷就继续执行*/
if(file_exists($this->path.$tmpfile)) {
$this->showMess("正在导入分卷".$volume_id.':'.$tmpfile."<br />");
if($this->importInto($tmpfile)) {
$this->showMess("分卷".$volume_id.':'.$tmpfile."导入成功!<br />");
}
else {
$this->showMess("导入分卷<span style='color:#f00;'>".$tmpfile."</span>失败!可能是数据库结构已被破坏,请尝试从分卷一开始导入。", true);
}
}
else {
$this->showMess("分卷备份全部导入成功!");
}
$volume_id ++; //下一个分卷
}
}
}
/**
*类内部调用的私有方法,进行提示信息输出
*@param string $mess 提示信息
*@param bool $err 错误信息标示符,默认为false,true为输出错误信息
*/
private function showMess($mess, $err = false) {
if($err)
$err = "<span>ERROR:</span>";
else
$err = '';
echo "<p>".$err.$mess."</p>";
}
/**
*类内部调用的私有方法,将SQL导入数据库
*@param string $sqlFile 导入的SQL文件名
*@return bool 返回写入是否成功,如果成功则返回true
*/
private function importInto($sqlFile) {
/*读取SQL文件*/
$f = fopen($this->path.$sqlFile, "rb");
/*创建表缓冲变量*/
$create_table = '';
while(!feof($f)) {
/*读取每一行sql*/
$line = fgets($f);
/*这一步为了将创建表合成完整的sql语句*/
//如果结尾没有包含';'(即为一个完整的sql语句,这里是插入语句),并且不包含'ENGINE='(即创建表的最后一句)
if (!preg_match('/;/', $line) || preg_match('/ENGINE=/', $line)) {
/*将本次sql语句与创建表sql连接存起来*/
$create_table .= $line;
/*如果包含了创建表的最后一句*/
if (preg_match('/ENGINE=/', $create_table)) {
/*执行sql语句创建表*/
$this->insertInto($create_table);
/*清空当前,准备下一个表的创建*/
$create_table = '';
}
/*跳过本次*/
continue;
}
/*执行sql语句*/
$this->insertInto($line);
}
fclose ($f);
return true;
}
/**
*类内部调用的私有方法,插入单条sql语句
*@return bool 是否插入成功,成功返回true
*/
private function insertInto($sql){
if (!mysql_query(trim($sql))) {
$this->showMess(mysql_error(), true);
return false;
}
}
/*析构函数*/
function __destruct() {
echo "再见<br />";
}
}
?>