OAuth.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. <?php
  2. // vim: foldmethod=marker
  3. /* Generic exception class
  4. */
  5. class OAuthException extends Exception {/*{{{*/
  6. // pass
  7. }/*}}}*/
  8. class OAuthConsumer {/*{{{*/
  9. public $key;
  10. public $secret;
  11. public function __construct($key, $secret, $callback_url=NULL) {/*{{{*/
  12. $this->key = $key;
  13. $this->secret = $secret;
  14. $this->callback_url = $callback_url;
  15. }/*}}}*/
  16. }/*}}}*/
  17. class OAuthToken {/*{{{*/
  18. // access tokens and request tokens
  19. public $key;
  20. public $secret;
  21. /**
  22. * key = the token
  23. * secret = the token secret
  24. */
  25. function __construct($key, $secret) {/*{{{*/
  26. $this->key = $key;
  27. $this->secret = $secret;
  28. }/*}}}*/
  29. /**
  30. * generates the basic string serialization of a token that a server
  31. * would respond to request_token and access_token calls with
  32. */
  33. function to_string() {/*{{{*/
  34. return "oauth_token=" . OAuthUtil::urlencodeRFC3986($this->key) .
  35. "&oauth_token_secret=" . OAuthUtil::urlencodeRFC3986($this->secret);
  36. }/*}}}*/
  37. function __toString() {/*{{{*/
  38. return $this->to_string();
  39. }/*}}}*/
  40. }/*}}}*/
  41. class OAuthSignatureMethod {/*{{{*/
  42. public function check_signature(&$request, $consumer, $token, $signature) {
  43. $built = $this->build_signature($request, $consumer, $token);
  44. return $built == $signature;
  45. }
  46. }/*}}}*/
  47. class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod {/*{{{*/
  48. function get_name() {/*{{{*/
  49. return "HMAC-SHA1";
  50. }/*}}}*/
  51. public function build_signature($request, $consumer, $token, $privKey=NULL) {/*{{{*/
  52. $base_string = $request->get_signature_base_string();
  53. $request->base_string = $base_string;
  54. $key_parts = array(
  55. $consumer->secret,
  56. ($token) ? $token->secret : ""
  57. );
  58. $key_parts = array_map(array('OAuthUtil','urlencodeRFC3986'), $key_parts);
  59. $key = implode('&', $key_parts);
  60. return base64_encode( hash_hmac('sha1', $base_string, $key, true));
  61. }/*}}}*/
  62. }/*}}}*/
  63. class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod {/*{{{*/
  64. public function get_name() {/*{{{*/
  65. return "RSA-SHA1";
  66. }/*}}}*/
  67. protected function fetch_public_cert(&$request) {/*{{{*/
  68. // not implemented yet, ideas are:
  69. // (1) do a lookup in a table of trusted certs keyed off of consumer
  70. // (2) fetch via http using a url provided by the requester
  71. // (3) some sort of specific discovery code based on request
  72. //
  73. // either way should return a string representation of the certificate
  74. throw Exception("fetch_public_cert not implemented");
  75. }/*}}}*/
  76. protected function fetch_private_cert($privKey) {//&$request) {/*{{{*/
  77. // not implemented yet, ideas are:
  78. // (1) do a lookup in a table of trusted certs keyed off of consumer
  79. //
  80. // either way should return a string representation of the certificate
  81. throw Exception("fetch_private_cert not implemented");
  82. }/*}}}*/
  83. public function build_signature(&$request, $consumer, $token, $privKey) {/*{{{*/
  84. $base_string = $request->get_signature_base_string();
  85. // Fetch the private key cert based on the request
  86. //$cert = $this->fetch_private_cert($consumer->privKey);
  87. //Pull the private key ID from the certificate
  88. //$privatekeyid = openssl_get_privatekey($cert);
  89. // hacked in
  90. if ($privKey == '') {
  91. $fp = fopen($GLOBALS['PRIV_KEY_FILE'], "r");
  92. $privKey = fread($fp, 8192);
  93. fclose($fp);
  94. }
  95. $privatekeyid = openssl_get_privatekey($privKey);
  96. //Check the computer signature against the one passed in the query
  97. $ok = openssl_sign($base_string, $signature, $privatekeyid);
  98. //Release the key resource
  99. openssl_free_key($privatekeyid);
  100. return base64_encode($signature);
  101. } /*}}}*/
  102. public function check_signature(&$request, $consumer, $token, $signature) {/*{{{*/
  103. $decoded_sig = base64_decode($signature);
  104. $base_string = $request->get_signature_base_string();
  105. // Fetch the public key cert based on the request
  106. $cert = $this->fetch_public_cert($request);
  107. //Pull the public key ID from the certificate
  108. $publickeyid = openssl_get_publickey($cert);
  109. //Check the computer signature against the one passed in the query
  110. $ok = openssl_verify($base_string, $decoded_sig, $publickeyid);
  111. //Release the key resource
  112. openssl_free_key($publickeyid);
  113. return $ok == 1;
  114. } /*}}}*/
  115. }/*}}}*/
  116. class OAuthRequest {/*{{{*/
  117. private $parameters;
  118. private $http_method;
  119. private $http_url;
  120. // for debug purposes
  121. public $base_string;
  122. public static $version = '1.0';
  123. function __construct($http_method, $http_url, $parameters=NULL) {/*{{{*/
  124. @$parameters or $parameters = array();
  125. $this->parameters = $parameters;
  126. $this->http_method = $http_method;
  127. $this->http_url = $http_url;
  128. }/*}}}*/
  129. /**
  130. * attempt to build up a request from what was passed to the server
  131. */
  132. public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) {/*{{{*/
  133. $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https';
  134. @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  135. @$http_method or $http_method = $_SERVER['REQUEST_METHOD'];
  136. $request_headers = OAuthRequest::get_headers();
  137. // let the library user override things however they'd like, if they know
  138. // which parameters to use then go for it, for example XMLRPC might want to
  139. // do this
  140. if ($parameters) {
  141. $req = new OAuthRequest($http_method, $http_url, $parameters);
  142. }
  143. // next check for the auth header, we need to do some extra stuff
  144. // if that is the case, namely suck in the parameters from GET or POST
  145. // so that we can include them in the signature
  146. else if (@substr($request_headers['Authorization'], 0, 5) == "OAuth") {
  147. $header_parameters = OAuthRequest::split_header($request_headers['Authorization']);
  148. if ($http_method == "GET") {
  149. $req_parameters = $_GET;
  150. }
  151. else if ($http_method = "POST") {
  152. $req_parameters = $_POST;
  153. }
  154. $parameters = array_merge($header_parameters, $req_parameters);
  155. $req = new OAuthRequest($http_method, $http_url, $parameters);
  156. }
  157. else if ($http_method == "GET") {
  158. $req = new OAuthRequest($http_method, $http_url, $_GET);
  159. }
  160. else if ($http_method == "POST") {
  161. $req = new OAuthRequest($http_method, $http_url, $_POST);
  162. }
  163. return $req;
  164. }/*}}}*/
  165. /**
  166. * pretty much a helper function to set up the request
  167. */
  168. public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) {/*{{{*/
  169. @$parameters or $parameters = array();
  170. $defaults = array("oauth_version" => OAuthRequest::$version,
  171. "oauth_nonce" => OAuthRequest::generate_nonce(),
  172. "oauth_timestamp" => OAuthRequest::generate_timestamp(),
  173. "oauth_consumer_key" => $consumer->key);
  174. $parameters = array_merge($defaults, $parameters);
  175. if ($token) {
  176. $parameters['oauth_token'] = $token->key;
  177. }
  178. // oauth v1.0a
  179. /*if (isset($_REQUEST['oauth_verifier'])) {
  180. $parameters['oauth_verifier'] = $_REQUEST['oauth_verifier'];
  181. }*/
  182. return new OAuthRequest($http_method, $http_url, $parameters);
  183. }/*}}}*/
  184. public function set_parameter($name, $value) {/*{{{*/
  185. $this->parameters[$name] = $value;
  186. }/*}}}*/
  187. public function get_parameter($name) {/*{{{*/
  188. return $this->parameters[$name];
  189. }/*}}}*/
  190. public function get_parameters() {/*{{{*/
  191. return $this->parameters;
  192. }/*}}}*/
  193. /**
  194. * Returns the normalized parameters of the request
  195. *
  196. * This will be all (except oauth_signature) parameters,
  197. * sorted first by key, and if duplicate keys, then by
  198. * value.
  199. *
  200. * The returned string will be all the key=value pairs
  201. * concated by &.
  202. *
  203. * @return string
  204. */
  205. public function get_signable_parameters() {/*{{{*/
  206. // Grab all parameters
  207. $params = $this->parameters;
  208. // Remove oauth_signature if present
  209. if (isset($params['oauth_signature'])) {
  210. unset($params['oauth_signature']);
  211. }
  212. // Urlencode both keys and values
  213. $keys = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_keys($params));
  214. $values = array_map(array('OAuthUtil', 'urlencodeRFC3986'), array_values($params));
  215. $params = array_combine($keys, $values);
  216. // Sort by keys (natsort)
  217. uksort($params, 'strnatcmp');
  218. if(isset($params['title']) && isset($params['title-exact'])) {
  219. $temp = $params['title-exact'];
  220. $title = $params['title'];
  221. unset($params['title']);
  222. unset($params['title-exact']);
  223. $params['title-exact'] = $temp;
  224. $params['title'] = $title;
  225. }
  226. // Generate key=value pairs
  227. $pairs = array();
  228. foreach ($params as $key=>$value ) {
  229. if (is_array($value)) {
  230. // If the value is an array, it's because there are multiple
  231. // with the same key, sort them, then add all the pairs
  232. natsort($value);
  233. foreach ($value as $v2) {
  234. $pairs[] = $key . '=' . $v2;
  235. }
  236. } else {
  237. $pairs[] = $key . '=' . $value;
  238. }
  239. }
  240. // Return the pairs, concated with &
  241. return implode('&', $pairs);
  242. }/*}}}*/
  243. /**
  244. * Returns the base string of this request
  245. *
  246. * The base string defined as the method, the url
  247. * and the parameters (normalized), each urlencoded
  248. * and the concated with &.
  249. */
  250. public function get_signature_base_string() {/*{{{*/
  251. $parts = array(
  252. $this->get_normalized_http_method(),
  253. $this->get_normalized_http_url(),
  254. $this->get_signable_parameters()
  255. );
  256. $parts = array_map(array('OAuthUtil', 'urlencodeRFC3986'), $parts);
  257. return implode('&', $parts);
  258. }/*}}}*/
  259. /**
  260. * just uppercases the http method
  261. */
  262. public function get_normalized_http_method() {/*{{{*/
  263. return strtoupper($this->http_method);
  264. }/*}}}*/
  265. /**
  266. * parses the url and rebuilds it to be
  267. * scheme://host/path
  268. */
  269. public function get_normalized_http_url() {
  270. $parts = parse_url($this->http_url);
  271. $scheme = (isset($parts['scheme'])) ? $parts['scheme'] : 'http';
  272. $port = (isset($parts['port'])) ? $parts['port'] : (($scheme == 'https') ? '443' : '80');
  273. $host = (isset($parts['host'])) ? strtolower($parts['host']) : '';
  274. $path = (isset($parts['path'])) ? $parts['path'] : '';
  275. if (($scheme == 'https' && $port != '443')
  276. || ($scheme == 'http' && $port != '80')) {
  277. $host = "$host:$port";
  278. }
  279. return "$scheme://$host$path";
  280. }
  281. /**
  282. * builds a url usable for a GET request
  283. */
  284. public function to_url() {/*{{{*/
  285. $out = $this->get_normalized_http_url() . "?";
  286. $out .= $this->to_postdata();
  287. return $out;
  288. }/*}}}*/
  289. /**
  290. * builds the data one would send in a POST request
  291. */
  292. public function to_postdata() {/*{{{*/
  293. $total = array();
  294. foreach ($this->parameters as $k => $v) {
  295. $total[] = OAuthUtil::urlencodeRFC3986($k) . "=" . OAuthUtil::urlencodeRFC3986($v);
  296. }
  297. $out = implode("&", $total);
  298. return $out;
  299. }/*}}}*/
  300. /**
  301. * builds the Authorization: header
  302. */
  303. public function to_header() {/*{{{*/
  304. $out ='Authorization: OAuth ';
  305. $total = array();
  306. /*
  307. $sig = $this->parameters['oauth_signature'];
  308. unset($this->parameters['oauth_signature']);
  309. uksort($this->parameters, 'strnatcmp');
  310. $this->parameters['oauth_signature'] = $sig;
  311. */
  312. foreach ($this->parameters as $k => $v) {
  313. if (substr($k, 0, 5) != "oauth") continue;
  314. $out .= OAuthUtil::urlencodeRFC3986($k) . '="' . OAuthUtil::urlencodeRFC3986($v) . '", ';
  315. }
  316. $out = substr_replace($out, '', strlen($out) - 2);
  317. return $out;
  318. }/*}}}*/
  319. public function __toString() {/*{{{*/
  320. return $this->to_url();
  321. }/*}}}*/
  322. public function sign_request($signature_method, $consumer, $token, $privKey=NULL) {/*{{{*/
  323. $this->set_parameter("oauth_signature_method", $signature_method->get_name());
  324. $signature = $this->build_signature($signature_method, $consumer, $token, $privKey);
  325. $this->set_parameter("oauth_signature", $signature);
  326. }/*}}}*/
  327. public function build_signature($signature_method, $consumer, $token, $privKey=NULL) {/*{{{*/
  328. $signature = $signature_method->build_signature($this, $consumer, $token, $privKey);
  329. return $signature;
  330. }/*}}}*/
  331. /**
  332. * util function: current timestamp
  333. */
  334. private static function generate_timestamp() {/*{{{*/
  335. return time();
  336. }/*}}}*/
  337. /**
  338. * util function: current nonce
  339. */
  340. private static function generate_nonce() {/*{{{*/
  341. $mt = microtime();
  342. $rand = mt_rand();
  343. return md5($mt . $rand); // md5s look nicer than numbers
  344. }/*}}}*/
  345. /**
  346. * util function for turning the Authorization: header into
  347. * parameters, has to do some unescaping
  348. */
  349. private static function split_header($header) {/*{{{*/
  350. // this should be a regex
  351. // error cases: commas in parameter values
  352. $parts = explode(",", $header);
  353. $out = array();
  354. foreach ($parts as $param) {
  355. $param = ltrim($param);
  356. // skip the "realm" param, nobody ever uses it anyway
  357. if (substr($param, 0, 5) != "oauth") continue;
  358. $param_parts = explode("=", $param);
  359. // rawurldecode() used because urldecode() will turn a "+" in the
  360. // value into a space
  361. $out[$param_parts[0]] = rawurldecode(substr($param_parts[1], 1, -1));
  362. }
  363. return $out;
  364. }/*}}}*/
  365. /**
  366. * helper to try to sort out headers for people who aren't running apache
  367. */
  368. private static function get_headers() {/*{{{*/
  369. if (function_exists('apache_request_headers')) {
  370. // we need this to get the actual Authorization: header
  371. // because apache tends to tell us it doesn't exist
  372. return apache_request_headers();
  373. }
  374. // otherwise we don't have apache and are just going to have to hope
  375. // that $_SERVER actually contains what we need
  376. $out = array();
  377. foreach ($_SERVER as $key => $value) {
  378. if (substr($key, 0, 5) == "HTTP_") {
  379. // this is chaos, basically it is just there to capitalize the first
  380. // letter of every word that is not an initial HTTP and strip HTTP
  381. // code from przemek
  382. $key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))));
  383. $out[$key] = $value;
  384. }
  385. }
  386. return $out;
  387. }/*}}}*/
  388. }/*}}}*/
  389. class OAuthServer {/*{{{*/
  390. protected $timestamp_threshold = 300; // in seconds, five minutes
  391. protected $version = 1.0; // hi blaine
  392. protected $signature_methods = array();
  393. protected $data_store;
  394. function __construct($data_store) {/*{{{*/
  395. $this->data_store = $data_store;
  396. }/*}}}*/
  397. public function add_signature_method($signature_method) {/*{{{*/
  398. $this->signature_methods[$signature_method->get_name()] =
  399. $signature_method;
  400. }/*}}}*/
  401. // high level functions
  402. /**
  403. * process a request_token request
  404. * returns the request token on success
  405. */
  406. public function fetch_request_token(&$request) {/*{{{*/
  407. $this->get_version($request);
  408. $consumer = $this->get_consumer($request);
  409. // no token required for the initial token request
  410. $token = NULL;
  411. $this->check_signature($request, $consumer, $token);
  412. $new_token = $this->data_store->new_request_token($consumer);
  413. return $new_token;
  414. }/*}}}*/
  415. /**
  416. * process an access_token request
  417. * returns the access token on success
  418. */
  419. public function fetch_access_token(&$request) {/*{{{*/
  420. $this->get_version($request);
  421. $consumer = $this->get_consumer($request);
  422. // requires authorized request token
  423. $token = $this->get_token($request, $consumer, "request");
  424. $this->check_signature($request, $consumer, $token);
  425. $new_token = $this->data_store->new_access_token($token, $consumer);
  426. return $new_token;
  427. }/*}}}*/
  428. /**
  429. * verify an api call, checks all the parameters
  430. */
  431. public function verify_request(&$request) {/*{{{*/
  432. $this->get_version($request);
  433. $consumer = $this->get_consumer($request);
  434. $token = $this->get_token($request, $consumer, "access");
  435. $this->check_signature($request, $consumer, $token);
  436. return array($consumer, $token);
  437. }/*}}}*/
  438. // Internals from here
  439. /**
  440. * version 1
  441. */
  442. private function get_version(&$request) {/*{{{*/
  443. $version = $request->get_parameter("oauth_version");
  444. if (!$version) {
  445. $version = 1.0;
  446. }
  447. if ($version && $version != $this->version) {
  448. throw new OAuthException("OAuth version '$version' not supported");
  449. }
  450. return $version;
  451. }/*}}}*/
  452. /**
  453. * figure out the signature with some defaults
  454. */
  455. private function get_signature_method(&$request) {/*{{{*/
  456. $signature_method =
  457. @$request->get_parameter("oauth_signature_method");
  458. if (!$signature_method) {
  459. $signature_method = "PLAINTEXT";
  460. }
  461. if (!in_array($signature_method,
  462. array_keys($this->signature_methods))) {
  463. throw new OAuthException(
  464. "Signature method '$signature_method' not supported try one of the following: " . implode(", ", array_keys($this->signature_methods))
  465. );
  466. }
  467. return $this->signature_methods[$signature_method];
  468. }/*}}}*/
  469. /**
  470. * try to find the consumer for the provided request's consumer key
  471. */
  472. private function get_consumer(&$request) {/*{{{*/
  473. $consumer_key = @$request->get_parameter("oauth_consumer_key");
  474. if (!$consumer_key) {
  475. throw new OAuthException("Invalid consumer key");
  476. }
  477. $consumer = $this->data_store->lookup_consumer($consumer_key);
  478. if (!$consumer) {
  479. throw new OAuthException("Invalid consumer");
  480. }
  481. return $consumer;
  482. }/*}}}*/
  483. /**
  484. * try to find the token for the provided request's token key
  485. */
  486. private function get_token(&$request, $consumer, $token_type="access") {/*{{{*/
  487. $token_field = @$request->get_parameter('oauth_token');
  488. $token = $this->data_store->lookup_token(
  489. $consumer, $token_type, $token_field
  490. );
  491. if (!$token) {
  492. throw new OAuthException("Invalid $token_type token: $token_field");
  493. }
  494. return $token;
  495. }/*}}}*/
  496. /**
  497. * all-in-one function to check the signature on a request
  498. * should guess the signature method appropriately
  499. */
  500. private function check_signature(&$request, $consumer, $token) {/*{{{*/
  501. // this should probably be in a different method
  502. $timestamp = @$request->get_parameter('oauth_timestamp');
  503. $nonce = @$request->get_parameter('oauth_nonce');
  504. $this->check_timestamp($timestamp);
  505. $this->check_nonce($consumer, $token, $nonce, $timestamp);
  506. $signature_method = $this->get_signature_method($request);
  507. $signature = $request->get_parameter('oauth_signature');
  508. $valid_sig = $signature_method->check_signature(
  509. $request,
  510. $consumer,
  511. $token,
  512. $signature
  513. );
  514. if (!$valid_sig) {
  515. throw new OAuthException("Invalid signature");
  516. }
  517. }/*}}}*/
  518. /**
  519. * check that the timestamp is new enough
  520. */
  521. private function check_timestamp($timestamp) {/*{{{*/
  522. // verify that timestamp is recentish
  523. $now = time();
  524. if ($now - $timestamp > $this->timestamp_threshold) {
  525. throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
  526. }
  527. }/*}}}*/
  528. /**
  529. * check that the nonce is not repeated
  530. */
  531. private function check_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
  532. // verify that the nonce is uniqueish
  533. $found = $this->data_store->lookup_nonce($consumer, $token, $nonce, $timestamp);
  534. if ($found) {
  535. throw new OAuthException("Nonce already used: $nonce");
  536. }
  537. }/*}}}*/
  538. }/*}}}*/
  539. class OAuthDataStore {/*{{{*/
  540. function lookup_consumer($consumer_key) {/*{{{*/
  541. // implement me
  542. }/*}}}*/
  543. function lookup_token($consumer, $token_type, $token) {/*{{{*/
  544. // implement me
  545. }/*}}}*/
  546. function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
  547. // implement me
  548. }/*}}}*/
  549. function fetch_request_token($consumer) {/*{{{*/
  550. // return a new token attached to this consumer
  551. }/*}}}*/
  552. function fetch_access_token($token, $consumer) {/*{{{*/
  553. // return a new access token attached to this consumer
  554. // for the user associated with this token if the request token
  555. // is authorized
  556. // should also invalidate the request token
  557. }/*}}}*/
  558. }/*}}}*/
  559. /* A very naive dbm-based oauth storage
  560. */
  561. class SimpleOAuthDataStore extends OAuthDataStore {/*{{{*/
  562. private $dbh;
  563. function __construct($path = "oauth.gdbm") {/*{{{*/
  564. $this->dbh = dba_popen($path, 'c', 'gdbm');
  565. }/*}}}*/
  566. function __destruct() {/*{{{*/
  567. dba_close($this->dbh);
  568. }/*}}}*/
  569. function lookup_consumer($consumer_key) {/*{{{*/
  570. $rv = dba_fetch("consumer_$consumer_key", $this->dbh);
  571. if ($rv === FALSE) {
  572. return NULL;
  573. }
  574. $obj = unserialize($rv);
  575. if (!($obj instanceof OAuthConsumer)) {
  576. return NULL;
  577. }
  578. return $obj;
  579. }/*}}}*/
  580. function lookup_token($consumer, $token_type, $token) {/*{{{*/
  581. $rv = dba_fetch("${token_type}_${token}", $this->dbh);
  582. if ($rv === FALSE) {
  583. return NULL;
  584. }
  585. $obj = unserialize($rv);
  586. if (!($obj instanceof OAuthToken)) {
  587. return NULL;
  588. }
  589. return $obj;
  590. }/*}}}*/
  591. function lookup_nonce($consumer, $token, $nonce, $timestamp) {/*{{{*/
  592. return dba_exists("nonce_$nonce", $this->dbh);
  593. }/*}}}*/
  594. function new_token($consumer, $type="request") {/*{{{*/
  595. $key = md5(time());
  596. $secret = time() + time();
  597. $token = new OAuthToken($key, md5(md5($secret)));
  598. if (!dba_insert("${type}_$key", serialize($token), $this->dbh)) {
  599. throw new OAuthException("doooom!");
  600. }
  601. return $token;
  602. }/*}}}*/
  603. function new_request_token($consumer) {/*{{{*/
  604. return $this->new_token($consumer, "request");
  605. }/*}}}*/
  606. function new_access_token($token, $consumer) {/*{{{*/
  607. $token = $this->new_token($consumer, 'access');
  608. dba_delete("request_" . $token->key, $this->dbh);
  609. return $token;
  610. }/*}}}*/
  611. }/*}}}*/
  612. class OAuthUtil {/*{{{*/
  613. public static function urlencodeRFC3986($string) {/*{{{*/
  614. return str_replace('%7E', '~', rawurlencode($string));
  615. }/*}}}*/
  616. public static function urldecodeRFC3986($string) {/*{{{*/
  617. return rawurldecode($string);
  618. }/*}}}*/
  619. }/*}}}*/
  620. ?>