wordpress站点更新监控-WP观察者

一、程序简介

这个是我自己开发使用的一个监控wp站点更新的程序,全程使用PHP开发,使用sqlite作为数据库存储,在宝塔计划任务的配合下,能完成站点更新后的1分钟内通过邮件通知到相关邮件。这个程序适用于个人监控别人网站的更新,也可以用于小网站的订阅功能。

邮件截图:

图片[1]-wordpress站点更新监控-WP观察者 - KEKC博客-KEKC博客
图片[2]-wordpress站点更新监控-WP观察者 - KEKC博客-KEKC博客

当收到邮件,可以点击删除以删除监控。

二、程序

1、服务端

主要是:储存信息,提供可调用API。

需要修改的地方,邮箱信息和一些高权限的API密码,我服务器上的名字是cronlist.php,其中,里面有两个地方的密码需要改,密码为自己设置的密码,邮箱密码为你的邮箱密码。

<?php
class crondb extends SQLite3
{
  function __construct()
  {
     $this->open('cron.db');
  }
}
class Smtp
{
    /* Public Variables */
    public $smtp_port;
    public $time_out;
    public $host_name;
    public $log_file;
    public $relay_host;
    public $debug;
    public $auth;
    public $user;
    public $pass;
    /* Private Variables */
    private $sock;
    /* Constractor */
    function __construct($relay_host = "", $smtp_port = 80,$auth = false,$user = null,$pass = null)
    {
        $this->debug = FALSE;
        $this->smtp_port = $smtp_port;
        $this->relay_host = $relay_host;
        $this->time_out = 30; //is used in fsockopen()
        $this->auth = $auth;//auth
        $this->user = $user;
        $this->pass = $pass;
        $this->host_name = "localhost"; //is used in HELO command
        $this->log_file = "";
        $this->sock = FALSE;
    }
    /* Main Function */
    function sendmail($to, $from, $subject, $body, $mailtype, $cc, $bcc, $additional_headers, $fromUser, $replyToAddress)
    {
        $mail_from = $this->get_address($this->strip_comment($from));
        $body = preg_replace("/(^|(\r\n))(\.)/", "k_e_k_c_cn.", $body);
        $header = "MIME-Version:1.0\r\n";
        if($mailtype=="HTML"){
            $header .= "Content-Type:text/html; charset=utf-8\r\n";
        }
        $header .= "To: ".$to."\r\n";
        if ($cc != "") {
            $header .= "Cc: ".$cc."\r\n";
        }
        $header .= "From: $fromUser<".$from.">\r\n";
        $header .= "Subject: ".$subject."\r\n";
        $header .= "Reply-To: ".$replyToAddress."\r\n";
        $header .= $additional_headers;
        $header .= "Date: ".date("r")."\r\n";
        $header .= "X-Mailer:By Redhat (PHP/".phpversion().")\r\n";
        list($msec, $sec) = explode(" ", microtime());
        $header .= "Message-ID: <".date("YmdHis", $sec).".".($msec*1000000).".".$mail_from.">\r\n";
        //若需要开启邮件跟踪服务,请使用以下代码设置跟踪链接头。前置条件和约束见文档"如何开启数据跟踪功能?"
        //$header .= "Content-Transfer-Encoding: quoted-printable\r\n";
        //$header .= "X-AliDM-Trace: ". base64_encode(json_encode(['TagName'=>'用户创建的Tag','OpenTrace'=>"1"]))."\r\n";
        $TO = explode(",", $this->strip_comment($to));
        if ($cc != "") {
            $TO = array_merge($TO, explode(",", $this->strip_comment($cc)));
        }
        if ($bcc != "") {
            $TO = array_merge($TO, explode(",", $this->strip_comment($bcc)));
        }
        $sent = TRUE;
        foreach ($TO as $rcpt_to) {
            $rcpt_to = $this->get_address($rcpt_to);
            if (!$this->smtp_sockopen($rcpt_to)) {
                $this->log_write("Error: Cannot send email to ".$rcpt_to."\n");
                $sent = FALSE;
                continue;
            }
            if ($this->smtp_send($this->host_name, $mail_from, $rcpt_to, $header, $body)) {
                $this->log_write("E-mail has been sent to <".$rcpt_to.">\n");
            } else {
                $this->log_write("Error: Cannot send email to <".$rcpt_to.">\n");
                $sent = FALSE;
            }
            fclose($this->sock);
            $this->log_write("Disconnected from remote host\n");
        }
        return $sent;
    }
    /* Private Functions */
    function smtp_send($helo, $from, $to, $header, $body = "")
    {
        if (!$this->smtp_putcmd("HELO", $helo)) {
            return $this->smtp_error("sending HELO command");
        }
        //auth
        if($this->auth){
            if (!$this->smtp_putcmd("AUTH LOGIN", base64_encode($this->user))) {
                return $this->smtp_error("sending HELO command");
            }
            if (!$this->smtp_putcmd("", base64_encode($this->pass))) {
                return $this->smtp_error("sending HELO command");
            }
        }
        if (!$this->smtp_putcmd("MAIL", "FROM:<".$from.">")) {
            return $this->smtp_error("sending MAIL FROM command");
        }
        if (!$this->smtp_putcmd("RCPT", "TO:<".$to.">")) {
            return $this->smtp_error("sending RCPT TO command");
        }
        if (!$this->smtp_putcmd("DATA")) {
            return $this->smtp_error("sending DATA command");
        }
        if (!$this->smtp_message($header, $body)) {
            return $this->smtp_error("sending message");
        }
        if (!$this->smtp_eom()) {
            return $this->smtp_error("sending <CR><LF>.<CR><LF> [EOM]");
        }
        if (!$this->smtp_putcmd("QUIT")) {
            return $this->smtp_error("sending QUIT command");
        }
        return TRUE;
    }
    function smtp_sockopen($address)
    {
        if ($this->relay_host == "") {
            return $this->smtp_sockopen_mx($address);
        } else {
            return $this->smtp_sockopen_relay();
        }
    }
    function smtp_sockopen_relay()
    {
        $this->log_write("Trying to ".$this->relay_host.":".$this->smtp_port."\n");
        $this->sock = @fsockopen($this->relay_host, $this->smtp_port, $errno, $errstr, $this->time_out);
        if (!($this->sock && $this->smtp_ok())) {
            $this->log_write("Error: Cannot connenct to relay host ".$this->relay_host."\n");
            $this->log_write("Error: ".$errstr." (".$errno.")\n");
            return FALSE;
        }
        $this->log_write("Connected to relay host ".$this->relay_host."\n");
        return TRUE;
    }
    function smtp_sockopen_mx($address)
    {
        $domain = preg_replace("/^.+@([^@]+)$/", "k_e_k_c_cn", $address);
        if (!@getmxrr($domain, $MXHOSTS)) {
            $this->log_write("Error: Cannot resolve MX \"".$domain."\"\n");
            return FALSE;
        }
        foreach ($MXHOSTS as $host) {
            $this->log_write("Trying to ".$host.":".$this->smtp_port."\n");
            $this->sock = @fsockopen($host, $this->smtp_port, $errno, $errstr, $this->time_out);
            if (!($this->sock && $this->smtp_ok())) {
                $this->log_write("Warning: Cannot connect to mx host ".$host."\n");
                $this->log_write("Error: ".$errstr." (".$errno.")\n");
                continue;
            }
            $this->log_write("Connected to mx host ".$host."\n");
            return TRUE;
        }
        $this->log_write("Error: Cannot connect to any mx hosts (".implode(", ", $MXHOSTS).")\n");
        return FALSE;
    }
    function smtp_message($header, $body)
    {
        fputs($this->sock, $header."\r\n".$body);
        $this->smtp_debug("> ".str_replace("\r\n", "\n"."> ", $header."\n> ".$body."\n> "));
        return TRUE;
    }
    function smtp_eom()
    {
        fputs($this->sock, "\r\n.\r\n");
        $this->smtp_debug(". [EOM]\n");
        return $this->smtp_ok();
    }
    function smtp_ok()
    {
        $response = str_replace("\r\n", "", fgets($this->sock, 512));
        $this->smtp_debug($response."\n");
        if (!preg_match("/^[23]/", $response)) {
            fputs($this->sock, "QUIT\r\n");
            fgets($this->sock, 512);
            $this->log_write("Error: Remote host returned \"".$response."\"\n");
            return FALSE;
        }
        return TRUE;
    }
    function smtp_putcmd($cmd, $arg = "")
    {
        if ($arg != "") {
            if($cmd=="") $cmd = $arg;
            else $cmd = $cmd." ".$arg;
        }
        fputs($this->sock, $cmd."\r\n");
        $this->smtp_debug("> ".$cmd."\n");
        return $this->smtp_ok();
    }
    function smtp_error($string)
    {
        $this->log_write("Error: Error occurred while ".$string.".\n");
        return FALSE;
    }
    function log_write($message)
    {
        $this->smtp_debug($message);
        if ($this->log_file == "") {
            return TRUE;
        }
        $message = date("M d H:i:s ").get_current_user()."[".getmypid()."]: ".$message;
        if (!@file_exists($this->log_file) || !($fp = @fopen($this->log_file, "a"))) {
            $this->smtp_debug("Warning: Cannot open log file \"".$this->log_file."\"\n");
            return FALSE;
        }
        flock($fp, LOCK_EX);
        fputs($fp, $message);
        fclose($fp);
        return TRUE;
    }
    function strip_comment($address)
    {
        $comment = "/\([^()]*\)/";
        while (preg_match($comment, $address)) {
            $address = preg_replace($comment, "", $address);
        }
        return $address;
    }
    function get_address($address)
    {
        $address = preg_replace("/([ \t\r\n])+/", "", $address);
        $address = preg_replace("/^.*<(.+)>.*$/", "k_e_k_c_cn", $address);
        return $address;
    }
    function smtp_debug($message)
    {
        if ($this->debug) {
            echo $message;
        }
    }
}
//发送邮件 宝塔邮件系统发送
function send_mail($email,$subject,$content){
        $mailto=$email;
        $mailsubject=$subject;
        $mailbody=$content;
    
        $smtpserver     = "ssl://smtp.qiye.aliyun.com";
        $smtpserverport = 465;
        // $smtpserver= "ssl://smtpdm.aliyun.com";
        // $smtpserverport = 465;
        $smtpusermail   = "kekc@mail.yinjiangbi.cn";
    
        // 发件人的账号,填写控制台配置的发信地址,比如xxx@xxx.com
        $smtpuser       = "kekc@mail.yinjiangbi.cn";
        // 访问SMTP服务时需要提供的密码(在控制台选择发信地址进行设置)
        $smtppass       = "邮箱密码";
    
        $mailsubject    = "=?UTF-8?B?" . base64_encode($mailsubject) . "?=";
        $mailtype       = "HTML";
    
        //可选,设置回信地址
        $smtpreplyto    = "yinjiangbi@qq.com";
    
        $smtp           = new smtp($smtpserver, $smtpserverport, true, $smtpuser, $smtppass);
        $smtp->debug    = false;
        $cc   ="";
        $bcc  = "";
        $additional_headers = "";
        //设置发件人名称,名称用户可以自定义填写。
        $sender  = "WP观察者";
        $res = $smtp->sendmail($mailto,$smtpusermail, $mailsubject, $mailbody, $mailtype, $cc, $bcc, $additional_headers, $sender, $smtpreplyto);
        if($res == true){
            return true;
        }else{
            return false;
        }
}
$db = new crondb();
if(!$db){
  echo $db->lastErrorMsg();
}
$sql =<<<EOF
      CREATE TABLE IF NOT EXISTS  cron
      (ID INTEGER PRIMARY KEY   AUTOINCREMENT,
      siteurl           TEXT    NOT NULL,
      sitename          TEXT     NOT NULL,
      adminemail        TEXT     NOT NULL,
      adminpasswd       TEXT     NOT NULL,
      lastid           TEXT     NOT NULL);
