読者です 読者をやめる 読者になる 読者になる

感謝のプログラミング 10000時間

たどり着いた結果(さき)は、感謝でした。

PHPでTwitterの特定ユーザのフォローしている人を取得するサンプル

PHP
<スポンサーリンク>

とりあえず動かしてみる

ライブラリ的なものは、以下のTwitterAPIExchangeを使った。
https://github.com/J7mbo/twitter-api-php/blob/master/TwitterAPIExchange.php

ソースが長いから、先に結果の画面を載せる。
動かした結果はこんな感じになる。
f:id:sho322:20131209023533j:plain

ソースコード

・とりあえず動かすだけ。
・再利用とか考えていない。
オブジェクト指向で書かれていない。
などの問題があるが、とりあえずPHPTwitterAPIを叩くことに慣れるという意味で、コードを書いてみた。
上の方にclass TwitterAPIExchange {}
と長々とクラスが書いてあって、別出ししてrequire_onceしろよ、という話になるかもしれないが、当方のWindows環境でうまく読み込んでくれないので後回しにした。
「//****サンプルここから*******」以下が実際にデータを取得している部分。

<?php
class TwitterAPIExchange 
{
    private $oauth_access_token;
    private $oauth_access_token_secret;
    private $consumer_key;
    private $consumer_secret;
    private $postfields;
    private $getfield;
    protected $oauth;
    public $url;
 
    /* Create the API access object. Requires an array of settings::
     * oauth access token, oauth access token secret, consumer key, consumer secret
     * These are all available by creating your own application on dev.twitter.com
     * Requires the cURL library
     * 
     * @param array $settings
     */
    public function __construct(array $settings)
    {
        if (!in_array('curl', get_loaded_extensions())) 
        {
            throw new Exception('You need to install cURL, see: http://curl.haxx.se/docs/install.html');
        }
 
        if (!isset($settings['oauth_access_token'])
            || !isset($settings['oauth_access_token_secret'])
            || !isset($settings['consumer_key'])
            || !isset($settings['consumer_secret']))
        {
            throw new Exception('Make sure you are passing in the correct parameters');
        }
 
        $this->oauth_access_token = $settings['oauth_access_token'];
        $this->oauth_access_token_secret = $settings['oauth_access_token_secret'];
        $this->consumer_key = $settings['consumer_key'];
        $this->consumer_secret = $settings['consumer_secret'];
    }
 
    
    /* Set postfields array, example: array('screen_name' => 'J7mbo')
     * 
     * @param array $array Array of parameters to send to API
     * @return \TwitterAPIExchange Instance of self for method chaining
     */
    public function setPostfields(array $array)
    {
        if (!is_null($this->getGetfield())) 
        { 
            throw new Exception('You can only choose get OR post fields.'); 
        }
        $this->postfields = $array;
        return $this;
    }
 
    /* Set getfield string, example: '?screen_name=J7mbo'
     * 
     * @param string $string Get key and value pairs as string
     * @return \TwitterAPIExchange Instance of self for method chaining
     */
    public function setGetfield($string)
    {
        if (!is_null($this->getPostfields())) 
        { 
            throw new Exception('You can only choose get OR post fields.'); 
        }
 
        $this->getfield = $string;
        return $this;
    }
 
    /* Get getfield string (simple getter)
     * 
     * @return string $this->getfields
     */
    public function getGetfield()
    {
        return $this->getfield;
    }
 
    /* Get postfields array (simple getter)
     * 
     * @return array $this->postfields
     */
    public function getPostfields()
    {
        return $this->postfields;
    }
 
    /* Build the Oauth object using params set in construct and additionals
     * passed to this method. For v1.1, see: https://dev.twitter.com/docs/api/1.1
     * 
     * @param string $url The API url to use. Example: https://api.twitter.com/1.1/search/tweets.json
     * @param string $requestMethod Either POST or GET
     * @return \TwitterAPIExchange Instance of self for method chaining
     */
    public function buildOauth($url, $requestMethod)
    {
        if (strtolower($requestMethod) !== 'post' && strtolower($requestMethod) !== 'get')
        {
            throw new Exception('Request method must be either POST or GET');
        }
 
        $consumer_key = $this->consumer_key;
        $consumer_secret = $this->consumer_secret;
        $oauth_access_token = $this->oauth_access_token;
        $oauth_access_token_secret = $this->oauth_access_token_secret;
 
        $oauth = array( 
            'oauth_consumer_key' => $consumer_key,
            'oauth_nonce' => time(),
            'oauth_signature_method' => 'HMAC-SHA1',
            'oauth_token' => $oauth_access_token,
            'oauth_timestamp' => time(),
            'oauth_version' => '1.0'
        );
 
        $getfield = $this->getGetfield();
 
        if (!is_null($getfield))
        {
            $getfields = str_replace('?', '', explode('&', $getfield));
            foreach ($getfields as $g)
            {
                $split = explode('=', $g);
                $oauth[$split[0]] = $split[1];
            }
        }
 
        $base_info = $this->buildBaseString($url, $requestMethod, $oauth);
        $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
        $oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
        $oauth['oauth_signature'] = $oauth_signature;
 
        $this->url = $url;
        $this->oauth = $oauth;
 
        return $this;
    }
 
