PHP通過面向對象實現數據庫備份

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章