cacheから取り出したデータについては今のところ100%正しい結果を得られるけど、HTTPでとって来たデータだと2回に1回失敗。
Atomの<link rel="next" type="~" href="http://~" />から次のURLを抜き出す処理をしてるんだけど、どうも2回に1回は失敗する。シリアライズして保存しているcacheデータを使った場合は失敗しない。
cacheにはオブジェクトをシリアライズして保存しているので、cacheデータを使う時にはZend_Feed内で行っているDOM処理が無い。一方、HTTPでとって来た場合、毎回DOM処理が入る。この辺が原因なのかな?
PHPのDOMDocumentを使う場合、後処理とかしないと駄目なのかな。Zend_Feedの後処理が必要なのかな?
追記:
とりあえず、cacheに入れてからそれを取り出して使うようにしました。
DOMオブジェクトであるべき変数が、文字列のままになっているようです。なんだろ。処理の呼び出し順序とか?
きっと、DOMDocumentとかZend_Feedとかじゃなくて、自分のコードの方に問題があるんでしょう。
一応、問題になってるソースコード貼っときます。
<?php if (!defined("HATENA_BOOKMARK_ATOMFEED_SLEEP_TIME")) { define("HATENA_BOOKMARK_ATOMFEED_SLEEP_TIME", 30); } require_once "Zend/Feed.php"; require_once "Zend/Cache.php"; require_once "HTTP/Request.php"; class Hatena_Bookmark_Atomfeed { private $username; private $cache; private $time; private $url; private $http; private $feed; private $isVerbose; public function __construct($username, $cacheConfig, $useragent, $time = 0, $isVerbose = false) { $this->isVerbose = $isVerbose; $this->username = $this->_filterUsername($username); $this->cache = Zend_Cache::factory("Core", "Sqlite", array( "lifeTime" => 86400, "automaticSerialization" => true ), array( "cacheDBCompletePath" => $cacheConfig["path"] )); $this->time = intval($time); $this->url = "http://b.hatena.ne.jp/" . $this->username . "/atomfeed"; $this->_setupHttp($useragent); $this->feed = $this->_import($this->url); } private function _filterUsername($username) { return preg_replace("/[^0-9a-zA-Z]/", "", $username); } private function _filterId($id) { return preg_replace("/[^\d]/", "", $id); } private function _setupHttp($useragent) { $this->http = new HTTP_Request("", array( "timeout" => 60, "allowRedirect" => true, "maxRedirect" => 3, )); $this->http->addHeader("User-Agent", $useragent); } public function fetch() { // test feed initialize if (is_null($this->feed)) { return null; } // test next entry or feed if (!$this->feed->valid()) { $nextUrl = $this->feed->link("next"); if ($nextUrl == null) { if ($this->isVerbose) { echo "no next\n"; } return null; } $this->feed = $this->_import($nextUrl); if ($this->feed == null) { if ($this->isVerbose) { echo "import-error: $nextUrl\n"; } return null; } } $entry = $this->feed->current(); // test sync diff if ($this->time > strtotime($entry->issued())) { return null; } // go next entry $this->feed->next(); // build entry data return $this->_entryArray($entry); } private function _entryArray($entry) { return array( "atom_id" => $entry->id(), "title" => $entry->title(), "url" => $entry->link("related"), "summary" => $entry->summary(), "tags" => $this->_getTags($entry), "timestamp" => strtotime($entry->issued()), ); } private function _getTags($entry) { $tags = ""; $subjects = $entry->{"dc:subject"}; if (is_array($subjects) and count($subjects) > 0) { $tags = '[' . implode("][", array_map(create_function('$e', 'return $e->__toString();'), $subjects)) . ']'; } else { $tags = "[" . $subjects->__toString() . "]"; } return $tags; } private function _import($url) { if (($feed = $this->cache->get($this->_getCacheId($url)))) { if ($this->isVerbose) { echo "cache: $url\n"; } return $feed; } try { $this->feed = null; $this->http->setURL($url); if (PEAR::isError($this->http->sendRequest())) { if ($this->isVerbose) { echo "request-error: $url\n"; } return null; } else { if ($this->isVerbose) { echo "load: $url\n"; } } $feed = Zend_Feed::importString($this->http->getResponseBody()); $this->cache->save($feed, $this->_getCacheId($url)); if ($this->isVerbose) { echo "wait..."; } sleep(HATENA_BOOKMARK_ATOMFEED_SLEEP_TIME); if ($this->isVerbose) { echo "start\n"; } return $this->cache->get($this->_getCacheId($url)); } catch (Zend_Feed_Exception $e) { if ($this->isVerbose) { echo "import-error: $url\n"; } return null; } } private function _getCacheId($seed) { return md5($seed); } } ?>

