edo1z blog

プログラミングなどに関するブログです

CakePHP2 - Pingサーバを構築してブログの更新通知を受け取る

XML-RPCという仕組みが使われていて、大体weblogUpdates.extendedPingか、weblogUpdates.pingというメソッド名が使われる。IXR_Library.phpというライブラリがあるのでこれを使って作る。飛んでくる情報の最小単位はブログ名とブログURLなので、ブログURLからRSSのURLを取得して、RSSから最新記事のURLとタイトルを取得する。WordPressがweblogUpdates.extendedPingで、アメブロとライブドアが、weblogUpdates.pingだった。wordpressは、array(ブログ名、ブログURL、RSS_URL)できた。RSS URLを取得するのにphpQuery使おうと思ったけど、どうもライブドアだとエラーになるから使うのやめた。あとアメブロのRSSは、新規投稿が1分後くらいにしか反映されないから、CRONで5分後に再チェックするようにした。

<?php
App::uses('AppController', 'Controller');
App::import('Vendor', 'xmlrpc');
//App::import('Vendor', 'phpquery/phpQuery/phpQuery');

class PingController extends AppController
{
    public $uses = array('Site');

    public function beforeFilter()
    {
        parent::beforeFilter();
        $this->Components->disable('Security');
        $this->Auth->allow(array('index'));
        Configure::write('debug', 0);
        $this->autoRender = false;
    }

    public function index()
    {
        $callbacks = array();
        $callbacks['weblogUpdates.ping'] = array(&amp;$this, '_updates');
        $callbacks['weblogUpdates.extendedPing'] = array(&amp;$this, '_updates_extended');
        $callbacks['weblogUpdates.pbping'] = array(&amp;$this, '_pbping');
        $this->server = new IXR_Server($callbacks);
    }

    public function _updates($data)
    {
        $this->log('weblogUpdates.ping', 'debug');
        if(empty($data[1])){
            $this->log('Fail to updates.', 'debug');
            $this->log($data, 'debug');
            return false;
        }
        if($this->_get_new_post($data[1])){
            return true;
        }
        return false;
    }

    public function _updates_extended($data)
    {
        $this->log('weblogUpdates.extendedPing', 'debug');
        if(empty($data[1]) || empty($data[2])){
            $this->log('Fail to updates_extended.', 'debug');
            $this->log($data, 'debug');
            return false;
        }
        if($this->_get_new_post($data[1], $data[2])){
            return true;
        }
        return false;
    }

    public function _pbping($data)
    {
        $this->log('weblogUpdates.pbping', 'debug');
        $this->log($data);
    }

    private function _get_new_post($blog_url, $rss_url = null)
    {
        if(!$site = $this->Site->findByUrlForPing($blog_url)) return false;
        if(!$rss_url){
            if(!$rss_url = $this->_get_rss_url($blog_url)) return false;
        }
        if(!$rss = $this->_get_rss($rss_url)) return false;
        if(!$this->Site->saveNewPost($rss['url'], $rss['title'], $site['Site']['id'])){
            $this->log('Fail to save new post', 'debug');
            return false;
        }
        return true;
    }

    private function _get_rss_url($blog_url)
    {
        $pattern = '/type="application\/rss\+xml".+?href="(.+?)"/s';
        $html = file_get_contents($blog_url);
        if(!preg_match($pattern, $html, $match)){
            $this->log('Not Match. '.$blog_url, 'debug');
            return null;
        }
        return $match[1];
    }

    //private function _get_rss_url($blog_url)
    //{
    //    try{
    //        $doc = phpQuery::newDocumentFile($blog_url);
    //        return pq($doc)->find('link[type=application/rss+xml]:first')->attr('href');
    //    }catch(Exception $e){
    //        $this->log('Fail to get rss url: '.$e->getCode().'|'.$e->getMessage(), 'debug');
    //        return null;
    //    }
    //}

    private function _get_rss($rss_url)
    {
        try{
            $rss = Xml::build($rss_url);
            if(!empty($rss->channel->item[0])){
                $item = $rss->channel->item[0];
            }elseif(!empty($rss->item[0])){
                $item = $rss->item[0];
            }
            return array(
                'url' => (string)$item->link,
                'title' => (string)$item->title
            );
        }catch(Exception $e){
            $this->log('Fail to get rss: '.$e->getCode().'|'.$e->getMessage(), 'debug');
            return null;
        }
    }

}

参考: 更新Pingの送信 Pingを送信する! Google ブログ検索の更新通知 API について CakePHP + 更新Ping送信で更新情報サービスを利用する方法 IXRライブラリの使い方 utils/Model/Behavior/PingbackableBehavior.php How-to-create-an-XML-RPC-server-with-CakePHP.rst CakePHP-Wordpress-Datasource/Vendor/IXR_Library.php [42-3] link rel="alternate" で他言語サイトやモバイル版へ導こう