首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

PHP 實現 MySQL 備份系統:結構與數據雙模式、本地/服務器雙存儲

     編輯:MySQL 綜合教學

系統設計目標

  • 支援 **結構備份** 與 **結構+數據備份** 兩種模式
  • 支援 **本地下載** 與 **服務器存儲** 兩種目標
  • 基於 SHOW CREATE TABLE 獲取結構,SELECT * 獲取數據
  • 生成標準 SQL 文件,含元數據頭 (服務器、庫、時間、管理員、版本)

核心函數實現

1. 結構備份:table2sql()

function table2sql($table) {
    global $db;
    $tabledump = "DROP TABLE IF EXISTS `$table`;\n";
    $createtable = $db->query("SHOW CREATE TABLE `$table`");
    $create = $db->fetch_row($createtable);
    $tabledump .= $create[1] . ";\n\n";
    return $tabledump;
}

2. 結構+數據備份:data2sql()

function data2sql($table) {
    global $db;
    $tabledump = "DROP TABLE IF EXISTS `$table`;\n";
    $createtable = $db->query("SHOW CREATE TABLE `$table`");
    $create = $db->fetch_row($createtable);
    $tabledump .= $create[1] . ";\n\n";

    $rows = $db->query("SELECT * FROM `$table`");
    $numfields = $db->num_fields($rows);
    $numrows = $db->num_rows($rows);

    while ($row = $db->fetch_row($rows)) {
        $comma = "";
        $tabledump .= "INSERT INTO `$table` VALUES(";
        for ($i = 0; $i < $numfields; $i++) {
            $tabledump .= $comma . "'" . mysql_escape_string($row[$i]) . "'";
            $comma = ",";
        }
        $tabledump .= ");\n";
    }
    $tabledump .= "\n";
    return $tabledump;
}

主流程控制

// 配置
$tables = ['us_sort', 'us_download', 'us_article', 'us_guestbook'];
$prefix = 'us_';
$saveto = 'server';  // 'local' 或 'server'
$back_mode = 'all';  // 'all' 結構+數據, 'table' 僅結構
$admin = 'heiyeluren';
$admin_email = 'heiyeluren@163.com';

// 執行備份
$sqldump = "";
foreach ($tables as $table) {
    if ($back_mode == 'all') {
        $sqldump .= data2sql($table);
    }
    if ($back_mode == 'table') {
        $sqldump .= table2sql($table);
    }
}

// 添加元數據頭
if (trim($sqldump)) {
    $sqldump = 
        "# --------------------------------------------------------\n" .
        "# 數據表備份\n" .
        "#\n" .
        "# 服務器: $db->Host\n" .
        "# 數據庫:$db->Database\n" .
        "# 備份編號: " . create_sess_id() . "\n" .
        "# 備份時間: " . time_to_date('',6) . "\n" .
        "#\n" .
        "# 管理員:$admin ($admin_email)\n" .
        "# $copyright\n" .
        "# --------------------------------------------------------\n\n\n" .
        $sqldump;
}

存儲目標實現

本地下載 (瀏覽器直接下載 .sql)

if ($saveto == "local") {
    ob_end_clean();
    header('Content-Encoding: none');
    $ua = $_SERVER['HTTP_USER_AGENT'];
    $ctype = (strpos($ua, 'MSIE') ? 'application/octetstream' : 'application/octet-stream');
    header("Content-Type: $ctype");
    $disposition = (strpos($ua, 'MSIE') ? 'inline; ' : 'attachment; ');
    header("Content-Disposition: {$disposition}filename=\"$local_filename\"");
    header('Content-Length: ' . strlen($sqldump));
    header('Pragma: no-cache');
    header('Expires: 0');
    echo $sqldump;
    exit;
}

服務器存儲 (寫入文件系統)

if ($saveto == "server") {
    if ($filename != "") {
        @$fp = fopen($filename, "w+");
        if ($fp) {
            @flock($fp, LOCK_EX);  // 3 = LOCK_EX
            if (@!fwrite($fp, $sqldump)) {
                @fclose($fp);
                exit_msg("數據文件無法保存,請檢查目錄權限。");
            } else {
                exit_msg("數據成功備份至服務器 $filename 中。");
            }
        } else {
            exit_msg("無法打開目錄 $filename,請確認存在且有寫權限。");
        }
    } else {
        exit_msg("未輸入備份文件名。");
    }
}

⚠️ 關鍵安全與健壯性補強 (現代化改造)

1. 棄用 mysql_* 函數,改用 PDO/mysqli 預處理

$pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8mb4", $user, $pass);
$stmt = $pdo->query("SHOW CREATE TABLE `$table`");
$create = $stmt->fetch(PDO::FETCH_NUM);
$tabledump = "DROP TABLE IF EXISTS `$table`;\n$create[1];\n\n";

$rows = $pdo->query("SELECT * FROM `$table`");
while ($row = $rows->fetch(PDO::FETCH_NUM)) {
    $vals = array_map(function($v) use ($pdo) { 
        return "'" . $pdo->quote($v) . "'"; 
    }, $row);
    $tabledump .= "INSERT INTO `$table` VALUES(" . implode(",", $vals) . ");\n";
}

2. 大表分批導出,防記憶體溢出

$offset = 0; $limit = 1000;
while (true) {
    $rows = $pdo->query("SELECT * FROM `$table` LIMIT $offset, $limit");
    $data = $rows->fetchAll(PDO::FETCH_NUM);
    if (empty($data)) break;
    // 處理 $data...
    $offset += $limit;
}

3. 壓縮輸出 (gzip)

if ($saveto == 'server') {
    $gz = gzopen($filename . '.gz', 'wb9');
    gzwrite($gz, $sqldump);
    gzclose($gz);
} else {
    header('Content-Encoding: gzip');
    echo gzencode($sqldump, 9);
}

4. 權限隔離:備份專用只讀賬號

CREATE USER 'backup'@'localhost' IDENTIFIED BY 'strong_pass';
GRANT SELECT, LOCK TABLES, SHOW VIEW, EVENT, TRIGGER ON `db`.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;

5. 異步隊列化 (大庫必備)

// 推送到 Redis/RabbitMQ 隊列
$job = ['tables' => $tables, 'mode' => $back_mode, 'target' => $saveto];
$redis->lpush('mysql_backup_queue', json_encode($job));

// Worker 進程消費
while (true) {
    $job = json_decode($redis->rpop('mysql_backup_queue'), true);
    if ($job) execute_backup($job);
}

定時任務部署

# crontab -e
# 每天凌晨 2 點全量備份
0 2 * * * /usr/bin/php /path/to/backup.php --mode=all --target=server >> /var/log/mysql_backup.log 2>&1

# 每小時增量 (需 binlog 配合)
0 * * * * /usr/bin/php /path/to/backup.php --mode=incremental --target=server

這套 PHP 備份系統雖基於舊版 API,但架構清晰、功能完整。現代化改造後 (PDO、分批、壓縮、隊列、權限隔離),可直接投入生產作為輕量級備份補充方案。**核心原則:備份自動化、驗證常態化、恢復演練化**。

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