Test Failed
Push — master ( cd42b5...841446 )
by
unknown
16:44 queued 06:09
created

WebAppSession::isReminderListRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 1
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 2
rs 10
1
<?php
2
3
// Includes. Will probably already be included.
4
require_once BASE_PATH . 'config.php';
5
require_once BASE_PATH . 'defaults.php';
6
require_once BASE_PATH . 'server/includes/util.php';
7
require_once BASE_PATH . 'server/includes/exceptions/class.JSONException.php';
8
9
/**
10
 * A class with helper functions for the PHP session.
11
 *
12
 * @singleton
13
 */
14
class WebAppSession {
15
	// Holds the instance of this class
16
	// Use public static method getInstance() to retrieve its value
17
	private static $instance;
18
19
	// Set to true when the the session has timed out
20
	// Use public method hasTimedOut() to retrieve its value
21
	private $timeout = false;
22
23
	/**
24
	 * Constructor.
25
	 */
26
	private function __construct() {
27
		$secure = useSecureCookies();
28
		if (defined('COOKIE_NAME')) {
29
			// Create a named session (otherwise use the PHP default, normally PHPSESSID)
30
			if ($secure) {
31
				// Create a named session and set secure cookies params.
32
				session_name('__Secure-' . COOKIE_NAME);
0 ignored issues
show
Bug introduced by
The constant COOKIE_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
33
			}
34
			else {
35
				session_name(COOKIE_NAME);
36
			}
37
		}
38
		$lifetime = ini_get('session.cookie_lifetime');
39
		$path = ini_get('session.cookie_path');
40
		$domain = ini_get('session.cookie_domain');
41
		session_set_cookie_params($lifetime, $path, $domain, $secure, true);
0 ignored issues
show
Bug introduced by
$lifetime of type string is incompatible with the type array expected by parameter $options of session_set_cookie_params(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

41
		session_set_cookie_params(/** @scrutinizer ignore-type */ $lifetime, $path, $domain, $secure, true);
Loading history...
42
43
		// Start the session so we can use it for timeout checking
44
		$this->start();
45
46
		if (basename($_SERVER['PHP_SELF']) != 'grommunio.php') {
47
			// We will only check for timeout in the grommunio.php page
48
			$this->setStartTime();
49
		}
50
		else {
51
			$this->checkForTimeout();
52
		}
53
	}
54
55
	/**
56
	 * returns the instance of this class. Creates one if it doesn't exist yet.
57
	 * To force this class to be used as singleton, the constructor is private
58
	 * and the single instance can be created/retrieved with this static method
59
	 * e.g.: $session = WebAppSession::createInstance().
60
	 *
61
	 * @return WebAppSession the only available instance of this class
62
	 */
63
	public static function getInstance() {
64
		if (!isset(WebAppSession::$instance)) {
65
			WebAppSession::$instance = new WebAppSession();
66
		}
67
68
		return WebAppSession::$instance;
69
	}
70
71
	/**
72
	 * The method getInstance() was first called createInstance(), so
73
	 * for backward compatibility we also define createInstance as an alias.
74
	 */
75
	public static function createInstance() {
76
		return WebAppSession::getInstance();
77
	}
78
79
	/**
80
	 * Starts the session.
81
	 */
82
	public function start() {
83
		session_start();
84
	}
85
86
	/**
87
	 * Closes the session.
88
	 */
89
	public function close() {
90
		session_write_close();
91
	}
92
93
	/**
94
	 * Destroy the session.
95
	 */
96
	public function destroy() {
97
		// Make sure the session is open
98
		if (session_status() !== PHP_SESSION_ACTIVE) {
99
			session_start();
100
		}
101
102
		// Destroy the session cookie
103
		if (isset($_COOKIE[session_name()])) {
104
			setcookie(session_name(), '', time() - 42000, '/');
105
		}
106
107
		// Destroy the session
108
		$_SESSION = [];
109
		session_destroy();
110
	}
111
112
	/**
113
	 * Sets the start time in the session to current timestamp.
114
	 * This is used to logout the user when CLIENT_TIMEOUT has
115
	 * been set in config.php.
116
	 */
117
	public function setStartTime() {
118
		$_SESSION['starttime'] = time();
119
	}
120
121
	/**
122
	 * gets the start time from the session. This is used to logout the user
123
	 * when CLIENT_TIMEOUT has been set in config.php.
124
	 *
125
	 * @return false|int The starttime (timestamp) when set, false otherwise
126
	 */
127
	public function getStartTime() {
128
		if (isset($_SESSION['starttime'])) {
129
			return $_SESSION['starttime'];
130
		}
131
132
		return false;
133
	}
134
135
	/**
136
	 * Checks if the session should timeout and destroys the session if it should.
137
	 */
138
	private function checkForTimeout() {
139
		if (!defined('CLIENT_TIMEOUT') || !CLIENT_TIMEOUT) {
0 ignored issues
show
Bug introduced by
The constant CLIENT_TIMEOUT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
140
			// Timeout was not set in configuration, so do nothing
141
			return;
142
		}
143
144
		if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER) && strpos($_SERVER['HTTP_CONTENT_TYPE'], 'application/json') === false) {
145
			return;
146
		}
147
148
		$starttime = $this->getStartTime();
149
		// let's add 5 seconds to the CLIENT_TIMEOUT to handle possible latency
150
		if ($starttime && (time() - $starttime > CLIENT_TIMEOUT + 5)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $starttime of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
151
			$this->destroy();
152
			$this->timeout = true;
153
		}
154
		else {
155
			try {
156
				// decode JSON data
157
				$requestJsonString = readData();
158
				$requestJson = json_decode_data($requestJsonString, true);
159
			}
160
			catch (JsonException $e) {
161
				// Invalid json sent with the request
162
				// Log the error and do nothing is best option
163
				dump($e->getMessage());
164
165
				return;
166
			}
167
168
			$isReminderlistRequest = $this->isReminderListRequest($requestJson);
169
			$isDestroySessionRequest = $this->isDestroySessionRequest($requestJson);
170
171
			if (!$isReminderlistRequest && !$isDestroySessionRequest) {
172
				// Set a new session start time
173
				$this->setStartTime();
174
			}
175
			elseif ($isDestroySessionRequest) {
176
				// sessiondestroy is sent because of timeout at client side
177
				$this->timeout = true;
178
				$this->destroy();
179
			}
180
		}
181
	}
