3 * @copyright Copyright (C) 2010-2022, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Core\Session\Handler;
24 use Friendica\Core\Session;
25 use Friendica\Database\Database as DBA;
26 use Psr\Log\LoggerInterface;
27 use SessionHandlerInterface;
30 * SessionHandler using database
32 class Database implements SessionHandlerInterface
36 /** @var LoggerInterface */
38 /** @var array The $_SERVER variable */
42 * DatabaseSessionHandler constructor.
45 * @param LoggerInterface $logger
46 * @param array $server
48 public function __construct(DBA $dba, LoggerInterface $logger, array $server)
51 $this->logger = $logger;
52 $this->server = $server;
55 public function open($path, $name): bool
60 public function read($id)
67 $session = $this->dba->selectFirst('session', ['data'], ['sid' => $id]);
68 if ($this->dba->isResult($session)) {
69 Session::$exists = true;
70 return $session['data'];
72 } catch (\Exception $exception) {
73 $this->logger->warning('Cannot read session.', ['id' => $id, 'exception' => $exception]);
77 $this->logger->notice('no data for session', ['session_id' => $id, 'uri' => $this->server['REQUEST_URI'] ?? '']);
83 * Standard PHP session write callback
85 * This callback updates the DB-stored session data and/or the expiration depending
86 * on the case. Uses the Session::expire global for existing session, 5 minutes
87 * for newly created session.
89 * @param string $id Session ID with format: [a-z0-9]{26}
90 * @param string $data Serialized session data
92 * @return bool Returns false if parameters are missing, true otherwise
94 public function write($id, $data): bool
101 return $this->destroy($id);
104 $expire = time() + Session::$expire;
105 $default_expire = time() + 300;
108 if (Session::$exists) {
109 $fields = ['data' => $data, 'expire' => $expire];
110 $condition = ["`sid` = ? AND (`data` != ? OR `expire` != ?)", $id, $data, $expire];
111 $this->dba->update('session', $fields, $condition);
113 $fields = ['sid' => $id, 'expire' => $default_expire, 'data' => $data];
114 $this->dba->insert('session', $fields);
116 } catch (\Exception $exception) {
117 $this->logger->warning('Cannot write session.', ['id' => $id, 'exception' => $exception]);
124 public function close(): bool
129 public function destroy($id): bool
132 return $this->dba->delete('session', ['sid' => $id]);
133 } catch (\Exception $exception) {
134 $this->logger->warning('Cannot destroy session.', ['id' => $id, 'exception' => $exception]);
139 public function gc($max_lifetime): bool
142 return $this->dba->delete('session', ["`expire` < ?", time()]);
143 } catch (\Exception $exception) {
144 $this->logger->warning('Cannot use garbage collector.', ['exception' => $exception]);