OAuthRequest.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. class OAuthRequest {
  3. protected $parameters;
  4. protected $http_method;
  5. protected $http_url;
  6. // for debug purposes
  7. public $base_string;
  8. public static $version = '1.0';
  9. public static $POST_INPUT = 'php://input';
  10. function __construct($http_method, $http_url, $parameters=NULL) {
  11. $parameters = ($parameters) ? $parameters : array();
  12. $parameters = array_merge( OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
  13. $this->parameters = $parameters;
  14. $this->http_method = $http_method;
  15. $this->http_url = $http_url;
  16. }
  17. /**
  18. * attempt to build up a request from what was passed to the server
  19. */
  20. public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {
  21. $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
  22. ? 'http'
  23. : 'https';
  24. $http_url = ($http_url) ? $http_url : $scheme .
  25. '://' . $_SERVER['SERVER_NAME'] .
  26. ':' .
  27. $_SERVER['SERVER_PORT'] .
  28. $_SERVER['REQUEST_URI'];
  29. $http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD'];
  30. // We weren't handed any parameters, so let's find the ones relevant to
  31. // this request.
  32. // If you run XML-RPC or similar you should use this to provide your own
  33. // parsed parameter-list
  34. if (!$parameters) {
  35. // Find request headers
  36. $request_headers = OAuthUtil::get_headers();
  37. // Parse the query-string to find GET parameters
  38. $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']);
  39. // It's a POST request of the proper content-type, so parse POST
  40. // parameters and add those overriding any duplicates from GET
  41. if ($http_method == "POST"
  42. && isset($request_headers['Content-Type'])
  43. && strstr($request_headers['Content-Type'],
  44. 'application/x-www-form-urlencoded')
  45. ) {
  46. $post_data = OAuthUtil::parse_parameters(
  47. file_get_contents(self::$POST_INPUT)
  48. );
  49. $parameters = array_merge($parameters, $post_data);
  50. }
  51. // We have a Authorization-header with OAuth data. Parse the header
  52. // and add those overriding any duplicates from GET or POST
  53. if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') {
  54. $header_parameters = OAuthUtil::split_header(
  55. $request_headers['Authorization']
  56. );
  57. $parameters = array_merge($parameters, $header_parameters);
  58. }
  59. }
  60. return new OAuthRequest($http_method, $http_url, $parameters);
  61. }
  62. /**
  63. * pretty much a helper function to set up the request
  64. */
  65. public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {
  66. $parameters = ($parameters) ? $parameters : array();
  67. $defaults = array("oauth_version" => OAuthRequest::$version,
  68. "oauth_nonce" => OAuthRequest::generate_nonce(),
  69. "oauth_timestamp" => OAuthRequest::generate_timestamp(),
  70. "oauth_consumer_key" => $consumer->key);
  71. if ($token)
  72. $defaults['oauth_token'] = $token->key;
  73. $parameters = array_merge($defaults, $parameters);
  74. return new OAuthRequest($http_method, $http_url, $parameters);
  75. }
  76. public function set_parameter($name, $value, $allow_duplicates = true) {
  77. if ($allow_duplicates && isset($this->parameters[$name])) {
  78. // We have already added parameter(s) with this name, so add to the list
  79. if (is_scalar($this->parameters[$name])) {
  80. // This is the first duplicate, so transform scalar (string)
  81. // into an array so we can add the duplicates
  82. $this->parameters[$name] = array($this->parameters[$name]);
  83. }
  84. $this->parameters[$name][] = $value;
  85. } else {
  86. $this->parameters[$name] = $value;
  87. }
  88. }
  89. public function get_parameter($name) {
  90. return isset($this->parameters[$name]) ? $this->parameters[$name] : null;
  91. }
  92. public function get_parameters() {
  93. return $this->parameters;
  94. }
  95. public function unset_parameter($name) {
  96. unset($this->parameters[$name]);
  97. }
  98. /**
  99. * The request parameters, sorted and concatenated into a normalized string.
  100. * @return string
  101. */
  102. public function get_signable_parameters() {
  103. // Grab all parameters
  104. $params = $this->parameters;
  105. // Remove oauth_signature if present
  106. // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.")
  107. if (isset($params['oauth_signature'])) {
  108. unset($params['oauth_signature']);
  109. }
  110. return OAuthUtil::build_http_query($params);
  111. }
  112. /**
  113. * Returns the base string of this request
  114. *
  115. * The base string defined as the method, the url
  116. * and the parameters (normalized), each urlencoded
  117. * and the concated with &.
  118. */
  119. public function get_signature_base_string() {
  120. $parts = array(
  121. $this->get_normalized_http_method(),
  122. $this->get_normalized_http_url(),
  123. $this->get_signable_parameters()
  124. );
  125. $parts = OAuthUtil::urlencode_rfc3986($parts);
  126. return implode('&', $parts);
  127. }
  128. /**
  129. * just uppercases the http method
  130. */
  131. public function get_normalized_http_method() {
  132. return strtoupper($this->http_method);
  133. }
  134. /**
  135. * parses the url and rebuilds it to be
  136. * scheme://host/path
  137. */
  138. public function get_normalized_http_url() {
  139. $parts = parse_url($this->http_url);
  140. $scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
  141. $port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
  142. $host = (isset($parts['host'])) ? strtolower($parts['host']) : '';
  143. $path = (isset($parts['path'])) ? $parts['path'] : '';
  144. if (($scheme == 'https' && $port != '443')
  145. || ($scheme == 'http' && $port != '80')) {
  146. $host = "$host:$port";
  147. }
  148. return "$scheme://$host$path";
  149. }
  150. /**
  151. * builds a url usable for a GET request
  152. */
  153. public function to_url() {
  154. $post_data = $this->to_postdata();
  155. $out = $this->get_normalized_http_url();
  156. if ($post_data) {
  157. $out .= '?'.$post_data;
  158. }
  159. return $out;
  160. }
  161. /**
  162. * builds the data one would send in a POST request
  163. */
  164. public function to_postdata() {
  165. return OAuthUtil::build_http_query($this->parameters);
  166. }
  167. /**
  168. * builds the Authorization: header
  169. */
  170. public function to_header($realm=null) {
  171. $first = true;
  172. if($realm) {
  173. $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
  174. $first = false;
  175. } else
  176. $out = 'Authorization: OAuth';
  177. $total = array();
  178. foreach ($this->parameters as $k => $v) {
  179. if (substr($k, 0, 5) != "oauth") continue;
  180. if (is_array($v)) {
  181. throw new OAuthException('Arrays not supported in headers');
  182. }
  183. $out .= ($first) ? ' ' : ',';
  184. $out .= OAuthUtil::urlencode_rfc3986($k) .
  185. '="' .
  186. OAuthUtil::urlencode_rfc3986($v) .
  187. '"';
  188. $first = false;
  189. }
  190. return $out;
  191. }
  192. public function __toString() {
  193. return $this->to_url();
  194. }
  195. public function sign_request($signature_method, $consumer, $token) {
  196. $this->set_parameter(
  197. "oauth_signature_method",
  198. $signature_method->get_name(),
  199. false
  200. );
  201. $signature = $this->build_signature($signature_method, $consumer, $token);
  202. $this->set_parameter("oauth_signature", $signature, false);
  203. }
  204. public function build_signature($signature_method, $consumer, $token) {
  205. $signature = $signature_method->build_signature($this, $consumer, $token);
  206. return $signature;
  207. }
  208. /**
  209. * util function: current timestamp
  210. */
  211. private static function generate_timestamp() {
  212. return time();
  213. }
  214. /**
  215. * util function: current nonce
  216. */
  217. private static function generate_nonce() {
  218. $mt = microtime();
  219. $rand = mt_rand();
  220. return md5($mt . $rand); // md5s look nicer than numbers
  221. }
  222. }