Curl.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <?php
  2. /**
  3. * Dropbox OAuth
  4. *
  5. * @package Dropbox
  6. * @copyright Copyright (C) 2011 Daniel Huesken
  7. * @author Daniel Huesken (http://www.danielhuesken.de/)
  8. * @license MIT
  9. */
  10. /**
  11. * This class is used to sign all requests to dropbox.
  12. *
  13. * This specific class uses WordPress WP_Http to authenticate.
  14. */
  15. class Dropbox_OAuth_Curl extends Dropbox_OAuth {
  16. /**
  17. *
  18. * @var string ConsumerKey
  19. */
  20. protected $consumerKey = null;
  21. /**
  22. *
  23. * @var string ConsumerSecret
  24. */
  25. protected $consumerSecret = null;
  26. /**
  27. *
  28. * @var string ProzessCallBack
  29. */
  30. public $ProgressFunction = false;
  31. /**
  32. * Constructor
  33. *
  34. * @param string $consumerKey
  35. * @param string $consumerSecret
  36. */
  37. public function __construct($consumerKey, $consumerSecret) {
  38. if (!function_exists('curl_exec'))
  39. throw new Dropbox_Exception('The PHP curl functions not available!');
  40. $this->consumerKey = $consumerKey;
  41. $this->consumerSecret = $consumerSecret;
  42. }
  43. /**
  44. * Fetches a secured oauth url and returns the response body.
  45. *
  46. * @param string $uri
  47. * @param mixed $arguments
  48. * @param string $method
  49. * @param array $httpHeaders
  50. * @return string
  51. */
  52. public function fetch($uri, $arguments = array(), $method = 'GET', $httpHeaders = array()) {
  53. $uri=str_replace('http://', 'https://', $uri); // all https, upload makes problems if not
  54. if (is_string($arguments) and strtoupper($method) == 'POST') {
  55. preg_match("/\?file=(.*)$/i", $uri, $matches);
  56. if (isset($matches[1])) {
  57. $uri = str_replace($matches[0], "", $uri);
  58. $filename = $matches[1];
  59. $httpHeaders=array_merge($httpHeaders,$this->getOAuthHeader($uri, array("file" => $filename), $method));
  60. }
  61. } else {
  62. $httpHeaders=array_merge($httpHeaders,$this->getOAuthHeader($uri, $arguments, $method));
  63. }
  64. $ch = curl_init();
  65. if (strtoupper($method) == 'POST') {
  66. curl_setopt($ch, CURLOPT_URL, $uri);
  67. curl_setopt($ch, CURLOPT_POST, true);
  68. // if (is_array($arguments))
  69. // $arguments=http_build_query($arguments);
  70. curl_setopt($ch, CURLOPT_POSTFIELDS, $arguments);
  71. // $httpHeaders['Content-Length']=strlen($arguments);
  72. } else {
  73. curl_setopt($ch, CURLOPT_URL, $uri.'?'.http_build_query($arguments));
  74. curl_setopt($ch, CURLOPT_POST, false);
  75. }
  76. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  77. curl_setopt($ch, CURLOPT_TIMEOUT, 300);
  78. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
  79. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  80. // curl_setopt($ch, CURLOPT_CAINFO, "rootca");
  81. curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
  82. //Build header
  83. $headers = array();
  84. foreach ($httpHeaders as $name => $value) {
  85. $headers[] = "{$name}: $value";
  86. }
  87. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  88. if (!ini_get('safe_mode') && !ini_get('open_basedir'))
  89. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true );
  90. if (function_exists($this->ProgressFunction) and defined('CURLOPT_PROGRESSFUNCTION')) {
  91. curl_setopt($ch, CURLOPT_NOPROGRESS, false);
  92. curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, $this->ProgressFunction);
  93. curl_setopt($ch, CURLOPT_BUFFERSIZE, 512);
  94. }
  95. $response=curl_exec($ch);
  96. $errorno=curl_errno($ch);
  97. $error=curl_error($ch);
  98. $status=curl_getinfo($ch,CURLINFO_HTTP_CODE);
  99. curl_close($ch);
  100. if (!empty($errorno))
  101. throw new Dropbox_Exception_NotFound('Curl error: ('.$errorno.') '.$error."\n");
  102. if ($status>=300) {
  103. $body = json_decode($response,true);
  104. switch ($status) {
  105. // Not modified
  106. case 304 :
  107. return array(
  108. 'httpStatus' => 304,
  109. 'body' => null,
  110. );
  111. break;
  112. case 403 :
  113. throw new Dropbox_Exception_Forbidden('Forbidden.
  114. This could mean a bad OAuth request, or a file or folder already existing at the target location.
  115. ' . $body["error"] . "\n");
  116. case 404 :
  117. throw new Dropbox_Exception_NotFound('Resource at uri: ' . $uri . ' could not be found. ' .
  118. $body["error"] . "\n");
  119. case 507 :
  120. throw new Dropbox_Exception_OverQuota('This dropbox is full. ' .
  121. $body["error"] . "\n");
  122. }
  123. if (!empty($body["error"]))
  124. throw new Dropbox_Exception_RequestToken('Error: ('.$status.') '.$body["error"]."\n");
  125. }
  126. return array(
  127. 'body' => $response,
  128. 'httpStatus' => $status
  129. );
  130. }
  131. /**
  132. * Returns named array with oauth parameters for further use
  133. * @return array Array with oauth_ parameters
  134. */
  135. private function getOAuthBaseParams() {
  136. $params['oauth_version'] = '1.0';
  137. $params['oauth_signature_method'] = 'HMAC-SHA1';
  138. $params['oauth_consumer_key'] = $this->consumerKey;
  139. $tokens = $this->getToken();
  140. if (isset($tokens['token']) && $tokens['token']) {
  141. $params['oauth_token'] = $tokens['token'];
  142. }
  143. $params['oauth_timestamp'] = time();
  144. $params['oauth_nonce'] = md5(microtime() . mt_rand());
  145. return $params;
  146. }
  147. /**
  148. * Creates valid Authorization header for OAuth, based on URI and Params
  149. *
  150. * @param string $uri
  151. * @param array $params
  152. * @param string $method GET or POST, standard is GET
  153. * @param array $oAuthParams optional, pass your own oauth_params here
  154. * @return array Array for request's headers section like
  155. * array('Authorization' => 'OAuth ...');
  156. */
  157. private function getOAuthHeader($uri, $params, $method = 'GET', $oAuthParams = null) {
  158. $oAuthParams = $oAuthParams ? $oAuthParams : $this->getOAuthBaseParams();
  159. // create baseString to encode for the sent parameters
  160. $baseString = $method . '&';
  161. $baseString .= $this->oauth_urlencode($uri) . "&";
  162. // OAuth header does not include GET-Parameters
  163. $signatureParams = array_merge($params, $oAuthParams);
  164. // sorting the parameters
  165. ksort($signatureParams);
  166. $encodedParams = array();
  167. foreach ($signatureParams as $key => $value) {
  168. $encodedParams[] = $this->oauth_urlencode($key) . '=' . $this->oauth_urlencode($value);
  169. }
  170. $baseString .= $this->oauth_urlencode(implode('&', $encodedParams));
  171. // encode the signature
  172. $tokens = $this->getToken();
  173. $hash = $this->hash_hmac_sha1($this->consumerSecret.'&'.$tokens['token_secret'], $baseString);
  174. $signature = base64_encode($hash);
  175. // add signature to oAuthParams
  176. $oAuthParams['oauth_signature'] = $signature;
  177. $oAuthEncoded = array();
  178. foreach ($oAuthParams as $key => $value) {
  179. $oAuthEncoded[] = $key . '="' . $this->oauth_urlencode($value) . '"';
  180. }
  181. return array('Authorization' => 'OAuth ' . implode(', ', $oAuthEncoded));
  182. }
  183. /**
  184. * Requests the OAuth request token.
  185. *
  186. * @return void
  187. */
  188. public function getRequestToken() {
  189. $result = $this->fetch(self::URI_REQUEST_TOKEN, array(), 'POST');
  190. if ($result['httpStatus'] == "200") {
  191. $tokens = array();
  192. parse_str($result['body'], $tokens);
  193. $this->setToken($tokens['oauth_token'], $tokens['oauth_token_secret']);
  194. return $this->getToken();
  195. } else {
  196. throw new Dropbox_Exception_RequestToken('We were unable to fetch request tokens. This likely means that your consumer key and/or secret are incorrect.');
  197. }
  198. }
  199. /**
  200. * Requests the OAuth access tokens.
  201. *
  202. * This method requires the 'unauthorized' request tokens
  203. * and, if successful will set the authorized request tokens.
  204. *
  205. * @return void
  206. */
  207. public function getAccessToken() {
  208. $result = $this->fetch(self::URI_ACCESS_TOKEN, array(), 'POST');
  209. if ($result['httpStatus'] == "200") {
  210. $tokens = array();
  211. parse_str($result['body'], $tokens);
  212. $this->setToken($tokens['oauth_token'], $tokens['oauth_token_secret']);
  213. return $this->getToken();
  214. } else {
  215. throw new Dropbox_Exception_RequestToken('We were unable to fetch request tokens. This likely means that your consumer key and/or secret are incorrect.');
  216. }
  217. }
  218. /**
  219. * Helper function to properly urlencode parameters.
  220. * See http://php.net/manual/en/function.oauth-urlencode.php
  221. *
  222. * @param string $string
  223. * @return string
  224. */
  225. private function oauth_urlencode($string) {
  226. return str_replace('%E7', '~', rawurlencode($string));
  227. }
  228. /**
  229. * Hash function for hmac_sha1; uses native function if available.
  230. *
  231. * @param string $key
  232. * @param string $data
  233. * @return string
  234. */
  235. private function hash_hmac_sha1($key, $data) {
  236. if (function_exists('hash_hmac') && in_array('sha1', hash_algos())) {
  237. return hash_hmac('sha1', $data, $key, true);
  238. } else {
  239. $blocksize = 64;
  240. $hashfunc = 'sha1';
  241. if (strlen($key) > $blocksize) {
  242. $key = pack('H*', $hashfunc($key));
  243. }
  244. $key = str_pad($key, $blocksize, chr(0x00));
  245. $ipad = str_repeat(chr(0x36), $blocksize);
  246. $opad = str_repeat(chr(0x5c), $blocksize);
  247. $hash = pack('H*', $hashfunc(( $key ^ $opad ) . pack('H*', $hashfunc(($key ^ $ipad) . $data))));
  248. return $hash;
  249. }
  250. }
  251. }