Bit.ly URL shorten service

Scalaレッスンの番組の途中ですが、BitlyのAPIクライアント for PHPを作りました。とりあえず、Links APIだけの実装。

当初の予定では、zendframework / Component_ZendHttpか、zendframework / ZendRestを使ってみようと思っていたが、結論からいうと、Bit.ly APIに対しては、これらのコンポーネントを使用できない。

Zend framework component

該当部分は割愛するけれど、Zend\Http\Client::send()メソッドがhttp_build_query()を使ってquery stringを組み立てているため、同一キーが配列の場合、key[]=value1&key[]=value2というクエリーが生成される。これに対応していないサーバー、あるいは実装の場合、当然のことながら、必要な値が届いていないことになる。Bit.lyのAPIも対応していないようで、[]の場合も、urlencodeした[]の場合も、500エラーとなってしまい、うまくいかなかった。

RFC 1738, 3986

RFCをざっと見てみたところ、同一キーに対する複数値の取り扱いについては、どうも言及されていないようだった(あるいは見落としているのかもしれない)。そういえば、PHP以外では、この形式を見た記憶がないが、他の言語では、どうやって取り扱っているのだろうか。

標準的なやり方でないのであれば、代替手段を用意しておかなければいけないが、zendコンポーネントのコードが長過ぎたので(200行もあるメソッドなんてorverrideできないよ!)、途中で読むのをやめて使用するのを諦めた。どうもversion 1の悪いところを引きずっている臭いがした。

とりあえず、zendのコンポーネントが使えない事が分かったので、必要最低限のrest clientを実装してBit.ly APIラッパーを作った。

urlencode

Bit.ly APIに渡すリクエストパラメータの中にはURLが入る。このURLはURL encodeしておく必要がある。

どちらでもいいのだけど、PHPでは、urlencode()するかhttp_build_query()すればいい。ただし、前述のように、key[]=value形式を使用できない場合は、複数値のそれぞれの値に対して、http_build_query()を実行するようにしなければいけない。

RestClient.php
<?php
protected function buildHttpQuery(array $query)
{
$qs = array();
foreach ($query as $key => $value) {
if (is_array($value)) {
foreach ($value as $v) {
if (is_array($v)) {
throw new \InvalidArgumentException('Invalid query string.');
}
$qs[] = http_build_query(array($key => $v));
}
} else {
$qs[] = http_build_query(array($key => $value));
}
}
return $qs;
}
protected function queryString(array $query, $prependQuery = true)
{
$queryString = implode('&', $this->buildHttpQuery($query));
if ($prependQuery) {
return '?' . $queryString;
}
return $queryString;
}

Reference