TwitterライブラリではなくcURLでStreaming APIを呼び出してWebページに随時表示

TwitterのAPIにStreamingというものがあります。Twitterのサーバとつなぎっぱなしにして新しいツイートを随時通知してもらうものです。対応しているライブラリもあるのですが、自作派の自分はライブラリを使用しないで作ってみました。ソースはGiHubに置いておきます。
https://github.com/tezuuuuuka/tw-stream-test

で、先にライブラリの話をしておきます。現状、PHPでStreaming APIを呼ぶ際によく使われているのは[Phirehose](https://github.com/fennb/phirehose “Phirehose”)というライブラリのようです。使ったことはないですが、みんな使っているんで使いやすいんでしょう。ちゃんとしたものを作りたいなら、こういうライブラリを使ったほうがいいですね。

ちなみに、PHPでTwitter APIというと[twitteroauth](https://github.com/abraham/twitteroauth “twitteroauth”)が古くからありますが、残念ながらこちらはStreaming APIには対応していません。でも、認証だけ行うってのもできるようなので、アクセストークンとシークレットだけ取得して、ストリームの部分は自分で作る、ってのも出来そうです。

というわけで、本題に入りますが、そもそもの大枠はこちらの方のコードを参考にさせてもらいました。
PHPでTwitterのOAuthを試してみる – yk5656 diary.
認証からAPIの呼び出しまでは必要最低限のものが詰まっていて非常に参考になりました。ただ、アプリ全体の設定や共通するパラメータなどが重複して定義されていたりしたので、その辺を整理させてもらいました。

話は変わりますが、Streaming APIはつなぎっぱなしにするものです。でもWebで使われているHTTPという通信方法は原則として「くれ」って言ったら「どうぞ」って返してくれて終わり、という短い会話を繰り返すように作られています。そのためWebでStreaming的なつなぎっぱなしのアプリを作る場合は工夫が必要になります。

そこで今回使ったのは「どうぞ、あ、これも、これもだ、これもあげる」的な、なかなか終わらない会話のようなものにしました。この部分は、ブラウザの種類が違ったり、通信途中にプロキシなどが挟まっている場合は動きが変わる可能性があるので注意です。それにサーバ側が無理矢理に通信を終わらせないようにしているだけなので、悪影響は他にもあるかもしれません。実用的にはJavaScriptを使うほうがいいでしょう。

それと、本題と関係なく詰まったのが、Streaming APIとの通信です。PHPで外部Webサービスを呼び出す場合、ストリームを開いてfile_get_contents()するのが簡単ですが、この方法ではHTTP通信が終了するまでPHPスクリプトの処理に戻ってきません。Streaming APIはエラーがない限り終了しないので、この方法ではAPIから受信した内容を随時表示するような動作は実装できません。

そこで出てくるのがcURL。cURLならデータ読み込みごとにコールバック関数を呼び出させることができます。PHP自身のストリーム機能にもフィルタがありますが、これはプログラムへ読み込む際に適用されるので、期待した通りには動かないかも?期待通りに動いたとしても、読み込んだデータはどこかに溜め込んでいるわけで、いつか溢れてダメになるんじゃないかな。ちょっと気にはなるから、今度やってみるかも。

で、Streaming APIを呼び出す部分をcURLのコールバック関数にすればいいってのを気づかせてくれたのがこのページ。
[PHP] ライブラリに頼らないTwitterAPI入門 – Qiita.
自分のはコールバックをクラスにまとめてオブジェクトのメソッドを呼び出すようにしています。Webページとして表示するため回数制限をしたかったからです。回数をグローバル関数に保存してもいいけど、クラスにまとめた方がカッコイイと思っただけです。よほど複雑なプログラムじゃなければ、実用的にはどっちでもいいんじゃないかな。

動くものを公開しようかと思ったけど、Streaming APIには呼び出し制限があって、アプリごと、IPごとに回数が決まっているんだそうです。何回かは分かりませんが、自分は10回も呼び出さないうちにHTTP 420エラーになって作業が止まりました。なので各自、自分のサーバでやりましょう。無制限にユーザを集めてサーバでStreamin APIを呼び出すような使い方は合っていないですね。モバイルアプリ向けかな?

というわけで、とりあえずソースと経緯を公開しておきました。気が向いたらソース解説なんかもするかも?しないだろうな、たぶん。