SAE 平台代码实现数据库定时备份以及同步到本地 2014/09/11 09:39:01 分类: 技术随笔 1人评论 次浏览 SAE 只允许用户通过phpMyAdmin管理远程数据库,

来源:互联网 发布:下列属于视频压缩算法 编辑:程序博客网 时间:2024/05/22 16:57

SAE 平台代码实现数据库定时备份以及同步到本地

2014/09/11 09:39:01    分类: 技术随笔    1人评论 次浏览

SAE 只允许用户通过phpMyAdmin管理远程数据库, 在做本地SAE环境开发的时候是是分不方便的.
因此写了点代码能够方便的将远程数据库同步到本地来.

一、SAE 无程数据库备份
可以通过SAE 提供的Cron, Storage, DeferredJob 来实现数据库备份. 其中有用到我的PhpLog 日志插件. 代码如下:

/cron/dbBackup.php

require('..' . DIRECTORY_SEPARATOR . 'ext' . DIRECTORY_SEPARATOR . 'PhpLog' . DIRECTORY_SEPARATOR . 'PhpLog.php');$filename = SAE_MYSQL_DB . '-' . date('Ymd-his') . '-' . substr(time(), -4, 4) . '.sql';$dj = new SaeDeferredJob();$taskID = $dj->addTask("export", "mysql", "wordpress", "dbBackup/$filename", SAE_MYSQL_DB, "", "");if ($taskID === false) {PhpLog::log('数据库备份失败 errno:' . $dj->errno() . ' errmsg:' . $dj->errmsg(),'error','dbBackup'); } else {PhpLog::log('数据库备份成功 id:' . $taskID, 'info', 'dbBackup'); }

然后需要在将此代码加入Cron 每月1号定时备份. 在config.yaml 加入以下代码:
config.yaml

name: dbBackupversion: 2cron:- description: db backup  url: /cron/dbBackup.php  schedule: "0 0 1 * *"

此时 dbBackup.php 是没有加入访问控制的. 所有人都可以通过web访问. 于是我们可以在dbBackup.php加入不允许通过web访问.

if(!isset($_SERVER['argv'])) {// || strncasecmp(php_sapi_name(),'cli',3))PhpLog::log('外部非法运行, 来自IP: ' . $_SERVER["REMOTE_ADDR"] . ' 运行环境: ' . $env, 'warning', 'dbBackup'); echo "<script language='javascript'>location.href='//www.madcoder.cn/404.php';</script>";die();}

到此处, 数据库备份代码已完成.

一、还原到本地数据库.
原理很简单, 就是通过Storage API 获取到最新的备份文件, 然后更新到本地数据库.
首先需要一个页面输出最新备份SQL文件.
/cron/dbRestore.php

$storage = new SaeStorage();$list = $storage->getListByPath('wordpress', 'dbBackup');if (count($list['files']) === 0) {echo '无文件';die;}header("Content-type: text/html; charset=utf-8");echo $storage->read('wordpress', $list['files'][0]['fullName']);

其次需要一个本地的php脚本导入SQL文件到数据库.
/cron/dbRestore.local.php

define("DB_HOST", 'localhost');define("DB_USER", 'root');define("DB_PASSWORD", 'root');define("DB_NAME", 'app_madcoder');define("DOWNLOAD_LINK", '//www.madcoder.cn/cron/dbRestore.php');  // 查看最新备份文件的页面.define("RESTORE_SQL", 'restore.sql'); // 导入成功后所要执行的SQL. 文件不存在刚不执行.echo iconv('UTF-8','GBK','最新备份文件下载中...').PHP_EOL;$sql = file_get_contents(DOWNLOAD_LINK);echo iconv('UTF-8','GBK','文件下载成功, 正在写入文件').PHP_EOL;$filename = md5(time()) . '.sql';if ($fp = fopen($filename, "w")) {@fwrite($fp, $sql);if (@fwrite($fp, $sql)) {echo iconv('UTF-8','GBK','写入文件成功, 准备导入MYSQL').PHP_EOL;fclose($fp);} else {echo iconv('UTF-8','GBK','写文件失败.').PHP_EOL;fclose($fp);die;}} echo iconv('UTF-8','GBK','正在还原数据库,请稍等....').PHP_EOL;$rst = exec('mysql -h ' . DB_HOST . ' -u ' . DB_USER . ' -p' . DB_PASSWORD .' --default-character-set=utf8 ' . DB_NAME. ' < ' . $filename); unlink($filename); // SQL 导入后删除临时文件.if (file_exists(RESTORE_SQL)) {echo iconv('UTF-8','GBK','正在执行还原SQL.').PHP_EOL;$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);$sql = str_replace(PHP_EOL, '', file_get_contents(RESTORE_SQL)); $rst = $mysqli->multi_query($sql);$errors = $mysqli->error;if ($errors) {echo iconv('UTF-8','GBK','还原SQL执行失败, 错误: ' . $errors).PHP_EOL;} else {echo iconv('UTF-8','GBK','还原SQL执行成功.').PHP_EOL;}$mysqli->close();}echo iconv('UTF-8','GBK','程序结束.').PHP_EOL;

同时, 支持在导入完成后执行指定SQL文件. 因为我在远程库里site url 是 www.madcoder.cn, dump到本地是, 我需要它变成 1.madcoder.sae.com 之类的. 加入 restore.sql:

update wp_posts set guid = replace(guid, 'www.madcoder.cn', '1.madcoder.sae.com') where guid like '%www.madcoder.cn%';update wp_options set option_value = replace(option_value, 'www.madcoder.cn', '1.madcoder.sae.com') where option_value like '%www.madcoder.cn%';

这样一键dump下来远程数据库之后本地就可以直接进行开发调试了.

当然, 这里的dbRestore.php是必须加入访问控制的, 不然所以人都能轻松dump下你的整个数据库那就麻烦了.
我们可以限定IP访问, 加上访问key, 等等方式来控制访问. 当然, 安全性很低, 大家自己取舍. 代码就不贴了, 不然人人能dump我的库了.

然后运行dbRestore.local.php 将本地数据库还原到最近远程备份.
运行结果如下图:

sae-db-backup-restore