Test Failed
Pull Request — master (#2054)
by Devin
05:04
created

Give_Session::get()   C

Complexity

Conditions 7
Paths 6

Size

Total Lines 39
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 10.4218

Importance

Changes 0
Metric Value
cc 7
eloc 23
nc 6
nop 1
dl 0
loc 39
rs 6.7272
c 0
b 0
f 0
ccs 10
cts 17
cp 0.5881
crap 10.4218
1
<?php
2
/**
3
 * Session
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Session
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Give_Session Class
19
 *
20
 * This is a wrapper class for WP_Session / PHP $_SESSION and handles the storage of Give sessions.
21
 *
22
 * @since 1.0
23
 */
24
class Give_Session {
25
26
	/**
27
	 * Holds our session data
28
	 *
29
	 * @since  1.0
30
	 * @access private
31
	 *
32
	 * @var    WP_Session/array
33
	 */
34
	private $session;
35
36
	/**
37
	 * Whether to use PHP $_SESSION or WP_Session
38
	 *
39
	 * @since  1.0
40
	 * @access private
41
	 *
42
	 * @var    bool
43
	 */
44
	private $use_php_sessions = false;
45
46
	/**
47
	 * Expiration Time
48
	 *
49
	 * @since  1.0
50
	 * @access private
51
	 *
52
	 * @var    int
53
	 */
54
	private $exp_option = false;
55
56
	/**
57
	 * Session index prefix
58
	 *
59
	 * @since  1.0
60
	 * @access private
61
	 *
62
	 * @var    string
63
	 */
64
	private $prefix = '';
65
66
	/**
67
	 * Class Constructor
68
	 *
69
	 * Defines our session constants, includes the necessary libraries and retrieves the session instance.
70 2
	 *
71
	 * @since  1.0
72 2
	 * @access public
73 2
	 */
74
	public function __construct() {
75
76 2
		$this->use_php_sessions = $this->use_php_sessions();
77
		$this->exp_option       = give_get_option( 'session_lifetime' );
78
79
		// PHP Sessions.
80
		if ( $this->use_php_sessions ) {
81
82
			if ( is_multisite() ) {
83
84
				$this->prefix = '_' . get_current_blog_id();
85
86
			}
87
88 2
			add_action( 'init', array( $this, 'maybe_start_session' ), - 2 );
89 2
90
		} else {
91
92
			if ( ! $this->should_start_session() ) {
93
				return;
94
			}
95
96
			// Use WP_Session.
97
			if ( ! defined( 'WP_SESSION_COOKIE' ) ) {
98
				define( 'WP_SESSION_COOKIE', 'give_wp_session' );
99
			}
100
101
			if ( ! class_exists( 'Recursive_ArrayAccess' ) ) {
102
				require_once GIVE_PLUGIN_DIR . 'includes/libraries/sessions/class-recursive-arrayaccess.php';
103
			}
104
105
			// Include utilities class
106
			if ( ! class_exists( 'WP_Session_Utils' ) ) {
107
				require_once GIVE_PLUGIN_DIR . 'includes/libraries/sessions/class-wp-session-utils.php';
108
			}
109
			if ( ! class_exists( 'WP_Session' ) ) {
110
				require_once GIVE_PLUGIN_DIR . 'includes/libraries/sessions/class-wp-session.php';
111
				require_once GIVE_PLUGIN_DIR . 'includes/libraries/sessions/wp-session.php';
112
			}
113
114
			add_filter( 'wp_session_expiration_variant', array( $this, 'set_expiration_variant_time' ), 99999 );
115
			add_filter( 'wp_session_expiration', array( $this, 'set_expiration_time' ), 99999 );
116
117
		}
118
119
		// Init Session.
120
		if ( empty( $this->session ) && ! $this->use_php_sessions ) {
121
			add_action( 'plugins_loaded', array( $this, 'init' ), 9999 );
122
		} else {
123
			add_action( 'init', array( $this, 'init' ), - 1 );
124
		}
125
126
		// Set cookie on Donation Completion page.
127
		add_action( 'give_pre_process_donation', array( $this, 'set_session_cookies' ) );
128
129
	}
130
131
	/**
132
	 * Session Init
133
	 *
134
	 * Setup the Session instance.
135
	 *
136
	 * @since  1.0
137
	 * @access public
138
	 *
139
	 * @return array Session instance
140
	 */
141
	public function init() {
142
143
		if ( $this->use_php_sessions ) {
144
			$this->session = isset( $_SESSION[ 'give' . $this->prefix ] ) && is_array( $_SESSION[ 'give' . $this->prefix ] ) ? $_SESSION[ 'give' . $this->prefix ] : array();
0 ignored issues
show
introduced by
Usage of $_SESSION variable is prohibited.
Loading history...
145
		} else {
146
			$this->session = WP_Session::get_instance();
147
		}
148
149
		return $this->session;
150
151
	}
152
153
	/**
154
	 * Get Session ID
155
	 *
156
	 * Retrieve session ID.
157
	 *
158
	 * @since  1.0
159
	 * @access public
160
	 *
161
	 * @return string Session ID.
162
	 */
163
	public function get_id() {
164
		return $this->session->session_id;
165 12
	}
166 12
167
	/**
168 12
	 * Get Session
169
	 *
170
	 * Retrieve session variable for a given session key.
171
	 *
172
	 * @since  1.0
173
	 * @access public
174
	 *
175
	 * @param  string $key Session key.
176
	 *
177
	 * @return string|array      Session variable.
178
	 */
179
	public function get( $key ) {
180
		$key    = sanitize_key( $key );
181
		$return = false;
182 11
183
		if ( isset( $this->session[ $key ] ) && ! empty( $this->session[ $key ] ) ) {
184 11
185
			preg_match( '/[oO]\s*:\s*\d+\s*:\s*"\s*(?!(?i)(stdClass))/', $this->session[ $key ], $matches );
186 11
			if ( ! empty( $matches ) ) {
187 9
				$this->set( $key, null );
188 9
189 9
				return false;
190
			}
191
192 11
			if ( is_numeric( $this->session[ $key ] ) ) {
193 11
				$return = $this->session[ $key ];
194 11
			} else {
195
196 11
				$maybe_json = json_decode( $this->session[ $key ] );
197
198
				// Since json_last_error is PHP 5.3+, we have to rely on a `null` value for failing to parse JSON.
199
				if ( is_null( $maybe_json ) ) {
200
					$is_serialized = is_serialized( $this->session[ $key ] );
201
					if ( $is_serialized ) {
202
						$value = @unserialize( $this->session[ $key ] );
0 ignored issues
show
Coding Style introduced by
Silencing errors is discouraged
Loading history...
203
						$this->set( $key, (array) $value );
0 ignored issues
show
Documentation introduced by
(array) $value is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
204
						$return = $value;
205
					} else {
206
						$return = $this->session[ $key ];
207
					}
208
				} else {
209
					$return = json_decode( $this->session[ $key ], true );
210
				}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
211
212
			}
213
		}
214
215
		return $return;
216
217
	}
218
219
	/**
220
	 * Set Session
221
	 *
222
	 * Create a new session.
223
	 *
224
	 * @since  1.0
225
	 * @access public
226
	 *
227
	 * @param  string $key   Session key.
228
	 * @param  string $value Session variable.
229
	 *
230
	 * @return string        Session variable.
231
	 */
232
	public function set( $key, $value ) {
233
234
		$key = sanitize_key( $key );
235
236
		if ( is_array( $value ) ) {
237
			$this->session[ $key ] = wp_json_encode( $value );
238
		} else {
239
			$this->session[ $key ] = esc_attr( $value );
240
		}
241
242
		if ( $this->use_php_sessions ) {
243
			$_SESSION[ 'give' . $this->prefix ] = $this->session;
0 ignored issues
show
introduced by
Usage of $_SESSION variable is prohibited.
Loading history...
244
		}
245
246
		return $this->session[ $key ];
247
	}
248
249
	/**
250
	 * Set Session Cookies
251
	 *
252
	 * Cookies are used to increase the session lifetime using the give setting. This is helpful for when a user closes their browser after making a donation and comes back to the
253
	 * site.
254
	 *
255
	 * @since  1.4
256
	 * @access public
257 4
	 *
258
	 * @hook
259 4
	 */
260
	public function set_session_cookies() {
261
		if ( ! headers_sent() ) {
262 4
			$lifetime = current_time( 'timestamp' ) + $this->set_expiration_time();
263
			@setcookie( session_name(), session_id(), $lifetime, COOKIEPATH, COOKIE_DOMAIN, false );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
Silencing errors is discouraged
Loading history...
introduced by
Due to using Batcache, server side based client related logic will not work, use JS instead.
Loading history...
introduced by
The use of PHP session function session_name() is prohibited.
Loading history...
introduced by
The use of PHP session function session_id() is prohibited.
Loading history...
264 4
			@setcookie( session_name() . '_expiration', $lifetime, $lifetime, COOKIEPATH, COOKIE_DOMAIN, false );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
Silencing errors is discouraged
Loading history...
introduced by
Due to using Batcache, server side based client related logic will not work, use JS instead.
Loading history...
introduced by
The use of PHP session function session_name() is prohibited.
Loading history...
265
		}
266
	}
267
268
	/**
269
	 * Set Cookie Variant Time
270
	 *
271
	 * Force the cookie expiration variant time to custom expiration option, less and hour. defaults to 23 hours (set_expiration_variant_time used in WP_Session).
272
	 *
273
	 * @since  1.0
274
	 * @access public
275
	 *
276
	 * @return int
277
	 */
278
	public function set_expiration_variant_time() {
279
280
		return ( ! empty( $this->exp_option ) ? ( intval( $this->exp_option ) - 3600 ) : 30 * 60 * 23 );
281
	}
282
283
	/**
284 4
	 * Set Cookie Expiration
285
	 *
286
	 * Force the cookie expiration time if set, default to 24 hours.
287
	 *
288 4
	 * @since  1.0
289
	 * @access public
290 4
	 *
291 4
	 * @return int
292 4
	 */
293
	public function set_expiration_time() {
294 4
295
		return ( ! empty( $this->exp_option ) ? intval( $this->exp_option ) : 30 * 60 * 24 );
296
	}
297
298
	/**
299
	 * Starts a new session if one has not started yet.
300
	 *
301
	 * Checks to see if the server supports PHP sessions or if the GIVE_USE_PHP_SESSIONS constant is defined.
302
	 *
303 2
	 * @since  1.0
304
	 * @access public
305 2
	 *
306
	 * @return bool $ret True if we are using PHP sessions, false otherwise.
307 2
	 */
308
	public function use_php_sessions() {
309 2
310 2
		$ret = false;
311 2
312 2
		// If the database variable is already set, no need to run auto detection.
313 2
		$give_use_php_sessions = (bool) get_option( 'give_use_php_sessions' );
314 2
315 2
		if ( ! $give_use_php_sessions ) {
316
317 2
			// Attempt to detect if the server supports PHP sessions.
318 2
			if ( function_exists( 'session_start' ) && ! ini_get( 'safe_mode' ) ) {
319 2
320 2
				$this->set( 'give_use_php_sessions', 1 );
321
322
				if ( $this->get( 'give_use_php_sessions' ) ) {
323 2
324
					$ret = true;
325
326 2
					// Set the database option.
327 2
					update_option( 'give_use_php_sessions', true );
328 2
329 2
				}
330
			}
331 2
		} else {
332
333
			$ret = $give_use_php_sessions;
334
		}
335
336
		// Enable or disable PHP Sessions based on the GIVE_USE_PHP_SESSIONS constant.
337
		if ( defined( 'GIVE_USE_PHP_SESSIONS' ) && GIVE_USE_PHP_SESSIONS ) {
338
			$ret = true;
339
		} elseif ( defined( 'GIVE_USE_PHP_SESSIONS' ) && ! GIVE_USE_PHP_SESSIONS ) {
340
			$ret = false;
341
		}
342
343
		return (bool) apply_filters( 'give_use_php_sessions', $ret );
344
	}
345
346
	/**
347
	 * Should Start Session
348
	 *
349
	 * Determines if we should start sessions.
350
	 *
351
	 * @since  1.4
352
	 * @access public
353
	 *
354
	 * @return bool
355
	 */
356
	public function should_start_session() {
357
358
		$start_session = true;
359
360
		if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
361
362
			$blacklist = apply_filters( 'give_session_start_uri_blacklist', array(
363
				'feed',
364
				'feed',
365
				'feed/rss',
366
				'feed/rss2',
367
				'feed/rdf',
368
				'feed/atom',
369
				'comments/feed/',
370
			) );
371
			$uri       = ltrim( $_SERVER['REQUEST_URI'], '/' );
0 ignored issues
show
introduced by
Detected usage of a non-sanitized input variable: $_SERVER
Loading history...
372
			$uri       = untrailingslashit( $uri );
373
			if ( in_array( $uri, $blacklist ) ) {
374
				$start_session = false;
375
			}
376
			if ( false !== strpos( $uri, 'feed=' ) ) {
377
				$start_session = false;
378
			}
379
			if ( is_admin() ) {
380
				$start_session = false;
381
			}
382
		}
383
384
		return apply_filters( 'give_start_session', $start_session );
385
	}
386
387
	/**
388
	 * Maybe Start Session
389
	 *
390
	 * Starts a new session if one hasn't started yet.
391
	 *
392
	 * @access public
393
	 *
394
	 * @see    http://php.net/manual/en/function.session-set-cookie-params.php
395
	 *
396
	 * @return void
397
	 */
398
	public function maybe_start_session() {
399
400
		if ( ! $this->should_start_session() ) {
401
			return;
402
		}
403
404
		if ( ! session_id() && ! headers_sent() ) {
0 ignored issues
show
introduced by
The use of PHP session function session_id() is prohibited.
Loading history...
405
			session_start();
0 ignored issues
show
introduced by
The use of PHP session function session_start() is prohibited.
Loading history...
406
		}
407
408
	}
409
410
	/**
411
	 * Get Session Expiration
412
	 *
413
	 * Looks at the session cookies and returns the expiration date for this session if applicable
414
	 *
415
	 * @access public
416
	 *
417
	 * @return string Formatted expiration date string.
418
	 */
419
	public function get_session_expiration() {
420
421
		$expiration = false;
422
423
		if ( session_id() && isset( $_COOKIE[ session_name() . '_expiration' ] ) ) {
0 ignored issues
show
introduced by
The use of PHP session function session_id() is prohibited.
Loading history...
introduced by
Due to using Batcache, server side based client related logic will not work, use JS instead.
Loading history...
introduced by
The use of PHP session function session_name() is prohibited.
Loading history...
424
425
			$expiration = date( 'D, d M Y h:i:s', intval( $_COOKIE[ session_name() . '_expiration' ] ) );
0 ignored issues
show
introduced by
Due to using Batcache, server side based client related logic will not work, use JS instead.
Loading history...
introduced by
The use of PHP session function session_name() is prohibited.
Loading history...
426
427
		}
428
429
		return $expiration;
430
431
	}
432
433
}
434