PageRenderTime 58ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/yosdk/lib/Yahoo.inc

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