1  <?php
  2  /* Copyright (c) 2013, Geert Bergman (geert@scrivo.nl)
  3   * All rights reserved.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions are met:
  7   *
  8   * 1. Redistributions of source code must retain the above copyright notice,
  9   *    this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright notice,
 11   *    this list of conditions and the following disclaimer in the documentation
 12   *    and/or other materials provided with the distribution.
 13   * 3. Neither the name of "Scrivo" nor the names of its contributors may be
 14   *    used to endorse or promote products derived from this software without
 15   *    specific prior written permission.
 16   *
 17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 18   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 19   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 20   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 21   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 22   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 23   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 24   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 25   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 26   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 27   * POSSIBILITY OF SUCH DAMAGE.
 28   *
 29   * $Id$
 30   */
 31  
 32  namespace Scrivo\Utilities;
 33  
 34  /**
 35   * Class that implements the OAuth 1.0 protocol. Using OAuth you can send
 36   * authorized requests to web services. This class implements some of these
 37   * authorization rules.
 38   *
 39   * Also see the OAuth rfc:
 40   *   1.0: (http://tools.ietf.org/html/rfc5849).
 41   * 
 42   * Example (using bogus values):
 43   * 
 44   * $oAuth = new OAuth(
 45   *   "xvz1evFS4wEEPTGEFPHBog", //< consumer key
 46   *   "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw", //< consumer secret
 47   *   "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", //< access token
 48   *   "LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE" //< access token secret
 49   * );
 50   * 
 51   * // Get the data to use for an authorized request.
 52   * $oAuthData = $oAuth->getAuthorizationData($requestMethod,
 53   *    "https://api.twitter.com/1.1/statuses/user_timeline.json?count=2");
 54   *
 55   * // This is the autorization header to use in your request:
 56   * echo $oAuthData->authorisationHeader;
 57   *
 58   */
 59  class OAuth {
 60  
 61      /**
 62       * The OAuth version (currently we're only supporting 1.0);
 63       * @var string
 64       */
 65      private $version "1.0";
 66  
 67      /**
 68       * The identifier portion of the client credentials (equivalent to
 69       * a username). The parameter name reflects a deprecated term
 70       * (Consumer Key) used in previous revisions of the specification,
 71       * and has been retained to maintain backward compatibility.
 72       * @link http://tools.ietf.org/html/rfc5849#page-15 reference
 73       * @var string
 74       */
 75      private $consumerKey null;
 76  
 77      /**
 78       * The client shared-secret, after being encoded
 79       * @var string
 80       */
 81      private $consumerSecret null;
 82  
 83      /**
 84       * The token value used to associate the request with the resource
 85       * owner. If the request is not associated with a resource owner
 86       * (no token available), clients MAY omit the parameter.
 87       * @link http://tools.ietf.org/html/rfc5849#page-15 reference
 88       * @var string
 89       */
 90      private $token null;
 91  
 92      /**
 93       * The token shared-secret, after being encoded
 94       * @var string
 95       */
 96      private $tokenSecret null;
 97      
 98      /**
 99       * Construct an OAuth object: an object that is able to do 
100       * authenticated requests.
101       * @param string $consumerKey The identifier portion of the client 
102       *   credentials (equivalent to a username).
103       * @param string $consumerSecret The client shared-secret.
104       * @param string $token The token value used to associate the request 
105       *   with the resource owner.
106       * @param string $tokenSecret The token shared-secret.
107       */
108      public function __construct(
109              $consumerKey$consumerSecret$token$tokenSecret) {
110          $this->consumerKey $consumerKey;
111          $this->consumerSecret $consumerSecret;
112          $this->token $token;
113          $this->tokenSecret $tokenSecret;
114      }
115      
116      /**
117       * A nonce is a random string, uniquely generated by the client to allow
118       * the server to verify that a request has never been made before and
119       * helps prevent replay attacks when requests are made over a non-secure
120       * channel.  The nonce value MUST be unique across all requests with the
121       * same timestamp, client credentials, and token combinations.
122       * @link http://tools.ietf.org/html/rfc5849#section-3.3 reference
123       * @return string A unique token to send with the request.
124       */
125      private function nonce() {
126          // Not really unique using an md5 hash, but good enough hopefully.
127          return hash("md5"mt_rand().time().mt_rand(), false);
128      }
129      
130      /**
131       * Return a percent encoded string.
132       * @link http://tools.ietf.org/html/rfc5849#section-3.6 reference
133       * @param string $toEncode The data to percent encode.
134       * @return string The percent encoded data.
135       */
136      private function encode($toEncode) {
137          return rawurlencode($toEncode);
138      }
139  
140      /**
141       * Percent encode an array of key/value pairs. The method allow for 
142       * different glues to glue the encoded sets of key/value pairs together
143       * (apmerand and comma for example). It is also possible to supply a 
144       * quotation mark for the values in the result string.
145       * @link http://tools.ietf.org/html/rfc5849#section-3.6 reference
146       * @param string[] $toEncode An array with key/value pairs.
147       * @param string[] $glue The glue to bind the key/value pairs.
148       * @param string $qoute An optional quotation sign for the value.
149       * @return string A string containing the percent encoded key/value pairs 
150       *   seperated by an '=' sign and glued together using the $glue parameter.
151       */
152      private function encodeKeyValuePairs(array $toEncode$glue$quote="") {
153          $res = array();
154          foreach ($toEncode as $k=>$v) {
155              $res[] = $this->encode($k)."=".$quote.$this->encode($v).$quote;  
156          }
157          return implode($glue$res);
158      }
159  
160      /**
161       * Normalize the collected parameters into a single string.
162       * @link http://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 reference
163       * @param string[] $oauthParam An array of OAuth key/value pairs.
164       * @param string[] $param An array of request parameter key/value pairs.
165       * @return string A string of percent encoded key/value pairs each 
166       *   seperated by an '=' sign and each pair seperated by an ampersand.
167       */
168      private function normalizeParam($oauthParam$param) {
169          $param += $oauthParam;
170          ksort($param);
171          return $this->encodeKeyValuePairs($param"&");
172      }
173  
174      /**
175       * The signature base string is a consistent, reproducible concatenation
176       * of several of the HTTP request elements into a single string. The
177       * string is used as an input to the "HMAC-SHA1" and "RSA-SHA1"
178       * signature methods.
179       * @link http://tools.ietf.org/html/rfc5849#section-3.4.1 reference
180       * @param string $requestMethod The HTTP request method to use in the
181       *   request.
182       * @param string $baseUrl The base URL of the request (= the request URL 
183       *   including the protocol, host and path but excluding the parameters).
184       * @param string[] $oauthParam An array of OAuth key/value pairs.
185       * @param string[] $param An array of request parameter key/value pairs.
186       * @return string The OAuth signature base string.
187       */
188      private function signatureBaseString(
189              $requestMethod$baseUrl$oauthParam$requestParam) {
190          return implode("&", array(strtoupper($requestMethod), 
191              $this->encode($baseUrl), $this->encode(
192                  $this->normalizeParam($oauthParam$requestParam))));
193      }
194      
195      /**
196       * Create the OAuth signature for a request.
197       * @link http://tools.ietf.org/html/rfc5849#section-3.4.2 reference
198       * @param string $requestMethod The HTTP request method to use in this 
199       *   Twitter API request.
200       * @param string $baseUrl The base URL of the Twitter API request (= the
201       *   request URL including the protocol, host and path but excluding the
202       *   parameters).
203       * @param string[] $oauthParam An array of OAuth key/value pairs.
204       * @param string[] $requestParam An array of request parameter key/value 
205       *   pairs.
206       * @return string The OAuth signature. 
207       */
208      private function sign(
209              $requestMethod$baseUrl$oauthParam$requestParam) {
210          return base64_encode(hash_hmac("sha1",
211              $this->signatureBaseString(
212                  $requestMethod$baseUrl$oauthParam$requestParam),
213              $this->consumerSecret."&".$this->tokenSecrettrue));
214      }
215      
216      /**
217       * Get the authorization request data for an OAuth reqeuest.
218       * @see https://dev.twitter.com/docs/auth/authorizing-request
219       * @param string $requestMethod The HTTP request method to use in the
220       *   request.
221       * @param string $baseUrl The base URL of the Twitter API request (= the
222       *   request URL including the protocol, host and path but excluding the
223       *   parameters).
224       * @param string[] $param An array of request parameter key/value 
225       *   pairs.
226       */
227      private function authorisationHeader($requestMethod$baseUrl$param) {
228          $o = array(
229              "oauth_consumer_key" => $this->consumerKey,
230              "oauth_token" => $this->token,
231              "oauth_version" => $this->version,
232              "oauth_timestamp" => time(),
233              "oauth_nonce" => $this->nonce(),
234              "oauth_signature_method" => "HMAC-SHA1");
235          $o["oauth_signature"] = 
236              $this->sign($requestMethod$baseUrl$o$param);
237          return "Authorization: OAuth " 238              $this->encodeKeyValuePairs($o", ""\"")."\r\n";
239      }
240  
241      /**
242       * Get the data for an OAuth 1.0 authorized request.
243       * @param string $requestMethod The HTTP request method to use in this 
244       *   request (GET or POST).
245       * @param string $url The URL for the request. Request parameters 
246       *   can be included in the URL.
247       *   Note: this is an unescaped URL: ampersands should be "&" (not "&amp;") 
248       *   and spaces should be " " (not "%20" or "+"), and this is not limited
249       *   to ampersands and spaces.
250       * @param string[] $param Optional extra request parameters given as a set
251       *   of name/value pairs. These parameters will get preceedence when 
252       *   name conflicts occur with parameters given in the $url parameter 
253       *   itself.
254       * @return object Object containting the following fields: 
255       *   authorisationHeader (string): The OAuth authorization header 
256       *      (including \r\n)
257       *   parameterString (string): The request parameters in an (percent 
258       *      encoded) application/x-www-form-urlencoded format.
259       *   baseUrl (string): The request URL without the parameters.
260       *   requestMethod (string): The request method (capitalized).
261       *   scheme (string): The request scheme.
262       *   hostname (string): The name of the host to send the request to.
263       */
264      public function getAuthorizationData(
265              $requestMethod$url, array $param=array()) {
266              
267          $requestMethod strtoupper($requestMethod);
268          $ud parse_url($url);
269          $baseUrl $ud["scheme"]."://".$ud["host"].$ud["path"];
270          if (isset($ud["query"])) {
271              parse_str($ud["query"], $param2);
272              $param += $param2;
273          }
274  
275          return (object)array(
276              "authorisationHeader" => 
277                  $this->authorisationHeader($requestMethod$baseUrl$param),
278              "parameterString" => 
279                  count($param) ? $this->encodeKeyValuePairs($param"&") : "",
280              "baseUrl" => $baseUrl,
281              "requestMethod" => $requestMethod,
282              "scheme" => $ud["scheme"],
283              "hostname" => $ud["host"]
284          );            
285              
286      }
287  }
288  
289  ?>

Documentation generated by phpDocumentor 2.0.0a12 and ScrivoDocumentor on August 29, 2013