設計目標
- 表結構(
CREATE TABLE)與資料(INSERT)分離儲存。
- 大表資料超過設定大小時自動分卷(避免單一檔案過大導致匯入困難)。
- 備份完成後自動打包成 ZIP,清理暫存檔。
- 支援多表指定備份、進度即時輸出。
核心類別結構
class DbBackup {
private $conn, $dbName, $host;
private $tag = '_b'; // 分卷檔案後綴
public function __construct($host, $user, $pwd, $db, $charset='utf8') { /* 連線 */ }
// 取得所有表名
public function getTableNames() { /* SHOW TABLES */ }
// 取得表結構 SQL
public function getFieldsByTable($table) { /* SHOW CREATE TABLE */ }
// 取得表資料 INSERT SQL
public function getDataByTable($table) { /* SELECT * 組裝 INSERT */ }
// 主備份流程
public function backup($tables, $path='', $fileName='backup', $subsection=2) { /* 2MB 分卷 */ }
// 輔助:寫入檔案、建立 ZIP、訊息輸出等
}
關鍵實作細節
1. 表結構備份
$res = mysql_query("SHOW CREATE TABLE `{$table}`");
$row = mysql_fetch_assoc($res);
$sql = str_replace("CREATE TABLE `{$table}` (", "", $row['Create Table']);
$sql = "--\n-- Table structure for table `{$table}`\n--\n\nCREATE TABLE IF NOT EXISTS `{$table}` ( {$sql};\n\n";
2. 資料分卷寫入
$insertSql = "INSERT INTO `{$table}` ({$columns}) VALUES\n";
while ($row = mysql_fetch_assoc($res)) {
$insertSql .= "(" . implode(',', array_map(function($v){ return is_numeric($v)?$v:"'{$v}'"; }, $row)) . "),\n";
if (strlen($insertSql) > $subsection * 1024 * 1024) {
$this->writeFile("{$path}{$table}{$part}$this->tag.sql", $insertSql);
$insertSql = '';
$part++;
}
}
// 寫入剩餘
3. 壓縮打包
$zip = new ZipArchive();
$zip->open("{$path}{$this->dbName}_".date('Ymd').".zip", ZipArchive::CREATE | ZipArchive::OVERWRITE);
foreach ($files as $file) {
$zip->addFile($file, basename($file)); // 僅存檔名,不含路徑
}
$zip->close();
// 刪除暫存 .sql 檔
使用範例
<?php
require 'DbBackup.class.php';
$backup = new DbBackup('localhost', 'root', 'password', 'my_database');
$tables = $backup->getTableNames(); // 或指定 ['users', 'orders']
$backup->backup($tables, '/data/backup/', 'my_db', 5); // 5MB 分卷
現代化改良建議
- 將
mysql_* 替換為 mysqli 或 PDO(mysql_* 已移除於 PHP 7)。
- 使用
mysqldump --single-transaction --quick --hex-blob 呼叫系統指令,效能更強、支援一致性備份。
- 加入上傳至雲端儲存(S3、OSS、GCS)功能。
- 採用
proc_open 非阻塞執行,避免 Web 請求超時。
還原腳本骨架
public function restore($zipPath, $extractDir) {
$zip = new ZipArchive();
$zip->open($zipPath);
$zip->extractTo($extractDir);
$zip->close();
// 先執行 *_table.sql 建表
// 再依序執行分卷資料檔
// 建議使用 mysql 客戶端管線:mysql -u root -p db < file.sql
}