Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

PHP5 で Bloglines Web Services をあれこれしてみる

Bloglines が Web Services を提供しはじめた(Bloglines API Documentation)ということで、あーそりゃ素晴らしいですな、ってんでさっそくごにょってみたいなぁと思ったけど、面倒になって放棄しましたよ、という記録。

miyagawa さんが作成された Perl モジュール WebService::Bloglines をじろじろ眺めつつ、Bloglines Web Services にアクセスするクラスを PHP5 で書いてみようと思った。とりあえず REST API 叩いてデータとってくるところまでは書いたけど、それをいい感じに加工するのが面倒くさ過ぎて、というか僕にはもうこれ以上は無理です…勘弁してください…ぎぎぎ…という感じで、中途で放棄。以下、コード。

Bloglines.php

<?php

require_once 'HTTP/Request.php';

class Bloglines
{

    private $version = '0.1';
    private $username;
    private $password;
    private $request;

    public function __construct ($username, $password = null)
    {
        $this->username = $username;
        $this->password = $password;

        $request = new HTTP_Request();
        $request->setMethod(HTTP_REQUEST_METHOD_GET);
        $request->addHeader('User-Agent', "Bloglines Client $this->version");
        $this->request = $request;
    }

    public function notify ()
    {
        $params = array('user' => $this->username, 'ver' => 1);
        $response = $this->getResponse('http://rpc.bloglines.com/update', $params);
        if (preg_match('/\|([\-\d]+)|(.*)|/', $response['body'], $matches)) {
            $unread = $matches[1];
            $url    = $matches[2];
            if ($matches[1] == -1) {
                $this->throwException("Bad username: $this->username");
            }
        } else {
            $this->throwException("Bad response: {$response['body']}");
        }
        return $unread;
    }

    public function listSubs ()
    {
        $response = $this->getResponse('http://rpc.bloglines.com/listsubs');
        if ($response['code'] == 401) {
            $this->throwException("Request failed: {$response['code']}");
        }
        $subscriptions = @simplexml_load_string($response['body']);
        return $subscriptions;
    }

    public function getItems ($subid, $mark_read = 1, $time = null)
    {
        $params = array('s' => $subid, 'n' => $mark_read, 'd' => $time);
        $response = $this->getResponse('http://rpc.bloglines.com/getitems', $params);
        if ($response['code'] != 200) {
            $this->throwException("Request failed: {$response['code']}");
        }
        $items = @simplexml_load_string($response['body']);
        return $items;
    }

    private function getResponse ($uri, $params = null)
    {
        $this->request->setURL($uri);
        if (is_array($params)) {
            foreach ($params as $key => $value) {
                $this->request->addQueryString($key, $value);
            }
        }
        $this->request->setBasicAuth($this->username, $this->password);
        $this->request->sendRequest();
        $response = array(
          'code' => $this->request->getResponseCode(),
          'body' => $this->request->getResponseBody()
        );
        return $response;
    }

    private function throwException ($message)
    {
        throw new BloglinesException($message);
    }

}

class BloglinesException extends exception
{
}

?>

まぁなんにもないよりはマシ…なのか? 的アレ。XML なデータとってきて、それを simplexml_load_string() でオブジェクトにして返すだけ。使いにくいことこの上ないという…。これだけじゃほぼ意味ないんで、subscriptions の階層や feed の RSS をあれこれごにょったりしないとならないなぁとは思いますが、まぁ思うだけでおしまいです!

とりあえず、未読記事を取得してずらずら並べるってな単純なことぐらいなら、上記のクラス程度でもまぁそれなりに簡単にできたりできなかったりします。以下に、実際にやってみた例を示します(HTML として保存しただけのものなので、更新はされません。こんな感じですよ、という表示例です)。

具体的には、以下の感じの、ごくテケトウなスクリプトで(例外を捕まえたりはしません!)。

<?php

require_once 'lib/Bloglines.php';

$username = 'メールアドレス';
$password = 'パスワード';

$bloglines = new Bloglines($username, $password);
$count = $bloglines->notify();
$subs = $bloglines->listSubs();

?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="bloglines.css" type="text/css" />
<title>My Bloglines</title>
</head>
<body>
<div id="header">
<h1>My Bloglines</h1>
<p>未読記事: <?php echo $count; ?> 件</p>
</div>
<?php

// outline 要素を、フォルダとかフィードとか無視して片っ端からぶんどる
foreach ($subs->xpath('//outline') as $outline) {

  // 未読記事を取得
  if ((int)$outline['BloglinesUnread'] > 0) {
    $rss = $bloglines->getItems($outline['BloglinesSubId'], 1);
    foreach ($rss as $channel) {
      echo "<div>";
      echo "<h2><a href=\"$channel->link\">$channel->title</a></h2>";
      echo "<dl>\n";
      foreach ($channel->item as $item) {
        echo "<dt><a href=\"$item->link\">$item->title</a></dt>\n";
        echo "<dd>$item->pubDate</dd>\n";
        echo "<dd class=\"description\">$item->description</dd>\n";
      }
      echo "</dl>\n";
      echo "</div>\n";
    }
  }
}
?>
<address>
My Bloglines: Powerd by <a href="http://www.bloglines.com/services/api/">Bloglines Web Services</a>
</address>
</body>
</html>

ていうか、Bloglines をほとんど使っていないというのは内緒の方向で…。