]> git.mxchange.org Git - friendica.git/blob - src/Core/Session.php
02e10482d52ba466e6cd5fa27a712c372cfb02e6
[friendica.git] / src / Core / Session.php
1 <?php
2
3 /**
4  * @file src/Core/Session.php
5  */
6 namespace Friendica\Core;
7
8 use Friendica\App;
9 use Friendica\Core\Session\CacheSessionHandler;
10 use Friendica\Core\Session\DatabaseSessionHandler;
11 use Friendica\Database\DBA;
12 use Friendica\Model\Contact;
13 use Friendica\Util\Strings;
14
15 /**
16  * High-level Session service class
17  *
18  * @author Hypolite Petovan <hypolite@mrpetovan.com>
19  */
20 class Session
21 {
22         public static $exists = false;
23         public static $expire = 180000;
24
25         public static function init()
26         {
27                 ini_set('session.gc_probability', 50);
28                 ini_set('session.use_only_cookies', 1);
29                 ini_set('session.cookie_httponly', 1);
30
31                 if (Config::get('system', 'ssl_policy') == App\BaseURL::SSL_POLICY_FULL) {
32                         ini_set('session.cookie_secure', 1);
33                 }
34
35                 $session_handler = Config::get('system', 'session_handler', 'database');
36                 if ($session_handler != 'native') {
37                         if ($session_handler == 'cache' && Config::get('system', 'cache_driver', 'database') != 'database') {
38                                 $SessionHandler = new CacheSessionHandler();
39                         } else {
40                                 $SessionHandler = new DatabaseSessionHandler();
41                         }
42
43                         session_set_save_handler($SessionHandler);
44                 }
45         }
46
47         public static function exists($name)
48         {
49                 return isset($_SESSION[$name]);
50         }
51
52         /**
53          * Retrieves a key from the session super global or the defaults if the key is missing or the value is falsy.
54          *
55          * Handle the case where session_start() hasn't been called and the super global isn't available.
56          *
57          * @param string $name
58          * @param mixed $defaults
59          * @return mixed
60          */
61         public static function get($name, $defaults = null)
62         {
63                 return $_SESSION[$name] ?? $defaults;
64         }
65
66         /**
67          * Sets a single session variable.
68          * Overrides value of existing key.
69          *
70          * @param string $name
71          * @param mixed $value
72          */
73         public static function set($name, $value)
74         {
75                 $_SESSION[$name] = $value;
76         }
77
78         /**
79          * Sets multiple session variables.
80          * Overrides values for existing keys.
81          *
82          * @param array $values
83          */
84         public static function setMultiple(array $values)
85         {
86                 $_SESSION = $values + $_SESSION;
87         }
88
89         /**
90          * Removes a session variable.
91          * Ignores missing keys.
92          *
93          * @param $name
94          */
95         public static function remove($name)
96         {
97                 unset($_SESSION[$name]);
98         }
99
100         /**
101          * Clears the current session array
102          */
103         public static function clear()
104         {
105                 session_unset();
106                 session_start();
107                 $_SESSION = [];
108         }
109
110         /**
111          * Returns contact ID for given user ID
112          *
113          * @param integer $uid User ID
114          * @return integer Contact ID of visitor for given user ID
115          */
116         public static function getRemoteContactID($uid)
117         {
118                 if (empty($_SESSION['remote'][$uid])) {
119                         return false;
120                 }
121
122                 return $_SESSION['remote'][$uid];
123         }
124
125         /**
126          * Returns User ID for given contact ID of the visitor
127          *
128          * @param integer $cid Contact ID
129          * @return integer User ID for given contact ID of the visitor
130          */
131         public static function getUserIDForVisitorContactID($cid)
132         {
133                 if (empty($_SESSION['remote'])) {
134                         return false;
135                 }
136
137                 return array_search($cid, $_SESSION['remote']);
138         }
139
140         /**
141          * Set the session variable that contains the contact IDs for the visitor's contact URL
142          *
143          * @param string $url Contact URL
144          */
145         public static function setVisitorsContacts()
146         {
147                 $_SESSION['remote'] = [];
148
149                 $remote_contacts = DBA::select('contact', ['id', 'uid'], ['nurl' => Strings::normaliseLink($_SESSION['my_url']), 'rel' => [Contact::FOLLOWER, Contact::FRIEND], 'self' => false]);
150                 while ($contact = DBA::fetch($remote_contacts)) {
151                         if (($contact['uid'] == 0) || Contact::isBlockedByUser($contact['id'], $contact['uid'])) {
152                                 continue;
153                         }
154
155                         $_SESSION['remote'][$contact['uid']] = $contact['id'];
156                 }
157                 DBA::close($remote_contacts);
158         }
159
160         /**
161          * Returns if the current visitor is authenticated
162          *
163          * @return boolean "true" when visitor is either a local or remote user
164          */
165         public static function isAuthenticated()
166         {
167                 if (empty($_SESSION['authenticated'])) {
168                         return false;
169                 }
170
171                 return $_SESSION['authenticated'];
172         }
173
174         /**
175          * @brief Calculate the hash that is needed for the "Friendica" cookie
176          *
177          * @param array $user Record from "user" table
178          *
179          * @return string Hashed data
180          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
181          */
182         private static function getCookieHashForUser($user)
183         {
184                 return hash_hmac(
185                         "sha256",
186                         hash_hmac("sha256", $user["password"], $user["prvkey"]),
187                         Config::get("system", "site_prvkey")
188                 );
189         }
190
191         /**
192          * @brief Set the "Friendica" cookie
193          *
194          * @param int   $time
195          * @param array $user Record from "user" table
196          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
197          */
198         public static function setCookie($time, $user = [])
199         {
200                 if ($time != 0) {
201                         $time = $time + time();
202                 }
203
204                 if ($user) {
205                         $value = json_encode([
206                                 "uid" => $user["uid"],
207                                 "hash" => self::getCookieHashForUser($user),
208                                 "ip" => ($_SERVER['REMOTE_ADDR'] ?? '') ?: '0.0.0.0'
209                         ]);
210                 } else {
211                         $value = "";
212                 }
213
214                 setcookie("Friendica", $value, $time, "/", "", (Config::get('system', 'ssl_policy') == App\BaseURL::SSL_POLICY_FULL), true);
215         }
216
217         /**
218          * @brief Checks if the "Friendica" cookie is set
219          *
220          * @param string $hash
221          * @param array  $user Record from "user" table
222          *
223          * @return boolean True, if the cookie is set
224          *
225          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
226          */
227         public static function checkCookie(string $hash, array $user)
228         {
229                 return hash_equals(
230                         self::getCookieHashForUser($user),
231                         $hash
232                 );
233         }
234
235         /**
236          * @brief Kills the "Friendica" cookie and all session data
237          */
238         public static function delete()
239         {
240                 self::setCookie(-3600); // make sure cookie is deleted on browser close, as a security measure
241                 session_unset();
242                 session_destroy();
243         }
244 }