File indexing completed on 2024-12-22 05:36:18

0001 <?php
0002 /**
0003  * Copyright 2011 Facebook, Inc.
0004  *
0005  * Licensed under the Apache License, Version 2.0 (the "License"); you may
0006  * not use this file except in compliance with the License. You may obtain
0007  * a copy of the License at
0008  *
0009  *     http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0013  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0014  * License for the specific language governing permissions and limitations
0015  * under the License.
0016  */
0017 
0018 require_once "base_facebook.php";
0019 
0020 /**
0021  * Extends the BaseFacebook class with the intent of using
0022  * PHP sessions to store user ids and access tokens.
0023  */
0024 class Facebook extends BaseFacebook
0025 {
0026   const FBSS_COOKIE_NAME = 'fbss';
0027 
0028   // We can set this to a high number because the main session
0029   // expiration will trump this.
0030   const FBSS_COOKIE_EXPIRE = 31556926; // 1 year
0031 
0032   // Stores the shared session ID if one is set.
0033   protected $sharedSessionID;
0034 
0035   /**
0036    * Identical to the parent constructor, except that
0037    * we start a PHP session to store the user ID and
0038    * access token if during the course of execution
0039    * we discover them.
0040    *
0041    * @param Array $config the application configuration. Additionally
0042    * accepts "sharedSession" as a boolean to turn on a secondary
0043    * cookie for environments with a shared session (that is, your app
0044    * shares the domain with other apps).
0045    * @see BaseFacebook::__construct in facebook.php
0046    */
0047   public function __construct($config) {
0048     if (!session_id()) {
0049       session_start();
0050     }
0051     parent::__construct($config);
0052     if (!empty($config['sharedSession'])) {
0053       $this->initSharedSession();
0054     }
0055   }
0056 
0057   protected static $kSupportedKeys =
0058     array('state', 'code', 'access_token', 'user_id');
0059 
0060   protected function initSharedSession() {
0061     $cookie_name = $this->getSharedSessionCookieName();
0062     if (isset($_COOKIE[$cookie_name])) {
0063       $data = $this->parseSignedRequest($_COOKIE[$cookie_name]);
0064       if ($data && !empty($data['domain']) &&
0065           self::isAllowedDomain($this->getHttpHost(), $data['domain'])) {
0066         // good case
0067         $this->sharedSessionID = $data['id'];
0068         return;
0069       }
0070       // ignoring potentially unreachable data
0071     }
0072     // evil/corrupt/missing case
0073     $base_domain = $this->getBaseDomain();
0074     $this->sharedSessionID = md5(uniqid(mt_rand(), true));
0075     $cookie_value = $this->makeSignedRequest(
0076       array(
0077         'domain' => $base_domain,
0078         'id' => $this->sharedSessionID,
0079       )
0080     );
0081     $_COOKIE[$cookie_name] = $cookie_value;
0082     if (!headers_sent()) {
0083       $expire = time() + self::FBSS_COOKIE_EXPIRE;
0084       setcookie($cookie_name, $cookie_value, $expire, '/', '.'.$base_domain);
0085     } else {
0086       // @codeCoverageIgnoreStart
0087       self::errorLog(
0088         'Shared session ID cookie could not be set! You must ensure you '.
0089         'create the Facebook instance before headers have been sent. This '.
0090         'will cause authentication issues after the first request.'
0091       );
0092       // @codeCoverageIgnoreEnd
0093     }
0094   }
0095 
0096   /**
0097    * Provides the implementations of the inherited abstract
0098    * methods.  The implementation uses PHP sessions to maintain
0099    * a store for authorization codes, user ids, CSRF states, and
0100    * access tokens.
0101    */
0102   protected function setPersistentData($key, $value) {
0103     if (!in_array($key, self::$kSupportedKeys)) {
0104       self::errorLog('Unsupported key passed to setPersistentData.');
0105       return;
0106     }
0107 
0108     $session_var_name = $this->constructSessionVariableName($key);
0109     $_SESSION[$session_var_name] = $value;
0110   }
0111 
0112   protected function getPersistentData($key, $default = false) {
0113     if (!in_array($key, self::$kSupportedKeys)) {
0114       self::errorLog('Unsupported key passed to getPersistentData.');
0115       return $default;
0116     }
0117 
0118     $session_var_name = $this->constructSessionVariableName($key);
0119     return isset($_SESSION[$session_var_name]) ?
0120       $_SESSION[$session_var_name] : $default;
0121   }
0122 
0123   protected function clearPersistentData($key) {
0124     if (!in_array($key, self::$kSupportedKeys)) {
0125       self::errorLog('Unsupported key passed to clearPersistentData.');
0126       return;
0127     }
0128 
0129     $session_var_name = $this->constructSessionVariableName($key);
0130     unset($_SESSION[$session_var_name]);
0131   }
0132 
0133   protected function clearAllPersistentData() {
0134     foreach (self::$kSupportedKeys as $key) {
0135       $this->clearPersistentData($key);
0136     }
0137     if ($this->sharedSessionID) {
0138       $this->deleteSharedSessionCookie();
0139     }
0140   }
0141 
0142   protected function deleteSharedSessionCookie() {
0143     $cookie_name = $this->getSharedSessionCookieName();
0144     unset($_COOKIE[$cookie_name]);
0145     $base_domain = $this->getBaseDomain();
0146     setcookie($cookie_name, '', 1, '/', '.'.$base_domain);
0147   }
0148 
0149   protected function getSharedSessionCookieName() {
0150     return self::FBSS_COOKIE_NAME . '_' . $this->getAppId();
0151   }
0152 
0153   protected function constructSessionVariableName($key) {
0154     $parts = array('fb', $this->getAppId(), $key);
0155     if ($this->sharedSessionID) {
0156       array_unshift($parts, $this->sharedSessionID);
0157     }
0158     return implode('_', $parts);
0159   }
0160 }