温馨提示×

Ubuntu PHP如何实现备份恢复

小樊
39
2025-12-18 11:51:47
栏目: 编程语言

Ubuntu PHP 备份与恢复实操指南

一 备份范围与策略

  • 建议将备份划分为三层:
    1. 代码与资源(网站根目录,如 /var/www/html);
    2. 数据库(如 MySQL/MariaDB,使用 mysqldump 导出为 .sql);
    3. PHP 与运行时配置(如 php.ini、PHP-FPM 配置)。
  • 存储与保留:至少保留7天历史,备份文件权限设为600,并同步到异地/云存储
  • 自动化:用 crontab 定时执行备份脚本,并记录日志便于审计与回滚。

二 用 PHP 实现一键备份与恢复

  • 备份脚本 backup.php(示例)

    • 功能:打包网站目录 + 导出数据库 + 可选 AES-256-CBC 加密 + 保留7天 + 写日志。
    • 使用:将脚本放到网站可写目录(如 /var/www/html/tools/),通过 CLI 执行:/usr/bin/php /var/www/html/tools/backup.php
    • 注意:Web 访问需做访问控制权限校验,避免被滥用。
    <?php
    // 配置区
    $backupRoot = '/var/backups/php_site';            // 备份根目录(确保可写)
    $wwwRoot   = '/var/www/html';                    // 网站根目录
    $dbHost    = 'localhost';
    $dbName    = 'your_db';
    $dbUser    = 'your_user';
    $dbPass    = 'your_password';
    $keepDays  = 7;
    $encrypt   = true;                               // 是否加密
    $cipher    = 'aes-256-cbc';
    
    // 初始化
    date_default_timezone_set('Asia/Shanghai');
    set_time_limit(300);
    if (!is_dir($backupRoot)) mkdir($backupRoot, 0700, true);
    $ts   = date('Ymd_His');
    $log  = "$backupRoot/backup_$ts.log";
    $zip  = "$backupRoot/site_$ts.zip";
    $sql  = "$backupRoot/db_$ts.sql";
    $enc  = "$zip.enc";
    
    function logMsg($msg, $log) { file_put_contents($log, date('Y-m-d H:i:s') . " $msg\n", FILE_APPEND); }
    
    // 1) 打包网站文件
    $zipOk = false;
    if (class_exists('ZipArchive')) {
        $zipArc = new ZipArchive();
        if ($zipArc->open($zip, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) {
            $files = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($wwwRoot, FilesystemIterator::SKIP_DOTS),
                RecursiveIteratorIterator::LEAVES_ONLY
            );
            foreach ($files as $file) {
                if (!$file->isDir()) {
                    $filePath = $file->getRealPath();
                    $relativePath = substr($filePath, strlen($wwwRoot) + 1);
                    $zipArc->addFile($filePath, $relativePath);
                }
            }
            $zipOk = $zipArc->close();
        }
    }
    logMsg($zipOk ? "ZIP created: $zip" : "ZIP failed", $log);
    
    // 2) 导出数据库
    $dumpOk = false;
    $cmd = sprintf(
        'mysqldump --single-transaction --routines --triggers --default-character-set=utf8mb4 -h%s -u%s -p%s %s > %s 2>>%s',
        escapeshellarg($dbHost), escapeshellarg($dbUser), escapeshellarg($dbPass), escapeshellarg($dbName), $sql, $log
    );
    system($cmd, $ret);
    $dumpOk = ($ret === 0);
    logMsg($dumpOk ? "DB dumped: $sql" : "DB dump failed", $log);
    
    // 3) 可选加密
    $finalArchive = $zip;
    if ($encrypt && $zipOk) {
        $key = random_bytes(32); // 生产环境请安全保存此密钥
        $iv  = random_bytes(16);
        $data = file_get_contents($zip);
        $encData = openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $iv);
        file_put_contents($enc, $iv . $encData);
        $finalArchive = $enc;
        @unlink($zip);
        logMsg("Encrypted -> $enc", $log);
    }
    
    // 4) 清理过期
    $files = glob("$backupRoot/*.{zip,sql,enc,log}", GLOB_BRACE);
    foreach ($files as $f) {
        if (filemtime($f) < time() - $keepDays * 86400) {
            @unlink($f);
            logMsg("Removed expired: $f", $log);
        }
    }
    
    echo "Backup finished. See $log\n";
    
  • 恢复脚本 restore.php(示例)

    • 功能:解密(如有)-> 解压覆盖 -> 导入 .sql
    • 使用:将备份包与脚本上传至服务器,执行:/usr/bin/php /var/www/html/tools/restore.php /var/backups/php_site/site_YYYYMMDD_HHIISS.zip[.enc]
    <?php
    // 配置区(与备份端一致)
    $wwwRoot   = '/var/www/html';
    $dbHost    = 'localhost';
    $dbName    = 'your_db';
    $dbUser    = 'your_user';
    $dbPass    = 'your_password';
    $cipher    = 'aes-256-cbc';
    
    date_default_timezone_set('Asia/Shanghai');
    set_time_limit(600);
    
    function logMsg($msg, $log) { file_put_contents($log, date('Y-m-d H:i:s') . " $msg\n", FILE_APPEND); }
    
    if ($argc < 2) die("Usage: php restore.php <backup.zip|backup.zip.enc>\n");
    $archive = $argv[1];
    $log     = dirname($archive) . '/restore_' . date('Ymd_His') . '.log';
    
    // 1) 解密
    $work = $archive;
    if (pathinfo($archive, PATHINFO_EXTENSION) === 'enc') {
        $key = ''; // 从安全位置读取密钥(不要硬编码在代码中)
        if (empty($key) || strlen($key) !== 32) die("Missing or invalid 32-byte key.\n");
        $data = file_get_contents($archive);
        $iv   = substr($data, 0, 16);
        $enc  = substr($data, 16);
        $dec  = openssl_decrypt($enc, $cipher, $key, OPENSSL_RAW_DATA, $iv);
        if ($dec === false) die("Decrypt failed.\n");
        $work = $archive . '.dec.zip';
        file_put_contents($work, $dec);
        logMsg("Decrypted -> $work", $log);
    }
    
    // 2) 解压覆盖
    $zip = new ZipArchive();
    if ($zip->open($work) !== TRUE) die("Cannot open archive: $work\n");
    if (!$zip->extractTo($wwwRoot)) die("Extract failed.\n");
    $zip->close();
    logMsg("Extracted to $wwwRoot", $log);
    if ($work !== $archive) @unlink($work);
    
    // 3) 导入数据库(查找同目录 .sql)
    $sqlFile = null;
    foreach (glob(dirname($archive) . '/*.sql') as $f) {
        if (time() - filemtime($f) < 86400 * 2) { $sqlFile = $f; break; } // 取最近
    }
    if (!$sqlFile) die("No .sql found near $archive\n");
    $cmd = sprintf(
        'mysql --default-character-set=utf8mb4 -h%s -u%s -p%s %s < %s 2>>%s',
        escapeshellarg($dbHost), escapeshellarg($dbUser), escapeshellarg($dbPass), escapeshellarg($dbName), $sqlFile, $log
    );
    system($cmd, $ret);
    logMsg($ret === 0 ? "DB imported: $sqlFile" : "DB import failed", $log);
    
    echo "Restore finished. See $log\n";
    
  • 定时任务(crontab)

    • 示例:每日 02:00 执行备份,保留 7天,日志与备份统一目录
    • 命令:0 2 * * * /usr/bin/php /var/www/html/tools/backup.php
    • 建议将备份目录加入 /etc/backup.include.gitignore,避免被代码仓库误提交。