EOF;
$db->exec($sql);//无表新建
$act = htmlspecialchars($_GET['act']);
if("getcronlist" == $act){//获取所有任务信息
    $sql = "SELECT * from cron;";
    $ret = $db->query($sql);
    if(!$ret){
        $data =array(
            'code'=>'0',
            'msg'=>'获取失败!'
        );
    }else{
        $res = array();
        while ($row = $ret->fetchArray()) {
            array_push($res,$row);
        }
        $data =array(
            'code'=>'1',
            'msg'=>'获取成功!',
            'data'=>$res
        );
    }
    $data_json = json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    header('Content-type:text/json');
    echo $data_json;
}elseif("addcron" == $act){//用户添加数据,http://observer.kekc.cn/cronlist.php?act=addcron&siteurl=https://www.kekc.cn/&sitename=KEKC%E5%8D%9A%E5%AE%A2&adminemail=2551654928@qq.com&adminpasswd=密码&lastid=111
    $siteurl = htmlspecialchars($_GET['siteurl']);
    $sitename = htmlspecialchars($_GET['sitename']);
    $adminemail = htmlspecialchars($_GET['adminemail']);
    $adminpasswd = htmlspecialchars($_GET['adminpasswd']);
    $lastid = htmlspecialchars($_GET['lastid']);
    $sql ="INSERT INTO cron (ID,siteurl,sitename,adminemail,adminpasswd,lastid) VALUES (NULL, '${siteurl}', '${sitename}', '${adminemail}', '${adminpasswd}','${lastid}' );";
    $ret = $db->exec($sql);
    if(!$ret){
    $data =array(
        'code'=>'0',
        'msg'=>'新增失败!'
    );
    } else {
    $data =array(
        'code'=>'1',
        'msg'=>'新增成功!'
    );
    }
    $data_json = json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    header('Content-type:text/json');
    echo $data_json;
}elseif("delcron" == $act){//用户删除单条数据
    $id = htmlspecialchars($_GET['id']);
    $adminpasswd = htmlspecialchars($_GET['adminpasswd']);
    $sql = "DELETE from cron where ID='${id}' and adminpasswd='${adminpasswd}';";
    $ret = $db->exec($sql);
    if(!$ret){
    $data =array(
        'code'=>'0',
        'msg'=>'删除失败!'
    );
    } else {
    $data =array(
        'code'=>'1',
        'msg'=>'删除成功!'
    );
    }
    $data_json = json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    header('Content-type:text/json');
    echo $data_json;
}elseif("delallcron" == $act){//管理员删除数据库
    $passwd = htmlspecialchars($_GET['passwd']);
    if('密码' == $passwd){
        unlink("cron.db");
        $data =array(
            'code'=>'1',
            'msg'=>'删除成功!'
        );
        $data_json = json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        header('Content-type:text/json');
        echo $data_json;
    }else{
        $data =array(
            'code'=>'0',
            'msg'=>'删除失败,密码错误!'
        );
        $data_json = json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        header('Content-type:text/json');
        echo $data_json;
    }

}elseif("updatelastid" == $act){//更新最后id,http://observer.kekc.cn/cronlist.php?act=updatelasturl&id=1&passwd=密码&lasturl=3327
    $passwd = htmlspecialchars($_GET['passwd']);
    if('密码' == $passwd){
        $id = htmlspecialchars($_GET['id']);
        $lastid = htmlspecialchars($_GET['lastid']);
        $sql = "UPDATE cron set lastid = '${lastid}' where ID='${id}';";
        $ret = $db->exec($sql);
        if(!$ret){
        $data =array(
            'code'=>'0',
            'msg'=>'更新失败!'
        );
        } else {
        $data =array(
            'code'=>'1',
            'msg'=>'更新成功!'
        );
        }
        $sql = "SELECT * from cron where ID='${id}';";
        $ret = $db->query($sql);
        $row = $ret->fetchArray();
        $sitename = $row['sitename'];
        $siteurl = $row['siteurl'];
        $email = $row['adminemail'];
        $adminpasswd = $row['adminpasswd'];
        $subject = "站点监控:".$sitename."更新!";
        $content = $sitename."已更新,最新文章链接:".$siteurl."?p=".$lastid."<br>删除监控:<a href='http://observer.kekc.cn/cronlist.php?act=delcron&id=".$id."&adminpasswd=".$adminpasswd."'>点击删除</a>";
        send_mail($email, $subject, $content);
        $data_json = json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        header('Content-type:text/json');
        echo $data_json;
    }else{
        $data =array(
            'code'=>'0',
            'msg'=>'更新失败,密码错误!'
        );
        $data_json = json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        header('Content-type:text/json');
        echo $data_json;
    }

}elseif('cron' == $act){//监控端,http://127.0.0.1/start.php?act=cron
    $datas = json_decode(file_get_contents("http://observer.kekc.cn/cronlist.php?act=getcronlist",false, stream_context_create($stream_opts)))->data;
    for ($i = 0; $i < count($datas); $i++) {
         $id = $datas[$i]->ID;//id
         $url = $datas[$i]->siteurl;//站点链接
         $sitename = $datas[$i]->sitename;//站点名称
         $adminemail = $datas[$i]->adminemail;//通知邮箱
         $lastid = $datas[$i]->lastid;//最后链接
         $lastpostid = json_decode(file_get_contents($url."/wp-json/wp/v2/posts?per_page=1&page=1&_fields=id",false, stream_context_create($stream_opts)))[0]->id;
         if($lastpostid != $lastid){
             file_get_contents("http://observer.kekc.cn/cronlist.php?act=updatelastid&id=${id}&passwd=密码&lastid=${lastpostid}",false, stream_context_create($stream_opts));//更新id
         }
    }
}
   $db->close();



