[Mapbender-commits] r5335 - in trunk/mapbender/http/extensions: . epicode

svn_mapbender at osgeo.org svn_mapbender at osgeo.org
Tue Jan 19 04:16:27 EST 2010


Author: christoph
Date: 2010-01-19 04:16:25 -0500 (Tue, 19 Jan 2010)
New Revision: 5335

Added:
   trunk/mapbender/http/extensions/epicode/
   trunk/mapbender/http/extensions/epicode/EpiCurl.php
   trunk/mapbender/http/extensions/epicode/EpiOAuth.php
   trunk/mapbender/http/extensions/epicode/EpiTwitter.php
Log:


Added: trunk/mapbender/http/extensions/epicode/EpiCurl.php
===================================================================
--- trunk/mapbender/http/extensions/epicode/EpiCurl.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/epicode/EpiCurl.php	2010-01-19 09:16:25 UTC (rev 5335)
@@ -0,0 +1,128 @@
+<?php
+class EpiCurl
+{
+  const timeout = 3;
+  static $inst = null;
+  static $singleton = 0;
+  private $mc;
+  private $msgs;
+  private $running;
+  private $requests = array();
+  private $responses = array();
+  private $properties = array();
+
+  function __construct()
+  {
+    if(self::$singleton == 0)
+    {
+      throw new Exception('This class cannot be instantiated by the new keyword.  You must instantiate it using: $obj = EpiCurl::getInstance();');
+    }
+
+    $this->mc = curl_multi_init();
+    $this->properties = array(
+      'code'  => CURLINFO_HTTP_CODE,
+      'time'  => CURLINFO_TOTAL_TIME,
+      'length'=> CURLINFO_CONTENT_LENGTH_DOWNLOAD,
+      'type'  => CURLINFO_CONTENT_TYPE
+      );
+  }
+
+  public function addCurl($ch)
+  {
+    $key = (string)$ch;
+    $this->requests[$key] = $ch;
+
+    $res = curl_multi_add_handle($this->mc, $ch);
+    
+    // (1)
+    if($res === CURLM_OK || $res === CURLM_CALL_MULTI_PERFORM)
+    {
+      do {
+          $mrc = curl_multi_exec($this->mc, $active);
+      } while ($mrc === CURLM_CALL_MULTI_PERFORM);
+
+      return new EpiCurlManager($key);
+    }
+    else
+    {
+      return $res;
+    }
+  }
+
+  public function getResult($key = null)
+  {
+    if($key != null)
+    {
+      if(isset($this->responses[$key]))
+      {
+        return $this->responses[$key];
+      }
+
+      $running = null;
+      do
+      {
+        $resp = curl_multi_exec($this->mc, $runningCurrent);
+        if($running !== null && $runningCurrent != $running)
+        {
+          $this->storeResponses($key);
+          if(isset($this->responses[$key]))
+          {
+            return $this->responses[$key];
+          }
+        }
+        $running = $runningCurrent;
+      }while($runningCurrent > 0);
+    }
+
+    return false;
+  }
+
+  private function storeResponses()
+  {
+    while($done = curl_multi_info_read($this->mc))
+    {
+      $key = (string)$done['handle'];
+      $this->responses[$key]['data'] = curl_multi_getcontent($done['handle']);
+      foreach($this->properties as $name => $const)
+      {
+        $this->responses[$key][$name] = curl_getinfo($done['handle'], $const);
+        curl_multi_remove_handle($this->mc, $done['handle']);
+      }
+    }
+  }
+
+  static function getInstance()
+  {
+    if(self::$inst == null)
+    {
+      self::$singleton = 1;
+      self::$inst = new EpiCurl();
+    }
+
+    return self::$inst;
+  }
+}
+
+class EpiCurlManager
+{
+  private $key;
+  private $epiCurl;
+
+  function __construct($key)
+  {
+    $this->key = $key;
+    $this->epiCurl = EpiCurl::getInstance();
+  }
+
+  function __get($name)
+  {
+    $responses = $this->epiCurl->getResult($this->key);
+    return $responses[$name];
+  }
+}
+
+/*
+ * Credits:
+ *  - (1) Alistair pointed out that curl_multi_add_handle can return CURLM_CALL_MULTI_PERFORM on success.
+ */
+?>