三 系统级备份与恢复 PHP 配置

  • 定位配置文件
    • 查看加载的 php.iniphp --ini
    • 常见路径(按 SAPI 与版本区分):
      • CLI:/etc/php/{版本号}/cli/php.ini
      • FPM:/etc/php/{版本号}/fpm/php.ini/etc/php/{版本号}/fpm/pool.d/*.conf
      • Apache:/etc/php/{版本号}/apache2/php.ini
  • 备份
    • 打包:sudo tar -czvf php-fpm-backup-$(date +%Y%m%d).tar.gz /etc/php/*/fpm/php-fpm.conf /etc/php/*/fpm/pool.d/ /etc/php/*/fpm/php.ini
    • 或 rsync:sudo rsync -av --progress /etc/php /path/to/backup/php/
  • 恢复
    • 建议先停服务:sudo systemctl stop php{版本号}-fpm
    • 解压:sudo tar -xzvf php-fpm-backup-YYYYMMDD.tar.gz -C /
    • 或 rsync:sudo rsync -av --progress /path/to/backup/php/ /etc/php/
    • 启动:sudo systemctl start php{版本号}-fpm
  • 版本控制与异地同步
    • 对配置目录做 Git 版本管理,记录每次变更与回滚点。
    • rsync+SSH 将配置同步到远程主机,提升容灾能力。

四 数据库备份恢复与运维要点

  • 数据库备份与恢复
    • 备份:mysqldump -u root -p --single-transaction --routines --triggers --default-character-set=utf8mb4 your_db > backup.sql
    • 恢复:mysql -u root -p your_db < backup.sql
    • 图形化:也可通过 phpMyAdmin 的“导出/导入”完成。
  • 安全与合规
    • 备份文件权限设为 600,存放于受限目录;加密敏感备份,密钥离线保存
    • 恢复前在测试环境验证;导入前可临时关闭外键检查:SET FOREIGN_KEY_CHECKS=0;(导入后恢复为 1)。
  • 系统级灾难恢复
    • 系统镜像:用 Timeshift(BTRFS/RSYNC)或 Clonezilla 做整盘快照/镜像,系统无法启动时可用 Live USB 进入恢复。

0