diff twitter/EpiTwitter.php @ 6:077b0a0a3e6d

remaining originals according to dependency walk
author Robert Boland <robert@markup.co.uk>
date Thu, 16 Feb 2017 22:29:02 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/twitter/EpiTwitter.php	Thu Feb 16 22:29:02 2017 +0000
@@ -0,0 +1,285 @@
+<?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/twitter-async
+*
+* @author Jaisen Mathai <jaisen@jmathai.com>
+*/
+class EpiTwitter extends EpiOAuth
+{
+  const EPITWITTER_SIGNATURE_METHOD = 'HMAC-SHA1';
+  const EPITWITTER_AUTH_OAUTH = 'oauth';
+  const EPITWITTER_AUTH_BASIC = 'basic';
+  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 $apiVersionedUrl= 'http://api.twitter.com';
+  protected $searchUrl = 'http://search.twitter.com';
+  protected $userAgent = 'EpiTwitter (http://github.com/jmathai/twitter-async/tree/)';
+  protected $apiVersion = '1';
+  protected $isAsynchronous = false;
+
+  /* OAuth methods */
+  public function delete($endpoint, $params = null)
+  {
+    return $this->request('DELETE', $endpoint, $params);
+  }
+
+  public function get($endpoint, $params = null)
+  {
+    return $this->request('GET', $endpoint, $params);
+  }
+
+  public function post($endpoint, $params = null)
+  {
+    return $this->request('POST', $endpoint, $params);
+  }
+
+  /* Basic auth methods */
+  public function delete_basic($endpoint, $params = null, $username = null, $password = null)
+  {
+    return $this->request_basic('DELETE', $endpoint, $params, $username, $password);
+  }
+
+  public function get_basic($endpoint, $params = null, $username = null, $password = null)
+  {
+    return $this->request_basic('GET', $endpoint, $params, $username, $password);
+  }
+
+  public function post_basic($endpoint, $params = null, $username = null, $password = null)
+  {
+    return $this->request_basic('POST', $endpoint, $params, $username, $password);
+  }
+
+  public function useApiVersion($version = null)
+  {
+    $this->apiVersion = $version;
+  }
+
+  public function useAsynchronous($async = true)
+  {
+    $this->isAsynchronous = (bool)$async;
+  }
+
+  public function __construct($consumerKey = null, $consumerSecret = null, $oauthToken = null, $oauthTokenSecret = null)
+  {
+    parent::__construct($consumerKey, $consumerSecret, self::EPITWITTER_SIGNATURE_METHOD);
+    $this->setToken($oauthToken, $oauthTokenSecret);
+  }
+
+  public function __call($name, $params = null/*, $username, $password*/)
+  {
+    $parts = explode('_', $name);
+    $method = strtoupper(array_shift($parts));
+    $parts = implode('_', $parts);
+    $endpoint = '/' . preg_replace('/[A-Z]|[0-9]+/e', "'/'.strtolower('\\0')", $parts) . '.json';
+    /* HACK: this is required for list support that starts with a user id */
+    $endpoint = str_replace('//','/',$endpoint);
+    $args = !empty($params) ? array_shift($params) : null;
+
+    // calls which do not have a consumerKey are assumed to not require authentication
+    if($this->consumerKey === null)
+    {
+      $username = null;
+      $password = null;
+
+      if(!empty($params))
+      {
+        $username = array_shift($params);
+        $password = !empty($params) ? array_shift($params) : null;
+      }
+
+      return $this->request_basic($method, $endpoint, $args, $username, $password);
+    }
+
+    return $this->request($method, $endpoint, $args);
+  }
+
+  private function getApiUrl($endpoint)
+  {
+    if(preg_match('@^/(trends|search)[./]?(?=(json|daily|current|weekly))@', $endpoint))
+      return "{$this->searchUrl}{$endpoint}";
+    elseif(!empty($this->apiVersion))
+      return "{$this->apiVersionedUrl}/{$this->apiVersion}{$endpoint}";
+    else
+      return "{$this->apiUrl}{$endpoint}";
+  }
+
+  private function request($method, $endpoint, $params = null)
+  {
+    $url = $this->getUrl($this->getApiUrl($endpoint));
+    $resp= new EpiTwitterJson(call_user_func(array($this, 'httpRequest'), $method, $url, $params, $this->isMultipart($params)), $this->debug);
+    if(!$this->isAsynchronous)
+      $resp->responseText;
+
+    return $resp;
+  }
+
+  private function request_basic($method, $endpoint, $params = null, $username = null, $password = null)
+  {
+    $url = $this->getApiUrl($endpoint);
+    if($method === 'GET')
+      $url .= is_null($params) ? '' : '?'.http_build_query($params, '', '&');
+    $ch = curl_init($url);
+    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+    curl_setopt($ch, CURLOPT_TIMEOUT, $this->requestTimeout);
+    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+    if($method === 'POST' && $params !== null)
+    {
+      if($this->isMultipart($params))
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
+      else
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params));
+    }
+    if(!empty($username) && !empty($password))
+      curl_setopt($ch, CURLOPT_USERPWD, "{$username}:{$password}");
+
+    $resp = new EpiTwitterJson(EpiCurl::getInstance()->addCurl($ch), $this->debug);
+    if(!$this->isAsynchronous)
+      $resp->responseText;
+
+    return $resp;
+  }
+}
+
+class EpiTwitterJson implements ArrayAccess, Countable, IteratorAggregate
+{
+  private $debug;
+  private $__resp;
+  public function __construct($response, $debug = false)
+  {
+    $this->__resp = $response;
+    $this->debug = $debug;
+  }
+
+  // ensure that calls complete by blocking for results, NOOP if already returned
+  public function __destruct()
+  {
+    $this->responseText;
+  }
+
+  // Implementation of the IteratorAggregate::getIterator() to support foreach ($this as $...)
+  public function getIterator ()
+  {
+    if ($this->__obj) {
+      return new ArrayIterator($this->__obj);
+    } else {
+      return new ArrayIterator($this->response);
+    }
+  }
+
+  // Implementation of Countable::count() to support count($this)
+  public function count ()
+  {
+    return count($this->response);
+  }
+  
+  // 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)
+  {
+    $accessible = array('responseText'=>1,'headers'=>1,'code'=>1);
+    $this->responseText = $this->__resp->data;
+    $this->headers = $this->__resp->headers;
+    $this->code = $this->__resp->code;
+    if(isset($accessible[$name]) && $accessible[$name])
+      return $this->$name;
+    elseif(($this->code < 200 || $this->code >= 400) && !isset($accessible[$name]))
+      EpiTwitterException::raise($this->__resp, $this->debug);
+
+    // Call appears ok so we can fill in the response
+    $this->response = json_decode($this->responseText, 1);
+    $this->__obj = json_decode($this->responseText);
+
+    if(gettype($this->__obj) === 'object')
+    {
+      foreach($this->__obj as $k => $v)
+      {
+        $this->$k = $v;
+      }
+    }
+
+    if (property_exists($this, $name)) {
+      return $this->$name;
+    }
+    return null;
+  }
+
+  public function __isset($name)
+  {
+    $value = self::__get($name);
+    return !empty($name);
+  }
+}
+
+class EpiTwitterException extends Exception
+{
+  public static function raise($response, $debug)
+  {
+    $message = $response->data;
+ 
+    switch($response->code)
+    {
+      case 400:
+        throw new EpiTwitterBadRequestException($message, $response->code);
+      case 401:
+        throw new EpiTwitterNotAuthorizedException($message, $response->code);
+      case 403:
+        throw new EpiTwitterForbiddenException($message, $response->code);
+      case 404:
+        throw new EpiTwitterNotFoundException($message, $response->code);
+      case 406:
+        throw new EpiTwitterNotAcceptableException($message, $response->code);
+      case 420:
+        throw new EpiTwitterEnhanceYourCalmException($message, $response->code);
+      case 500:
+        throw new EpiTwitterInternalServerException($message, $response->code);
+      case 502:
+        throw new EpiTwitterBadGatewayException($message, $response->code);
+      case 503:
+        throw new EpiTwitterServiceUnavailableException($message, $response->code);
+      default:
+        throw new EpiTwitterException($message, $response->code);
+    }
+  }
+}
+class EpiTwitterBadRequestException extends EpiTwitterException{}
+class EpiTwitterNotAuthorizedException extends EpiTwitterException{}
+class EpiTwitterForbiddenException extends EpiTwitterException{}
+class EpiTwitterNotFoundException extends EpiTwitterException{}
+class EpiTwitterNotAcceptableException extends EpiTwitterException{}
+class EpiTwitterEnhanceYourCalmException extends EpiTwitterException{}
+class EpiTwitterInternalServerException extends EpiTwitterException{}
+class EpiTwitterBadGatewayException extends EpiTwitterException{}
+class EpiTwitterServiceUnavailableException extends EpiTwitterException{}
+