基於 `mysql_*` 擴充 (舊版 PHP,現代建議用 `mysqli`/`PDO`),核心邏輯通用:連線 → 列表 → `SHOW CREATE TABLE` 導出結構 → `SELECT *` 組裝 `INSERT` → 檔案落地 → 還原時 `DROP TABLE` → 解析 SQL 分批執行。本文重點講解**資料轉義、NULL 處理、分隔符設計、大檔案記憶體控制**等關鍵細節。
⚠️ 重要提醒: `mysql_*` 函數 **PHP 7.0 移除**。生產環境請移植至 `mysqli` (程序式/物件式) 或 `PDO`,本文邏輯完全適用,僅替換 API。
class DbBackup {
public $host = 'localhost';
public $user = 'root';
public $pwd = '';
public $database;
public $charset = 'utf8';
public $delimiter = ';-- --'; // SQL 分割標記 (必須為註釋形式)
// 連線
private function connect() { ... }
// 取得所有表名
private function getTables() { ... }
// 導出結構 SQL
public function dumpStructure() { ... }
// 導出資料 INSERT SQL
public function dumpData() { ... }
// 執行備份
public function backup($filepath) { ... }
// 執行還原
public function restore($filepath) { ... }
}
public function dumpStructure() {
$sql = '';
foreach ($this->getTables() as $table) {
$row = mysql_fetch_row(mysql_query("SHOW CREATE TABLE `$table`"));
$sql .= "-- 表結構:{$row[0]} --\r\n";
$sql .= "{$row[1]}" . $this->delimiter . "\r\n\r\n";
}
return $sql;
}
public function dumpData() {
$sql = '';
foreach ($this->getTables() as $table) {
$res = mysql_query("SELECT * FROM `$table`");
if (!mysql_num_rows($res)) continue; // 空表跳過
$sql .= "-- 表資料:$table --\r\n";
$sql .= "INSERT INTO `$table` VALUES\r\n";
$firstRow = true;
while ($row = mysql_fetch_row($res)) {
if (!$firstRow) $sql .= ",\r\n";
$firstRow = false;
$sql .= '(';
$vals = [];
foreach ($row as $val) {
if ($val === null) {
$vals[] = 'NULL';
} else {
// 必須轉義:防止單引號、反斜線、控制字元注入破壞 SQL
$vals[] = "'" . mysql_real_escape_string($val) . "'";
}
}
$sql .= implode(',', $vals) . ')';
}
$sql .= $this->delimiter . "\r\n\r\n";
}
return $sql;
}
關鍵點:
public function restore($filepath) {
$this->connect();
// 1. 刪除現有表 (按外鍵順序較複雜,簡化版全刪)
$tables = $this->getTables();
if ($tables) {
$dropSql = 'DROP TABLE ' . implode(',', array_map(fn($t)=>"`$t`", $tables));
if (!mysql_query($dropSql)) return false;
}
// 2. 讀取檔案並分割執行
$content = file_get_contents($filepath); // 大檔案建議 fgets 逐行緩衝解析
$statements = explode($this->delimiter, $content);
array_pop($statements); // 移除末尾空段
foreach ($statements as $stmt) {
$stmt = trim($stmt);
if ($stmt === '') continue;
if (!mysql_query($stmt)) {
error_log("Restore failed: " . mysql_error() . " | SQL: " . substr($stmt, 0, 200));
return false;
}
}
return true;
}
// 備份
$backup = new DbBackup();
$backup->database = 'my_db';
$backup->user = 'backup_user';
$backup->pwd = 'strong_pwd';
$result = $backup->backup('/backups/my_db_' . date('Ymd_His') . '.sql');
var_dump($result); // int(bytes) or false
// 還原
$restore = new DbBackup();
$restore->database = 'my_db';
$restore->user = 'root';
$restore->pwd = 'pwd';
$result = $restore->restore('/backups/my_db_20230101_000000.sql');
var_dump($result); // bool
備份還原看似簡單,**細節決定成敗**:轉義、NULL、分隔符、記憶體、外鍵、字元集、權限、驗證。本類別提供核心骨架,**生產上線前務必移植至 mysqli/PDO、加入流式處理與完整錯誤處理**。