PageRenderTime 62ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/library/Yahoo.inc

https://github.com/SOSbeacon/SOSBeacon
Pascal | 2010 lines | 971 code | 205 blank | 834 comment | 152 complexity | a277fd358382bc2f868b1222d9d7b3ca MD5 | raw file
  1. <?php
  2. /**
  3. * YOS PHP SDK for accessing social and data apis at Yahoo!
  4. *
  5. * @package yos-social-php
  6. * @author Yahoo! Developer Network
  7. * @example http://developer.yahoo.com/social/sdk/php/
  8. *
  9. * @copyright Copyright (c) 2009 Yahoo! Inc. All rights reserved.
  10. * @license BSD License (http://www.opensource.org/licenses/bsd-license.php)
  11. *
  12. * The copyrights embodied in the content of this file are licensed under the
  13. * BSD (revised) open source license.
  14. *
  15. * Redistribution and use of this software in source and binary forms, with
  16. * or without modification, are permitted provided that the following
  17. * conditions are met:
  18. *
  19. * * Redistributions of source code must retain the above
  20. * copyright notice, this list of conditions and the
  21. * following disclaimer.
  22. *
  23. * * Redistributions in binary form must reproduce the above
  24. * copyright notice, this list of conditions and the
  25. * following disclaimer in the documentation and/or other
  26. * materials provided with the distribution.
  27. *
  28. * * Neither the name of Yahoo! Inc. nor the names of its
  29. * contributors may be used to endorse or promote products
  30. * derived from this software without specific prior
  31. * written permission of Yahoo! Inc.
  32. *
  33. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  34. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  35. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  36. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  37. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  38. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  39. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  40. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  41. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  42. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43. *
  44. * Please see the Yahoo! Developer Network forums for support: http://developer.yahoo.net/forum/
  45. *
  46. * Documentation: http://developer.yahoo.com/social/sdk/php/
  47. */
  48. // Use OAuthConsumer as a test to see if any other instances of OAuth.php may
  49. // have been included. require_once() won't catch situations where multiple
  50. // copies of OAuth.php are included by different parts of an application.
  51. //
  52. //if(!class_exists("OAuthConsumer")) {
  53. require_once("OAuth.php");
  54. //}
  55. define("OAUTH_PARAMS_IN_HEADERS", "HEADERS");
  56. define("OAUTH_PARAMS_IN_POST_BODY", "POSTBODY");
  57. define("OAUTH_SIGNATURE_PLAINTEXT", "PLAINTEXT");
  58. define("OAUTH_SIGNATURE_HMAC_SHA1", "HMAC_SHA1");
  59. define("YAHOO_YAP_SESSION_TYPE", "YAHOO_YAP_SESSION_TYPE");
  60. define("YAHOO_OAUTH_RT_SESSION_TYPE", "YAHOO_OAUTH_RT_SESSION_TYPE");
  61. define("YAHOO_OAUTH_AT_SESSION_TYPE", "YAHOO_OAUTH_AT_SESSION_TYPE");
  62. global $YahooConfig, $GLOBAL_YAHOO_SESSION, $GLOBAL_YAHOO_LOGGER_DEBUG, $GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION;
  63. $YahooConfig = array(
  64. "SOCIAL_WS_HOSTNAME" => "social.yahooapis.com",
  65. "PRESENCE_WS_HOSTNAME" => "social.yahooapis.com",
  66. "UPDATES_WS_HOSTNAME" => "social.yahooapis.com",
  67. "QUERY_WS_HOSTNAME" => "query.yahooapis.com",
  68. "OAUTH_HOSTNAME" => "api.login.yahoo.com",
  69. "YAP_WS_HOSTNAME" => "appstore.apps.yahooapis.com"
  70. );
  71. $GLOBAL_YAHOO_SESSION = NULL;
  72. $GLOBAL_YAHOO_LOGGER_DEBUG = false;
  73. $GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION = "LOG";
  74. class YahooUtil {
  75. function current_url() {
  76. return sprintf("http://%s%s",$_SERVER["HTTP_HOST"],$_SERVER["REQUEST_URI"]);
  77. }
  78. function verify_signature($consumer, $token=NULL, $oauth_signature) {
  79. $oauth_signature_method = new OAuthSignatureMethod_HMAC_SHA1();
  80. $oauth_consumer = new OAuthConsumer($consumer->key, $consumer->secret);
  81. $oauth_token = ($token) ? new OAuthToken($token->key, $token->secret) : NULL;
  82. $oauth_request = OAuthRequest::from_request();
  83. $ok = $oauth_signature_method->check_signature($oauth_request, $oauth_consumer, $oauth_token, $oauth_signature);
  84. return $ok;
  85. }
  86. function is_yap_canvas() {
  87. return (isset($_POST['yap_appid'])
  88. && isset($_POST['yap_view']));
  89. }
  90. function is_response_error($response) {
  91. return (is_null($response) || $response["code"] != 200);
  92. }
  93. }
  94. class YahooException extends Exception {
  95. }
  96. /**
  97. * Logging wrapper for the Yahoo objects.
  98. *
  99. * @brief Logging wrapper for the Yahoo objects.
  100. */
  101. class YahooLogger {
  102. /**
  103. * Log a message at the debug level.
  104. *
  105. * @param $message The message to log.
  106. */
  107. function debug($message, $object = NULL) {
  108. global $GLOBAL_YAHOO_LOGGER_DEBUG;
  109. global $GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION;
  110. if($GLOBAL_YAHOO_LOGGER_DEBUG) {
  111. if($GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION == "CONSOLE") {
  112. print("DEBUG - $message\n");
  113. if(!is_null($object)) {
  114. print("DEBUG OBJECT - " . print_r($object, true) . "\n");
  115. }
  116. }
  117. else if($GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION == "LOG") {
  118. error_log("DEBUG - $message");
  119. if(!is_null($object)) {
  120. error_log("DEBUG OBJECT - " . print_r($object, true));
  121. }
  122. }
  123. }
  124. }
  125. /**
  126. * Log a message at the info level.
  127. *
  128. * @param $message The message to log.
  129. */
  130. function info($message, $object = NULL) {
  131. global $GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION;
  132. if($GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION == "CONSOLE") {
  133. print("INFO - $message\n");
  134. if(!is_null($object)) {
  135. print("INFO OBJECT - " . print_r($object, true) . "\n");
  136. }
  137. }
  138. else if($GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION == "LOG") {
  139. error_log("INFO - $message");
  140. if(!is_null($object)) {
  141. error_log("INFO OBJECT - " . print_r($object, true));
  142. }
  143. }
  144. }
  145. /**
  146. * Log a message at the error level.
  147. *
  148. * @param $message The message to log.
  149. */
  150. function error($message, $object = NULL) {
  151. global $GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION;
  152. if($GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION == "CONSOLE") {
  153. print("ERROR - $message\n");
  154. if(!is_null($object)) {
  155. print("ERROR OBJECT - " . print_r($object, true) . "\n");
  156. }
  157. }
  158. else if($GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION == "LOG") {
  159. error_log("ERROR - $message");
  160. if(!is_null($object)) {
  161. error_log("ERROR OBJECT - " . print_r($object, true));
  162. }
  163. }
  164. }
  165. /**
  166. * Enables/disables session debugging.
  167. *
  168. * @param $debug Boolean to enable/disable debugging.
  169. */
  170. function setDebug($debug) {
  171. global $GLOBAL_YAHOO_LOGGER_DEBUG;
  172. $GLOBAL_YAHOO_LOGGER_DEBUG = (bool) $debug;
  173. }
  174. /**
  175. * Allows callers to configure where debugging output is sent.
  176. *
  177. * @param $destination "LOG" to use YahooLogger::error, "CONSOLE" to use printf,
  178. * "NULL" to disable all logging output.
  179. * @return boolean True on success, false on failure.
  180. */
  181. function setDebugDestination($destination) {
  182. global $GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION;
  183. if($destination == "LOG" || $destination == "CONSOLE" ||
  184. $destination == "NULL") {
  185. $GLOBAL_YAHOO_LOGGER_DEBUG_DESTINATION = $destination;
  186. return true;
  187. }
  188. else {
  189. return false;
  190. }
  191. }
  192. }
  193. /**
  194. * Defines a session between an application and the Yahoo! platform.
  195. *
  196. * @brief Defines a session between an application and the Yahoo! platform.
  197. */
  198. class YahooSession {
  199. /**
  200. * @private
  201. */
  202. var $guid = NULL;
  203. /**
  204. * @private
  205. */
  206. var $consumer = NULL;
  207. /**
  208. * @private
  209. */
  210. var $accessToken = NULL;
  211. /**
  212. * @private
  213. */
  214. var $applicationId = NULL;
  215. /**
  216. * @private
  217. */
  218. var $client = NULL;
  219. /**
  220. * @private
  221. */
  222. var $application = NULL;
  223. /**
  224. * @private
  225. */
  226. function YahooSession($consumer, $accessToken, $applicationId)
  227. {
  228. $this->consumer = $consumer;
  229. $this->accessToken = $accessToken;
  230. $this->applicationId = $applicationId;
  231. $this->guid = $accessToken->guid;
  232. $this->client = new OAuthClient($consumer, $accessToken);
  233. $this->application = new YahooApplication($consumer->key, $consumer->secret);
  234. $this->application->token = $this->accessToken;
  235. }
  236. /**
  237. * @private
  238. */
  239. function getConsumer() {
  240. return $this->consumer;
  241. }
  242. /**
  243. * @private
  244. */
  245. function getAccessToken() {
  246. return $this->accessToken;
  247. }
  248. /**
  249. * @private
  250. */
  251. function getApplicationId() {
  252. return $this->applicationId;
  253. }
  254. /**
  255. * Gets the currently sessioned user.
  256. *
  257. * @return YahooUser The currently sessioned YahooUser.
  258. */
  259. function getSessionedUser() {
  260. return new YahooUser($this, $this->guid, true);
  261. }
  262. /**
  263. * Gets the user who owns the application install.
  264. * Only valid when viewed in YAP, otherwise will default
  265. * to the logged-in user.
  266. *
  267. * @return YahooUser The currently sessioned YahooUser.
  268. */
  269. function getOwner() {
  270. if(isset($this->accessToken->owner)) {
  271. return $this->getUser($this->accessToken->owner);
  272. }
  273. else {
  274. return $this->getSessionedUser();
  275. }
  276. }
  277. /**
  278. * Gets the user indicated by the GUID given.
  279. *
  280. * @param $guid The GUID of the user to get.
  281. * @return YahooUser The user indicated by the GUID given.
  282. */
  283. function getUser($guid) {
  284. return new YahooUser($this, $guid, isset($this->guid) && ($guid == $this->guid));
  285. }
  286. /**
  287. * Executes the given YQL query.
  288. *
  289. * @param $yql The query to execute.
  290. * @param $env A URL to a YQL environment file.
  291. * @return The response or NULL if the request fails..
  292. */
  293. function query($yql, $env=NULL) {
  294. return $this->application->query($yql, $env);
  295. }
  296. /**
  297. * @private
  298. */
  299. function redirectForAuthorization($consumerKey, $consumerSecret, $callback = NULL, $sessionStore = NULL) {
  300. $url = YahooSession::createAuthorizationUrl($consumerKey, $consumerSecret, $callback, $sessionStore);
  301. if(!is_null($url)) {
  302. header(sprintf("Location: %s", $url));
  303. exit();
  304. }
  305. else {
  306. // TODO: throw a YahooException
  307. YahooLogger::error("Failed to create authorization URLs");
  308. }
  309. }
  310. /**
  311. * Destroys the current session, effectively logging out the current
  312. * user.
  313. *
  314. * @param $sessionStore The session store implementation to clear. See
  315. * YahooSessionStore for more information. If no
  316. * session store is provided, clearSession will
  317. * instantiate a NativeSessionStore and use that.
  318. */
  319. function clearSession($sessionStore = NULL) {
  320. global $GLOBAL_YAHOO_SESSION;
  321. if(is_null($sessionStore)) {
  322. $sessionStore = new NativeSessionStore();
  323. }
  324. $sessionStore->clearRequestToken();
  325. $sessionStore->clearAccessToken();
  326. $GLOBAL_YAHOO_SESSION = NULL;
  327. }
  328. /**
  329. * Checks to see if there is a session in this PHP page request.
  330. * Doesn't cause any redirects for the user to log in, for that
  331. * you should call requireSession().
  332. *
  333. * @param $consumerKey The OAuth consumer key.
  334. * @param $consumerSecret The OAuth consumer key secret.
  335. * @param $applicationId The application ID, optional.
  336. * @param $sessionStore The session store implementation to use. See
  337. * YahooSessionStore for more information. If no
  338. * session store is provided, clearSession will
  339. * instantiate a NativeSessionStore and use that.
  340. * @return boolean True if a session is present, false otherwise.
  341. */
  342. function hasSession($consumerKey, $consumerSecret, $applicationId = NULL, $sessionStore = NULL, $verifier = NULL)
  343. {
  344. if(is_null($sessionStore)) {
  345. $sessionStore = new NativeSessionStore();
  346. }
  347. if(is_null($verifier) && array_key_exists("oauth_verifier", $_GET)) {
  348. $verifier = $_GET["oauth_verifier"];
  349. }
  350. $session = YahooSession::initSession($consumerKey, $consumerSecret, $applicationId, FALSE, NULL, $sessionStore, $verifier);
  351. return !is_null($session);
  352. }
  353. /**
  354. * Requires that there be a session in this PHP page request. Generates
  355. * a redirect for the user to log in, if necessary. You must call
  356. * requireSession() before any data is sent back to the user in order
  357. * for the redirect to work.
  358. *
  359. * @param $consumerKey The OAuth consumer key.
  360. * @param $consumerSecret The OAuth consumer key secret.
  361. * @param $applicationId The application ID, optional.
  362. * @param $callback The callback URL to redirect the user to after
  363. * they verify the application access. If no callback
  364. * is provided, the current page URL will be used.
  365. * @param $sessionStore The session store implementation to use. See
  366. * YahooSessionStore for more information. If no
  367. * session store is provided, clearSession will
  368. * instantiate a NativeSessionStore and use that.
  369. * @param $verifier The oauth_verifier returned by the OAuth servers
  370. * after authorization. Passing NULL indicates that
  371. * authorization was completed previously or that
  372. * requireSession() should look for oauth_verifier in
  373. * the $_GET superglobal.
  374. * @return YahooSession The current session or NULL if a session cannot
  375. * be established.
  376. */
  377. function requireSession($consumerKey, $consumerSecret, $applicationId = NULL,
  378. $callback = NULL, $sessionStore = NULL, $verifier = NULL)
  379. {
  380. if(is_null($sessionStore)) {
  381. $sessionStore = new NativeSessionStore();
  382. }
  383. if(is_null($verifier) && array_key_exists("oauth_verifier", $_GET)) {
  384. $verifier = $_GET["oauth_verifier"];
  385. }
  386. return YahooSession::initSession($consumerKey, $consumerSecret, $applicationId, TRUE, $callback, $sessionStore, $verifier);
  387. }
  388. /**
  389. * Creates authorization URLs, allowing applications to manage their
  390. * user experience when the user needs to be sent to Yahoo! to authorize
  391. * the application to access their account.
  392. *
  393. * @param $consumerKey The OAuth consumer key.
  394. * @param $consumerSecret The OAuth consumer key secret.
  395. * @param $callback The callback URL to redirect the user to after
  396. * they verify the application access. If no callback
  397. * is provided, the current page URL will be used.
  398. * Use the "oob" callback for desktop clients or for
  399. * web clients where no callback should be used.
  400. * @param $sessionStore The session store implementation to use. See
  401. * YahooSessionStore for more information. If no
  402. * session store is provided, createAuthorizationUrl
  403. * will instantiate a NativeSessionStore and use that.
  404. * @return stdclass A PHP object with two properties: "urlWithCallback"
  405. * and "urlWithoutCallback". This allows the application
  406. * to mix and match authorizations that do and don't
  407. * have callbacks in the URLs. urlWithoutCallback is
  408. * useful for JavaScript popup windows while
  409. * urlWithCallback is useful for normal <a href>
  410. * tags.
  411. */
  412. function createAuthorizationUrl($consumerKey, $consumerSecret, $callback = NULL, $sessionStore = NULL)
  413. {
  414. global $GLOBAL_YAHOO_SESSION;
  415. if(is_null($sessionStore)) {
  416. $sessionStore = new NativeSessionStore();
  417. }
  418. // No callback URL supplied. Build one from the current URL.
  419. if(is_null($callback)) {
  420. $callback = YahooUtil::current_url();
  421. }
  422. // Redirect the user to log in.
  423. $requestToken = YahooAuthorization::getRequestToken($consumerKey, $consumerSecret, $callback);
  424. if(!is_null($requestToken))
  425. {
  426. $sessionStore->storeRequestToken($requestToken);
  427. $url = YahooAuthorization::createAuthorizationUrl($requestToken, $callback);
  428. return $url;
  429. }
  430. else
  431. {
  432. YahooLogger::error("Failed to create request token");
  433. $GLOBAL_YAHOO_SESSION = NULL;
  434. return null;
  435. }
  436. }
  437. function initSessionFromYAP($consumerKey, $consumerSecret, $appid)
  438. {
  439. global $GLOBAL_YAHOO_SESSION;
  440. if(!YahooUtil::is_yap_canvas()) {
  441. // TODO: throw a YahooException
  442. return NULL;
  443. }
  444. $consumer = new stdclass();
  445. $consumer->key = $consumerKey;
  446. $consumer->secret = $consumerSecret;
  447. if ($consumer->key != $_POST["yap_consumer_key"]) {
  448. YahooLogger::error("Consumer key from YAP does not match provided key.");
  449. // TODO: throw a YahooException
  450. $GLOBAL_YAHOO_SESSION = NULL;
  451. return;
  452. }
  453. $signature_ok = YahooUtil::verify_signature($consumer, null, $_REQUEST['oauth_signature']);
  454. if (!$signature_ok)
  455. {
  456. YahooLogger::error("Signature from YAP failed.");
  457. // TODO: throw a YahooException
  458. $GLOBAL_YAHOO_SESSION = NULL;
  459. return;
  460. }
  461. $accessToken = new stdclass();
  462. $accessToken->key = $_POST["yap_viewer_access_token"];
  463. $accessToken->secret = $_POST["yap_viewer_access_token_secret"];
  464. $accessToken->guid = $_POST["yap_viewer_guid"];
  465. $accessToken->owner = $_POST["yap_owner_guid"];
  466. $accessToken->tokenExpires = -1;
  467. YahooLogger::debug("YAP AT: " . $accessToken->key . " ATS: " . $accessToken->secret);
  468. $applicationId = $_POST["yap_appid"];
  469. $GLOBAL_YAHOO_SESSION = new YahooSession($consumer, $accessToken, $applicationId);
  470. return $GLOBAL_YAHOO_SESSION;
  471. }
  472. /**
  473. * @private
  474. */
  475. function initSession($consumerKey, $consumerSecret, $applicationId, $redirect, $callback, $sessionStore, $verifier)
  476. {
  477. global $GLOBAL_YAHOO_SESSION;
  478. if(!is_null($GLOBAL_YAHOO_SESSION)) {
  479. return $GLOBAL_YAHOO_SESSION;
  480. }
  481. $consumer = new stdclass();
  482. $consumer->key = $consumerKey;
  483. $consumer->secret = $consumerSecret;
  484. $checkSession = YahooSession::checkSession($type, $sessionStore);
  485. if(!$checkSession) {
  486. // There doesn't appear to be a session here.
  487. if($redirect) {
  488. $GLOBAL_YAHOO_SESSION = NULL;
  489. YahooSession::redirectForAuthorization($consumerKey, $consumerSecret, $callback, $sessionStore);
  490. }
  491. else {
  492. // Don't redirect the user, just inform the caller that
  493. // no session is present.
  494. // TODO: throw a YahooException
  495. $GLOBAL_YAHOO_SESSION = NULL;
  496. }
  497. }
  498. else if($type == YAHOO_OAUTH_AT_SESSION_TYPE) {
  499. // Found an OAuth Access Token session.
  500. $accessToken = $sessionStore->fetchAccessToken();
  501. $now = time();
  502. YahooLogger::debug("OAuth AT: " . $accessToken->key . " ATS: ". $accessToken->secret);
  503. if($accessToken->consumer != $consumerKey)
  504. {
  505. YahooLogger::error("Consumer key for token does not match the defined Consumer Key. The Consumer Key has probably changed since the user last authorized the application.");
  506. YahooSession::clearSession($sessionStore);
  507. if($redirect) {
  508. YahooSession::redirectForAuthorization($consumerKey, $consumerSecret, $callback, $sessionStore);
  509. }
  510. }
  511. if($accessToken->tokenExpires >= 0) {
  512. YahooLogger::debug('AT Expires in: ' . ($accessToken->tokenExpires - $now));
  513. }
  514. if(($accessToken->tokenExpires >= 0) && ($accessToken->tokenExpires - $now) < 30) {
  515. // The access token will expire in less than 30 seconds or
  516. // it may have expired already. Try to get a new one.
  517. YahooSession::accessTokenExpired($accessToken, $consumer, $applicationId, $sessionStore);
  518. }
  519. else {
  520. // The access token is still good for a little while, continue using it.
  521. $GLOBAL_YAHOO_SESSION = new YahooSession($consumer, $accessToken, $applicationId);
  522. }
  523. }
  524. else if($type == YAHOO_OAUTH_RT_SESSION_TYPE)
  525. {
  526. if(is_null($verifier)) {
  527. // Can't proceed without the oauth_verifier, treat it as
  528. // though there's no session present.
  529. $sessionStore->clearRequestToken();
  530. // TODO: throw a YahooException
  531. $GLOBAL_YAHOO_SESSION = NULL;
  532. }
  533. // Found an OAuth Request Token session.
  534. $requestToken = $sessionStore->fetchRequestToken();
  535. $accessToken = YahooAuthorization::getAccessToken($consumerKey, $consumerSecret, $requestToken, $verifier);
  536. if(!is_null($accessToken)) {
  537. $sessionStore->storeAccessToken($accessToken);
  538. $sessionStore->clearRequestToken();
  539. $GLOBAL_YAHOO_SESSION = new YahooSession($consumer, $accessToken, $applicationId);
  540. }
  541. else if($redirect)
  542. {
  543. // TODO: Add redirect counter so this doesn't happen over and over and over when Yahoo! is completely busted.
  544. // The fetch for the access token failed. Generate a new
  545. // request token and try again.
  546. $GLOBAL_YAHOO_SESSION = NULL;
  547. YahooSession::redirectForAuthorization($consumerKey, $consumerSecret, $callback, $sessionStore);
  548. }
  549. else
  550. {
  551. // Don't redirect the user, just inform the caller that
  552. // no session is present.
  553. $sessionStore->clearRequestToken();
  554. $GLOBAL_YAHOO_SESSION = NULL;
  555. }
  556. }
  557. else if($type == YAHOO_YAP_SESSION_TYPE)
  558. {
  559. // Found a YAP session.
  560. $GLOBAL_YAHOO_SESSION = YahooSession::initSessionFromYAP($consumerKey, $consumerSecret, $applicationId);
  561. }
  562. else
  563. {
  564. YahooLogger::error("Unknown session type found");
  565. // TODO: throw a YahooException
  566. $GLOBAL_YAHOO_SESSION = NULL;
  567. }
  568. return $GLOBAL_YAHOO_SESSION;
  569. }
  570. /**
  571. * @private
  572. */
  573. function accessTokenExpired($accessToken, $consumer, $applicationId, $sessionStore)
  574. {
  575. global $GLOBAL_YAHOO_SESSION;
  576. $now = time();
  577. if(($accessToken->handleExpires === -1) ||
  578. ($now < $accessToken->handleExpires)) {
  579. // Either the access session handle doesn't expire
  580. // or it hasn't expired yet. Get a new access token.
  581. $newAccessToken = YahooAuthorization::getAccessToken(
  582. $consumer->key, $consumer->secret, $accessToken, null);
  583. if(is_null($newAccessToken)) {
  584. YahooLogger::error("Failed to fetch access token");
  585. $GLOBAL_YAHOO_SESSION = NULL;
  586. }
  587. $sessionStore->storeAccessToken($newAccessToken);
  588. YahooLogger::debug("Got new AT/ATS from ASH!");
  589. YahooLogger::debug("OAuth AT: " . $newAccessToken->key . " ATS: ". $newAccessToken->secret);
  590. $GLOBAL_YAHOO_SESSION = new YahooSession(
  591. $consumer, $newAccessToken, $applicationId);
  592. }
  593. else
  594. {
  595. // The access token is expired and we don't have
  596. // a sufficient access session handle to renew
  597. // the access token. Clear the cookie and redirect
  598. // to authorization point or return a NULL session.
  599. $sessionStore->clearAccessToken();
  600. if ($redirect) {
  601. YahooSession::redirectForAuthorization($consumer->key, $consumer->secret, $callback, $sessionStore);
  602. } else {
  603. $GLOBAL_YAHOO_SESSION = NULL;
  604. }
  605. }
  606. }
  607. /**
  608. * @private
  609. *
  610. * Checks to see if the current PHP page request has a session and, if so,
  611. * indicates what type of session is present.
  612. *
  613. * @param[out] $sessionType The session type present, if any.
  614. * @return boolean True if a session is present, false otherwise.
  615. */
  616. function checkSession(&$sessionType, $sessionStore) {
  617. if(array_key_exists("yap_appid", $_POST)) {
  618. $sessionType = YAHOO_YAP_SESSION_TYPE;
  619. return true;
  620. }
  621. else if($sessionStore->hasAccessToken()) {
  622. $sessionType = YAHOO_OAUTH_AT_SESSION_TYPE;
  623. return true;
  624. }
  625. else if($sessionStore->hasRequestToken()) {
  626. $sessionType = YAHOO_OAUTH_RT_SESSION_TYPE;
  627. return true;
  628. }
  629. else {
  630. return false;
  631. }
  632. }
  633. }
  634. /**
  635. * Represents a Yahoo! application.
  636. *
  637. * @brief Represents a Yahoo! application.
  638. */
  639. class YahooApplication {
  640. /**
  641. * @private
  642. */
  643. var $consumer = NULL;
  644. /**
  645. * @private
  646. * @deprecated
  647. */
  648. var $client = NULL;
  649. /**
  650. * @private
  651. */
  652. var $token = NULL;
  653. /**
  654. * Constructs a new YahooApplication object.
  655. *
  656. * @param $consumerKey The consumer key of the application.
  657. * @param $consumerKeySecret The consumer key secret of the application.
  658. */
  659. function YahooApplication($consumerKey, $consumerKeySecret) {
  660. $this->consumer = new OAuthConsumer($consumerKey, $consumerKeySecret);
  661. }
  662. /**
  663. * Sets the small view for the user given by the GUID.
  664. *
  665. * @param $guid The GUID of the user to set the small view for.
  666. * @param $content The content to set the small view to.
  667. * @return True on success, false otherwise.
  668. */
  669. function setSmallView($guid, $content) {
  670. global $YahooConfig;
  671. $client = new OAuthClient($this->consumer, NULL);
  672. $request_url = sprintf("http://%s/v1/cache/view/small/%s", $YahooConfig["YAP_WS_HOSTNAME"], urlencode($guid));
  673. $response = $client->put($request_url, "text/html;charset=utf-8", $content);
  674. return !(YahooUtil::is_response_error($response));
  675. }
  676. /**
  677. * Executes the given YQL query.
  678. *
  679. * @param $yql The query to execute.
  680. * @param $env A URL to a YQL environment file.
  681. * @return The response or NULL if the request fails..
  682. */
  683. function query($yql, $env=NULL)
  684. {
  685. global $YahooConfig;
  686. $client = new OAuthClient($this->consumer, $this->token);
  687. $request_url = sprintf("http://%s/v1/yql",$YahooConfig["QUERY_WS_HOSTNAME"]);
  688. $params = array('q' => $yql, 'format' => 'json', 'env' => 'http://datatables.org/alltables.env');
  689. if(!is_null($env)) {
  690. $params['env'] = $env;
  691. }
  692. $response = $client->get($request_url, $params, 30);
  693. if(YahooUtil::is_response_error($response)) {
  694. return NULL;
  695. }
  696. $resultSet = json_decode($response["responseBody"]);
  697. return $resultSet;
  698. }
  699. }
  700. /**
  701. * Represents a Yahoo! user.
  702. *
  703. * @brief Represents a Yahoo! user.
  704. */
  705. class YahooUser {
  706. /**
  707. * @private
  708. */
  709. var $session = NULL;
  710. /**
  711. * @private
  712. */
  713. var $guid = NULL;
  714. /**
  715. * @private
  716. */
  717. var $sessioned = false;
  718. /**
  719. * @private
  720. */
  721. var $client = NULL;
  722. /**
  723. * @private
  724. */
  725. function YahooUser($session, $guid, $sessioned) {
  726. $this->session = $session;
  727. $this->client = $session->client;
  728. $this->guid = $guid;
  729. $this->sessioned = $sessioned;
  730. }
  731. /**
  732. * Gets the user's status message.
  733. *
  734. * @return The status of the user or NULL if the fetch fails.
  735. */
  736. function getStatus() {
  737. global $YahooConfig;
  738. $request_url = sprintf("http://%s/v1/user/%s/profile/status",
  739. $YahooConfig["SOCIAL_WS_HOSTNAME"],urlencode($this->guid));
  740. $response = $this->client->get($request_url);
  741. if(is_null($response)) {
  742. return NULL;
  743. }
  744. else if($response["code"] == 404) {
  745. // No presence is set, return an empty presence.
  746. $status = new stdclass();
  747. $status->message = "";
  748. $status->lastStatusModified = NULL;
  749. $status->uri = NULL;
  750. return $status;
  751. }
  752. else if($response["code"] != 200) {
  753. return NULL;
  754. }
  755. else {
  756. $rsp = json_decode($response["responseBody"]);
  757. return $rsp->status;
  758. }
  759. }
  760. /**
  761. * Sets the user's status message.
  762. *
  763. * @param $message The new status message for the user.
  764. * @return The status message on success, NULL on failure.
  765. */
  766. function setStatus($message) {
  767. global $YahooConfig;
  768. if(!$this->sessioned) {
  769. YahooLogger::error("Can't set the status of an unsessioned user");
  770. return NULL;
  771. }
  772. $message = array("message" => $message);
  773. $status = array("status" => $message);
  774. $status_json = json_encode($status);
  775. $request_url = sprintf("http://%s/v1/user/%s/profile/status", $YahooConfig["SOCIAL_WS_HOSTNAME"], $this->guid);
  776. $response = $this->client->put($request_url, "application/json", $status_json);
  777. if(YahooUtil::is_response_error($response)) {
  778. return NULL;
  779. }
  780. $status = json_decode($response["responseBody"]);
  781. return $status;
  782. }
  783. /**
  784. * Gets the updates for the current user.
  785. *
  786. * @param $start The starting offset to list updates from. (default = 0)
  787. * @param $count The number of updates to request. (default = 10)
  788. * @return An array of updates for the current user.
  789. */
  790. function getUpdates($start = 0, $count = 10) {
  791. $parameters = array("start" => $start, "count" => $count, "transform" => '(sort "pubDate" numeric descending (all))');
  792. $updates = $this->get_resource("updates", $parameters);
  793. return $updates->updates;
  794. }
  795. /**
  796. * Gets the updates for the connections of the current user.
  797. *
  798. * @param $start The starting offset to list updates from.
  799. * @param $count The number of updates to request.
  800. * @return A list of updates for the connections of the current user.
  801. */
  802. function getConnectionUpdates($start = 0, $count = 10) {
  803. $parameters = array("start" => $start, "count" => $count, "transform" => '(sort "pubDate" numeric descending (all))');
  804. $updates = $this->get_resource("updates/connections", $parameters);
  805. return $updates->updates;
  806. }
  807. /**
  808. * Inserts an update for the current user.
  809. *
  810. * @param $suid Identifier that globally unique for a given
  811. * collectionId within producing source.
  812. * @param $title Title for the update.
  813. * @param $link Link back to the cause of the event.
  814. * @param $description Descriptive text associated with the update,
  815. * optional.
  816. * @param $date The date of the update event, optional, defaults to now.
  817. */
  818. function insertUpdate($suid, $title, $link, $description="", $date=NULL) {
  819. global $YahooConfig;
  820. // Make sure this YahooUser is sessioned.
  821. if(!$this->sessioned) {
  822. YahooLogger::error("Can't insert updates for an unsessioned user");
  823. return NULL;
  824. }
  825. if (is_null($date)) {
  826. $date = time();
  827. }
  828. // Make sure an application ID was given.
  829. $appid = $this->session->getApplicationId();
  830. if(empty($appid)) {
  831. YahooLogger::error("No application ID given, can't insert update");
  832. return NULL;
  833. }
  834. $source = sprintf("APP.%s", $appid);
  835. $update = array(
  836. "collectionID" => $this->guid,
  837. "collectionType" => "guid",
  838. "class" => "app",
  839. "source" => $source,
  840. "type" => 'appActivity',
  841. "suid" => $suid,
  842. "title" => $title,
  843. "description" => $description,
  844. "link" => $link,
  845. "pubDate" => (string)$date
  846. );
  847. $update_body = array("updates" => array($update));
  848. $update_body_json = json_encode($update_body);
  849. $request_url = sprintf("http://%s/v1/user/%s/updates/%s/%s", $YahooConfig["UPDATES_WS_HOSTNAME"], $this->guid, $source, urlencode($suid));
  850. $response = $this->client->put($request_url, "application/json", $update_body_json);
  851. return !(YahooUtil::is_response_error($response));
  852. }
  853. /**
  854. * Deletes the update of the given SUID. Only allows deleting updates
  855. * that were inserted by your own application. You won't be able to
  856. * delete updates from other applications.
  857. *
  858. * @param $suid The SUID of the update to be deleted.
  859. * @return boolean True on success, false on failure.
  860. */
  861. function deleteUpdate($suid) {
  862. global $YahooConfig;
  863. // Make sure this YahooUser is sessioned.
  864. if(!$this->sessioned) {
  865. YahooLogger::error("Can't delete updates for an unsessioned user");
  866. return FALSE;
  867. }
  868. // Make sure an application ID was given.
  869. $appid = $this->session->getApplicationId();
  870. if( empty($appid) ) {
  871. YahooLogger::error("No application ID given, can't delete update");
  872. return FALSE;
  873. }
  874. $source = sprintf("APP.%s", $appid);
  875. $request_url = sprintf("http://%s/v1/user/%s/updates/%s/%s", $YahooConfig["UPDATES_WS_HOSTNAME"], $this->guid, $source, urlencode($suid));
  876. $response = $this->client->delete($request_url);
  877. return !(YahooUtil::is_response_error($response));
  878. }
  879. /**
  880. * Loads the extended profile of the current user.
  881. *
  882. * @return The extended profile of the current user.
  883. */
  884. function getProfile() {
  885. global $YahooConfig;
  886. $profile = $this->get_resource("profile");
  887. return $profile->profile;
  888. }
  889. /**
  890. * Gets a list of connections for the current user.
  891. *
  892. * @param[in,out] $start The starting offset.
  893. * @param[in,out] $count The number of connections to fetch.
  894. * @param[out] $total The total number of contacts available.
  895. * @return List of connections for the current user.
  896. */
  897. function getConnections(&$start, &$count, &$total) {
  898. global $YahooConfig;
  899. $parameters = array("view" => "usercard", "start" => $start, "count" => $count);
  900. $connections = $this->get_resource("connections",$parameters);
  901. $start = $connections->connections->start;
  902. $count = $connections->connections->count;
  903. $total = $connections->connections->total;
  904. return $connections->connections->connection;
  905. }
  906. /**
  907. * Gets a list of contacts for the current user.
  908. *
  909. * @param $start The starting offset.
  910. * @param $count The number of contacts to fetch.
  911. * @return List of contacts for the current user.
  912. */
  913. function getContacts($start = 0, $count = 10) {
  914. global $YahooConfig;
  915. if(!$this->sessioned) {
  916. YahooLogger::error("Can't get contacts for an unsessioned user");
  917. return NULL;
  918. }
  919. $parameters = array("view" => "tinyusercard", "start" => $start, "count" => $count);
  920. $contacts = $this->get_resource("contacts",$parameters);
  921. return $contacts;
  922. }
  923. function getContact($contact_id)
  924. {
  925. global $YahooConfig;
  926. if(!$this->sessioned) {
  927. YahooLogger::error("Can't get contacts for an unsessioned user");
  928. return NULL;
  929. }
  930. $parameters = array();
  931. $contacts = $this->get_resource(sprintf("contact/%s", $contact_id), $parameters);
  932. return $contacts;
  933. }
  934. function getContactSync($rev = 0)
  935. {
  936. global $YahooConfig;
  937. if(!$this->sessioned) {
  938. YahooLogger::error("Can't get contacts for an unsessioned user");
  939. return NULL;
  940. }
  941. $parameters = array('view' => 'sync', 'rev' => $rev);
  942. $contactsync = $this->get_resource("contacts",$parameters);
  943. return $contactsync;
  944. }
  945. function syncContacts($contactsync)
  946. {
  947. global $YahooConfig;
  948. if(!$this->sessioned) {
  949. YahooLogger::error("Can't get contacts for an unsessioned user");
  950. return NULL;
  951. }
  952. $parameters = array('format' => 'json');
  953. $data = array('contactsync' => $contactsync);
  954. $body = json_encode($data);
  955. $request_url = sprintf("http://%s/v1/user/%s/contacts", $YahooConfig["SOCIAL_WS_HOSTNAME"], $this->guid);
  956. $response = $this->client->put($request_url, "application/json", $body);
  957. return !(YahooUtil::is_response_error($response));
  958. }
  959. function addContact($contact)
  960. {
  961. global $YahooConfig;
  962. if(!$this->sessioned) {
  963. YahooLogger::error("Can't get contacts for an unsessioned user");
  964. return NULL;
  965. }
  966. $data = array('contact' => $contact);
  967. $body = json_encode($data);
  968. $request_url = sprintf("http://%s/v1/user/%s/contacts", $YahooConfig["SOCIAL_WS_HOSTNAME"], $this->guid);
  969. $response = $this->client->post($request_url, "application/json", $body);
  970. return !(YahooUtil::is_response_error($response));
  971. }
  972. /**
  973. * Sets the small view for the current user.
  974. *
  975. * @param $content The content to set the small view to.
  976. * @return True on success, false otherwise.
  977. */
  978. function setSmallView($content) {
  979. return $this->session->application->setSmallView($this->guid, $content);
  980. }
  981. /**
  982. * @private
  983. */
  984. function get_resource($resource, $parameters=array())
  985. {
  986. global $YahooConfig;
  987. $request_url = sprintf("http://%s/v1/user/%s/%s",
  988. $YahooConfig["SOCIAL_WS_HOSTNAME"], urlencode($this->guid), $resource);
  989. $response = $this->client->get($request_url,$parameters);
  990. $data = json_decode($response["responseBody"]);
  991. return (YahooUtil::is_response_error($response)) ? null : $data;
  992. }
  993. ///////////////////////////////////////////////////////////////////////////
  994. // Deprecated methods
  995. ///////////////////////////////////////////////////////////////////////////
  996. /**
  997. * Loads the extended profile of the current user.
  998. * @deprecated As of 1.2, replaced by getProfile.
  999. * @return The extended profile of the current user.
  1000. */
  1001. function loadProfile() {
  1002. // method renamed, keeping for compatibility.
  1003. YahooLogger::info("loadProfile is deprecated since 1.2: Please use getProfile");
  1004. return $this->getProfile();
  1005. }
  1006. /**
  1007. * Lists the updates for the current user.
  1008. * @deprecated As of 1.2, replaced by getUpdates.
  1009. *
  1010. *
  1011. * @param $start The starting offset to list updates from. (default = 0)
  1012. * @param $count The number of updates to request. (default = 10)
  1013. * @return A list of updates for the current user.
  1014. */
  1015. function listUpdates($start = 0, $count = 10) {
  1016. // method renamed, keeping for compatibility.
  1017. YahooLogger::info("listUpdates is deprecated since 1.2: Please use getUpdates");
  1018. return $this->getUpdates($start, $count);
  1019. }
  1020. /**
  1021. * Gets the updates for the connections of the current user.
  1022. * @deprecated As of 1.2, replaced by getConnectionUpdates.
  1023. * @param $start The starting offset to list updates from.
  1024. * @param $count The number of updates to request.
  1025. * @return An array of updates for the connections of the current user.
  1026. */
  1027. function listConnectionUpdates($start = 0, $count = 10) {
  1028. // method renamed, keeping for compatibility.
  1029. YahooLogger::info("listConnectionUpdates is deprecated since 1.2: Please use getConnectionUpdates");
  1030. return $this->getConnectionUpdates($start, $count);
  1031. }
  1032. /**
  1033. * Gets the presence of the user, including the status.
  1034. *
  1035. * @return The presence of the user or NULL if the fetch fails.
  1036. * @deprecated As of 1.2, replaced by getStatus
  1037. */
  1038. function getPresence() {
  1039. global $YahooConfig;
  1040. YahooLogger::info("getPresence is deprecated since 1.2: Please use getStatus.");
  1041. $request_url = sprintf("http://%s/v1/user/%s/presence/presence",
  1042. $YahooConfig["PRESENCE_WS_HOSTNAME"],urlencode($this->guid));
  1043. $response = $this->client->get($request_url);
  1044. if(is_null($response)) {
  1045. return NULL;
  1046. }
  1047. else if($response["code"] == 404) {
  1048. // No presence is set, return an empty presence.
  1049. $presence = new stdclass();
  1050. $presence->value = new stdclass();
  1051. $presence->value->status = "";
  1052. return $presence;
  1053. }
  1054. else if($response["code"] != 200) {
  1055. return NULL;
  1056. }
  1057. else {
  1058. $presence = json_decode($response["responseBody"]);
  1059. return $presence->presence;
  1060. }
  1061. }
  1062. /**
  1063. * Sets the presence of the user.
  1064. *
  1065. * @param $status The new status message for the user.
  1066. * @return The status message on success, NULL on failure.
  1067. * @deprecated As of 1.2, replaced by setStatus
  1068. */
  1069. function setPresence($status) {
  1070. global $YahooConfig;
  1071. YahooLogger::info("setPresence is deprecated since 1.2: Please use setStatus");
  1072. if(!$this->sessioned) {
  1073. YahooLogger::error("Can't set the presence of an unsessioned user");
  1074. return NULL;
  1075. }
  1076. $presence = array("status" => $status);
  1077. $presence_json = json_encode($presence);
  1078. $request_url = sprintf("http://%s/v1/user/%s/presence/presence", $YahooConfig["PRESENCE_WS_HOSTNAME"], $this->guid);
  1079. $response = $this->client->put($request_url, "application/json", $presence_json);
  1080. if(YahooUtil::is_response_error($response)) {
  1081. return NULL;
  1082. }
  1083. $presence = json_decode($response["responseBody"]);
  1084. return $presence;
  1085. }
  1086. ///////////////////////////////////////////////////////////////////////////
  1087. // End Deprecated methods
  1088. ///////////////////////////////////////////////////////////////////////////
  1089. }
  1090. /**
  1091. * @private
  1092. */
  1093. class YahooAuthorization {
  1094. function getRequestToken($consumerKey, $consumerSecret, $callback) {
  1095. global $YahooConfig;
  1096. if(is_null($callback)) {
  1097. $callback = "oob";
  1098. }
  1099. $consumer = new OAuthConsumer($consumerKey, $consumerSecret);
  1100. $client = new OAuthClient($consumer, NULL, OAUTH_PARAMS_IN_POST_BODY, OAUTH_SIGNATURE_HMAC_SHA1);
  1101. $request_url = sprintf("https://%s/oauth/v2/get_request_token", $YahooConfig["OAUTH_HOSTNAME"]);
  1102. $parameters = array("oauth_callback" => $callback);
  1103. $response = $client->post($request_url, "application/x-www-form-urlencoded", $parameters);
  1104. if(is_null($response)) {
  1105. YahooLogger::error("OAuth call to get request token failed");
  1106. return NULL;
  1107. }
  1108. parse_str($response["responseBody"], $token);
  1109. if($response["code"] != 200) {
  1110. $problem = array_key_exists("oauth_problem", $token) ?
  1111. $token["oauth_problem"] : "unknown problem";
  1112. YahooLogger::error("Failed to create request token: $problem");
  1113. return NULL;
  1114. }
  1115. if(!array_key_exists("oauth_callback_confirmed", $token) ||
  1116. !$token["oauth_callback_confirmed"]) {
  1117. // Callback wasn't confirmed.
  1118. YahooLogger::error("Failed to create request token: callback was not confirmed");
  1119. return NULL;
  1120. }
  1121. $requestToken = new stdclass();
  1122. $requestToken->key = $token["oauth_token"];
  1123. $requestToken->secret = $token["oauth_token_secret"];
  1124. return $requestToken;
  1125. }
  1126. function createAuthorizationUrl($requestToken) {
  1127. global $YahooConfig;
  1128. if(!is_object($requestToken) || !property_exists($requestToken, "key")) {
  1129. YahooLogger::error("Request token doesn't have a 'key' property");
  1130. return NULL;
  1131. }
  1132. return sprintf("https://%s/oauth/v2/request_auth?oauth_token=%s", $YahooConfig["OAUTH_HOSTNAME"], urlencode($requestToken->key));
  1133. }
  1134. function getAccessToken($consumerKey, $consumerSecret, $requestToken, $verifier) {
  1135. $at = YahooAuthorization::getAccessTokenProxy($consumerKey, $consumerSecret, $requestToken, $verifier);
  1136. if(is_null($at)) {
  1137. // Failed to fetch the access token, sleep for 250ms and
  1138. // then try one more time.
  1139. YahooLogger::info("Failed to fetch access token, retrying");
  1140. usleep(250000);
  1141. $at = YahooAuthorization::getAccessTokenProxy($consumerKey, $consumerSecret, $requestToken, $verifier);
  1142. }
  1143. return $at;
  1144. }
  1145. function getAccessTokenProxy($consumerKey, $consumerSecret, $requestToken, $verifier) {
  1146. global $YahooConfig;
  1147. $request_url = sprintf("https://%s/oauth/v2/get_token", $YahooConfig["OAUTH_HOSTNAME"]);
  1148. $consumer = new OAuthConsumer($consumerKey, $consumerSecret);
  1149. $parameters = array();
  1150. if(property_exists($requestToken, "sessionHandle")) {
  1151. $parameters["oauth_session_handle"] = $requestToken->sessionHandle;
  1152. }
  1153. if(!is_null($verifier)) {
  1154. $parameters["oauth_verifier"] = $verifier;
  1155. }
  1156. $client = new OAuthClient($consumer, $requestToken, OAUTH_PARAMS_IN_POST_BODY);
  1157. $response = $client->post($request_url, "application/x-www-form-urlencoded", $parameters);
  1158. if(is_null($response)) {
  1159. YahooLogger::error("OAuth call to get access token failed");
  1160. return NULL;
  1161. }
  1162. parse_str($response["responseBody"], $token);
  1163. if($response["code"] != 200) {
  1164. YahooLogger::error("Failed to fetch access token: " . $token["oauth_problem"]);
  1165. return NULL;
  1166. }
  1167. $now = time();
  1168. $accessToken = new stdclass();
  1169. $accessToken->key = $token["oauth_token"];
  1170. $accessToken->secret = $token["oauth_token_secret"];
  1171. $accessToken->guid = $token["xoauth_yahoo_guid"];
  1172. $accessToken->consumer = $consumerKey;
  1173. $accessToken->sessionHandle = $token["oauth_session_handle"];
  1174. // Check to see if the access token ever expires.
  1175. YahooLogger::debug('AT expires in '.$token['oauth_expires_in'].'; ASH expires in '.$token["oauth_authorization_expires_in"]);
  1176. if(array_key_exists("oauth_expires_in", $token)) {
  1177. $accessToken->tokenExpires = $now + $token["oauth_expires_in"];
  1178. }
  1179. else {
  1180. $accessToken->tokenExpires = -1;
  1181. }
  1182. // Check to see if the access session handle ever expires.
  1183. if(array_key_exists("oauth_authorization_expires_in", $token)) {
  1184. $accessToken->handleExpires = $now +
  1185. $token["oauth_authorization_expires_in"];
  1186. }
  1187. else {
  1188. $accessToken->handleExpires = -1;
  1189. }
  1190. return $accessToken;
  1191. }
  1192. }
  1193. /**
  1194. * Cookie-based implementation of the session store. This is the default
  1195. * session storage used by the Y!OS PHP SDK. Developers are free to
  1196. * implement their own session store implementations and pass them to
  1197. * YahooSession::hasSession, YahooSession::requireSession and
  1198. * YahooSession::clearSession. By default, if no session store is passed
  1199. * to YahooSession::hasSession or YahooSession::requireSession, an instance
  1200. * of a NativeSessionStore is used.
  1201. *
  1202. * @brief Cookie-based implementation of the session store.
  1203. */
  1204. class CookieSessionStore {
  1205. /**
  1206. * Indicates if the session store has a request token.
  1207. *
  1208. * @return True if a request token is present, false otherwise.
  1209. */
  1210. function hasRequestToken() {
  1211. return array_key_exists("yosdk_rt", $_COOKIE) && (strlen($_COOKIE["yosdk_rt"]) > 0);
  1212. }
  1213. /**
  1214. * Indicates if the session store has an access token.
  1215. *
  1216. * @return True if an access token is present, false otherwise.
  1217. */
  1218. function hasAccessToken() {
  1219. return array_key_exists("yosdk_at", $_COOKIE) && (strlen($_COOKIE["yosdk_at"]) > 0);
  1220. }
  1221. /**
  1222. * Stores the given request token in the session store.
  1223. *
  1224. * @param $token A PHP stdclass object containing the components of
  1225. * the OAuth request token.
  1226. * @return True on success, false otherwise.
  1227. */
  1228. function storeRequestToken($token) {
  1229. if(!headers_sent()) {
  1230. return setcookie("yosdk_rt", base64_encode(json_encode($token)), time() + 600);
  1231. }
  1232. else {
  1233. return false;
  1234. }
  1235. }
  1236. /**
  1237. * Fetches and returns the request token from the session store.
  1238. *
  1239. * @return The request token.
  1240. */
  1241. function fetchRequestToken() {
  1242. return json_decode(base64_decode($_COOKIE["yosdk_rt"]));
  1243. }
  1244. /**
  1245. * Clears the request token from the session store.
  1246. *
  1247. * @return True on success, false otherwise.
  1248. */
  1249. function clearRequestToken() {
  1250. if(!headers_sent()) {
  1251. return setcookie("yosdk_rt", "", time() - 600);
  1252. }
  1253. else {
  1254. return false;
  1255. }
  1256. }
  1257. /**
  1258. * Stores the given access token in the session store.
  1259. *
  1260. * @param $token A PHP stdclass object containing the components of
  1261. * the OAuth access token.
  1262. * @return True on success, false otherwise.
  1263. */
  1264. function storeAccessToken($token) {
  1265. if(!headers_sent()) {
  1266. return setcookie("yosdk_at", base64_encode(json_encode($token)),
  1267. time() + (30 * 24 * 60 * 60));
  1268. }
  1269. else {
  1270. return false;
  1271. }
  1272. }
  1273. /**
  1274. * Fetches and returns the access token from the session store.
  1275. *
  1276. * @return The access token.
  1277. */
  1278. function fetchAccessToken() {
  1279. return json_decode(base64_decode($_COOKIE["yosdk_at"]));
  1280. }
  1281. /**
  1282. * Clears the access token from the session store.
  1283. *
  1284. * @return True on success, false otherwise.
  1285. */
  1286. function clearAccessToken() {
  1287. if(!headers_sent()) {
  1288. return setcookie("yosdk_at", "", time() - 600);
  1289. }
  1290. else {
  1291. return false;
  1292. }
  1293. }
  1294. }
  1295. /**
  1296. * PHP session based implementation of the session store. This is the default
  1297. * session storage used by the Y!OS PHP SDK. Developers are free to
  1298. * implement their own session store implementations and pass them to
  1299. * YahooSession::hasSession, YahooSession::requireSession and
  1300. * YahooSession::clearSession. By default, if no session store is passed
  1301. * to YahooSession::hasSession or YahooSession::requireSession, an instance
  1302. * of a NativeSessionStore is used.
  1303. *
  1304. * @brief Native php session based implementation of the session store, by default
  1305. * stored on file system, but can be database or memcache backend.
  1306. */
  1307. class NativeSessionStore {
  1308. function NativeSessionStore() {
  1309. $id = session_id();
  1310. if(empty($id)) {
  1311. session_start();
  1312. }
  1313. }
  1314. /**
  1315. * Indicates if the session store has a request token.
  1316. *
  1317. * @return True if a request token is present, false otherwise.
  1318. */
  1319. function hasRequestToken() {
  1320. return array_key_exists("yosdk_rt", $_SESSION) && (strlen($_SESSION["yosdk_rt"]) > 0);
  1321. }
  1322. /**
  1323. * Indicates if the session store has an access token.
  1324. *
  1325. * @return True if an access token is present, false otherwise.
  1326. */
  1327. function hasAccessToken() {
  1328. return array_key_exists("yosdk_at", $_SESSION) && (strlen($_SESSION["yosdk_at"]) > 0);
  1329. }
  1330. /**
  1331. * Stores the given request token in the session store.
  1332. *
  1333. * @param $token A PHP stdclass object containing the components of the OAuth request token.
  1334. */
  1335. function storeRequestToken($token) {
  1336. $_SESSION['yosdk_rt'] = json_encode($token);
  1337. }
  1338. /**
  1339. * Fetches and returns the request token from the session store.
  1340. *
  1341. * @return The request token.
  1342. */
  1343. function fetchRequestToken() {
  1344. return isset($_SESSION["yosdk_rt"]) ? json_decode($_SESSION["yosdk_rt"]) : false;
  1345. }
  1346. /**
  1347. * Clears the request token from the session store.
  1348. *
  1349. */
  1350. function clearRequestToken() {
  1351. unset($_SESSION['yosdk_rt']);
  1352. }
  1353. /**
  1354. * Stores the given access token in the session store.
  1355. *
  1356. * @param $token A PHP stdclass object containing the components of the OAuth access token.
  1357. */
  1358. function storeAccessToken($token) {
  1359. $_SESSION['yosdk_at'] = json_encode($token);
  1360. }
  1361. /**
  1362. * Fetches and returns the access token from the session store.
  1363. *
  1364. * @return The access token.
  1365. */
  1366. function fetchAccessToken() {
  1367. return isset($_SESSION["yosdk_at"]) ? json_decode($_SESSION["yosdk_at"]) : false;
  1368. }
  1369. /**
  1370. * Clears the access token from the session store.
  1371. *
  1372. */
  1373. function clearAccessToken() {
  1374. unset($_SESSION['yosdk_at']);
  1375. }
  1376. }
  1377. /**
  1378. * A simple OAuth client class for making 2 and 3 legged OAuth HTTP requests.
  1379. *
  1380. * @brief A simple OAuth client class for making 2 and 3 legged OAuth HTTP requests.
  1381. */
  1382. class OAuthClient {
  1383. /**
  1384. * @private
  1385. */
  1386. var $consumer = NULL;
  1387. /**
  1388. * @private
  1389. */
  1390. var $token = NULL;
  1391. /**
  1392. * @private
  1393. */
  1394. var $defaultTimeout = 3;
  1395. /**
  1396. * @private
  1397. */
  1398. var $oauthParamsLocation = NULL;
  1399. /**
  1400. * @private
  1401. */
  1402. var $signatureMethod = NULL;
  1403. /**
  1404. * @private
  1405. */
  1406. var $accepts = "application/json";
  1407. /**
  1408. * Constructs a new OAuth client.
  1409. *
  1410. * @param $consumer The OAuthConsumer object to use for the requests.
  1411. * @param $token The OAuthToken to use for the requests. Optional.
  1412. * @param $oauthParamsLocation OAUTH_PARAMS_IN_HEADERS or OAUTH_PARAMS_IN_POST_BODY, depending on where you want the OAuth parameters to show up. Optional, defaults to using the headers.
  1413. * @param $signatureMethod OAUTH_SIGNATURE_PLAINTEXT or OAUTH_SIGNATURE_HMAC_SHA1, depending on what request signing mechanism to use. Optional, defaults to HMAC SHA1 signatures.
  1414. */
  1415. function OAuthClient($consumer, $token = NULL, $oauthParamsLocation = OAUTH_PARAMS_IN_HEADERS, $signatureMethod = OAUTH_SIGNATURE_HMAC_SHA1) {
  1416. $this->consumer = $consumer;
  1417. $this->token = $token;
  1418. $this->oauthParamsLocation = $oauthParamsLocation;
  1419. if($signatureMethod == OAUTH_SIGNATURE_HMAC_SHA1) {
  1420. $this->signatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
  1421. }
  1422. else if($signatureMethod == OAUTH_SIGNATURE_PLAINTEXT) {
  1423. $this->signatureMethod = new OAuthSignatureMethod_PLAINTEXT();
  1424. }
  1425. else {
  1426. YahooLogger::error("Invalid signature method: $signatureMethod");
  1427. }
  1428. }
  1429. /**
  1430. * Executes a properly signed OAuth HTTP GET request.
  1431. *
  1432. * @param $url The URL to request.
  1433. * @param $queryParameters Any query string parameters to be sent in the request.
  1434. * @param $timeout Optional, the number of seconds to wait for the request to return.
  1435. * @return The response object.
  1436. */
  1437. function get($url, $queryParameters = array(), $timeout = NULL) {
  1438. if(strpos($url, "?") !== FALSE) {
  1439. YahooLogger::error("Put the query parameters in the second argument to OAuthClient::get(), not in the URL itself: URL = $url");
  1440. return NULL;
  1441. }
  1442. return $this->request(array(
  1443. "method" => "GET",
  1444. "url" => $url,
  1445. "query" => $queryParameters,
  1446. "timeout" => $timeout));
  1447. }
  1448. /**
  1449. * Executes a properly signed OAuth HTTP DELETE request.
  1450. *
  1451. * @param $url The URL to request.
  1452. * @param $queryParameters Any query string parameters to be sent in the request.
  1453. * @param $timeout Optional, the number of seconds to wait for the request to return.
  1454. * @return The response object.
  1455. */
  1456. function delete($url, $queryParameters = array(), $timeout = NULL) {
  1457. if(strpos($url, "?") !== FALSE) {
  1458. YahooLogger::error("Put the query parameters in the second argument to OAuthClient::delete(), not in the URL itself: URL = $url");
  1459. return NULL;
  1460. }
  1461. return $this->request(array(
  1462. "method" => "DELETE",
  1463. "url" => $url,
  1464. "query" => $queryParameters,
  1465. "timeout" => $timeout));
  1466. }
  1467. /**
  1468. * Executes a properly signed OAuth HTTP PUT request.
  1469. *
  1470. * @param $url The URL to request.
  1471. * @param $contentType The Content-Type of the PUT data.
  1472. * @param $content The raw content to be PUT.
  1473. * @param $timeout Optional, the number of seconds to wait for the request to return.
  1474. * @return The response object.
  1475. */
  1476. function put($url, $contentType, $content, $timeout = NULL) {
  1477. return $this->request(array(
  1478. "method" => "PUT",
  1479. "url" => $url,
  1480. "content" => $content,
  1481. "contentType" => $contentType,
  1482. "timeout" => $timeout));
  1483. }
  1484. /**
  1485. * Executes a properly signed OAuth HTTP POST request.
  1486. *
  1487. * @param $url The URL to request.
  1488. * @param $contentType The Content-Type of the POST data.
  1489. * @param $content The content to be POST.
  1490. * @param $timeout Optional, the number of seconds to wait for the request to return.
  1491. * @return The response object.
  1492. */
  1493. function post($url, $contentType = "application/x-www-form-urlencoded",
  1494. $content = array(), $timeout = NULL) {
  1495. return $this->request(array(
  1496. "method" => "POST",
  1497. "url" => $url,
  1498. "content" => $content,
  1499. "contentType" => $contentType,
  1500. "timeout" => $timeout));
  1501. }
  1502. /**
  1503. * @private
  1504. */
  1505. function request($request) {
  1506. if(!array_key_exists("content", $request)) {
  1507. $request["content"] = array();
  1508. }
  1509. if(!array_key_exists("query", $request)) {
  1510. $request["query"] = array();
  1511. }
  1512. if(is_array($request["content"])) {
  1513. $combinedParams = array_merge(
  1514. $request["query"], $request["content"]);
  1515. }
  1516. else {
  1517. $combinedParams = $request["query"];
  1518. }
  1519. $oauthRequest = OAuthRequest::from_consumer_and_token(
  1520. $this->consumer, $this->token, $request["method"],
  1521. $request["url"], $combinedParams);
  1522. $oauthRequest->sign_request($this->signatureMethod, $this->consumer,
  1523. $this->token);
  1524. $headers = array("Accept: " . $this->accepts);
  1525. if($this->oauthParamsLocation == OAUTH_PARAMS_IN_HEADERS) {
  1526. $headers[] = $oauthRequest->to_header();
  1527. }
  1528. if(!empty($request["content"]) || $this->oauthParamsLocation == OAUTH_PARAMS_IN_POST_BODY) {
  1529. $headers[] = "Content-Type: " . $request["contentType"];
  1530. }
  1531. if(!empty($request["query"])) {
  1532. $requestUrl = sprintf("%s?%s", $request["url"], oauth_http_build_query($request["query"]));
  1533. }
  1534. else {
  1535. $requestUrl = $request["url"];
  1536. }
  1537. $requestTimeout = array_key_exists("timeout", $request) ?
  1538. $request["timeout"] : $this->defaultTimeout;
  1539. $ch = curl_init($requestUrl);
  1540. curl_setopt($ch, CURLOPT_TIMEOUT, $requestTimeout);
  1541. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  1542. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  1543. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $request["method"]);
  1544. if(($this->oauthParamsLocation == OAUTH_PARAMS_IN_POST_BODY) ||
  1545. (!empty($request["content"]) && is_array($request["content"]))) {
  1546. // Content is an array, URL encode it.
  1547. if($this->oauthParamsLocation == OAUTH_PARAMS_IN_POST_BODY) {
  1548. $request["content"] = $oauthRequest->to_postdata();
  1549. curl_setopt($ch, CURLOPT_POSTFIELDS, $request["content"]);
  1550. }
  1551. else {
  1552. curl_setopt($ch, CURLOPT_POSTFIELDS, oauth_http_build_query($request["content"]));
  1553. }
  1554. }
  1555. else if(!empty($request["content"])) {
  1556. // Content is raw.
  1557. curl_setopt($ch, CURLOPT_POSTFIELDS, $request["content"]);
  1558. }
  1559. // Enable compressed responses from the servers.
  1560. curl_setopt($ch, CURLOPT_ENCODING, "");
  1561. // Set the user agent so the SDK properly identifies itself for
  1562. // usage tracking purposes. Include the version of the SDK and
  1563. // the version of PHP being used.
  1564. $sdkVersion = "1.2";
  1565. $agent = sprintf("YosPhpSdk/%s php/%s", $sdkVersion, phpversion());
  1566. curl_setopt($ch, CURLOPT_USERAGENT, $agent);
  1567. $headerParser = new YahooHeaderParser();
  1568. curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$headerParser, "read"));
  1569. $response = curl_exec($ch);
  1570. if(is_bool($response) && !$response) {
  1571. YahooLogger::error("Error making libcurl request(" . $requestUrl . "): " . curl_error($ch));
  1572. return NULL;
  1573. }
  1574. $response = array(
  1575. 'method' => $request["method"],
  1576. 'url' => $requestUrl,
  1577. 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
  1578. 'requestHeaders' => $headers,
  1579. 'requestBody' => !empty($request["content"]) ? $request["content"] : NULL,
  1580. 'responseHeaders' => $headerParser->headers,
  1581. 'responseBody' => $response
  1582. );
  1583. if(($response["code"] > 200) && ($response["code"] < 300)) {
  1584. YahooLogger::error("HTTP request failed", $response);
  1585. $this->checkExpired($response["code"], $headerParser);
  1586. return NULL;
  1587. }
  1588. YahooLogger::debug("HTTP request details", $response);
  1589. return $response;
  1590. }
  1591. /**
  1592. * Checks to see if the code and headers indicate an expired OAuth token.
  1593. * If so, requests a new one.
  1594. *
  1595. * @private
  1596. */
  1597. function checkExpired($code, $headerParser) {
  1598. if ($code != 401) return; // HTTP Unauthorized
  1599. $authenticateHeader = $headerParser->get('WWW-Authenticate');
  1600. if (!$authenticateHeader) return;
  1601. if (!preg_match('/oauth_problem="([^"]+)"/', $authenticateHeader, $match)) return;
  1602. $oauth_problem = $match[1];
  1603. if ($oauth_problem == 'token_expired') {
  1604. YahooLogger::error('Access token expired. Please fetch a new one');
  1605. }
  1606. if ($oauth_problem == 'consumer_key_unknown') {
  1607. YahooLogger::error('Consumer Key unkown. Please check that the Consumer Key is valid.');
  1608. }
  1609. if ($oauth_problem == 'additional_authorization_required') {
  1610. YahooLogger::error('The app identified by this Consumer Key is not authorized to access this resource. Authorization is defined under Access Scopes on the application\'s settings page.');
  1611. }
  1612. }
  1613. }
  1614. /**
  1615. * @private
  1616. */
  1617. class YahooHeaderParser {
  1618. var $headers = array();
  1619. function YahooHeaderParser() {
  1620. }
  1621. function read($ch, $header) {
  1622. $pos = strpos($header, ":");
  1623. if($pos !== FALSE) {
  1624. $name = substr($header, 0, $pos);
  1625. $value = trim(substr($header, $pos + 1));
  1626. $this->headers[$name] = $value;
  1627. }
  1628. return strlen($header);
  1629. }
  1630. function get($name) {
  1631. if(array_key_exists($name, $this->headers)) {
  1632. return $this->headers[$name];
  1633. }
  1634. else {
  1635. return NULL;
  1636. }
  1637. }
  1638. }
  1639. /**
  1640. * Interface to modify the underlying configuration of the library.
  1641. */
  1642. class YahooConfig {
  1643. function setSocialWsHostname($hostname) {
  1644. global $YahooConfig;
  1645. $YahooConfig["SOCIAL_WS_HOSTNAME"] = $hostname;
  1646. }
  1647. function setPresenceWsHostname($hostname) {
  1648. global $YahooConfig;
  1649. $YahooConfig["PRESENCE_WS_HOSTNAME"] = $hostname;
  1650. }
  1651. function setUpdatesWsHostname($hostname) {
  1652. global $YahooConfig;
  1653. $YahooConfig["UPDATES_WS_HOSTNAME"] = $hostname;
  1654. }
  1655. function setQueryWsHostname($hostname) {
  1656. global $YahooConfig;
  1657. $YahooConfig["QUERY_WS_HOSTNAME"] = $hostname;
  1658. }
  1659. function setOauthHostname($hostname) {
  1660. global $YahooConfig;
  1661. $YahooConfig["OAUTH_HOSTNAME"] = $hostname;
  1662. }
  1663. function setYapWsHostname($hostname) {
  1664. global $YahooConfig;
  1665. $YahooConfig["YAP_WS_HOSTNAME"] = $hostname;
  1666. }
  1667. }
  1668. /**
  1669. * An OAuth compatible version of http_build_query. http_build_query
  1670. * doesn't work because it turns spaces into "+", which isn't allowed
  1671. * by OAuth.
  1672. */
  1673. function oauth_http_build_query($parameters) {
  1674. $strings = array();
  1675. foreach($parameters as $name => $value) {
  1676. $strings[] = sprintf("%s=%s", rawurlencode($name), rawurlencode($value));
  1677. }
  1678. $query = implode("&", $strings);
  1679. return $query;
  1680. }
  1681. /**
  1682. * PHP4/5 compatibility functions
  1683. */
  1684. if(!function_exists("property_exists")) {
  1685. function property_exists( $class, $property ) {
  1686. if ( is_object( $class ) ) {
  1687. $vars = get_object_vars( $class );
  1688. } else {
  1689. $vars = get_class_vars( $class );
  1690. }
  1691. return array_key_exists( $property, $vars );
  1692. }
  1693. }
  1694. // If json_decode doesn't exist, then php-json must not be included in this
  1695. // version of PHP. Include fake versions of json_encode/json_decode that
  1696. // are backed by the native PHP php-json library, which is available in PEAR.
  1697. if(!function_exists("json_decode")) {
  1698. // Only include JSON.php if someone else hasn't already. Depending on
  1699. // the operating environment, other code may have brought their own
  1700. // version of that source code.
  1701. if(!class_exists("Services_JSON")) {
  1702. include_once("JSON.php");
  1703. }
  1704. function json_decode($json) {
  1705. $js = new Services_JSON();
  1706. return $js->decode($json);
  1707. }
  1708. function json_encode($value) {
  1709. $js = new Services_JSON();
  1710. return $js->encode($value);
  1711. }
  1712. }