]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - extlib/OAuth.php
Merge branch '0.9.x' of git@gitorious.org:statusnet/mainline into 0.9.x
[quix0rs-gnu-social.git] / extlib / OAuth.php
index 6dc6b3f356faf87d243132ec5f82e6f161e4a194..648627b57637f34ed93ea66d226c9244cc396931 100644 (file)
@@ -16,6 +16,10 @@ class OAuthConsumer {/*{{{*/
     $this->secret = $secret;
     $this->callback_url = $callback_url;
   }/*}}}*/
+
+  function __toString() {/*{{{*/
+    return "OAuthConsumer[key=$this->key,secret=$this->secret]";
+  }/*}}}*/
 }/*}}}*/
 
 class OAuthToken {/*{{{*/
@@ -37,8 +41,8 @@ class OAuthToken {/*{{{*/
    * would respond to request_token and access_token calls with
    */
   function to_string() {/*{{{*/
-    return "oauth_token=" . OAuthUtil::urlencodeRFC3986($this->key) . 
-        "&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret);
+    return "oauth_token=" . OAuthUtil::urlencode_rfc3986($this->key) . 
+        "&oauth_token_secret=" . OAuthUtil::urlencode_rfc3986($this->secret);
   }/*}}}*/
 
   function __toString() {/*{{{*/
@@ -67,7 +71,7 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/
       ($token) ? $token->secret : ""
     );
 
-    $key_parts = array_map(array('OAuthUtil','urlencodeRFC3986'), $key_parts);
+    $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
     $key = implode('&', $key_parts);
 
     return base64_encode( hash_hmac('sha1', $base_string, $key, true));
@@ -81,11 +85,11 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/
 
   public function build_signature($request, $consumer, $token) {/*{{{*/
     $sig = array(
-      OAuthUtil::urlencodeRFC3986($consumer->secret)
+      OAuthUtil::urlencode_rfc3986($consumer->secret)
     );
 
     if ($token) {
-      array_push($sig, OAuthUtil::urlencodeRFC3986($token->secret));
+      array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret));
     } else {
       array_push($sig, '');
     }
@@ -94,7 +98,7 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod {/*{{{*/
     // for debug purposes
     $request->base_string = $raw;
 
-    return OAuthUtil::urlencodeRFC3986($raw);
+    return OAuthUtil::urlencode_rfc3986($raw);
   }/*}}}*/
 }/*}}}*/
 
@@ -182,7 +186,7 @@ class OAuthRequest {/*{{{*/
    */
   public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {/*{{{*/
     $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https';
-    @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+    @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI'];
     @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
     
     $request_headers = OAuthRequest::get_headers();
@@ -192,27 +196,24 @@ class OAuthRequest {/*{{{*/
     // do this
     if ($parameters) {
       $req = new OAuthRequest($http_method, $http_url, $parameters);
+    } else {
+      // collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority)
+      $req_parameters = $_GET;
+      if ($http_method == "POST" &&
+        ( @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") || @strstr($_ENV["CONTENT_TYPE"], "application/x-www-form-urlencoded") )) {
+        $req_parameters = array_merge($req_parameters, $_POST);
+      }
+
+      // next check for the auth header, we need to do some extra stuff
+      // if that is the case, namely suck in the parameters from GET or POST
+      // so that we can include them in the signature
+      if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") {
+        $header_parameters = OAuthRequest::split_header($request_headers['Authorization']);
+        $parameters = array_merge($req_parameters, $header_parameters);
+        $req = new OAuthRequest($http_method, $http_url, $parameters);
+      } else $req = new OAuthRequest($http_method, $http_url, $req_parameters);
     }
-    // next check for the auth header, we need to do some extra stuff
-    // if that is the case, namely suck in the parameters from GET or POST
-    // so that we can include them in the signature
-    else if (@substr($request_headers['Authorization'], 0, 5) == "OAuth") {
-      $header_parameters = OAuthRequest::split_header($request_headers['Authorization']);
-      if ($http_method == "GET") {
-        $req_parameters = $_GET;
-      } 
-      else if ($http_method == "POST") {
-        $req_parameters = $_POST;
-      } 
-      $parameters = array_merge($header_parameters, $req_parameters);
-      $req = new OAuthRequest($http_method, $http_url, $parameters);
-    }
-    else if ($http_method == "GET") {
-      $req = new OAuthRequest($http_method, $http_url, $_GET);
-    }
-    else if ($http_method == "POST") {
-      $req = new OAuthRequest($http_method, $http_url, $_POST);
-    }
+
     return $req;
   }/*}}}*/
 
@@ -238,7 +239,7 @@ class OAuthRequest {/*{{{*/
   }/*}}}*/
 
   public function get_parameter($name) {/*{{{*/
-    return $this->parameters[$name];
+    return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
   }/*}}}*/
 
   public function get_parameters() {/*{{{*/
@@ -267,12 +268,12 @@ class OAuthRequest {/*{{{*/
     }
                
     // Urlencode both keys and values
-    $keys = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_keys($params));
-    $values = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_values($params));
+    $keys = OAuthUtil::urlencode_rfc3986(array_keys($params));
+    $values = OAuthUtil::urlencode_rfc3986(array_values($params));
     $params = array_combine($keys, $values);
 
     // Sort by keys (natsort)
-    uksort($params, 'strnatcmp');
+    uksort($params, 'strcmp');
 
     // Generate key=value pairs
     $pairs = array();
@@ -307,7 +308,7 @@ class OAuthRequest {/*{{{*/
       $this->get_signable_parameters()
     );
 
-    $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $parts);
+    $parts = OAuthUtil::urlencode_rfc3986($parts);
 
     return implode('&', $parts);
   }/*}}}*/
