1<?php declare(strict_types = 1); 2/* 3** Zabbix 4** Copyright (C) 2001-2021 Zabbix SIA 5** 6** This program is free software; you can redistribute it and/or modify 7** it under the terms of the GNU General Public License as published by 8** the Free Software Foundation; either version 2 of the License, or 9** (at your option) any later version. 10** 11** This program is distributed in the hope that it will be useful, 12** but WITHOUT ANY WARRANTY; without even the implied warranty of 13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14** GNU General Public License for more details. 15** 16** You should have received a copy of the GNU General Public License 17** along with this program; if not, write to the Free Software 18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19**/ 20 21 22/** 23 * Session wrapper uses cookie for session store. 24 */ 25class CCookieSession implements SessionHandlerInterface { 26 27 /** 28 * Cookie name. 29 */ 30 public const COOKIE_NAME = ZBX_SESSION_NAME; 31 32 /** 33 * Class consturctor. Set session handlers and start session. 34 */ 35 public function __construct() { 36 // Set use standard cookie PHPSESSID to false. 37 ini_set('session.use_cookies', '0'); 38 39 session_set_save_handler([$this, 'open'], [$this, 'close'], [$this, 'read'], [$this, 'write'], 40 [$this, 'destroy'], [$this, 'gc'] 41 ); 42 } 43 44 /** 45 * @inheritDoc 46 * 47 * @return boolean 48 */ 49 public function close() { 50 echo ob_get_clean(); 51 52 return true; 53 } 54 55 /** 56 * @inheritDoc 57 * 58 * @param string $session_id 59 * 60 * @return boolean 61 */ 62 public function destroy($session_id) { 63 CCookieHelper::unset(self::COOKIE_NAME); 64 65 return true; 66 } 67 68 /** 69 * @inheritDoc 70 * 71 * @param integer $maxlifetime 72 * 73 * @return integer 74 */ 75 public function gc($maxlifetime) { 76 return true; 77 } 78 79 /** 80 * @inheritDoc 81 * 82 * @param string $save_path 83 * @param string $session_name 84 * 85 * @return boolean 86 */ 87 public function open($save_path, $session_name) { 88 ob_start(); 89 90 return session_status() === PHP_SESSION_ACTIVE; 91 } 92 93 /** 94 * @inheritDoc 95 * 96 * @param string $session_id 97 * 98 * @return string 99 */ 100 public function read($session_id) { 101 $session_data = json_decode($this->parseData(), true); 102 103 if (!is_array($session_data)) { 104 return ''; 105 } 106 107 foreach ($session_data as $key => $value) { 108 CSessionHelper::set($key, $value); 109 } 110 111 return session_encode(); 112 } 113 114 /** 115 * @inheritDoc 116 * 117 * @param string $session_id 118 * @param string $session_data 119 * 120 * @return boolean 121 */ 122 public function write($session_id, $session_data) { 123 session_decode($session_data); 124 $session_data = $this->prepareData(CSessionHelper::getAll()); 125 126 if (!CCookieHelper::set(self::COOKIE_NAME, $session_data, $this->isAutologinEnabled() ? time() + SEC_PER_MONTH : 0)) { 127 throw new \Exception(_('Cannot set session cookie.')); 128 } 129 130 return true; 131 } 132 133 /** 134 * Run session_start. 135 * 136 * @param string $sessionid 137 * 138 * @return boolean 139 */ 140 public function session_start(string $sessionid): bool { 141 if (headers_sent() || session_status() !== PHP_SESSION_NONE) { 142 return false; 143 } 144 145 session_id($sessionid); 146 147 return session_start(); 148 } 149 150 /** 151 * Extract session id from session data. 152 * 153 * @return string|null 154 */ 155 public function extractSessionId(): ?string { 156 $session_data = $this->parseData(); 157 158 if ($session_data === '') { 159 return null; 160 } 161 162 $session_data = json_decode($session_data, true); 163 164 if (!is_array($session_data) || !array_key_exists('sessionid', $session_data)) { 165 return null; 166 } 167 168 return $session_data['sessionid']; 169 } 170 171 /** 172 * Prepare session data. 173 * 174 * @param array $data 175 * 176 * @return string 177 */ 178 protected function prepareData(array $data): string { 179 return base64_encode(json_encode($data)); 180 } 181 182 /** 183 * Parse session data. 184 * 185 * @return string 186 */ 187 protected function parseData(): string { 188 if (CCookieHelper::has(self::COOKIE_NAME)) { 189 return base64_decode(CCookieHelper::get(self::COOKIE_NAME)); 190 } 191 192 return ''; 193 } 194 195 protected function isAutologinEnabled(): bool { 196 return (CWebUser::$data['autologin'] === '1'); 197 } 198} 199