Added: trunk/mapbender/http/extensions/epicode/EpiOAuth.php
===================================================================
--- trunk/mapbender/http/extensions/epicode/EpiOAuth.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/epicode/EpiOAuth.php	2010-01-19 09:16:25 UTC (rev 5335)
@@ -0,0 +1,258 @@
+<?php
+class EpiOAuth
+{
+  public $version = '1.0';
+
+  protected $requestTokenUrl;
+  protected $accessTokenUrl;
+  protected $authenticateUrl;
+  protected $authorizeUrl;
+  protected $consumerKey;
+  protected $consumerSecret;
+  protected $token;
+  protected $tokenSecret;
+  protected $signatureMethod;
+
+  public function getAccessToken()
+  {
+    $resp = $this->httpRequest('GET', $this->accessTokenUrl);
+    return new EpiOAuthResponse($resp);
+  }
+
+  public function getAuthenticateUrl()
+  { 
+    $token = $this->getRequestToken();
+    return $this->authenticateUrl . '?oauth_token=' . $token->oauth_token;
+  }
+
+  public function getAuthorizationUrl()
+  { 
+    $token = $this->getRequestToken();
+    return $this->authorizeUrl . '?oauth_token=' . $token->oauth_token;
+  }
+
+  public function getRequestToken()
+  {
+    $resp = $this->httpRequest('GET', $this->requestTokenUrl);
+    return new EpiOAuthResponse($resp);
+  }
+
+  public function httpRequest($method = null, $url = null, $params = null)
+  {
+    if(empty($method) || empty($url))
+      return false;
+
+    if(empty($params['oauth_signature']))
+      $params = $this->prepareParameters($method, $url, $params);
+
+    switch($method)
+    {
+      case 'GET':
+        return $this->httpGet($url, $params);
+        break;
+      case 'POST':
+        return $this->httpPost($url, $params);
+        break;
+    }
+  }
+
+  public function setToken($token = null, $secret = null)
+  {
+    $params = func_get_args();
+    $this->token = $token;
+    $this->tokenSecret = $secret;
+  } 
+
+  protected function encode_rfc3986($string)
+  {
+    return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($string))));
+  }
+
+  protected function addOAuthHeaders(&$ch, $url, $oauthHeaders)
+  {
+    $_h = array('Expect:');
+    $urlParts = parse_url($url);
+    $oauth = 'Authorization: OAuth realm="' . $urlParts['path'] . '",';
+    foreach($oauthHeaders as $name => $value)
+    {
+      $oauth .= "{$name}=\"{$value}\",";
+    }
+    $_h[] = substr($oauth, 0, -1);
+  
+    curl_setopt($ch, CURLOPT_HTTPHEADER, $_h); 
+  }
+
+  protected function generateNonce()
+  {
+    if(isset($this->nonce)) // for unit testing
+      return $this->nonce;
+
+    return md5(uniqid(rand(), true));
+  }
+
+  protected function generateSignature($method = null, $url = null, $params = null)
+  {
+    if(empty($method) || empty($url))
+      return false;
+
+
+    // concatenating
+    $concatenatedParams = '';
+    foreach($params as $k => $v)
+    {
+      $v = $this->encode_rfc3986($v);
+      $concatenatedParams .= "{$k}={$v}&";
+    }
+    $concatenatedParams = $this->encode_rfc3986(substr($concatenatedParams, 0, -1));
+
+    // normalize url
+    $normalizedUrl = $this->encode_rfc3986($this->normalizeUrl($url));
+    $method = $this->encode_rfc3986($method); // don't need this but why not?
+
+    $signatureBaseString = "{$method}&{$normalizedUrl}&{$concatenatedParams}";
+    return $this->signString($signatureBaseString);
+  }
+
+  protected function httpGet($url, $params = null)
+  {
+    if(count($params['request']) > 0)
+    {
+      $url .= '?';
+      foreach($params['request'] as $k => $v)
+      {
+        $url .= "{$k}={$v}&";
+      }
+      $url = substr($url, 0, -1);
+    }
+    $ch = curl_init($url);
+    $this->addOAuthHeaders($ch, $url, $params['oauth']);
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+    $resp  = $this->curl->addCurl($ch);
+
+    return $resp;
+  }
+
+  protected function httpPost($url, $params = null)
+  {
+    $ch = curl_init($url);
+    $this->addOAuthHeaders($ch, $url, $params['oauth']);
+    curl_setopt($ch, CURLOPT_POST, 1);
+    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params['request']));
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+    $resp  = $this->curl->addCurl($ch);
+    return $resp;
+  }
+
+  protected function normalizeUrl($url = null)
+  {
+    $urlParts = parse_url($url);
+    $scheme = strtolower($urlParts['scheme']);
+    $host   = strtolower($urlParts['host']);
+    $port = intval($urlParts['port']);
+
+    $retval = "{$scheme}://{$host}";
+    if($port > 0 && ($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443))
+    {
+      $retval .= ":{$port}";
+    }
+    $retval .= $urlParts['path'];
+    if(!empty($urlParts['query']))
+    {
+      $retval .= "?{$urlParts['query']}";
+    }
+
+    return $retval;
+  }
+
+  protected function prepareParameters($method = null, $url = null, $params = null)
+  {
+    if(empty($method) || empty($url))
+      return false;
+
+    $oauth['oauth_consumer_key'] = $this->consumerKey;
+    $oauth['oauth_token'] = $this->token;
+    $oauth['oauth_nonce'] = $this->generateNonce();
+    $oauth['oauth_timestamp'] = !isset($this->timestamp) ? time() : $this->timestamp; // for unit test
+    $oauth['oauth_signature_method'] = $this->signatureMethod;
+    $oauth['oauth_version'] = $this->version;
+
+    // encoding
+    array_walk($oauth, array($this, 'encode_rfc3986'));
+    if(is_array($params))
+      array_walk($params, array($this, 'encode_rfc3986'));
+    $encodedParams = array_merge($oauth, (array)$params);
+
+    // sorting
+    ksort($encodedParams);
+
+    // signing
+    $oauth['oauth_signature'] = $this->encode_rfc3986($this->generateSignature($method, $url, $encodedParams));
+    return array('request' => $params, 'oauth' => $oauth);
+  }
+
+  protected function signString($string = null)
+  {
+    $retval = false;
+    switch($this->signatureMethod)
+    {
+      case 'HMAC-SHA1':
+        $key = $this->encode_rfc3986($this->consumerSecret) . '&' . $this->encode_rfc3986($this->tokenSecret);
+        $retval = base64_encode(hash_hmac('sha1', $string, $key, true));
+        break;
+    }
+
+    return $retval;
+  }
+
+  public function __construct($consumerKey, $consumerSecret, $signatureMethod='HMAC-SHA1')
+  {
+    $this->consumerKey = $consumerKey;
+    $this->consumerSecret = $consumerSecret;
+    $this->signatureMethod = $signatureMethod;
+    $this->curl = EpiCurl::getInstance();
+  }
+}
+
+class EpiOAuthResponse
+{
+  private $__resp;
+
+  public function __construct($resp)
+  {
+    $this->__resp = $resp;
+  }
+
+  public function __get($name)
+  {
+    if($this->__resp->code != 200)
+      EpiOAuthException::raise($this->__resp->data, $this->__resp->code);
+
+    parse_str($this->__resp->data, $result);
+    foreach($result as $k => $v)
+    {
+      $this->$k = $v;
+    }
+
+    return $result[$name];
+  }
+}
+
+class EpiOAuthException extends Exception
+{
+  public static function raise($message, $code)
+  {
+    switch($code)
+    {
+      case 400:
+        throw new EpiOAuthBadRequestException($message, $code);
+      case 401:
+        throw new EpiOAuthUnauthorizedException($message, $code);
+      default:
+        throw new EpiOAuthException($message, $code);
+    }
+  }
+}
+
+
+class EpiOAuthBadRequestException extends EpiOAuthException{}
+class EpiOAuthUnauthorizedException extends EpiOAuthException{}

