用 mysqldump 备份需先确认 php 进程权限及 mysqldump 完整路径,数据库账号需 select 和 lock tables 权限(innodb 可用 --single-transaction),密码应存于权限为 600 的 ~/.my.cnf;调用时须用 escapeshellarg() 包裹各参数、escapeshellcmd() 处理命令路径,避免注入;恢复时注意字符集、目标库存在性及权限。

用 mysqldump 命令做备份,PHP 调用前先确认权限和路径
PHP 本身不直接导出 MySQL 数据库结构和数据,必须靠系统命令 mysqldump。不是写个 exec() 就能跑通——常见错误是 PHP 进程没权限执行该命令,或根本找不到它。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 先在服务器终端执行
which mysqldump,记下完整路径(比如/usr/bin/mysqldump),别硬写mysqldump; - 检查 PHP 运行用户(如
www-data或nginx)是否被允许执行该命令(有些主机禁用exec类函数,或通过disable_functions屏蔽了); - 数据库账号需有
SELECT、LOCK TABLES权限(--single-transaction可绕过锁表,但要求引擎为 InnoDB); - 避免在命令里明文写密码:用
~/.my.cnf配置文件更安全,且 PHP 调用时自动读取(注意该文件权限必须是600)。
exec() 调用 mysqldump 的安全写法
直接拼接字符串调用极易被 SQL 注入或命令注入,尤其是库名、表名来自用户输入时。错误现象包括:备份空文件、报错 Unknown database、甚至删库(如果误拼了 rm -rf)。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 数据库名、用户名、主机地址等参数,全部用
escapeshellarg()包裹; - 不要用
system()或shell_exec(),优先选exec()并捕获输出和返回码; - 示例关键片段:
exec(escapeshellcmd('/usr/bin/mysqldump') . ' '
. escapeshellarg('-h' . $host) . ' '
. escapeshellarg('-u' . $user) . ' '
. escapeshellarg('-p' . $pass) . ' '
. escapeshellarg($dbname) . ' > ' . escapeshellarg($backupPath),
$output,
$returnCode);
if ($returnCode !== 0) {
// 备份失败,$output 里通常有具体错误
}
注意:escapeshellcmd() 用于整个命令路径,escapeshellarg() 用于每个参数值——两者不能混用或省略。
恢复时用 mysql 命令导入,但要注意字符集和权限
备份文件只是 SQL 文本,恢复不是“双击运行”,而是重放。典型问题包括:中文乱码、主键冲突、无权限创建库。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 导入前确保目标库已存在(
CREATE DATABASE IF NOT EXISTS不在 dump 文件里,除非你加了--databases参数); - dump 文件头部若没指定
SET NAMES utf8mb4,导入时得手动加:mysql --default-character-set=utf8mb4 -u user -p db_name ; - 大文件别用
exec()直接导入,容易超时或内存溢出;改用mysql命令后台执行 + 检查进程状态; - 恢复账号需要
CREATE、INSERT、DROP等权限,比备份时要求更高。
自动备份的坑:时间戳、磁盘空间、权限继承
写个定时脚本每天备份,结果某天发现只留了最新一个文件,或者备份目录被 PHP 写满磁盘,或者恢复时提示“Permission denied”——这些都不是代码逻辑问题,而是部署细节没控住。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 文件名必须含时间戳,推荐格式:
backup_{$dbname}_' . date('Y-m-d_H-i-s') . '.sql; - 备份前检查磁盘剩余空间(
disk_free_space()),低于阈值就跳过并记录日志; - PHP 创建的备份文件,属主是 web server 用户(如
www-data),但如果你用 crontab 以 root 运行清理脚本,可能删不掉——统一用 PHP 自己清理旧文件; - 别依赖
gzip压缩后再备份,mysqldump本身不压缩,压缩应作为独立步骤(用proc_open()管道流式压缩更稳)。
真正麻烦的从来不是怎么调用命令,而是谁在什么上下文里执行它、对什么路径有读写权、以及失败后有没有可靠反馈。这些点漏一个,备份就等于没做。