@@ -326,7 +327,7 @@ class OAuthRequest {/*{{{*/
   public function get_normalized_http_url() {/*{{{*/
     $parts = parse_url($this->http_url);
 
-    $port = @$parts['port'];
+    $port = isset($parts['port']) ? $parts['port'] : null;
     $scheme = $parts['scheme'];
     $host = $parts['host'];
     $path = @$parts['path'];
@@ -351,11 +352,21 @@ class OAuthRequest {/*{{{*/
 
   /**
    * builds the data one would send in a POST request
+   *
+   * TODO(morten.fangel):
+   * this function might be easily replaced with http_build_query()
+   * and corrections for rfc3986 compatibility.. but not sure
    */
   public function to_postdata() {/*{{{*/
     $total = array();
     foreach ($this->parameters as $k => $v) {
-      $total[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v);
+      if (is_array($v)) {
+        foreach ($v as $va) {
+          $total[] = OAuthUtil::urlencode_rfc3986($k) . "[]=" . OAuthUtil::urlencode_rfc3986($va);
+        }
+      } else {
+        $total[] = OAuthUtil::urlencode_rfc3986($k) . "=" . OAuthUtil::urlencode_rfc3986($v);
+      }
     }
     $out = implode("&", $total);
     return $out;
@@ -364,12 +375,13 @@ class OAuthRequest {/*{{{*/
   /**
    * builds the Authorization: header
    */
-  public function to_header($realm="") {/*{{{*/
-    $out ='"Authorization: OAuth realm="' . $realm . '",';
+  public function to_header() {/*{{{*/
+    $out ='Authorization: OAuth realm=""';
     $total = array();
     foreach ($this->parameters as $k => $v) {
       if (substr($k, 0, 5) != "oauth") continue;
-      $out .= ',' . OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::urlencodeRFC3986($v) . '"';
+      if (is_array($v)) throw new OAuthException('Arrays not supported in headers');
+      $out .= ',' . OAuthUtil::urlencode_rfc3986($k) . '="' . OAuthUtil::urlencode_rfc3986($v) . '"';
     }
     return $out;
   }/*}}}*/
@@ -412,24 +424,22 @@ class OAuthRequest {/*{{{*/
    * parameters, has to do some unescaping
    */
   private static function split_header($header) {/*{{{*/
-    // remove 'OAuth ' at the start of a header 
-    $header = substr($header, 6); 
-
-    // error cases: commas in parameter values?
-    $parts = explode(",", $header);
-    $out = array();
-    foreach ($parts as $param) {
-      $param = ltrim($param);
-      // skip the "realm" param, nobody ever uses it anyway
-      if (substr($param, 0, 5) != "oauth") continue;
-
-      $param_parts = explode("=", $param);
-
-      // rawurldecode() used because urldecode() will turn a "+" in the
-      // value into a space
-      $out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, -1));
+    $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/';
+    $offset = 0;
+    $params = array();
+    while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
+      $match = $matches[0];
+      $header_name = $matches[2][0];
+      $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0];
+      $params[$header_name] = OAuthUtil::urldecode_rfc3986( $header_content );
+      $offset = $match[1] + strlen($match[0]);
     }
-    return $out;
+  
+    if (isset($params['realm'])) {
+       unset($params['realm']);
+    }
+
+    return $params;
   }/*}}}*/
 
   /**
@@ -506,6 +516,7 @@ class OAuthServer {/*{{{*/
     // requires authorized request token
     $token = $this->get_token($request, $consumer, "request");
 
+
     $this->check_signature($request, $consumer, $token);
 
     $new_token = $this->data_store->new_access_token($token, $consumer);
@@ -654,11 +665,11 @@ class OAuthDataStore {/*{{{*/
     // implement me
   }/*}}}*/
 
-  function fetch_request_token($consumer) {/*{{{*/
+  function new_request_token($consumer) {/*{{{*/
     // return a new token attached to this consumer
   }/*}}}*/
 
-  function fetch_access_token($token, $consumer) {/*{{{*/
+  function new_access_token($token, $consumer) {/*{{{*/
     // return a new access token attached to this consumer
     // for the user associated with this token if the request token
     // is authorized
@@ -737,17 +748,22 @@ class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/
 }/*}}}*/
 
 class OAuthUtil {/*{{{*/
-  public static function urlencodeRFC3986($string) {/*{{{*/
-    return str_replace('+', ' ',
-                       str_replace('%7E', '~', rawurlencode($string)));
-    
+  public static function urlencode_rfc3986($input) {/*{{{*/
+       if (is_array($input)) {
+               return array_map(array('OAuthUtil','urlencode_rfc3986'), $input);
+       } else if (is_scalar($input)) {
+               return str_replace('+', ' ',
+                              str_replace('%7E', '~', rawurlencode($input)));
+       } else {
+               return '';
+       }
   }/*}}}*/
     
 
   // This decode function isn't taking into consideration the above 
   // modifications to the encoding process. However, this method doesn't 
   // seem to be used anywhere so leaving it as is.
-  public static function urldecodeRFC3986($string) {/*{{{*/
+  public static function urldecode_rfc3986($string) {/*{{{*/
     return rawurldecode($string);
   }/*}}}*/
 }/*}}}*/