phpでtwitterbotを作ってみたい(準備)の続きです。環境構築まではできたはずなので、実際に作成してみましょう。
APIを知る
twitterへのアクセスは、用意されたAPIを通じて行います。APIがわからない人に説明しますと、twitter側が提供する「twitterにアクセスするために手段」です。つまり、その手段を知ることによって、自由自在なtwitter操作ができるようになるわけです。
日本語化されたAPI仕様書
本来は英語なのですが、すばらしいことに日本語訳されている方がいらっしゃいます。私が見たところ、訳注もすばらしい。英語が苦手な私にとって、本当にありがたい話です。感謝しながら閲覧させてもらいましょう。
API仕様書を読む
基本的に、必要なときに引けば良いわけですが、読み方くらいは理解しておいたほうが良いでしょう。
twitte APIは、「メソッド」「パラメータ」から成ります。良くあるプログラミング言語で言うと、メソッドが関数名で、パラメータが引数というイメージです(ライブラリを用いれば、APIの実態がどうなっているか気にする必要がありません)。
実際にやってみる
とりあえずコードを示してみます。
<?php // ライブラリ(同じフォルダにおいてください) require_once("twitteroauth.php"); // 前記事で取得したはずのkeyをそれぞれ設定してください(書き変えるのは右側です) // OAuthアプリ登録で取得したConsumer keyを設定 define("CONSUMER_KEY", "xxxxxxxxxx"); // OAuthアプリ登録で取得したConsumer secretを設定 define("CONSUMER_SECRET", "xxxxxxxxxx"); // OAuthトークン取得プログラムで取得したoauth_tokenを設定 define("OAUTH_TOKEN", "xxxxxxxxxx"); // OAuthトークン取得プログラムで取得したoauth_token_secretを設定 define("OAUTH_TOKEN_SECRET", "xxxxxxxxxx"); // ライブラリを使用する $twitter = new TwitterOAuth( CONSUMER_KEY, CONSUMER_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET ); // メソッドの設定 $method = "statuses/mentions"; // パラメータの設定(各パラメータの意味は仕様書参照) $parameters = array("count" => 200, "since_id" => "28884095177"); // APIでtwitterにアクセス // $twitter->get(), $twitter->post()がライブラリで用意されていますが、 // どちらを用いれば良いかは仕様書に書かれていますので参照してください。 // ちなみに、statuses/mentionsはGETを使用しろと書いてあります。 $mentions = $twitter->get($method, $parameters); // httpレスポンスコードは、$twitterから調べることができるようです。 // 200(正常)以外なら、処理を終了します。 if($twitter->http_info['http_code'] != 200) return; // 詳しいレスポンスはvar_dump()してください。 foreach($mentions as $mention){ // mentionをくれたユーザをフォローしてみます。 // friendships/createはフォローをするためのメソッドです。 $follow_method = "friendships/create"; $follow_parameters = array("user_id" => $mention->user->id_str); // フォローしてみます。 // friendships/createはPOSTを用いると仕様書に書いてあります。 $follow_response = $twitter->post($follow_method, $follow_parameters); }
サンプルプログラムというにはお粗末ですが、このようになっています。
レスポンスに関しては、私も試行錯誤でした。結果から言うと、$twitter->get()と$twitter->post()のレスポンスをvar_dump()した結果を見ると一発です。
[warning]phpでは変数の明示的な型指定ができないので、idなどの値がオーバーフローする可能性があります。そのため、->idではなく、->id_strを利用したほうがよさそうです。おあつらえ向きに用意してあるところが、ちょっと感動ですね。[/warning]
ライブラリ内部ではどうなってるか
APIを利用した結果の形式を指定できます。xml, json, rss, atomが利用できると仕様書に書いてあります。しかし、ライブラリを用いる場合は気にする必要がありません。内部的にはjsonを自動的に用いています。phpにはjson_decode()があるので、内部でパース(解析)して、先ほどのソースコードのようにアロー演算子(->)でアクセスできる形式で用意してくれます。
実行方法
では、せっかく作ったので実行してみましょう。
shellを立ち上げて、php [filename].phpと実行してみましょう。正常に動作すればおkです。ウェブブラウザで結果を確かめるか、phpスクリプトに正常に終了したときはログを吐き出させるようにでもしてください。
次の記事
phpでtwitterbotを作ってみた(設置)xrea+に設置した例です。
レスポンス
レスポンスのデータ形式がわからないと利用のしようがないので、私が今回用いたものをvar_dump()した結果を単に貼り付けておきます。加工していないので、恥ずかしいデータが入っているかもしれませんが……。
direct_messages
array(2) { [0]=> object(stdClass)#5 (10) { ["sender_screen_name"]=> string(7) "blanite" ["recipient_screen_name"]=> string(10) "koedamebot" ["recipient_id"]=> int(206206937) ["created_at"]=> string(30) "Sat Oct 23 13:35:56 +0000 2010" ["recipient"]=> object(stdClass)#6 (33) { ["geo_enabled"]=> bool(false) ["time_zone"]=> NULL ["description"]=> string(0) "" ["profile_sidebar_fill_color"]=> string(6) "DDEEF6" ["followers_count"]=> int(1) ["verified"]=> bool(false) ["notifications"]=> bool(false) ["follow_request_sent"]=> bool(false) ["profile_use_background_image"]=> bool(true) ["profile_sidebar_border_color"]=> string(6) "C0DEED" ["url"]=> NULL ["profile_background_image_url"]=> string(59) "http://s.twimg.com/a/1287523226/images/themes/theme1/bg.png" ["lang"]=> string(2) "ja" ["created_at"]=> string(30) "Fri Oct 22 13:54:02 +0000 2010" ["profile_background_color"]=> string(6) "C0DEED" ["location"]=> string(0) "" ["listed_count"]=> int(0) ["profile_background_tile"]=> bool(false) ["friends_count"]=> int(1) ["protected"]=> bool(false) ["profile_image_url"]=> string(67) "http://s.twimg.com/a/1287523226/images/default_profile_6_normal.png" ["statuses_count"]=> int(3) ["profile_text_color"]=> string(6) "333333" ["name"]=> string(7) "koedame" ["show_all_inline_media"]=> bool(false) ["following"]=> bool(true) ["favourites_count"]=> int(0) ["screen_name"]=> string(10) "koedamebot" ["id"]=> int(206206937) ["id_str"]=> string(9) "206206937" ["contributors_enabled"]=> bool(false) ["utc_offset"]=> NULL ["profile_link_color"]=> string(6) "0084B4" } ["sender"]=> object(stdClass)#7 (33) { ["geo_enabled"]=> bool(false) ["time_zone"]=> string(5) "Osaka" ["description"]=> string(314) "暇つぶしに忙しい、どうしもない高専生。言語→日本語/C/C#/php/Java/xhtml/css/Q3Scriptなど。ポインタを愛する英語嫌いなGC信望者。他言語→C++/Ruby/JS/AS/Python、趣味→アニソン/画像収集癖/ショート*2/mixi/wp弄り、ゲーム→ポケモンBW/Civ4/FPS(ET)" ["profile_sidebar_fill_color"]=> string(6) "ffffff" ["followers_count"]=> int(151) ["verified"]=> bool(false) ["notifications"]=> bool(false) ["follow_request_sent"]=> bool(false) ["profile_use_background_image"]=> bool(false) ["profile_sidebar_border_color"]=> string(6) "ffffff" ["url"]=> string(20) "https://jikkenjo.net/" ["profile_background_image_url"]=> string(59) "http://s.twimg.com/a/1287010001/images/themes/theme1/bg.png" ["lang"]=> string(2) "ja" ["created_at"]=> string(30) "Tue Jul 28 16:06:45 +0000 2009" ["profile_background_color"]=> string(6) "ffffff" ["location"]=> string(17) "Shunan, Yamaguchi" ["listed_count"]=> int(27) ["profile_background_tile"]=> bool(false) ["friends_count"]=> int(108) ["protected"]=> bool(false) ["profile_image_url"]=> string(88) "http://a3.twimg.com/profile_images/1093067523/charactor_head_mouth_blood_only_normal.png" ["statuses_count"]=> int(11915) ["profile_text_color"]=> string(6) "000000" ["name"]=> string(22) "baw@ポケモン中毒" ["show_all_inline_media"]=> bool(false) ["following"]=> bool(false) ["favourites_count"]=> int(70) ["screen_name"]=> string(7) "blanite" ["id"]=> int(60942793) ["id_str"]=> string(8) "60942793" ["contributors_enabled"]=> bool(false) ["utc_offset"]=> int(32400) ["profile_link_color"]=> string(6) "ff0000" } ["id"]=> int(1813293764) ["id_str"]=> string(10) "1813293764" ["sender_id"]=> int(60942793) ["text"]=> string(5) "test2" } [1]=> object(stdClass)#8 (10) { ["sender_screen_name"]=> string(7) "blanite" ["recipient_screen_name"]=> string(10) "koedamebot" ["recipient_id"]=> int(206206937) ["created_at"]=> string(30) "Sat Oct 23 13:33:30 +0000 2010" ["recipient"]=> object(stdClass)#9 (33) { ["time_zone"]=> NULL ["description"]=> string(0) "" ["verified"]=> bool(false) ["profile_sidebar_fill_color"]=> string(6) "DDEEF6" ["followers_count"]=> int(1) ["follow_request_sent"]=> bool(false) ["notifications"]=> bool(false) ["profile_use_background_image"]=> bool(true) ["profile_sidebar_border_color"]=> string(6) "C0DEED" ["url"]=> NULL ["profile_background_image_url"]=> string(59) "http://s.twimg.com/a/1287523226/images/themes/theme1/bg.png" ["listed_count"]=> int(0) ["lang"]=> string(2) "ja" ["created_at"]=> string(30) "Fri Oct 22 13:54:02 +0000 2010" ["friends_count"]=> int(1) ["profile_background_color"]=> string(6) "C0DEED" ["location"]=> string(0) "" ["statuses_count"]=> int(3) ["profile_background_tile"]=> bool(false) ["protected"]=> bool(false) ["profile_image_url"]=> string(67) "http://s.twimg.com/a/1287523226/images/default_profile_6_normal.png" ["show_all_inline_media"]=> bool(false) ["favourites_count"]=> int(0) ["profile_text_color"]=> string(6) "333333" ["name"]=> string(7) "koedame" ["contributors_enabled"]=> bool(false) ["following"]=> bool(true) ["screen_name"]=> string(10) "koedamebot" ["id"]=> int(206206937) ["id_str"]=> string(9) "206206937" ["geo_enabled"]=> bool(false) ["utc_offset"]=> NULL ["profile_link_color"]=> string(6) "0084B4" } ["sender"]=> object(stdClass)#10 (33) { ["time_zone"]=> string(5) "Osaka" ["description"]=> string(314) "暇つぶしに忙しい、どうしもない高専生。言語→日本語/C/C#/php/Java/xhtml/css/Q3Scriptなど。ポインタを愛する英語嫌いなGC信望者。他言語→C++/Ruby/JS/AS/Python、趣味→アニソン/画像収集癖/ショート*2/mixi/wp弄り、ゲーム→ポケモンBW/Civ4/FPS(ET)" ["verified"]=> bool(false) ["profile_sidebar_fill_color"]=> string(6) "ffffff" ["followers_count"]=> int(151) ["follow_request_sent"]=> bool(false) ["notifications"]=> bool(false) ["profile_use_background_image"]=> bool(false) ["profile_sidebar_border_color"]=> string(6) "ffffff" ["url"]=> string(20) "https://jikkenjo.net/" ["profile_background_image_url"]=> string(59) "http://s.twimg.com/a/1287010001/images/themes/theme1/bg.png" ["listed_count"]=> int(27) ["lang"]=> string(2) "ja" ["created_at"]=> string(30) "Tue Jul 28 16:06:45 +0000 2009" ["friends_count"]=> int(108) ["profile_background_color"]=> string(6) "ffffff" ["location"]=> string(17) "Shunan, Yamaguchi" ["statuses_count"]=> int(11915) ["profile_background_tile"]=> bool(false) ["protected"]=> bool(false) ["profile_image_url"]=> string(88) "http://a3.twimg.com/profile_images/1093067523/charactor_head_mouth_blood_only_normal.png" ["show_all_inline_media"]=> bool(false) ["favourites_count"]=> int(70) ["profile_text_color"]=> string(6) "000000" ["name"]=> string(22) "baw@ポケモン中毒" ["contributors_enabled"]=> bool(false) ["following"]=> bool(false) ["screen_name"]=> string(7) "blanite" ["id"]=> int(60942793) ["id_str"]=> string(8) "60942793" ["geo_enabled"]=> bool(false) ["utc_offset"]=> int(32400) ["profile_link_color"]=> string(6) "ff0000" } ["id"]=> int(1813287627) ["id_str"]=> string(10) "1813287627" ["sender_id"]=> int(60942793) ["text"]=> string(4) "test" } }
friendships/show
object(stdClass)#9 (1) { ["relationship"]=> object(stdClass)#10 (2) { ["target"]=> object(stdClass)#11 (5) { ["followed_by"]=> bool(true) ["following"]=> bool(true) ["screen_name"]=> string(7) "blanite" ["id"]=> int(60942793) ["id_str"]=> string(8) "60942793" } ["source"]=> object(stdClass)#12 (10) { ["marked_spam"]=> bool(false) ["all_replies"]=> bool(false) ["notifications_enabled"]=> bool(false) ["followed_by"]=> bool(true) ["blocking"]=> bool(false) ["want_retweets"]=> bool(true) ["following"]=> bool(true) ["screen_name"]=> string(10) "koedamebot" ["id"]=> int(206206937) ["id_str"]=> string(9) "206206937" } } }
statuses/mentions
array(2) { [0]=> object(stdClass)#5 (19) { ["place"]=> NULL ["retweet_count"]=> NULL ["geo"]=> NULL ["retweeted"]=> bool(false) ["in_reply_to_status_id"]=> NULL ["source"]=> string(86) "<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>" ["truncated"]=> bool(false) ["in_reply_to_status_id_str"]=> NULL ["created_at"]=> string(30) "Sun Oct 24 04:58:06 +0000 2010" ["in_reply_to_user_id"]=> int(206206937) ["favorited"]=> bool(false) ["in_reply_to_user_id_str"]=> string(9) "206206937" ["user"]=> object(stdClass)#6 (33) { ["show_all_inline_media"]=> bool(false) ["time_zone"]=> string(5) "Osaka" ["favourites_count"]=> int(71) ["description"]=> string(314) "暇つぶしに忙しい、どうしもない高専生。言語→日本語/C/C#/php/Java/xhtml/css/Q3Scriptなど。ポインタを愛する英語嫌いなGC信望者。他言語→C++/Ruby/JS/AS/Python、趣味→アニソン/画像収集癖/ショート*2/mixi/wp弄り、ゲーム→ポケモンBW/Civ4/FPS(ET)" ["contributors_enabled"]=> bool(false) ["profile_sidebar_fill_color"]=> string(6) "ffffff" ["followers_count"]=> int(153) ["geo_enabled"]=> bool(false) ["notifications"]=> bool(false) ["profile_use_background_image"]=> bool(false) ["profile_sidebar_border_color"]=> string(6) "ffffff" ["verified"]=> bool(false) ["url"]=> string(20) "https://jikkenjo.net/" ["follow_request_sent"]=> bool(false) ["profile_background_image_url"]=> string(59) "http://s.twimg.com/a/1287010001/images/themes/theme1/bg.png" ["lang"]=> string(2) "ja" ["created_at"]=> string(30) "Tue Jul 28 16:06:45 +0000 2009" ["profile_background_color"]=> string(6) "ffffff" ["location"]=> string(17) "Shunan, Yamaguchi" ["profile_background_tile"]=> bool(false) ["protected"]=> bool(false) ["profile_image_url"]=> string(88) "http://a3.twimg.com/profile_images/1093067523/charactor_head_mouth_blood_only_normal.png" ["profile_text_color"]=> string(6) "000000" ["name"]=> string(22) "baw@ポケモン中毒" ["listed_count"]=> int(27) ["following"]=> bool(true) ["friends_count"]=> int(108) ["screen_name"]=> string(7) "blanite" ["id"]=> int(60942793) ["id_str"]=> string(8) "60942793" ["statuses_count"]=> int(11980) ["utc_offset"]=> int(32400) ["profile_link_color"]=> string(6) "ff0000" } ["contributors"]=> NULL ["coordinates"]=> NULL ["in_reply_to_screen_name"]=> string(10) "koedamebot" ["id"]=> float(28566849973) ["id_str"]=> string(11) "28566849973" ["text"]=> string(17) "@koedamebot test2" } [1]=> object(stdClass)#7 (19) { ["place"]=> NULL ["retweet_count"]=> NULL ["geo"]=> NULL ["retweeted"]=> bool(false) ["in_reply_to_status_id"]=> NULL ["source"]=> string(86) "<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>" ["truncated"]=> bool(false) ["in_reply_to_status_id_str"]=> NULL ["created_at"]=> string(30) "Sun Oct 24 04:58:00 +0000 2010" ["in_reply_to_user_id"]=> int(206206937) ["favorited"]=> bool(false) ["in_reply_to_user_id_str"]=> string(9) "206206937" ["user"]=> object(stdClass)#8 (33) { ["show_all_inline_media"]=> bool(false) ["time_zone"]=> string(5) "Osaka" ["favourites_count"]=> int(71) ["description"]=> string(314) "暇つぶしに忙しい、どうしもない高専生。言語→日本語/C/C#/php/Java/xhtml/css/Q3Scriptなど。ポインタを愛する英語嫌いなGC信望者。他言語→C++/Ruby/JS/AS/Python、趣味→アニソン/画像収集癖/ショート*2/mixi/wp弄り、ゲーム→ポケモンBW/Civ4/FPS(ET)" ["contributors_enabled"]=> bool(false) ["profile_sidebar_fill_color"]=> string(6) "ffffff" ["followers_count"]=> int(153) ["geo_enabled"]=> bool(false) ["notifications"]=> bool(false) ["profile_use_background_image"]=> bool(false) ["profile_sidebar_border_color"]=> string(6) "ffffff" ["verified"]=> bool(false) ["url"]=> string(20) "https://jikkenjo.net/" ["follow_request_sent"]=> bool(false) ["profile_background_image_url"]=> string(59) "http://s.twimg.com/a/1287010001/images/themes/theme1/bg.png" ["lang"]=> string(2) "ja" ["created_at"]=> string(30) "Tue Jul 28 16:06:45 +0000 2009" ["profile_background_color"]=> string(6) "ffffff" ["location"]=> string(17) "Shunan, Yamaguchi" ["profile_background_tile"]=> bool(false) ["protected"]=> bool(false) ["profile_image_url"]=> string(88) "http://a3.twimg.com/profile_images/1093067523/charactor_head_mouth_blood_only_normal.png" ["profile_text_color"]=> string(6) "000000" ["name"]=> string(22) "baw@ポケモン中毒" ["listed_count"]=> int(27) ["following"]=> bool(true) ["friends_count"]=> int(108) ["screen_name"]=> string(7) "blanite" ["id"]=> int(60942793) ["id_str"]=> string(8) "60942793" ["statuses_count"]=> int(11980) ["utc_offset"]=> int(32400) ["profile_link_color"]=> string(6) "ff0000" } ["contributors"]=> NULL ["coordinates"]=> NULL ["in_reply_to_screen_name"]=> string(10) "koedamebot" ["id"]=> float(28566843459) ["id_str"]=> string(11) "28566843459" ["text"]=> string(16) "@koedamebot test" } }
statuses/followers
object(stdClass)#5 (5) { ["users"]=> array(1) { [0]=> object(stdClass)#6 (34) { ["geo_enabled"]=> bool(false) ["time_zone"]=> string(5) "Osaka" ["description"]=> string(314) "暇つぶしに忙しい、どうしもない高専生。言語→日本語/C/C#/php/Java/xhtml/css/Q3Scriptなど。ポインタを愛する英語嫌いなGC信望者。他言語→C++/Ruby/JS/AS/Python、趣味→アニソン/画像収集癖/ショート*2/mixi/wp弄り、ゲーム→ポケモンBW/Civ4/FPS(ET)" ["profile_sidebar_fill_color"]=> string(6) "ffffff" ["followers_count"]=> int(152) ["status"]=> object(stdClass)#7 (18) { ["place"]=> NULL ["retweet_count"]=> NULL ["geo"]=> NULL ["retweeted"]=> bool(false) ["in_reply_to_status_id"]=> float(28572685201) ["source"]=> string(86) "<a href="http://sourceforge.jp/projects/tween/wiki/FrontPage" rel="nofollow">Tween</a>" ["truncated"]=> bool(false) ["in_reply_to_status_id_str"]=> string(11) "28572685201" ["created_at"]=> string(30) "Sun Oct 24 06:43:28 +0000 2010" ["in_reply_to_user_id"]=> int(109259014) ["favorited"]=> bool(false) ["in_reply_to_user_id_str"]=> string(9) "109259014" ["contributors"]=> NULL ["coordinates"]=> NULL ["in_reply_to_screen_name"]=> string(7) "ganmasu" ["id"]=> float(28572800758) ["id_str"]=> string(11) "28572800758" ["text"]=> string(210) "@ganmasu 作業中に開いてたファイルとかフォルダとかプログラムとかが終了したのが面倒くさい。画面に良い具合に配置してるから、それが崩れるのが嫌だ。" } ["verified"]=> bool(false) ["notifications"]=> bool(false) ["follow_request_sent"]=> bool(false) ["profile_use_background_image"]=> bool(false) ["profile_sidebar_border_color"]=> string(6) "ffffff" ["url"]=> string(20) "https://jikkenjo.net/" ["profile_background_image_url"]=> string(59) "http://s.twimg.com/a/1287010001/images/themes/theme1/bg.png" ["lang"]=> string(2) "ja" ["created_at"]=> string(30) "Tue Jul 28 16:06:45 +0000 2009" ["profile_background_color"]=> string(6) "ffffff" ["location"]=> string(17) "Shunan, Yamaguchi" ["listed_count"]=> int(27) ["profile_background_tile"]=> bool(false) ["friends_count"]=> int(108) ["protected"]=> bool(false) ["profile_image_url"]=> string(88) "http://a3.twimg.com/profile_images/1093067523/charactor_head_mouth_blood_only_normal.png" ["statuses_count"]=> int(11996) ["profile_text_color"]=> string(6) "000000" ["name"]=> string(22) "baw@ポケモン中毒" ["show_all_inline_media"]=> bool(false) ["following"]=> bool(true) ["favourites_count"]=> int(71) ["screen_name"]=> string(7) "blanite" ["id"]=> int(60942793) ["id_str"]=> string(8) "60942793" ["contributors_enabled"]=> bool(false) ["utc_offset"]=> int(32400) ["profile_link_color"]=> string(6) "ff0000" } } ["next_cursor"]=> int(0) ["previous_cursor"]=> int(0) ["next_cursor_str"]=> string(1) "0" ["previous_cursor_str"]=> string(1) "0" }
$twitterの中身
これだけは勘弁してください。中身を加工しました。
object(TwitterOAuth)#1 (13) { ["http_code"]=> NULL ["url"]=> NULL ["host"]=> string(26) "https://api.twitter.com/1/" ["timeout"]=> int(30) ["connecttimeout"]=> int(30) ["ssl_verifypeer"]=> bool(false) ["format"]=> string(4) "json" ["decode_json"]=> bool(true) ["http_info"]=> NULL ["useragent"]=> string(25) "TwitterOAuth v0.2.0-beta2" ["sha1_method"]=> object(OAuthSignatureMethod_HMAC_SHA1)#2 (0) { } ["consumer"]=> object(OAuthConsumer)#3 (3) { ["key"]=> string(21) "xxxxxxxxxx" ["secret"]=> string(40) "xxxxxxxxxx" ["callback_url"]=> NULL } ["token"]=> object(OAuthConsumer)#4 (3) { ["key"]=> string(50) "xxxxxxxxxx" ["secret"]=> string(43) "xxxxxxxxxx" ["callback_url"]=> NULL } }
後は自分なりに工夫してみてください。
ピンバック: phpでtwitterbotを作ってみたい(準備) | jikkenjo.net
ピンバック: phpでtwitterbotを作ってみた(設置) | jikkenjo.net