參照了網上一些文檔,最後自己總結寫出了兩個類,我試了,可以實現數據庫備份與上傳功能
<?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 />";
}
}
?>