首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

ThinkPHP 數據庫備份導出完整實現:基於 PDO 的結構與數據雙重備份

     編輯:PHP 相關知識

ThinkPHP 數據庫備份導出完整實現:基於 PDO 的結構與數據雙重備份

ThinkPHP 早期版本缺乏內建數據庫備份功能。本文提供一個基於 PDO 的完整備份類,支持數據庫結構(DDL)與數據(DML)的一鍵導出,生成標準 SQL 文件供下載,可直接用於遷移或恢復。

核心功能特性

  • ✅ 自動讀取 ThinkPHP 配置項(`C('DB_HOST')` 等)
  • ✅ 基於 PDO 預處理語句,防注入、兼容性強
  • ✅ 完整導出:`CREATE DATABASE`、`CREATE TABLE`、`INSERT DATA`
  • ✅ 自動檢測字符集與排序規則(`CHARSET`、`COLLATE`)
  • ✅ 可選「僅結構」或「結構+數據」模式
  • ✅ 直接觸發瀏覽器下載 `.sql` 文件

控制器入口代碼

<?php
class SqlAction extends Action {
    public function outsql() {
        header("Content-Type: text/html; charset=utf-8");
        
        // 從配置讀取數據庫信息
        $host     = C('DB_HOST');
        $db_name  = C('DB_NAME');
        $user     = C('DB_USER');
        $password = C('DB_PWD');
        
        // 調用私有方法生成 SQL 內容
        $outstream = $this->outputSql($host, $db_name, $user, $password);
        
        // 觸發文件下載
        header("Content-Disposition: attachment; filename={$db_name}.sql");
        echo $outstream;
    }
    // ... 私有方法見下文
}
?>

核心導出邏輯:outputSql() 方法深度解析

private function outputSql($host, $dbname, $user, $password, $flag = 1) {
    try {
        // 1. 建立 PDO 連接,啟用異常模式
        $pdo = new PDO("mysql:host=$host;dbname=$dbname", $user, $password);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) {
        echo $e->getMessage();
        exit;
    }

    $mysql = "DROP DATABASE IF EXISTS `$dbname`;\n";
    
    // 2. 獲取數據庫創建語句,提取字符集
    $creat_db = $pdo->query("SHOW CREATE DATABASE `$dbname`")->fetch();
    preg_match('/DEFAULT CHARACTER SET\s+(\w+)/', $creat_db['Create Database'], $matches);
    $mysql .= "CREATE DATABASE `$dbname` DEFAULT CHARACTER SET {$matches[1]}";
    
    // 3. 獲取排序規則
    $db_collate = $pdo->query("SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '$dbname' LIMIT 1")->fetch();
    $mysql .= " COLLATE {$db_collate['DEFAULT_COLLATION_NAME']};\nUSE `$dbname`;\n\n";

    // 4. 遍歷所有表
    $statments = $pdo->query("SHOW TABLES");
    foreach ($statments as $value) {
        $table_name = $value[0];
        $mysql .= "DROP TABLE IF EXISTS `$table_name`;\n";
        
        // 4.1 導出表結構
        $table_query = $pdo->query("SHOW CREATE TABLE `$table_name`");
        $create_sql = $table_query->fetch();
        $mysql .= $create_sql['Create Table'] . ";\r\n\r\n";
        
        // 4.2 導出表數據 (若 $flag != 0)
        if ($flag != 0) {
            $items_query = $pdo->query("SELECT * FROM `$table_name`");
            $values = "";
            $items  = "";
            
            while ($item_query = $items_query->fetch(PDO::FETCH_ASSOC)) {
                // 字段名處理
                $item_names = array_keys($item_query);
                $item_names = array_map('addslashes', $item_names);
                $items = join('`,`', $item_names);  // 反引號包裹
                
                // 字段值處理
                $item_values = array_values($item_query);
                $item_values = array_map('addslashes', $item_values);
                $value_string = join("','", $item_values);  // 單引號包裹
                $value_string = "('" . $value_string . "'),";
                
                $values .= "\n" . $value_string;
            }
            
            if ($values) {
                $insert_sql = "INSERT INTO `$table_name` (`$items`) VALUES" . rtrim($values, ",") . ";\n\r";
                $mysql .= $insert_sql;
            }
        }
    }
    return $mysql;
}

關鍵技術點提煉

  1. 信息庫查詢:利用 `information_schema.SCHEMATA` 精確獲取數據庫級別的字符集與排序規則
  2. 正則提取字符集:`/DEFAULT CHARACTER SET\s+(\w+)/` 兼容 MySQL 5.7+ 輸出格式
  3. 數據轉義:`addslashes()` 對特殊字符轉義,配合反引號/單引號包裹,生成合法 SQL
  4. 內存效率:逐表處理、逐行拼接,避免大表一次性載入導致 OOM

擴展建議

  • 分卷導出:大數據庫單文件過大,建議按表或按行數分割文件
  • 壓縮下載:導出後調用 `gzencode()` 生成 `.sql.gz`,節省帶寬
  • 異步任務:結合消息隊列(Redis/RabbitMQ)後台生成,避免 HTTP 超時
  • 增量備份:記錄 `binlog` 位點或 `UPDATE_TIME`,實現增量導出

遷移至 ThinkPHP 6/8 的注意事項

  • 配置讀取改為 `Config::get('database.host')`
  • 控制器繼承 `think\Controller`,返回 `Response` 對象而非直接 `echo`
  • 建議使用框架內建的 `think\console\Command` 做 CLI 備份命令

這個備份類雖然簡潔,但涵蓋了數據庫導出的核心邏輯,是理解 MySQL 元數據操作與 SQL 生成的優秀教學案例,也可直接移植到項目中作為應急備份工具使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved