ブックマークの流れはこんな感じになってる。
- MovableTypeでエントリを投稿
- エントリをはてなブックマークにPOST(Hatena Boomarker)
- タイトルを自動的に取得する(はてなブックマークのクローラー)
- タイトルの設定が完了
- GET EditURIで登録済みのタイトルを取得(Hatena Boomarker)
- 登録済みタイトルがエントリタイトルと違っていたらPUT EditURIで編集(Hatena Boomarker)
- ブックマーク完了
MobavleType経由の場合、再構築処理のタイミングの関係で、3のクローラーが来るタイミングではまだエントリページが作成されていないことがある。その場合、ブックマークはとりあえずURLをタイトルとして登録される。
仮にURLがタイトルとなってしまっても、Hatena Boomarkerがそれを正常に戻してくれる。Hatena Boomarkerでタイトルを編集できない場合、タイトルはURLのまま。
再構築処理が軽い場合は、エントリ作成がはてなのクローラーに間に合うので何の問題もないのだけど、重い場合はHatena Boomarkerの編集動作が必要。
で、正常にブックマークできないことがある。
考えてみれば当たり前の話だったなぁ。
状況からすれば全て正しい動きですね。
うーむ、そうか。
オマケ
PEAR::HTTP_Clientを使ってメソッドの動作をチェックしてみたらこうなった。
POST PostURI
リクエスト
require_once('HTTP/Client.php');
$username = 'konaze';
$password = 'pass';
$wsse = getWSSE($username, $password);
$title = 'http://www.yahoo.co.jp/';
$rowPostData = <<<EOF
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#">
<title>dummy</title>
<link rel="related" type="text/html" href="{$title}" />
<summary type="text/plain"></summary>
</entry>
EOF;
$client = new HTTP_Client();
$client->post(
'http://b.hatena.ne.jp/atom/post',
$rowPostData,
true,
array(),
array(
'Accept' => 'application/x.atom+xml, application/xml, text/xml, */*',
'Authorization' => 'WSSE profile="UsernameToken"',
'X-WSSE' => $wsse,
'Content-Type', 'application/x.atom+xml'
)
);
var_dump($client->currentResponse());
function getWSSE($username, $password) {
$nowtime = date('Y-m-d\TH:i:s\Z');
$nonce = pack('H*', sha1(md5(time())));
$digest = base64_encode(pack('H*', sha1($nonce . $nowtime . $password)));
return 'UsernameToken Username="' . $username.'", PasswordDigest="'. $digest .'", Nonce="'. base64_encode($nonce) .', Created="'.$nowtime.'"';
}
レスポンス
array
'url' => string 'http://b.hatena.ne.jp/atom/post' (length=31)
'code' => int 201
'headers' =>
array
'date' => string 'Fri, 12 Mar 2010 04:40:11 GMT' (length=29)
'server' => string 'Apache/2.2.3 (CentOS)' (length=21)
'location' => string 'atom/edit/18' (length=12)
'x-framework' => string 'Ridge/0.05' (length=10)
'x-runtime' => string '23688ms' (length=7)
'content-type' => string 'application/x.atom+xml; charset=utf-8' (length=37)
'vary' => string 'Accept-Encoding' (length=15)
'content-encoding' => string 'gzip' (length=4)
'content-length' => string '347' (length=3)
'connection' => string 'close' (length=5)
'body' => string '
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#">
<title>Yahoo! JAPAN</title>
<link rel="related" type="text/html" href="http://www.yahoo.co.jp/" />
<link rel="alternate" type="text/html" href="konaze/#18" />
<link rel="service.edit" type="application/x.atom+xml" href="atom/edit/18" title="Yahoo! JAPAN" />
<author>
<name>konaze</name>
</author>
<generator url="" version="0.1">Hatena::Bookmark</generator>
<issued></issued>
<id>tag:hatena.ne.jp,2005:bookma'... (length=579)
GET EditURI
リクエスト
require_once('HTTP/Client.php');
$username = 'user';
$password = 'pass';
$wsse = getWSSE($username, $password);
$client = new HTTP_Client();
$client->get(
'http://b.hatena.ne.jp/atom/edit/18',
'',
true,
array(
'Accept' => 'application/x.atom+xml, application/xml, text/xml, */*',
'Authorization' => 'WSSE profile="UsernameToken"',
'X-WSSE' => $wsse,
'Content-Type', 'application/x.atom+xml'
)
);
var_dump($client->currentResponse());
function getWSSE($username, $password) {
$nowtime = date('Y-m-d\TH:i:s\Z');
$nonce = pack('H*', sha1(md5(time())));
$digest = base64_encode(pack('H*', sha1($nonce . $nowtime . $password)));
return 'UsernameToken Username="' . $username.'", PasswordDigest="'. $digest .'", Nonce="'. base64_encode($nonce) .', Created="'.$nowtime.'"';
}
レスポンス
array
'url' => string 'http://b.hatena.ne.jp/atom/edit/18' (length=34)
'code' => int 200
'headers' =>
array
'date' => string 'Fri, 12 Mar 2010 05:08:27 GMT' (length=29)
'server' => string 'Apache/2.2.3 (CentOS)' (length=21)
'x-framework' => string 'Ridge/0.05' (length=10)
'x-runtime' => string '23ms' (length=4)
'content-type' => string 'application/x.atom+xml; charset=utf-8' (length=37)
'vary' => string 'Accept-Encoding' (length=15)
'content-encoding' => string 'gzip' (length=4)
'content-length' => string '389' (length=3)
'connection' => string 'close' (length=5)
'body' => string '
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<title>Yahoo! JAPAN</title>
<link rel="related" type="text/html" href="http://www.yahoo.co.jp/" />
<link rel="alternate" type="text/html" href="konaze/20100312#18" />
<link rel="service.edit" type="application/x.atom+xml" href="atom/edit/18" title="Yahoo! JAPAN" />
<author>
<name>konaze</name>
</author>
<generator url="" version="0.1">Hatena::Bookmark</generator>
'... (length=650)
POST PostURIのレスポンスを見る限り、XML::Atom::Client->createEntry()は正しく、EditURIを返しているように見える。
ということは...?
何らかの事情で、XML::Atom::Client->getEntry()がEditURIを解決できていないということなんだろうなぁ。
って、これはあれじゃん、前言ってた話題と同じじゃんね。
Ogawa::Buzz: はてなブックマークAtomAPIのPostURIのレスポンスがおかしい
XML::Atomのソースも見てみたけど別になにも難しいことはしていなくて、createEntry()では単純に返ってきたAtomの中のLocationをEditURIとして返しているだけ、getEntry()では与えられたURIにGETリクエストしてるだけだし、やっぱ結局はてなのせいか。
ただ今回違うのは...単純に追加しようとすると怒られるんだよね。なんだこれ。
Operation "ne": no method found, left argument in overloaded package XML::LibXML::Error, right argument has no overloaded magic
オブジェクトに文字列を無理に追加してもダメってことなのか。そりゃそうだろうけども、どうしたらいいかまでは解らない。
あーもうなんか他の方法探るしかないかなー...