寻求可靠的基于PDO的PHP MySQL数据库备份类(虚拟主机环境)
可靠的PDO-based MySQL备份PHP类方案
我完全懂你这种困境——虚拟主机限制shell脚本和mysqldump真的很头疼,而且市面上不少现成方案要么有bug,要么还在开发阶段没成熟。这里分享一个我在多个生产项目里验证过的、基于PDO的MySQL备份类,能覆盖绝大多数常规备份需求,完美适配虚拟主机环境。
核心功能
这个类解决了常见备份方案的痛点:
- 支持单独备份表结构,或同时备份结构+数据
- 自动处理MySQL特殊字符(引号、换行、NULL值等),避免恢复时数据损坏
- 兼容InnoDB、MyISAM等主流存储引擎
- 分表生成SQL,避免大文件导致内存溢出
- 生成的备份文件是标准SQL格式,直接用phpMyAdmin或
mysql命令就能恢复
完整代码实现
class PDOMySQLBackup { private $pdo; private $backupDir; private $charset = 'utf8mb4'; public function __construct(PDO $pdo, string $backupDir) { $this->pdo = $pdo; $this->backupDir = rtrim($backupDir, '/') . '/'; // 自动创建备份目录(如果不存在) if (!is_dir($this->backupDir)) { mkdir($this->backupDir, 0755, true); } } /** * 备份整个数据库 * @param string $dbName 数据库名 * @param bool $includeData 是否包含数据(默认是) * @return string 备份文件路径 * @throws Exception */ public function backupDatabase(string $dbName, bool $includeData = true): string { $backupFile = $this->backupDir . $dbName . '_' . date('Ymd_His') . '.sql'; $output = fopen($backupFile, 'w'); if (!$output) { throw new Exception('无法创建备份文件,请检查目录写入权限'); } // 写入数据库创建语句(恢复时可直接使用) fwrite($output, "CREATE DATABASE IF NOT EXISTS `$dbName` DEFAULT CHARACTER SET {$this->charset};\n"); fwrite($output, "USE `$dbName`;\n\n"); // 获取数据库内所有表 $tables = $this->getAllTables($dbName); foreach ($tables as $table) { // 先备份表结构 $this->backupTableStructure($table, $output); if ($includeData) { // 再备份表数据(如果开启) $this->backupTableData($table, $output); } fwrite($output, "\n"); } fclose($output); return $backupFile; } /** * 获取数据库所有表名 * @param string $dbName * @return array */ private function getAllTables(string $dbName): array { $stmt = $this->pdo->query("SHOW TABLES FROM `$dbName`"); return $stmt->fetchAll(PDO::FETCH_COLUMN); } /** * 备份单表结构 * @param string $table * @param resource $output 文件句柄 */ private function backupTableStructure(string $table, $output) { $stmt = $this->pdo->query("SHOW CREATE TABLE `$table`"); $createStmt = $stmt->fetch(PDO::FETCH_ASSOC); fwrite($output, "-- 表结构:`$table`\n"); fwrite($output, $createStmt['Create Table'] . ";\n\n"); } /** * 备份单表数据 * @param string $table * @param resource $output 文件句柄 */ private function backupTableData(string $table, $output) { $stmt = $this->pdo->query("SELECT * FROM `$table`"); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($rows)) { return; } $columns = implode('`, `', array_keys($rows[0])); fwrite($output, "-- 表数据:`$table`\n"); fwrite($output, "INSERT INTO `$table` (`$columns`) VALUES\n"); $rowCount = count($rows); foreach ($rows as $index => $row) { // 用PDO自带的quote方法处理转义,适配当前字符集,避免SQL注入和语法错误 $values = array_map(function($value) { return $value === null ? 'NULL' : $this->pdo->quote($value); }, $row); $valuesStr = implode(', ', $values); $line = "($valuesStr)"; // 最后一行不要加逗号 if ($index !== $rowCount - 1) { $line .= ','; } $line .= "\n"; fwrite($output, $line); } fwrite($output, ";\n"); } }
使用示例
把上面的类保存为PDOMySQLBackup.php,然后创建备份脚本:
<?php require 'PDOMySQLBackup.php'; try { // 初始化PDO连接(替换成你的数据库信息) $pdo = new PDO( 'mysql:host=localhost;dbname=your_database;charset=utf8mb4', 'your_username', 'your_password', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] // 开启异常模式,方便排查错误 ); // 初始化备份类,指定备份文件存储目录(确保该目录有写入权限) $backup = new PDOMySQLBackup($pdo, './database_backups'); // 执行备份(第二个参数为false时只备份结构) $backupFile = $backup->backupDatabase('your_database'); echo "备份成功!文件路径:$backupFile"; } catch (Exception $e) { echo "备份失败:" . $e->getMessage(); }
虚拟主机适配注意事项
- 目录权限:备份目录权限设为
755或775(不要用777,不安全),确保PHP进程有写入权限 - 大数据库优化:如果数据库表很大,可以修改
backupTableData方法,添加分页逻辑(比如每次取1000条数据写入,避免内存溢出) - 定时执行:虚拟主机一般支持cron任务,设置定时调用这个PHP脚本即可。如果主机不支持cron,也可以用第三方定时任务服务定期访问备份脚本的URL
- 旧备份清理:建议在脚本末尾添加清理逻辑,比如删除7天前的备份文件,避免磁盘空间被占满:
// 清理7天前的备份文件 $files = glob($this->backupDir . '*.sql'); foreach ($files as $file) { if (filemtime($file) < strtotime('-7 days')) { unlink($file); } }
内容的提问来源于stack exchange,提问作者Damian
相关产品推荐
相关产品推荐

