CakePHPのShellでtwitterのログを保存する

ふと思い立って書いてみたので適当にメモしておきます。
CakePHPコアライブラリの使い方の勉強を兼ねてやりました。

table

適当にテーブルを作ります。

+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| id         | int(10) unsigned    | NO   | PRI | NULL    | auto_increment |
| status_id  | bigint(20) unsigned | NO   |     | NULL    |                |
| text       | text                | NO   |     | NULL    |                |
| created_at | datetime            | NO   |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+

model

テーブルから最新のstatus_idを取得するメソッドとAPIからのレスポンス配列を整形してsaveAllするメソッドを定義しています。

<?php
class TwitterLog extends AppModel
{
    var $name = 'TwitterLog';

    function getSinceId()
    {
        $this->order = 'TwitterLog.id DESC';
        $latestStatus = $this->find();
        if ($latestStatus) {
            return $latestStatus['TwitterLog']['status_id'];
        }
        return false;
    }

    function saveStatus($statuses)
    {
        foreach ($statuses as $status) {
            $dateTime =  date('Y-m-d H:i:s', strtotime($status['created_at']));
            $data[] = array(
                'status_id'  => $status['id'] ,
                'text'       => $status['text'],
                'created_at' => $dateTime
            );
        }
        return $this->saveAll($data);
    }
}

shell

XmlとHttpSocketを使用します。最初にinit()を実行することでこれまでのつぶやきを全て(APIの制限内で)保存します。

<?php
App::import('Core', array('Xml', 'HttpSocket'));

class TwitterLogShell extends Shell
{
    var $uses = array('TwitterLog');

    const API_URL = 'http://twitter.com/statuses/user_timeline.xml';
    const USER = 'username';
    const PASS = 'password';

    function startup()
    {
        $this->sock =& new HttpSocket();
        $this->request = array(
            'auth' => array(
                'user' => self::USER,
                'pass' => self::PASS
            )
        );
    }

    function main()
    {
        while (true) {
            $query = array(
                'since_id' => $this->TwitterLog->getSinceId(),
                'count'    => 200
            );
            $ret = $this->_getStatus($query);
            if (empty($ret['Statuses']['Status'])) break;

            if (empty($ret['Statuses']['Status'][0])) {
                $statuses[] = $ret['Statuses']['Status'];
            } else {
                $statuses = array_reverse($ret['Statuses']['Status']);
            }
            $this->TwitterLog->saveStatus($statuses);
        }
    }

    function init()
    {
        $query = array('count' => 1);
        $ret = $this->_getStatus($query);
        $statusCount = $ret['Statuses']['Status']['User']['statuses_count'];
        $page = ceil($statusCount/20);

        while ($page > 0) {
            $query = array('page' => $page);
            $ret = $this->_getStatus($query);
            $statuses = array_reverse($ret['Statuses']['Status']);
            $this->TwitterLog->saveStatus($statuses);
            $page--;
        }
    }

    function _getStatus($query)
    {
        $res = $this->sock->get(self::API_URL, $query, $this->request);
        $xml = new Xml($res);
        $array = $xml->toArray();

        $xml->__killParent();
        $xml->__destruct();
        $xml = null;
        unset($xml);

        return $array;
    }
}

あとはcrontabで下記の様なコマンドを適当なタイミングで実行すれば自分のつぶやきログがDBに保存されていきます。

CAKE_DIR/console/cake twitter_log -app APP_DIR