    /* Perform the acual data retrieval from the API
     * 
     * @param boolean optional $return If true, returns data. 
     * @return json If $return param is true, returns json data.
     */
    public function performRequest($return = true)
    {
        if (!is_bool($return)) 
        { 
            throw new Exception('performRequest parameter must be true or false'); 
        }
 
        $header = array($this->buildAuthorizationHeader($this->oauth), 'Expect:');
 
        $getfield = $this->getGetfield();
        $postfields = $this->getPostfields();
 
        $options = array( 
            CURLOPT_HTTPHEADER => $header,
            CURLOPT_HEADER => false,
            CURLOPT_URL => $this->url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false
        );
 
        if (!is_null($postfields))
        {
            $options[CURLOPT_POSTFIELDS] = $postfields;
        }
        else
        {
            if ($getfield !== '')
            {
                $options[CURLOPT_URL] .= $getfield;
            }
        }
 
        $feed = curl_init();
        curl_setopt_array($feed, $options);
        $json = curl_exec($feed);
        curl_close($feed);
 
        if ($return) { return $json; }
    }
 
    /* Private method to generate the base string used by cURL
     * 
     * @param string $baseURI
     * @param string $method
     * @param string $params
     * @return string Built base string
     */
    private function buildBaseString($baseURI, $method, $params) 
    {
        $return = array();
        ksort($params);
 
        foreach($params as $key=>$value)
        {
            $return[] = "$key=" . $value;
        }
 
        return $method . "&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $return)); 
    }
 
    /**
     * Private method to generate authorization header used by cURL
     * 
     * @param array $oauth Array of oauth data generated by buildOauth()
     * @return string $return Header used by cURL for request
     */    
    private function buildAuthorizationHeader($oauth) 
    {
        $return = 'Authorization: OAuth ';
        $values = array();
 
        foreach($oauth as $key => $value)
        {
            $values[] = "$key=\"" . rawurlencode($value) . "\"";
        }
        $return .= implode(', ', $values);
        return $return;
    }
 
}


//****サンプルここから*******

$target_name = 'kazu_fujisawa'; 
$consumerKey = 'XXXXXX';
$consumerKeySecret = 'FFFFF';
$accessToken = '927525590-QQqq';
$accessTokenSecret = 'ZZZZ';
 
$settings = array(
  'oauth_access_token' => $accessToken,
  'oauth_access_token_secret' => $accessTokenSecret,
  'consumer_key' => $consumerKey,
  'consumer_secret' => $consumerKeySecret
);
 
$i = 0;
$cursor = -1;
 
do {
  //$url = 'https://api.twitter.com/1.1/followers/list.json'; //フォロワーを取得
  $url = 'https://api.twitter.com/1.1/friends/list.json';
  $getfield = '?cursor='.$cursor.'&screen_name='.$target_name;
  $requestMethod = 'GET';
  $twitter = new TwitterAPIExchange($settings);
  $response = $twitter->setGetfield($getfield)
                      ->buildOauth($url, $requestMethod)
                      ->performRequest();
 
  $response = json_decode($response, true);

  if (!empty($response["next_cursor_str"])) {
    $next_cursor = $response["next_cursor_str"];
  } else {
    $next_cursor = 0;
  }

  $errors = $response["errors"];

  if (!empty($errors)) {
    foreach($errors as $error){
      $code = $error['code'];
      $msg = $error['message'];
      echo "<br><br>Error " . $code . ": " . $msg;
    }
    $cursor = 0;
  } else {
  	//var_dump($response);
    //for($i=0;$i<count($response);$i++) {
      $users = $response["users"];
      //var_dump($users);
      foreach($users as $user) {
          $screen_name = $user['screen_name'];
          $name = $user['name'];
          $description = $user['description'];
          $profiele_image_url = $user['profile_image_url'];
          $followers_count = $user['followers_count'];
          $friends_count = $user['friends_count'];
          echo '<img src="' . $profiele_image_url . '"></br>';
          echo '名前:' . $name . ':::スクリーン名:::' . $screen_name . '</br>';
          echo 'フォロワー数:' . $followers_count . ':::フォロー数:::' . $friends_count .'</br>' . $description .'</br><hr>'; 
      }
    //}
  }
  if ($next_cursor != null) {
    $cursor = $next_cursor;
  }
  //$cursor = 0;
} while ( $cursor != 0);
 
if (!empty($users)) {
  echo '<br><br>Total: ' . $i;
}
 
?>

(メモ)require_once()はWindowsでは大文字小文字を区別しないらしい

require_once("a.php"); // a.phpを読み込みます
require_once("A.php"); // Windowsはこれもa.phpを読み込みます! (PHP 4のみ)

http://manual.xwd.jp/function.require-once.html

PHPってキャメルケースで変数書くの?それともスネークケース?

PHPを手探りで勉強し始めてちょっと迷っているのが、変数名の書き方。
なんかネットで調べてると、変数をキャメルケース(myNameみたいなの)で書く人とか、スネークケース(my_name的な)で書く人とか色々いて、定まらない。

スクリプト言語は基本はスネークケースで書くっていうのをどっかで読んだけど、JavaScriptはキャメルケースで書くし、クラス名をMy_Serviceとか書くのもなんか嫌だなぁ。
というわけで、来週末はなんかオープンソースを読んでみて真似しようと思う。

PHPにひと苦労

あと、慣れてないせいか、PHPはエラーメッセージがわかりづらい。そしてスコープがわかりづらい。
Sublime Textで書いてるけど、EclipsePHP pluginでも入れてみようかな。

今までいかにEclipseに助けられてきたのかがよくわかる。慣れたらきっと愛せるけど、やっぱり今のところはJavaの方が好きだ。

色々と手こずったけど、だいぶ慣れてきた。