Services_TwitterでHTTPプロキシを使いたい

ソースを読んでるだけでも楽しいCodeRepos
PHPからTwitterAPIを使うためのライブラリを見つけました。

会社にいるときにちょっと触ってみたのですが、うちの会社はプロキシサーバーを経由しないとWebに繋げないので、TwitterAPIが使えませんでした。社内LANの内側で使うためにプロキシを設定できるようにしたい。ちょっとやってみよう。

PEAR/HttpRequest.phpソースコードを見ながら、Services_Twitterソースコードに手を加えてみた。(ほとんどPEAR/HttpRequest.phpからのコピペ。いいのかなこんなんで。)

Index: src/Services/Twitter/Connector.php
===================================================================
--- src/Services/Twitter/Connector.php  (revision 3381)
+++ src/Services/Twitter/Connector.php  (working copy)
@@ -42,6 +42,30 @@
     var $_body;

     /**
+     * Proxy server
+     * @var string
+     */
+    var $_proxy_host;
+
+    /**
+     * Proxy port
+     * @var integer
+     */
+    var $_proxy_port;
+
+    /**
+     * Proxy username
+     * @var string
+     */
+    var $_proxy_user;
+
+    /**
+     * Proxy password
+     * @var string
+     */
+    var $_proxy_pass;
+
+    /**
      * Class constructor
      *
      * @access public
@@ -99,6 +123,19 @@
             }
         }

+        // Proxy authentication
+        if (!empty($this->_proxy_user)) {
+            $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass));
+        }
+
+        // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
+        // connection token to a proxy server...
+        if (isset($this->_proxy_host) && !empty($this->_headers['connection']) &&
+            'Keep-Alive' == $this->_headers['connection'])
+        {
+            $this->removeHeader('connection');
+        }
+
         if (count($this->_body) > 0) {
             foreach ($this->_body as $line) {
                 $body .= $line . "\r\n";
@@ -111,6 +148,9 @@
         if (isset($url['query'])) {
             $path .= '?' . $url['query'];
         }
+        $proxy_host = isset($this->_proxy_host) ? $url['scheme'] . '://' . $url['host'] : '';
+        $proxy_port = (isset($this->_proxy_host) AND $url['port'] != 80) ? ':' . $url['port'] : '';
+        $path = $proxy_host . $proxy_port . $path;

         // definity send target
         $request .= $method . ' ' . $path . ' HTTP/1.1'."\r\n";
@@ -130,7 +170,11 @@
         $request .= $body;

         // send request
-        $fp  = fsockopen($url['host'], $url['port']);
+        if( $this->_proxy_host ) {
+            $fp  = fsockopen( $this->_proxy_host, $this->_proxy_port );
+        } else {
+            $fp  = fsockopen($url['host'], $url['port']);
+        }
         if (!$fp) return false;
         fputs($fp, $request);
         $response = '';
@@ -234,4 +278,22 @@
         return $this->_basic_auth;
     }

+
+    /**
+     * Sets a proxy to be used
+     *
+     * @param string     Proxy host
+     * @param int        Proxy port
+     * @param string     Proxy username
+     * @param string     Proxy password
+     * @access public
+     */
+    function setProxy($host, $port = 8080, $user = null, $pass = null)
+    {
+        $this->_proxy_host = $host;
+        $this->_proxy_port = $port;
+        $this->_proxy_user = $user;
+        $this->_proxy_pass = $pass;
+    }
+
 }
\ No newline at end of file
Index: src/Services/Twitter.php
===================================================================
--- src/Services/Twitter.php    (revision 3381)
+++ src/Services/Twitter.php    (working copy)
@@ -330,6 +330,30 @@
     var $_cache_dir;

     /**
+     * Proxy server
+     * @var string
+     */
+    var $_proxy_host;
+
+    /**
+     * Proxy port
+     * @var integer
+     */
+    var $_proxy_port;
+
+    /**
+     * Proxy username
+     * @var string
+     */
+    var $_proxy_user;
+
+    /**
+     * Proxy password
+     * @var string
+     */
+    var $_proxy_pass;
+
+    /**
      * class constructor
      *
      * @access public
@@ -491,6 +515,23 @@
     }

     /**
+     * Sets a proxy to be used
+     *
+     * @param string     Proxy host
+     * @param int        Proxy port
+     * @param string     Proxy username
+     * @param string     Proxy password
+     * @access public
+     */
+    function setProxy($host, $port = 8080, $user = null, $pass = null)
+    {
+        $this->_proxy_host = $host;
+        $this->_proxy_port = $port;
+        $this->_proxy_user = $user;
+        $this->_proxy_pass = $pass;
+    }
+
+    /**
      * send update request
      *
      * @access private
@@ -503,6 +544,13 @@
     {
         $req =& new Services_Twitter_Connector();

+        if( isset($this->_proxy_host) ) {
+            $req->setProxy( $this->_proxy_host
+                          , $this->_proxy_port
+                          , $this->_proxy_user
+                          , $this->_proxy_pass );
+        }
+
         if (!$this->checkAuth()) {
             $req->enableBasicAuth($this->_user, $this->_pass);
         }
@@ -605,6 +653,13 @@

         $req =& new Services_Twitter_Connector();

+        if( isset($this->_proxy_host) ) {
+            $req->setProxy( $this->_proxy_host
+                          , $this->_proxy_port
+                          , $this->_proxy_user
+                          , $this->_proxy_pass );
+        }
+
         if (!$this->checkAuth()) {
             $req->enableBasicAuth($this->_user, $this->_pass);
         }
@@ -712,6 +767,13 @@
         }

         $req =& new Services_Twitter_Connector();
+        if( isset($this->_proxy_host) ) {
+            $req->setProxy( $this->_proxy_host
+                          , $this->_proxy_port
+                          , $this->_proxy_user
+                          , $this->_proxy_pass );
+        }
+
         $req->addHeader('User-Agent', 'PHP/' . phpversion());
         $response = $req->sendRequest($url, $method);
         $response = explode("\r\n", $response);
@@ -1078,4 +1140,4 @@
             return false;
         }
     }
-}
\ No newline at end of file
+}

BlackJumboDogでプロキシサーバーを立ててテスト。無事にFriendsTimelineが取得できました。やったね!

<?php

// ソースのある場所にパスを通す。
set_include_path('.;C:\Program Files\xampp\php\PEAR;C:\work\coderepos\lang\php\Services_Twitter\src');

require_once( 'Services/Twitter.php' );

// Services_Twitterを生成して、JSONをデコードしてもらうように設定する。
$twitter = new Services_Twitter( 'drgqst', '********');
$twitter->enableJsonConvert();

// 今回追加したメソッド。プロキシサーバーをセットする。
$twitter->setProxy('localhost', 8080 );

// お友達のタイムラインを取得
$friendsTimeline = $twitter->getFriendsTimeline();

var_dump( $friendsTimeline );
?>

ところで、これってコミットしていいものなのかな・・・?
この辺の空気がまだよくわかってない。やっぱり勝手にコミットしたりしちゃマズいよね。。。作った人に連絡してみよう。そうだそうだそれがいいそうしよう。

追記

メールした。初めての人にメールするのは未だに緊張するなー。
CodeReposの文化がまだ良くわかってないのだと思う。IRCっていうのを使って誰かとお話してみようかな。ドキドキ