引言
阮一峰大家基本都認識,很厲害的一個人,經濟學博士,文章寫得很棒,知識面很廣泛,計算機、算法、英語、文采,這是能想到的他的一些標簽,他的博客應該算是最受歡迎的博客之一了。
我經常回去看他的博客,但有時候時間長了,再次去看,發現他已經有好幾篇新文章了,我就在想,能不能自己寫個程序,監控的他博客,當他有新文章的時候,第一時間推送給我。
思路
他的博客中有一個feed,是一個返回xml格式文檔的接口,這個接口是最新的文章列表,總共15篇,可以通過監控這個接口中前幾篇文章列表的變化來間接的檢測他的文章更新,如果有新的文章馬上給我的郵箱發送郵件,這樣我就可以盡可能早的get到阮老師的最新文章了。
這是設計思路圖:

首先就是rss解析了,這個使用php的原生函數simplexml_load_string得到一個解析之后的SimpleXMLElement對象,通過該對象可以很輕松的獲取到阮老師更新的前幾篇文章。然后和redis中的已發送文章列表集合作對比,如果有新的更新,將更新的信息發送給UDPserver,讓UDPserver去發送郵件給用戶列表。檢測程序循環執行,每10分鍾跑一次。
開始編碼
有了思路編碼就很快了(這里其實優化了好幾次,剛開始的時候思路也沒有這么明了,邊做邊改,當然了,還是要慢慢鍛煉,開始之前盡可能多的完善思路)。
使用PHP依賴管理利器——Composer,經常使用PHP的開發者對這個工具應該很熟悉,不熟悉的同學可以點擊前面的鏈接進行腦補,文檔是中文的,很好懂。這個小系統將會使用到三個類庫:
phpmailer,predis,workerman。第一個是一個發送郵件的類庫,可以點擊這里查看他的相關信息,第二個類庫是php對redis接口的封裝,這里是他的源碼地址,第三個是一個創建UDPserver的類庫,這里是他的官方網站。
安裝依賴的類庫
首先新建一個項目目錄,然后進入項目目錄安裝依賴
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中的內容如下,至此依賴的類庫安裝好了。
{
"require": {
"phpmailer/phpmailer": "^5.2",
"predis/predis": "^1.0",
"workerman/workerman": "^3.3"
}
}
監控博客更新&推送更新消息給UDP
下面是主要代碼,由於是服務端程序,所以這里設置為daemon進程,我這里UDPserver為udp://127.0.0.1:1234
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);
}
UDPserver程序
有了workerman,可以很方便的實現UDPserver,比自己寫來的快得多。
$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的形式運行,不會隨着終端的關閉而停止。
php xmldup.php start
php xmlmail.php
總結
這是一個小系統,當然了還有很多不規范的地方,比如daemon進程一般都會以字母d結尾,還有就是啟動很不方便,要啟動兩次腳本,哈哈,當然了,這只是自己先來無事玩玩了,要真設計一個完成的系統估計會考慮很多很多的東西,加油吧,繼續前進。
這里是github地址:blog-observer,自己試用的時候記得修改郵箱名稱和密碼。
如果誰也想第一時間獲取到最新的阮老師的文章可以給我發郵件,我把你們的郵件地添加到郵件list中,但不保證會發送到,有時候關了電腦程序就停止了~