// $act = htmlspecialchars($_GET['act']);
// $stream_opts = [    "ssl" => [        "verify_peer"=>false,
//         "verify_peer_name"=>false,
//     ]
// ]; 
// if('cron' == $act){
//     $datas = json_decode(file_get_contents("http://observer.kekc.cn/cronlist.php?act=getcronlist",false, stream_context_create($stream_opts)))->data;
//     for ($i = 0; $i < count($datas); $i++) {
//          $id = $datas[$i]->ID;//id
//          $url = $datas[$i]->siteurl;//站点链接
//          $sitename = $datas[$i]->sitename;//站点名称
//          $adminemail = $datas[$i]->adminemail;//通知邮箱
//          $lastid = $datas[$i]->lastid;//最后链接
//          $lastpostid = json_decode(file_get_contents($url."/wp-json/wp/v2/posts?per_page=1&page=1&_fields=id",false, stream_context_create($stream_opts)))[0]->id;
//          if($lastpostid != $lastid){
//              file_get_contents("http://observer.kekc.cn/cronlist.php?act=updatelastid&id=${id}&passwd=密码&lastid=${lastpostid}",false, stream_context_create($stream_opts));//更新id
//          }
//     }
// }



?>

2、客户端

也叫做监控端,主要是怕被监控的网站反过来攻击我们的网站,可以用无公网的本地设备持续监控。我服务器上是start.php

