oauthclient.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <?php
  2. /**
  3. * StatusNet, the distributed open-source microblogging tool
  4. *
  5. * Base class for doing OAuth calls as a consumer
  6. *
  7. * PHP version 5
  8. *
  9. * LICENCE: This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Affero General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Affero General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Affero General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. * @category Action
  23. * @package StatusNet
  24. * @author Zach Copley <zach@status.net>
  25. * @copyright 2009 StatusNet, Inc.
  26. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  27. * @link http://status.net/
  28. */
  29. if (!defined('STATUSNET') && !defined('LACONICA')) {
  30. exit(1);
  31. }
  32. require_once 'OAuth.php';
  33. /**
  34. * Exception wrapper for cURL errors
  35. *
  36. * @category Integration
  37. * @package StatusNet
  38. * @author Zach Copley <zach@status.net>
  39. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  40. * @link http://status.net/
  41. *
  42. */
  43. class OAuthClientException extends Exception
  44. {
  45. }
  46. /**
  47. * Base class for doing OAuth calls as a consumer
  48. *
  49. * @category Integration
  50. * @package StatusNet
  51. * @author Zach Copley <zach@status.net>
  52. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  53. * @link http://status.net/
  54. *
  55. */
  56. class OAuthClient
  57. {
  58. var $consumer;
  59. var $token;
  60. /**
  61. * Constructor
  62. *
  63. * Can be initialized with just consumer key and secret for requesting new
  64. * tokens or with additional request token or access token
  65. *
  66. * @param string $consumer_key consumer key
  67. * @param string $consumer_secret consumer secret
  68. * @param string $oauth_token user's token
  69. * @param string $oauth_token_secret user's secret
  70. *
  71. * @return nothing
  72. */
  73. function __construct($consumer_key, $consumer_secret,
  74. $oauth_token = null, $oauth_token_secret = null)
  75. {
  76. $this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
  77. $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
  78. $this->token = null;
  79. if (isset($oauth_token) && isset($oauth_token_secret)) {
  80. $this->token = new OAuthToken($oauth_token, $oauth_token_secret);
  81. }
  82. }
  83. /**
  84. * Gets a request token from the given url
  85. *
  86. * @param string $url OAuth endpoint for grabbing request tokens
  87. * @param string $callback authorized request token callback
  88. *
  89. * @return OAuthToken $token the request token
  90. */
  91. function getRequestToken($url, $callback = null)
  92. {
  93. $params = null;
  94. if (!is_null($callback)) {
  95. $params['oauth_callback'] = $callback;
  96. }
  97. $response = $this->oAuthGet($url, $params);
  98. $arr = array();
  99. parse_str($response, $arr);
  100. $token = $arr['oauth_token'];
  101. $secret = $arr['oauth_token_secret'];
  102. $confirm = $arr['oauth_callback_confirmed'];
  103. if (isset($token) && isset($secret)) {
  104. $token = new OAuthToken($token, $secret);
  105. if (isset($confirm)) {
  106. if ($confirm == 'true') {
  107. return $token;
  108. } else {
  109. throw new OAuthClientException(
  110. 'Callback was not confirmed by remote OAuth side.'
  111. );
  112. }
  113. }
  114. return $token;
  115. } else {
  116. throw new OAuthClientException(
  117. 'Could not get a request token from remote OAuth side.'
  118. );
  119. }
  120. }
  121. /**
  122. * Builds a link that can be redirected to in order to
  123. * authorize a request token.
  124. *
  125. * @param string $url endpoint for authorizing request tokens
  126. * @param OAuthToken $request_token the request token to be authorized
  127. *
  128. * @return string $authorize_url the url to redirect to
  129. */
  130. function getAuthorizeLink($url, $request_token)
  131. {
  132. $authorize_url = $url . '?oauth_token=' .
  133. $request_token->key;
  134. return $authorize_url;
  135. }
  136. /**
  137. * Fetches an access token
  138. *
  139. * @param string $url OAuth endpoint for exchanging authorized request tokens
  140. * for access tokens
  141. * @param string $verifier 1.0a verifier
  142. *
  143. * @return OAuthToken $token the access token
  144. */
  145. function getAccessToken($url, $verifier = null)
  146. {
  147. $params = array();
  148. if (!is_null($verifier)) {
  149. $params['oauth_verifier'] = $verifier;
  150. }
  151. $response = $this->oAuthPost($url, $params);
  152. $arr = array();
  153. parse_str($response, $arr);
  154. $token = $arr['oauth_token'];
  155. $secret = $arr['oauth_token_secret'];
  156. if (isset($token) && isset($secret)) {
  157. $token = new OAuthToken($token, $secret);
  158. return $token;
  159. } else {
  160. throw new OAuthClientException(
  161. 'Could not get a access token from remote OAuth side.'
  162. );
  163. }
  164. }
  165. /**
  166. * Use HTTP GET to make a signed OAuth requesta
  167. *
  168. * @param string $url OAuth request token endpoint
  169. * @param array $params additional parameters
  170. *
  171. * @return mixed the request
  172. */
  173. function oAuthGet($url, $params = null)
  174. {
  175. $request = OAuthRequest::from_consumer_and_token($this->consumer,
  176. $this->token, 'GET', $url, $params);
  177. $request->sign_request($this->sha1_method,
  178. $this->consumer, $this->token);
  179. return $this->httpRequest($request->to_url());
  180. }
  181. /**
  182. * Use HTTP POST to make a signed OAuth request
  183. *
  184. * @param string $url OAuth endpoint
  185. * @param array $params additional post parameters
  186. *
  187. * @return mixed the request
  188. */
  189. function oAuthPost($url, $params = null)
  190. {
  191. $request = OAuthRequest::from_consumer_and_token($this->consumer,
  192. $this->token, 'POST', $url, $params);
  193. $request->sign_request($this->sha1_method,
  194. $this->consumer, $this->token);
  195. return $this->httpRequest($request->get_normalized_http_url(),
  196. $request->to_postdata());
  197. }
  198. /**
  199. * Make a HTTP request.
  200. *
  201. * @param string $url Where to make the
  202. * @param array $params post parameters
  203. *
  204. * @return mixed the request
  205. */
  206. function httpRequest($url, $params = null)
  207. {
  208. $request = new HTTPClient($url);
  209. $request->setConfig(array(
  210. 'connect_timeout' => 120,
  211. 'timeout' => 120,
  212. 'follow_redirects' => true,
  213. 'ssl_verify_peer' => false,
  214. 'ssl_verify_host' => false
  215. ));
  216. // Twitter was strict about accepting invalid "Expect" headers
  217. // between 2008ish and October 2012. Caused "417 Expectation failed"
  218. //$request->setHeader('Expect', '');
  219. if (isset($params)) {
  220. $request->setMethod(HTTP_Request2::METHOD_POST);
  221. $request->setBody($params);
  222. }
  223. try {
  224. $response = $request->send();
  225. $code = $response->getStatus();
  226. if ($code < 200 || $code >= 400) {
  227. throw new OAuthClientException($response->getBody(), $code);
  228. }
  229. return $response->getBody();
  230. } catch (Exception $e) {
  231. throw new OAuthClientException($e->getMessage(), $e->getCode());
  232. }
  233. }
  234. }