[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