<?php
$act = htmlspecialchars($_GET['act']);
$stream_opts = [    "ssl" => [        "verify_peer"=>false,
        "verify_peer_name"=>false,
    ]
]; 
if('cron' == $act){
    $datas = json_decode(file_get_contents("http://observer.kekc.cn/cronlist.php?act=getcronlist",false, stream_context_create($stream_opts)))->data;//链接改为自己服务端的链接
    for ($i = 0; $i < count($datas); $i++) {
         $id = $datas[$i]->ID;//id
         $url = $datas[$i]->siteurl;//站点链接
         $sitename = $datas[$i]->sitename;//站点名称
         $adminemail = $datas[$i]->adminemail;//通知邮箱
         $lastid = $datas[$i]->lastid;//最后链接
         $lastpostid = json_decode(file_get_contents($url."/wp-json/wp/v2/posts?per_page=1&page=1&_fields=id",false, stream_context_create($stream_opts)))[0]->id;
         if($lastpostid != $lastid){
             file_get_contents("http://observer.kekc.cn/cronlist.php?act=updatelastid&id=${id}&passwd=服务端的密码&lastid=${lastpostid}",false, stream_context_create($stream_opts));//更新id
         }
    }
}

三、使用

1、监控

在部署好客户端和服务端,修改好相关信息后,我们需要监控客户端,例如我的:

图片[3]-wordpress站点更新监控-WP观察者 - KEKC博客-KEKC博客

2、支持的API

1、用户添加数据

2、用户删除单条数据

3、管理员删除数据库(删除所有数据)

4、更新最后id并发送邮件(客户端的使用的接口)

5、获取所有任务信息(客户端获取服务端所有监控)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享