SAE域名绑定之后,一般是用CNAME方式将域名绑定到应用中。但是有时候我们需要用到A记录(比如说根域名,虽然在DNSPOD上可以设置CNAME记录,但很可能会影响到MX记录),而SAE的IP地址经常改变,ping应用二级域名得到的IP没多久就失效了(前些天网站因此几天打不开都没发现,我用的是教育网,自己能打开,但是电信线路变了)。还好DNSPOD有个功能叫D监控,可以帮你监控网站能否正常打开。如果发现宕机,DNSPOD会用邮件、短信、微信等方式提醒你。这里用到的是它的另一个通知方式,那就是URL回调"通过DNSPod 提供的D监控 URL 回调功能,您可以让宕机或恢复信息提交到您指定的 URL 上,从而更加灵活地处理各种通知信息。"
我们可以通过宕机之后的URL回调取得相关参数,并通过DNSPOD API实现自动修改记录的功能,再通过飞信发送宕机通知。
代码在后面,先说设置方法:
1.点此下载代码,修改其中的参数为你自己的。
2.将代码上传到网站。
3.在DNSPOD开启D监控,在通知设置中回调URL一栏填入monitorCallback.php的地址,如http://blog.gimhoy.com/monitorCallback.php?rHost=hipic.sinaapp.com.其中rHost是SAE的二级域名。并设置回调密钥。
4.Enjoy~ dnspod-monitor-callback
monitorCallback.php,代码如下:
<?php /* * Copyright 2007-2014 Gimhoy Studio. * * @author Gimhoy * @email contact@gimhoy.com * @version 1.0.0 */ $rHost = $_GET['rHost']; // SAE二级域名 if (emptyempty($rHost)) $rHost = 'sinaapp.com'; $logName = 'monitorLog.txt'; //log 文件名 $logStorDomain = 'log'; // Storage Domain $FetionNum = ''; //飞信登陆号码 $FetionPwd = ''; //飞信登陆密码 $MobileNum = ''; //接收通知短信的号码 $callback_key = 'MYKEY'; // 添加监控时设置的密钥 $monitor_id = $_POST['monitor_id']; // 监控编号 $domain_id = $_POST['domain_id']; // 域名编号 $domain = $_POST['domain']; // 域名名称 $record_id = $_POST['record_id']; // 记录编号 $sub_domain = $_POST['sub_domain']; // 主机名称 $record_line = $_POST['record_line']; // 记录线路 $ip = $_POST['ip']; // 记录IP $status = $_POST['status']; // 当前状态 $status_code = $_POST['status_code']; // 状态代码 $reason = $_POST['reason']; // 宕机原因 $created_at = $_POST['created_at']; // 发生时间 $checksum = $_POST['checksum']; // 校检代码 if (md5($monitor_id . $domain_id . $record_id . $callback_key . $created_at) != $checksum) { // 非法请求 echo 'BAD REQUEST'; } else { // 开始处理 if ($status == 'Warn' || $status == 'Ok') { // 宕机恢复 $msg = date("Y-m-d H:i:s") . ' ' . $sub_domain . '.' . $domain . "(" . $record_line . " " . $ip . ")宕机恢复"; } elseif ($status == 'Down') { // 宕机 $msg = date("Y-m-d H:i:s") . ' ' . $sub_domain . '.' . $domain . "(" . $record_line . " " . $ip . ")在" . $created_at . "宕机。宕机原因:" . $reason . "可用IP:"; $ips = @gethostbyname($rHost); include_once 'dnspod.class.php'; $newIP = $ips; $data = array( 'domain_id' => $domain_id, 'record_id' => $record_id, 'sub_domain' => $sub_domain, 'record_type' => 'A', 'record_line' => $record_line, 'ttl' => '600', 'value' => $newIP ); $dnspod = new dnspod(); $response = $dnspod->api_call('Record.Modify', $data); if (isset($response['status']['code']) && $response['status']['code'] == 1) { $msg = $msg . $newIP . '(已切换)'; } else { $msg = $msg . $newIP . '(切换失败,错误代码' . $response['status']['code'] . ')'; } } //飞信通知 require_once 'Fetion.class.php'; $fetion = new PHPFetion($FetionNum, $FetionPwd); $result = $fetion->send($MobileNum, $msg); if (strpos($result, '短信发送成功!') || strpos($result, '发送消息成功!')) { $r = "成功。"; } else { $r = "失败。"; } $s = new SaeStorage(); $content = $s->read($logStorDomain, $logName); $content = $content . $msg . '。飞信通知' . $r . ' '; //开源代码phprm.com $s->write($logStorDomain, $logName, $content); // 处理完成 echo 'DONE'; } dnspod . class . php /* * DNSPod API PHP Web 示例 * http://www.phprm.com/ * * Copyright 2011, Kexian Li * Released under the MIT, BSD, and GPL Licenses. * */ class dnspod { public function api_call($api, $data) { if ($api == '' || !is_array($data)) { exit('内部错误:参数错误'); } $api = 'https://dnsapi.cn/' . $api; $data = array_merge($data, array( 'login_email' => 'DNSPOD登陆账号', 'login_password' => 'DNSPOD登陆密码', 'format' => 'json', 'lang' => 'cn', 'error_on_empty' => 'yes' )); $result = $this->post_data($api, $data); if (!$result) { exit('内部错误:调用失败'); } $results = @json_decode($result, 1); if (!is_array($results)) { exit('内部错误:返回错误'); } if ($results['status']['code'] != 1) { exit($results['status']['message']); } return $results; } private function post_data($url, $data) { if ($url == '' || !is_array($data)) { return false; } $ch = @curl_init(); if (!$ch) { exit('内部错误:服务器不支持CURL'); } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); curl_setopt($ch, CURLOPT_USERAGENT, 'Gimhoy Monitor/1.0 (contact@gimhoy.com)'); $result = curl_exec($ch); curl_close($ch); return $result; } } ?>
Fetion.class.php,代码如下:
<?php header('Content-Type: text/html; charset=utf-8'); /** * PHP飞信发送类 * @author quanhengzhuang * @version 1.5.0 */ class PHPFetion { /** * 发送者手机号 * @var string */ protected $_mobile; /** * 飞信密码 * @param string */ protected $_password; /** * Cookie字符串 * @param string */ protected $_cookie = ''; /** * Uid缓存 * @var array */ protected $_uids = array(); /** * csrfToken * @param string */ protected $_csrfToten = null; /** * 构造函数 * @param string $mobile 手机号(登录者) * @param string $password 飞信密码 */ public function __construct($mobile, $password) { if ($mobile === '' || $password === '') { return; } $this->_mobile = $mobile; $this->_password = $password; $this->_login(); } /** * 析构函数 */ public function __destruct() { $this->_logout(); } /** * 登录 * @return string */ protected function _login() { $uri = '/huc/user/space/login.do?m=submit&fr=space'; $data = 'mobilenum=' . $this->_mobile . '&password=' . urlencode($this->_password); $result = $this->_postWithCookie($uri, $data); //解析Cookie preg_match_all('/.*?rnSet-Cookie: (.*?);.*?/si', $result, $matches); if (isset($matches[1])) { $this->_cookie = implode('; ', $matches[1]); } $result = $this->_postWithCookie('/im/login/cklogin.action', ''); return $result; } /** * 获取csrfToken,给好友发飞信时需要这个字段 * @param string $uid 飞信ID * @return string */ protected function _getCsrfToken($uid) { if ($this->_csrfToten === null) { $uri = '/im/chat/toinputMsg.action?touserid=' . $uid; $result = $this->_postWithCookie($uri, ''); preg_match('/name="csrfToken".*?value="(.*?)"/', $result, $matches); $this->_csrfToten = isset($matches[1]) ? $matches[1] : ''; } return $this->_csrfToten; } /** * 向指定的手机号发送飞信 * @param string $mobile 手机号(接收者) * @param string $message 短信内容 * @return string */ public function send($mobile, $message) { if ($message === '') { return ''; } // 判断是给自己发还是给好友发 if ($mobile === $this->_mobile) { return $this->_toMyself($message); } else if (strlen($mobile) === 11) { $uid = $this->_getUid($mobile); } else { $uid = $mobile; } return $uid === '' ? $this->_addFriend($mobile) : $this->_toUid($uid, $message); } protected function _getname() { $uri = '/im/index/index.action'; $result = $this->_postWithCookie($uri, '#'); // 匹配 preg_match('/(.*?)</a>/si', $result, $matches); return $matches[2]; } /* * 通过手机号增加好友 * @param string $number 手机号(要加的好友手机) * @param string $nickname 你的名字,出现在对方的验证短信里 * @param string $buddylist 分组,默认为空 * @param string $localName 好友屏显名 * @return string */ protected function _addFriend($number) { $uri = '/im/user/insertfriendsubmit.action'; $data = 'nickname=' . urlencode($this->_getname()) . '&buddylist=1&localName=&number=' . $number . '&type=0'; $result = $this->_postWithCookie($uri, $data); return $result; } /** * 获取飞信ID * @param string $mobile 手机号 * @return string */ protected function _getUid($mobile) { if (emptyempty($this->_uids[$mobile])) { $uri = '/im/index/searchOtherInfoList.action'; $data = 'searchText=' . $mobile; $result = $this->_postWithCookie($uri, $data); //匹配 preg_match('/toinputMsg.action?touserid=(d+)/si', $result, $matches); $this->_uids[$mobile] = isset($matches[1]) ? $matches[1] : ''; } return $this->_uids[$mobile]; } /** * 向好友发送飞信 * @param string $uid 飞信ID * @param string $message 短信内容 * @return string */ protected function _toUid($uid, $message) { $uri = '/im/chat/sendMsg.action?touserid=' . $uid; $csrfToken = $this->_getCsrfToken($uid); $data = 'msg=' . urlencode($message) . '&csrfToken=' . $csrfToken; $result = $this->_postWithCookie($uri, $data); return $result; } /** * 给自己发飞信 * @param string $message * @return string */ protected function _toMyself($message) { $uri = '/im/user/sendMsgToMyselfs.action'; $result = $this->_postWithCookie($uri, 'msg=' . urlencode($message)); return $result; } /** * 退出飞信 * @return string */ protected function _logout() { $uri = '/im/index/logoutsubmit.action'; $result = $this->_postWithCookie($uri, ''); return $result; } protected function getgroup() { $uri = '/im/index/index.action'; $data = 'type=group'; $result = $this->_postWithCookie($uri, $data); // 匹配 preg_match_all('/contactlistView.action?idContactList=(d+)/si', $result, $matches); foreach ($matches[1] as $k => $v) { if ($k == 0) { $min = $v; $max = $v; } else if ($v != 9998 && $v != 9999) { $min = min($min, $v); $max = max($max, $v); } } return $max; } public function getyou1() { $list = $this->getgroup(); for ($i = 0; $i <= $list; $i++) { $uri = '/im/index/contactlistView.action'; $data = 'idContactList=' . $i . '&type=group'; $result = $this->_postWithCookie($uri, $data); preg_match('/(.*?)|(.*?)((.*?)/(.*?))/si', $result, $listn); if (!$listn[2]) { continue; } $shuchu.= str_replace(" ", "", $listn[2]) . "(" . $listn[4] . ")n"; preg_match('/共(d+)页/si', $result, $zpage); preg_match('/共(d+)</a>页/si', $result, $dpage); isset($zpage[1]) ? $page = $zpage[1] : $page = $dpage[4]; for ($j = 1; $j <= $page; $j++) { $uri = '/im/index/contactlistView.action'; $data = 'idContactList=' . $i . '&page=' . $j; $result = $this->_postWithCookie($uri, $data); preg_match_all('/(.*?)</a>/si', $result, $matches); if (!$matches[1][0]) { break; } for ($x = 0; $x <= 9; $x++) { if (!$matches[1][$x]) { continue; } $shuchu.= $matches[1][$x] . " " . str_replace(" ", "", $matches[3][$x]) . "n"; } } } return $shuchu; } public function getyou() { $list = $this->getgroup(); for ($i = 0; $i <= $list; $i++) { $uri = '/im/index/contactlistView.action'; $data = 'idContactList=' . $i . '&type=group'; $result = $this->_postWithCookie($uri, $data); preg_match('/(.*?)|(.*?)((.*?)/(.*?))/si', $result, $listn); if (!$listn[2]) { continue; } $shuchu.= str_replace(" ", "", $listn[2]) . "(" . $listn[4] . ")n"; preg_match('/共(d+)页/si', $result, $zpage); preg_match('/共(d+)</a>页/si', $result, $dpage); isset($zpage[1]) ? $page = $zpage[1] : $page = $dpage[4]; for ($j = 1; $j <= $page; $j++) { $uri = '/im/index/contactlistView.action'; $data = 'idContactList=' . $i . '&page=' . $j; $result = $this->_postWithCookie($uri, $data); preg_match_all('/(.*?)</a>/si', $result, $matches); if (!$matches[1][0]) { break; } for ($x = 0; $x <= 9; $x++) { if (!$matches[1][$x]) { continue; } $shuchu.= $matches[1][$x] . " " . str_replace(" ", "", $matches[3][$x]) . "n"; } } } return $shuchu; } /** * 携带Cookie向f.10086.cn发送POST请求 * @param string $uri * @param string $data */ protected function _postWithCookie($uri, $data) { $fp = fsockopen('f.10086.cn', 80); fputs($fp, "POST $uri HTTP/1.1rn"); fputs($fp, "Host: f.10086.cnrn"); fputs($fp, "Cookie: {$this->_cookie}rn"); fputs($fp, "Content-Type: application/x-www-form-urlencodedrn"); fputs($fp, "User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1rn"); fputs($fp, "Content-Length: " . strlen($data) . "rn"); fputs($fp, "Connection: closernrn"); fputs($fp, $data); $result = ''; while (!feof($fp)) { $result.= fgets($fp); } fclose($fp); return $result; } } ?>