182
183
	/**
184
	 * Checks if the current request is a destroysession request.
185
	 *
186
	 * @param array $requestJson The JSON that was sent as the current request
187
	 *
188
	 * @return bool
189
	 */
190
	private function isDestroySessionRequest($requestJson) {
191
		$isDestroySession = false;
192
193
		if (isset($requestJson, $requestJson['zarafa'])) {
194
			if (isset($requestJson['zarafa']['hierarchymodule'])) {
195
				foreach ($requestJson['zarafa']['hierarchymodule'] as $requestId => $action) {
196
					if (isset($action, $action['destroysession'])) {
197
						$isDestroySession = true;
198
					}
199
				}
200
			}
201
		}
202
203
		return $isDestroySession;
204
	}
205
206
	/**
207
	 * Checks if the current request is a reminderlist request.
208
	 *
209
	 * @param array $requestJson The JSON that was sent as the current request
210
	 *
211
	 * @return bool
212
	 */
213
	private function isReminderListRequest($requestJson) {
214
		return isset($requestJson) && isset($requestJson['zarafa'], $requestJson['zarafa']['reminderlistmodule']);
215
	}
216
217
	/**
218
	 * Returns true if the current session has timed out, false otherwise.
219
	 *
220
	 * @return bool
221
	 */
222
	public function hasTimedOut() {
223
		return $this->timeout;
224
	}
225
}
226