1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
17:
18: if (!function_exists('curl_init')) {
19: throw new Exception('Facebook needs the CURL PHP extension.');
20: }
21: if (!function_exists('json_decode')) {
22: throw new Exception('Facebook needs the JSON PHP extension.');
23: }
24:
25: 26: 27: 28: 29:
30: class FacebookApiException extends Exception
31: {
32: 33: 34:
35: protected $result;
36:
37: 38: 39: 40: 41:
42: public function __construct($result) {
43: $this->result = $result;
44:
45: $code = isset($result['error_code']) ? $result['error_code'] : 0;
46:
47: if (isset($result['error_description'])) {
48:
49: $msg = $result['error_description'];
50: } else if (isset($result['error']) && is_array($result['error'])) {
51:
52: $msg = $result['error']['message'];
53: } else if (isset($result['error_msg'])) {
54:
55: $msg = $result['error_msg'];
56: } else {
57: $msg = 'Unknown Error. Check getResult()';
58: }
59:
60: parent::__construct($msg, $code);
61: }
62:
63: 64: 65: 66: 67:
68: public function getResult() {
69: return $this->result;
70: }
71:
72: 73: 74: 75: 76: 77:
78: public function getType() {
79: if (isset($this->result['error'])) {
80: $error = $this->result['error'];
81: if (is_string($error)) {
82:
83: return $error;
84: } else if (is_array($error)) {
85:
86: if (isset($error['type'])) {
87: return $error['type'];
88: }
89: }
90: }
91:
92: return 'Exception';
93: }
94:
95: 96: 97: 98: 99:
100: public function __toString() {
101: $str = $this->getType() . ': ';
102: if ($this->code != 0) {
103: $str .= $this->code . ': ';
104: }
105: return $str . $this->message;
106: }
107: }
108:
109: 110: 111: 112: 113: 114: 115: 116: 117:
118: abstract class BaseFacebook
119: {
120: 121: 122:
123: const VERSION = '3.1.1';
124:
125: 126: 127:
128: public static $CURL_OPTS = array(
129: CURLOPT_CONNECTTIMEOUT => 10,
130: CURLOPT_RETURNTRANSFER => true,
131: CURLOPT_TIMEOUT => 60,
132: CURLOPT_USERAGENT => 'facebook-php-3.1',
133: );
134:
135: 136: 137: 138:
139: protected static $DROP_QUERY_PARAMS = array(
140: 'code',
141: 'state',
142: 'signed_request',
143: );
144:
145: 146: 147:
148: public static $DOMAIN_MAP = array(
149: 'api' => 'https://api.facebook.com/',
150: 'api_video' => 'https://api-video.facebook.com/',
151: 'api_read' => 'https://api-read.facebook.com/',
152: 'graph' => 'https://graph.facebook.com/',
153: 'graph_video' => 'https://graph-video.facebook.com/',
154: 'www' => 'https://www.facebook.com/',
155: );
156:
157: 158: 159: 160: 161:
162: protected $appId;
163:
164: 165: 166: 167: 168:
169: protected $appSecret;
170:
171: 172: 173: 174: 175:
176: protected $user;
177:
178: 179: 180:
181: protected $signedRequest;
182:
183: 184: 185:
186: protected $state;
187:
188: 189: 190: 191: 192: 193:
194: protected $accessToken = null;
195:
196: 197: 198: 199: 200:
201: protected $fileUploadSupport = false;
202:
203: 204: 205: 206: 207: 208: 209: 210: 211: 212:
213: public function __construct($config) {
214: $this->setAppId($config['appId']);
215: $this->setAppSecret($config['secret']);
216: if (isset($config['fileUpload'])) {
217: $this->setFileUploadSupport($config['fileUpload']);
218: }
219:
220: $state = $this->getPersistentData('state');
221: if (!empty($state)) {
222: $this->state = $this->getPersistentData('state');
223: }
224: }
225:
226: 227: 228: 229: 230: 231:
232: public function setAppId($appId) {
233: $this->appId = $appId;
234: return $this;
235: }
236:
237: 238: 239: 240: 241:
242: public function getAppId() {
243: return $this->appId;
244: }
245:
246: 247: 248: 249: 250: 251: 252:
253: public function setApiSecret($apiSecret) {
254: $this->setAppSecret($apiSecret);
255: return $this;
256: }
257:
258: 259: 260: 261: 262: 263:
264: public function setAppSecret($appSecret) {
265: $this->appSecret = $appSecret;
266: return $this;
267: }
268:
269: 270: 271: 272: 273: 274:
275: public function getApiSecret() {
276: return $this->getAppSecret();
277: }
278:
279: 280: 281: 282: 283:
284: public function getAppSecret() {
285: return $this->appSecret;
286: }
287:
288: 289: 290: 291: 292: 293:
294: public function setFileUploadSupport($fileUploadSupport) {
295: $this->fileUploadSupport = $fileUploadSupport;
296: return $this;
297: }
298:
299: 300: 301: 302: 303:
304: public function getFileUploadSupport() {
305: return $this->fileUploadSupport;
306: }
307:
308: 309: 310: 311: 312: 313: 314:
315: public function useFileUploadSupport() {
316: return $this->getFileUploadSupport();
317: }
318:
319: 320: 321: 322: 323: 324: 325: 326:
327: public function setAccessToken($access_token) {
328: $this->accessToken = $access_token;
329: return $this;
330: }
331:
332: 333: 334: 335: 336: 337: 338: 339: 340:
341: public function getAccessToken() {
342: if ($this->accessToken !== null) {
343:
344: return $this->accessToken;
345: }
346:
347:
348:
349:
350: $this->setAccessToken($this->getApplicationAccessToken());
351: $user_access_token = $this->getUserAccessToken();
352: if ($user_access_token) {
353: $this->setAccessToken($user_access_token);
354: }
355:
356: return $this->accessToken;
357: }
358:
359: 360: 361: 362: 363: 364: 365: 366: 367: 368:
369: protected function getUserAccessToken() {
370:
371:
372:
373: $signed_request = $this->getSignedRequest();
374: if ($signed_request) {
375:
376: if (array_key_exists('oauth_token', $signed_request)) {
377: $access_token = $signed_request['oauth_token'];
378: $this->setPersistentData('access_token', $access_token);
379: return $access_token;
380: }
381:
382:
383: if (array_key_exists('code', $signed_request)) {
384: $code = $signed_request['code'];
385: $access_token = $this->getAccessTokenFromCode($code, '');
386: if ($access_token) {
387: $this->setPersistentData('code', $code);
388: $this->setPersistentData('access_token', $access_token);
389: return $access_token;
390: }
391: }
392:
393:
394:
395: $this->clearAllPersistentData();
396: return false;
397:
398: }
399:
400: $code = $this->getCode();
401: if ($code && $code != $this->getPersistentData('code')) {
402: $access_token = $this->getAccessTokenFromCode($code);
403: if ($access_token) {
404: $this->setPersistentData('code', $code);
405: $this->setPersistentData('access_token', $access_token);
406: return $access_token;
407: }
408:
409:
410: $this->clearAllPersistentData();
411: return false;
412: }
413:
414:
415:
416:
417:
418: return $this->getPersistentData('access_token');
419: }
420:
421: 422: 423: 424: 425: 426:
427: public function getSignedRequest() {
428: if (!$this->signedRequest) {
429: if (isset($_REQUEST['signed_request'])) {
430: $this->signedRequest = $this->parseSignedRequest(
431: $_REQUEST['signed_request']);
432: } else if (isset($_COOKIE[$this->getSignedRequestCookieName()])) {
433: $this->signedRequest = $this->parseSignedRequest(
434: $_COOKIE[$this->getSignedRequestCookieName()]);
435: }
436: }
437: return $this->signedRequest;
438: }
439:
440: 441: 442: 443: 444: 445:
446: public function getUser() {
447: if ($this->user !== null) {
448:
449: return $this->user;
450: }
451:
452: return $this->user = $this->getUserFromAvailableData();
453: }
454:
455: 456: 457: 458: 459: 460: 461: 462:
463: protected function getUserFromAvailableData() {
464:
465:
466: $signed_request = $this->getSignedRequest();
467: if ($signed_request) {
468: if (array_key_exists('user_id', $signed_request)) {
469: $user = $signed_request['user_id'];
470: $this->setPersistentData('user_id', $signed_request['user_id']);
471: return $user;
472: }
473:
474:
475:
476: $this->clearAllPersistentData();
477: return 0;
478: }
479:
480: $user = $this->getPersistentData('user_id', $default = 0);
481: $persisted_access_token = $this->getPersistentData('access_token');
482:
483:
484:
485: $access_token = $this->getAccessToken();
486: if ($access_token &&
487: $access_token != $this->getApplicationAccessToken() &&
488: !($user && $persisted_access_token == $access_token)) {
489: $user = $this->getUserFromAccessToken();
490: if ($user) {
491: $this->setPersistentData('user_id', $user);
492: } else {
493: $this->clearAllPersistentData();
494: }
495: }
496:
497: return $user;
498: }
499:
500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511:
512: public function getLoginUrl($params=array()) {
513: $this->establishCSRFTokenState();
514: $currentUrl = $this->getCurrentUrl();
515:
516:
517: $scopeParams = isset($params['scope']) ? $params['scope'] : null;
518: if ($scopeParams && is_array($scopeParams)) {
519: $params['scope'] = implode(',', $scopeParams);
520: }
521:
522: return $this->getUrl(
523: 'www',
524: 'dialog/oauth',
525: array_merge(array(
526: 'client_id' => $this->getAppId(),
527: 'redirect_uri' => $currentUrl,
528: 'state' => $this->state),
529: $params));
530: }
531:
532: 533: 534: 535: 536: 537: 538: 539: 540:
541: public function getLogoutUrl($params=array()) {
542: return $this->getUrl(
543: 'www',
544: 'logout.php',
545: array_merge(array(
546: 'next' => $this->getCurrentUrl(),
547: 'access_token' => $this->getAccessToken(),
548: ), $params)
549: );
550: }
551:
552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562:
563: public function getLoginStatusUrl($params=array()) {
564: return $this->getUrl(
565: 'www',
566: 'extern/login_status.php',
567: array_merge(array(
568: 'api_key' => $this->getAppId(),
569: 'no_session' => $this->getCurrentUrl(),
570: 'no_user' => $this->getCurrentUrl(),
571: 'ok_session' => $this->getCurrentUrl(),
572: 'session_version' => 3,
573: ), $params)
574: );
575: }
576:
577: 578: 579: 580: 581:
582: public function api() {
583: $args = func_get_args();
584: if (is_array($args[0])) {
585: return $this->_restserver($args[0]);
586: } else {
587: return call_user_func_array(array($this, '_graph'), $args);
588: }
589: }
590:
591: 592: 593: 594: 595: 596: 597: 598: 599:
600: protected function getSignedRequestCookieName() {
601: return 'fbsr_'.$this->getAppId();
602: }
603:
604: 605: 606: 607: 608: 609: 610:
611: protected function getMetadataCookieName() {
612: return 'fbm_'.$this->getAppId();
613: }
614:
615: 616: 617: 618: 619: 620: 621: 622:
623: protected function getCode() {
624: if (isset($_REQUEST['code'])) {
625: if ($this->state !== null &&
626: isset($_REQUEST['state']) &&
627: $this->state === $_REQUEST['state']) {
628:
629:
630: $this->state = null;
631: $this->clearPersistentData('state');
632: return $_REQUEST['code'];
633: } else {
634: self::errorLog('CSRF state token does not match one provided.');
635: return false;
636: }
637: }
638:
639: return false;
640: }
641:
642: 643: 644: 645: 646: 647: 648: 649: 650: 651:
652: protected function getUserFromAccessToken() {
653: try {
654: $user_info = $this->api('/me');
655: return $user_info['id'];
656: } catch (FacebookApiException $e) {
657: return 0;
658: }
659: }
660:
661: 662: 663: 664: 665: 666: 667:
668: protected function getApplicationAccessToken() {
669: return $this->appId.'|'.$this->appSecret;
670: }
671:
672: 673: 674: 675: 676:
677: protected function establishCSRFTokenState() {
678: if ($this->state === null) {
679: $this->state = md5(uniqid(mt_rand(), true));
680: $this->setPersistentData('state', $this->state);
681: }
682: }
683:
684: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695:
696: protected function getAccessTokenFromCode($code, $redirect_uri = null) {
697: if (empty($code)) {
698: return false;
699: }
700:
701: if ($redirect_uri === null) {
702: $redirect_uri = $this->getCurrentUrl();
703: }
704:
705: try {
706:
707:
708: $access_token_response =
709: $this->_oauthRequest(
710: $this->getUrl('graph', '/oauth/access_token'),
711: $params = array('client_id' => $this->getAppId(),
712: 'client_secret' => $this->getAppSecret(),
713: 'redirect_uri' => $redirect_uri,
714: 'code' => $code));
715: } catch (FacebookApiException $e) {
716:
717:
718: return false;
719: }
720:
721: if (empty($access_token_response)) {
722: return false;
723: }
724:
725: $response_params = array();
726: parse_str($access_token_response, $response_params);
727: if (!isset($response_params['access_token'])) {
728: return false;
729: }
730:
731: return $response_params['access_token'];
732: }
733:
734: 735: 736: 737: 738: 739: 740: 741:
742: protected function _restserver($params) {
743:
744: $params['api_key'] = $this->getAppId();
745: $params['format'] = 'json-strings';
746:
747: $result = json_decode($this->_oauthRequest(
748: $this->getApiUrl($params['method']),
749: $params
750: ), true);
751:
752:
753: if (is_array($result) && isset($result['error_code'])) {
754: $this->throwAPIException($result);
755: }
756:
757: if ($params['method'] === 'auth.expireSession' ||
758: $params['method'] === 'auth.revokeAuthorization') {
759: $this->destroySession();
760: }
761:
762: return $result;
763: }
764:
765: 766: 767: 768: 769: 770: 771: 772:
773: protected function isVideoPost($path, $method = 'GET') {
774: if ($method == 'POST' && preg_match("/^(\/)(.+)(\/)(videos)$/", $path)) {
775: return true;
776: }
777: return false;
778: }
779:
780: 781: 782: 783: 784: 785: 786: 787: 788: 789:
790: protected function _graph($path, $method = 'GET', $params = array()) {
791: if (is_array($method) && empty($params)) {
792: $params = $method;
793: $method = 'GET';
794: }
795: $params['method'] = $method;
796:
797: if ($this->isVideoPost($path, $method)) {
798: $domainKey = 'graph_video';
799: } else {
800: $domainKey = 'graph';
801: }
802:
803: $result = json_decode($this->_oauthRequest(
804: $this->getUrl($domainKey, $path),
805: $params
806: ), true);
807:
808:
809: if (is_array($result) && isset($result['error'])) {
810: $this->throwAPIException($result);
811: }
812:
813: return $result;
814: }
815:
816: 817: 818: 819: 820: 821: 822: 823: 824:
825: protected function _oauthRequest($url, $params) {
826: if (!isset($params['access_token'])) {
827: $params['access_token'] = $this->getAccessToken();
828: }
829:
830:
831: foreach ($params as $key => $value) {
832: if (!is_string($value)) {
833: $params[$key] = json_encode($value);
834: }
835: }
836:
837: return $this->makeRequest($url, $params);
838: }
839:
840: 841: 842: 843: 844: 845: 846: 847: 848: 849: 850:
851: protected function makeRequest($url, $params, $ch=null) {
852: if (!$ch) {
853: $ch = curl_init();
854: }
855:
856: $opts = self::$CURL_OPTS;
857: if ($this->getFileUploadSupport()) {
858: $opts[CURLOPT_POSTFIELDS] = $params;
859: } else {
860: $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
861: }
862: $opts[CURLOPT_URL] = $url;
863:
864:
865:
866: if (isset($opts[CURLOPT_HTTPHEADER])) {
867: $existing_headers = $opts[CURLOPT_HTTPHEADER];
868: $existing_headers[] = 'Expect:';
869: $opts[CURLOPT_HTTPHEADER] = $existing_headers;
870: } else {
871: $opts[CURLOPT_HTTPHEADER] = array('Expect:');
872: }
873:
874: curl_setopt_array($ch, $opts);
875: $result = curl_exec($ch);
876:
877: if (curl_errno($ch) == 60) {
878: self::errorLog('Invalid or no certificate authority found, '.
879: 'using bundled information');
880: curl_setopt($ch, CURLOPT_CAINFO,
881: dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
882: $result = curl_exec($ch);
883: }
884:
885: if ($result === false) {
886: $e = new FacebookApiException(array(
887: 'error_code' => curl_errno($ch),
888: 'error' => array(
889: 'message' => curl_error($ch),
890: 'type' => 'CurlException',
891: ),
892: ));
893: curl_close($ch);
894: throw $e;
895: }
896: curl_close($ch);
897: return $result;
898: }
899:
900: 901: 902: 903: 904: 905:
906: protected function parseSignedRequest($signed_request) {
907: list($encoded_sig, $payload) = explode('.', $signed_request, 2);
908:
909:
910: $sig = self::base64UrlDecode($encoded_sig);
911: $data = json_decode(self::base64UrlDecode($payload), true);
912:
913: if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
914: self::errorLog('Unknown algorithm. Expected HMAC-SHA256');
915: return null;
916: }
917:
918:
919: $expected_sig = hash_hmac('sha256', $payload,
920: $this->getAppSecret(), $raw = true);
921: if ($sig !== $expected_sig) {
922: self::errorLog('Bad Signed JSON signature!');
923: return null;
924: }
925:
926: return $data;
927: }
928:
929: 930: 931: 932: 933: 934:
935: protected function getApiUrl($method) {
936: static $READ_ONLY_CALLS =
937: array('admin.getallocation' => 1,
938: 'admin.getappproperties' => 1,
939: 'admin.getbannedusers' => 1,
940: 'admin.getlivestreamvialink' => 1,
941: 'admin.getmetrics' => 1,
942: 'admin.getrestrictioninfo' => 1,
943: 'application.getpublicinfo' => 1,
944: 'auth.getapppublickey' => 1,
945: 'auth.getsession' => 1,
946: 'auth.getsignedpublicsessiondata' => 1,
947: 'comments.get' => 1,
948: 'connect.getunconnectedfriendscount' => 1,
949: 'dashboard.getactivity' => 1,
950: 'dashboard.getcount' => 1,
951: 'dashboard.getglobalnews' => 1,
952: 'dashboard.getnews' => 1,
953: 'dashboard.multigetcount' => 1,
954: 'dashboard.multigetnews' => 1,
955: 'data.getcookies' => 1,
956: 'events.get' => 1,
957: 'events.getmembers' => 1,
958: 'fbml.getcustomtags' => 1,
959: 'feed.getappfriendstories' => 1,
960: 'feed.getregisteredtemplatebundlebyid' => 1,
961: 'feed.getregisteredtemplatebundles' => 1,
962: 'fql.multiquery' => 1,
963: 'fql.query' => 1,
964: 'friends.arefriends' => 1,
965: 'friends.get' => 1,
966: 'friends.getappusers' => 1,
967: 'friends.getlists' => 1,
968: 'friends.getmutualfriends' => 1,
969: 'gifts.get' => 1,
970: 'groups.get' => 1,
971: 'groups.getmembers' => 1,
972: 'intl.gettranslations' => 1,
973: 'links.get' => 1,
974: 'notes.get' => 1,
975: 'notifications.get' => 1,
976: 'pages.getinfo' => 1,
977: 'pages.isadmin' => 1,
978: 'pages.isappadded' => 1,
979: 'pages.isfan' => 1,
980: 'permissions.checkavailableapiaccess' => 1,
981: 'permissions.checkgrantedapiaccess' => 1,
982: 'photos.get' => 1,
983: 'photos.getalbums' => 1,
984: 'photos.gettags' => 1,
985: 'profile.getinfo' => 1,
986: 'profile.getinfooptions' => 1,
987: 'stream.get' => 1,
988: 'stream.getcomments' => 1,
989: 'stream.getfilters' => 1,
990: 'users.getinfo' => 1,
991: 'users.getloggedinuser' => 1,
992: 'users.getstandardinfo' => 1,
993: 'users.hasapppermission' => 1,
994: 'users.isappuser' => 1,
995: 'users.isverified' => 1,
996: 'video.getuploadlimits' => 1);
997: $name = 'api';
998: if (isset($READ_ONLY_CALLS[strtolower($method)])) {
999: $name = 'api_read';
1000: } else if (strtolower($method) == 'video.upload') {
1001: $name = 'api_video';
1002: }
1003: return self::getUrl($name, 'restserver.php');
1004: }
1005:
1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 1014:
1015: protected function getUrl($name, $path='', $params=array()) {
1016: $url = self::$DOMAIN_MAP[$name];
1017: if ($path) {
1018: if ($path[0] === '/') {
1019: $path = substr($path, 1);
1020: }
1021: $url .= $path;
1022: }
1023: if ($params) {
1024: $url .= '?' . http_build_query($params, null, '&');
1025: }
1026:
1027: return $url;
1028: }
1029:
1030: 1031: 1032: 1033: 1034: 1035:
1036: protected function getCurrentUrl() {
1037: if (isset($_SERVER['HTTPS']) &&
1038: ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
1039: isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
1040: $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
1041: $protocol = 'https://';
1042: }
1043: else {
1044: $protocol = 'http://';
1045: }
1046: $currentUrl = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
1047: $parts = parse_url($currentUrl);
1048:
1049: $query = '';
1050: if (!empty($parts['query'])) {
1051:
1052: $params = explode('&', $parts['query']);
1053: $retained_params = array();
1054: foreach ($params as $param) {
1055: if ($this->shouldRetainParam($param)) {
1056: $retained_params[] = $param;
1057: }
1058: }
1059:
1060: if (!empty($retained_params)) {
1061: $query = '?'.implode($retained_params, '&');
1062: }
1063: }
1064:
1065:
1066: $port =
1067: isset($parts['port']) &&
1068: (($protocol === 'http://' && $parts['port'] !== 80) ||
1069: ($protocol === 'https://' && $parts['port'] !== 443))
1070: ? ':' . $parts['port'] : '';
1071:
1072:
1073: return $protocol . $parts['host'] . $port . $parts['path'] . $query;
1074: }
1075:
1076: 1077: 1078: 1079: 1080: 1081: 1082: 1083: 1084: 1085: 1086:
1087: protected function shouldRetainParam($param) {
1088: foreach (self::$DROP_QUERY_PARAMS as $drop_query_param) {
1089: if (strpos($param, $drop_query_param.'=') === 0) {
1090: return false;
1091: }
1092: }
1093:
1094: return true;
1095: }
1096:
1097: 1098: 1099: 1100: 1101: 1102: 1103: 1104:
1105: protected function throwAPIException($result) {
1106: $e = new FacebookApiException($result);
1107: switch ($e->getType()) {
1108:
1109: case 'OAuthException':
1110:
1111: case 'invalid_token':
1112:
1113: case 'Exception':
1114: $message = $e->getMessage();
1115: if ((strpos($message, 'Error validating access token') !== false) ||
1116: (strpos($message, 'Invalid OAuth access token') !== false) ||
1117: (strpos($message, 'An active access token must be used') !== false)
1118: ) {
1119: $this->destroySession();
1120: }
1121: break;
1122: }
1123:
1124: throw $e;
1125: }
1126:
1127:
1128: 1129: 1130: 1131: 1132:
1133: protected static function errorLog($msg) {
1134:
1135:
1136: if (php_sapi_name() != 'cli') {
1137: error_log($msg);
1138: }
1139:
1140:
1141:
1142: }
1143:
1144: 1145: 1146: 1147: 1148: 1149: 1150: 1151: 1152:
1153: protected static function base64UrlDecode($input) {
1154: return base64_decode(strtr($input, '-_', '+/'));
1155: }
1156:
1157: 1158: 1159:
1160: public function destroySession() {
1161: $this->accessToken = null;
1162: $this->signedRequest = null;
1163: $this->user = null;
1164: $this->clearAllPersistentData();
1165:
1166:
1167:
1168: $cookie_name = $this->getSignedRequestCookieName();
1169: if (array_key_exists($cookie_name, $_COOKIE)) {
1170: unset($_COOKIE[$cookie_name]);
1171: if (!headers_sent()) {
1172:
1173:
1174: $base_domain = '.'. $_SERVER['HTTP_HOST'];
1175:
1176: $metadata = $this->getMetadataCookie();
1177: if (array_key_exists('base_domain', $metadata) &&
1178: !empty($metadata['base_domain'])) {
1179: $base_domain = $metadata['base_domain'];
1180: }
1181:
1182: setcookie($cookie_name, '', 0, '/', $base_domain);
1183: } else {
1184: self::errorLog(
1185: 'There exists a cookie that we wanted to clear that we couldn\'t '.
1186: 'clear because headers was already sent. Make sure to do the first '.
1187: 'API call before outputing anything'
1188: );
1189: }
1190: }
1191: }
1192:
1193: 1194: 1195: 1196: 1197:
1198: protected function getMetadataCookie() {
1199: $cookie_name = $this->getMetadataCookieName();
1200: if (!array_key_exists($cookie_name, $_COOKIE)) {
1201: return array();
1202: }
1203:
1204:
1205: $cookie_value = trim($_COOKIE[$cookie_name], '"');
1206:
1207: if (empty($cookie_value)) {
1208: return array();
1209: }
1210:
1211: $parts = explode('&', $cookie_value);
1212: $metadata = array();
1213: foreach ($parts as $part) {
1214: $pair = explode('=', $part, 2);
1215: if (!empty($pair[0])) {
1216: $metadata[urldecode($pair[0])] =
1217: (count($pair) > 1) ? urldecode($pair[1]) : '';
1218: }
1219: }
1220:
1221: return $metadata;
1222: }
1223:
1224: 1225: 1226: 1227: 1228: 1229: 1230: 1231: 1232:
1233:
1234: 1235: 1236: 1237: 1238: 1239: 1240: 1241: 1242:
1243: abstract protected function setPersistentData($key, $value);
1244:
1245: 1246: 1247: 1248: 1249: 1250: 1251: 1252:
1253: abstract protected function getPersistentData($key, $default = false);
1254:
1255: 1256: 1257: 1258: 1259: 1260:
1261: abstract protected function clearPersistentData($key);
1262:
1263: 1264: 1265: 1266: 1267:
1268: abstract protected function clearAllPersistentData();
1269: }
1270: