阮一峰你们基本都认识,很厉害的一我的,经济学博士,文章写得很棒,知识面很普遍,计算机、算法、英语、文采,这是能想到的他的一些标签,他的博客应该算是最受欢迎的博客之一了。
我常常回去看他的博客,但有时候时间长了,再次去看,发现他已经有好几篇新文章了,我就在想,能不能本身写个程序,监控的他博客,当他有新文章的时候,第一时间推送给我。php
他的博客中有一个feed,是一个返回xml格式文档的接口,这个接口是最新的文章列表,总共15篇,能够经过监控这个接口中前几篇文章列表的变化来间接的检测他的文章更新,若是有新的文章立刻给个人邮箱发送邮件,这样我就能够尽量早的get到阮老师的最新文章了。
这是设计思路图:
git
首先就是rss解析了,这个使用php的原生函数simplexml_load_string获得一个解析以后的SimpleXMLElement对象,经过该对象能够很轻松的获取到阮老师更新的前几篇文章。而后和redis中的已发送文章列表集合做对比,若是有新的更新,将更新的信息发送给UDPserver,让UDPserver去发送邮件给用户列表。检测程序循环执行,每10分钟跑一次。github
有了思路编码就很快了(这里其实优化了好几回,刚开始的时候思路也没有这么明了,边作边改,固然了,仍是要慢慢锻炼,开始以前尽量多的完善思路)。
使用PHP依赖管理利器——Composer,常用PHP的开发者对这个工具应该很熟悉,不熟悉的同窗能够点击前面的连接进行脑补,文档是中文的,很好懂。这个小系统将会使用到三个类库:
phpmailer
,predis
,workerman
。第一个是一个发送邮件的类库,能够点击这里查看他的相关信息,第二个类库是php对redis接口的封装,这里是他的源码地址,第三个是一个建立UDPserver的类库,这里是他的官方网站。redis
首先新建一个项目目录,而后进入项目目录安装依赖算法
mkdir blog-observer cd blog-observer composer require phpmailer/phpmailer composer require predis/predis composer require workerman/workerman
执行完上面的命令以后,会在项目目录blog-observer目录下面看到下面几个文件composer.json
,composer.lock
和文件夹vender
,composer.json中的内容以下,至此依赖的类库安装好了。shell
{ "require": { "phpmailer/phpmailer": "^5.2", "predis/predis": "^1.0", "workerman/workerman": "^3.3" } }
下面是主要代码,因为是服务端程序,因此这里设置为daemon进程,我这里UDPserver为udp://127.0.0.1:1234
json
daemonize(); while(1) { //获取最新的几篇文章,看看是否须要推送 $c = file_get_contents(XML_URL); $parse = @simplexml_load_string($c); if($parse) { $count = count($parse->entry); $count = $count > RECENT_NUM ? RECENT_NUM : $count; $maynew = []; for($i = 0; $i < $count; $i++) { $maynew[$parse->entry[$i]->link->attributes()->href->__toString()] = $parse->entry[$i]->title->__toString(); } $body = ""; //是否推送 foreach($maynew as $url => $title) { if($client->sadd(SENDED_SET_KEY, $url)) { //send EMAIL $body .= "<a href='".$url."'>".$title."</a><br>"; } } if($body) { $msg = []; $msg['type'] = 1; $msg['mailbody'] = $body; $start = 0; while($mailaddrs = $client->lrange(EMAIL_LIST_KEY ,$start, ($start + EVERY_SEND_NUM -1 ))) { $msg['mailaddrs'] = $mailaddrs; $send_msg = json_encode($msg); socket_sendto($sock, $send_msg, strlen($send_msg), 0, '127.0.0.1', 1234); $start += EVERY_SEND_NUM; } } } sleep(GAP_SECONDS); }
有了workerman,能够很方便的实现UDPserver,比本身写来的快得多。composer
$udp_worker = new Workerman\Worker("udp://0.0.0.0:".MAIL_UDP_PORT); $udp_worker->count = 2; $udp_worker->onMessage = function($connection, $data) use ($mail) { $arr = json_decode($data, true); switch($arr['type']) { //发送邮件 case '1': { $mailaddrs = $arr['mailaddrs']; if(!empty($mailaddrs) && $arr['mailbody']) { foreach($mailaddrs as $to) { $mail->clearAddresses(); $mail->AddAddress($to); $mail->Body = $arr['mailbody']; if(!$mail->Send()) { echo "发送邮件失败:\n"."address:".$to."\n"; } } } break; } default: break; } }; Workerman\Worker::runAll();
好了,至此全部的设计编码工做就完成了,如今启动程序,进程启动以后会议daemon的形式运行,不会随着终端的关闭而中止。socket
php xmldup.php start php xmlmail.php
这是一个小系统,固然了还有不少不规范的地方,好比daemon进程通常都会以字母d
结尾,还有就是启动很不方便,要启动两次脚本,哈哈,固然了,这只是本身先来无事玩玩了,要真设计一个完成的系统估计会考虑不少不少的东西,加油吧,继续前进。函数
这里是github地址:blog-observer,本身试用的时候记得修改邮箱名称和密码。
若是谁也想第一时间获取到最新的阮老师的文章能够给我发邮件,我把大家的邮件地添加到邮件list中,但不保证会发送到,有时候关了电脑程序就中止了~