Added: trunk/mapbender/http/extensions/epicode/EpiTwitter.php
===================================================================
--- trunk/mapbender/http/extensions/epicode/EpiTwitter.php	                        (rev 0)
+++ trunk/mapbender/http/extensions/epicode/EpiTwitter.php	2010-01-19 09:16:25 UTC (rev 5335)
@@ -0,0 +1,118 @@
+<?php
+/*
+ *  Class to integrate with Twitter's API.
+ *    Authenticated calls are done using OAuth and require access tokens for a user.
+ *    API calls which do not require authentication do not require tokens (i.e. search/trends)
+ * 
+ *  Full documentation available on github
+ *    http://wiki.github.com/jmathai/epicode/epitwitter
+ * 
+ *  @author Jaisen Mathai <jaisen at jmathai.com>
+ */
+class EpiTwitter extends EpiOAuth
+{
+  const EPITWITTER_SIGNATURE_METHOD = 'HMAC-SHA1';
+  protected $requestTokenUrl= 'http://twitter.com/oauth/request_token';
+  protected $accessTokenUrl = 'http://twitter.com/oauth/access_token';
+  protected $authorizeUrl   = 'http://twitter.com/oauth/authorize';
+  protected $authenticateUrl= 'http://twitter.com/oauth/authenticate';
+  protected $apiUrl         = 'http://twitter.com';
+  protected $searchUrl      = 'http://search.twitter.com';
+
+  public function __call($name, $params = null)
+  {
+    $parts  = explode('_', $name);
+    $method = strtoupper(array_shift($parts));
+    $parts  = implode('_', $parts);
+    $path   = '/' . preg_replace('/[A-Z]|[0-9]+/e', "'/'.strtolower('\\0')", $parts) . '.json';
+    if(!empty($params))
+      $args = array_shift($params);
+
+    // intercept calls to the search api
+    if(preg_match('/^(search|trends)/', $parts))
+    {
+      $query = isset($args) ? http_build_query($args) : '';
+      $url = "{$this->searchUrl}{$path}?{$query}";
+      $ch = curl_init($url);
+      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+
+      return new EpiTwitterJson(EpiCurl::getInstance()->addCurl($ch));
+    }
+
+    return new EpiTwitterJson(call_user_func(array($this, 'httpRequest'), $method, "{$this->apiUrl}{$path}", $args));
+  }
+
+  public function __construct($consumerKey = null, $consumerSecret = null, $oauthToken = null, $oauthTokenSecret = null)
+  {
+    parent::__construct($consumerKey, $consumerSecret, self::EPITWITTER_SIGNATURE_METHOD);
+    $this->setToken($oauthToken, $oauthTokenSecret);
+  }
+}
+
+class EpiTwitterJson implements ArrayAccess, Countable,  IteratorAggregate
+{
+  private $__resp;
+  public function __construct($response)
+  {
+    $this->__resp = $response;
+  }
+
+  // Implementation of the IteratorAggregate::getIterator() to support foreach ($this as $...)
+  public function getIterator ()
+  {
+    return new ArrayIterator($this->__obj);
+  }
+
+  // Implementation of Countable::count() to support count($this)
+  public function count ()
+  {
+    return count($this->__obj);
+  }
+  
+  // Next four functions are to support ArrayAccess interface
+  // 1
+  public function offsetSet($offset, $value) 
+  {
+    $this->response[$offset] = $value;
+  }
+
+  // 2
+  public function offsetExists($offset) 
+  {
+    return isset($this->response[$offset]);
+  }
+  
+  // 3
+  public function offsetUnset($offset) 
+  {
+    unset($this->response[$offset]);
+  }
+
+  // 4
+  public function offsetGet($offset) 
+  {
+    return isset($this->response[$offset]) ? $this->response[$offset] : null;
+  }
+
+  public function __get($name)
+  {
+    if($this->__resp->code != 200)
+      EpiOAuthException::raise($this->__resp->data, $this->__resp->code);
+
+    $this->responseText = $this->__resp->data;
+    $this->response     = json_decode($this->responseText, 1);
+    $this->__obj        = json_decode($this->responseText);
+    foreach($this->__obj as $k => $v)
+    {
+      $this->$k = $v;
+    }
+
+    return $this->$name;
+  }
+
+  public function __isset($name)
+  {
+    $value = self::__get($name);
+    return empty($name);
+  }
+}



More information about the Mapbender_commits mailing list