PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / trunk
GiveWP – Donation Plugin and Fundraising Platform vtrunk
4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / class-give-session.php
give / includes Last commit date
admin 19 hours ago api 3 years ago database 5 months ago deprecated 1 month ago donors 5 months ago emails 9 months ago forms 19 hours ago frontend 6 years ago gateways 9 months ago libraries 9 months ago payments 2 months ago actions.php 9 months ago ajax-functions.php 2 days ago class-give-async-process.php 1 year ago class-give-background-updater.php 9 months ago class-give-cache-setting.php 1 year ago class-give-cache.php 9 months ago class-give-cli-commands.php 1 year ago class-give-comment.php 9 months ago class-give-cron.php 9 months ago class-give-donate-form.php 1 year ago class-give-donor.php 2 years ago class-give-email-access.php 5 years ago class-give-license-handler.php 1 month ago class-give-logging.php 9 months ago class-give-readme-parser.php 4 years ago class-give-roles.php 5 months ago class-give-scripts.php 2 weeks ago class-give-session.php 9 months ago class-give-stats.php 6 years ago class-give-template-loader.php 6 years ago class-give-tooltips.php 6 years ago class-give-translation.php 4 years ago class-notices.php 9 months ago country-functions.php 7 months ago currencies-list.php 7 months ago currency-functions.php 3 years ago error-tracking.php 6 years ago filters.php 9 months ago formatting.php 9 months ago install.php 9 months ago login-register.php 2 years ago misc-functions.php 1 month ago plugin-compatibility.php 6 years ago post-types.php 1 year ago price-functions.php 6 years ago process-donation.php 1 year ago setting-functions.php 6 years ago shortcodes.php 1 year ago template-functions.php 1 year ago user-functions.php 3 years ago
class-give-session.php
704 lines
1 <?php
2 /**
3 * Session
4 *
5 * @since 1.0
6 * @subpackage Classes/Give_Session
7 * @copyright Copyright (c) 2016, GiveWP
8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 * @package Give
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Class Give_Session
19 */
20 class Give_Session {
21 /**
22 * Instance.
23 *
24 * @since 2.2.0
25 * @access private
26 * @var Give_Session
27 */
28 private static $instance;
29
30 /**
31 * Holds our session data
32 *
33 * @since 1.0
34 * @access private
35 *
36 * @var array
37 */
38 private $session = [];
39
40 /**
41 * Holds our session data
42 *
43 * @since 1.0
44 * @access private
45 *
46 * @var string
47 */
48 private $session_data_changed = false;
49
50 /**
51 * Cookie Name
52 *
53 * @since 1.0
54 * @access private
55 *
56 * @var string
57 */
58 private $cookie_name = '';
59
60 /**
61 * Donor Unique ID
62 *
63 * @since 1.0
64 * @access private
65 *
66 * @var string
67 */
68 private $donor_id = '';
69
70 /**
71 * Session expiring time
72 *
73 * @since 2.2.0
74 * @access private
75 *
76 * @var string
77 */
78 private $session_expiring = false;
79
80 /**
81 * Session expiration time
82 *
83 * @since 2.2.0
84 * @access private
85 *
86 * @var string
87 */
88 private $session_expiration = false;
89
90 /**
91 * Flag to check if donor has cookie or not
92 *
93 * @since 2.2.0
94 * @access private
95 *
96 * @var bool
97 */
98 private $has_cookie = false;
99
100 /**
101 * Expiration Time
102 *
103 * @since 1.0
104 * @access private
105 *
106 * @var int
107 */
108 private $exp_option = false;
109
110 /**
111 * Expiration Time
112 *
113 * @since 2.2.0
114 * @access private
115 *
116 * @var string
117 */
118 private $nonce_cookie_name = '';
119
120 /**
121 * Singleton pattern.
122 *
123 * @since 2.2.0
124 * @access private
125 */
126 private function __construct() {
127 }
128
129
130 /**
131 * Get instance.
132 *
133 * @since 2.2.0
134 * @access public
135 * @return Give_Session
136 */
137 public static function get_instance() {
138 if ( null === static::$instance ) {
139 self::$instance = new static();
140 self::$instance->__setup();
141 }
142
143 return self::$instance;
144 }
145
146 /**
147 * Setup
148 *
149 * @since 2.2.0
150 * @access public
151 */
152 private function __setup() { // @codingStandardsIgnoreLine
153 $this->exp_option = give_get_option( 'session_lifetime' );
154 $this->exp_option = ! empty( $this->exp_option )
155 ? $this->exp_option
156 : 30 * 60 * 24; // Default expiration time is 12 hours
157
158 $this->set_cookie_name();
159 $cookie = $this->get_session_cookie();
160
161 if ( ! empty( $cookie ) ) {
162 $this->donor_id = $cookie[0];
163 $this->session_expiration = $cookie[1];
164 $this->session_expiring = $cookie[2];
165 $this->has_cookie = true;
166
167 // Update session if its close to expiring.
168 if ( time() > $this->session_expiring ) {
169 $this->set_expiration_time();
170 Give()->session_db->update_session_timestamp( $this->donor_id, $this->session_expiration );
171 }
172
173 // Load session.
174 $this->session = $this->get_session_data();
175
176 } else {
177 $this->generate_donor_id();
178 }
179
180 add_action( 'give_process_donation_after_validation', [ $this, 'maybe_start_session' ] );
181 add_action( 'wp_login', [ $this, 'startSessionWhenLoginAsWPUser' ], 10, 2 );
182
183 add_action( 'shutdown', [ $this, 'save_data' ], 20 );
184 add_action( 'wp_logout', [ $this, 'destroy_session' ] );
185
186 if ( ! is_user_logged_in() ) {
187 add_filter( 'nonce_user_logged_out', [$this, 'nonce_user_logged_out'] );
188 }
189
190 // Remove old sessions.
191 Give_Cron::add_daily_event( [$this, 'cleanup_sessions'] );
192 }
193
194 /**
195 * Get session data
196 *
197 * @since 2.2.0
198 * @access public
199 *
200 * @return array
201 */
202 public function get_session_data() {
203 return $this->has_session() ? (array) Give()->session_db->get_session( $this->donor_id, [] ) : [];
204 }
205
206
207 /**
208 * Get session by session id
209 *
210 * @since 2.2.0
211 * @access public
212 *
213 * @return array
214 */
215 public function get_session_cookie() {
216 $session = [];
217 $cookie_value = isset( $_COOKIE[ $this->cookie_name ] ) ? give_clean( $_COOKIE[ $this->cookie_name ] ) : $this->handle_ajax_cookie(); // @codingStandardsIgnoreLine.
218
219 if ( empty( $cookie_value ) || ! is_string( $cookie_value ) ) {
220 return $session;
221 }
222
223 [ $donor_id, $session_expiration, $session_expiring, $cookie_hash ] = explode( '||', $cookie_value );
224
225 if ( empty( $donor_id ) ) {
226 return $session;
227 }
228
229 require_once ABSPATH . WPINC . '/pluggable.php';
230
231 // Validate hash.
232 $to_hash = $donor_id . '|' . $session_expiration;
233 $hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) );
234
235 if ( empty( $cookie_hash ) || ! hash_equals( $hash, $cookie_hash ) ) {
236 return $session;
237 }
238
239 /**
240 * Filter the session cookie data
241 *
242 * @since 2.2.6
243 */
244 $cookie_data = apply_filters(
245 'give_get_session_cookie',
246 [ $donor_id, $session_expiration, $session_expiring, $cookie_hash ]
247 );
248
249 return $cookie_data;
250 }
251
252
253 /**
254 * Load session cookie by ajax
255 *
256 * @since 4.9.0 rename function - PHP 8 compatibility
257 * @since 2.2.6
258 * @access private
259 *
260 * @return array|bool|string
261 */
262 private function handle_ajax_cookie()
263 {
264 $cookie = false;
265
266 // @see https://github.com/impress-org/give/issues/3705
267 if (
268 empty( $cookie )
269 && wp_doing_ajax()
270 && isset( $_GET['action'] )
271 && 'get_receipt' === $_GET['action']
272 ) {
273 $cookie = isset( $_GET[ $this->cookie_name ] ) ? give_clean( $_GET[ $this->cookie_name ] ) : false;
274 }
275
276 return $cookie;
277 }
278
279
280 /**
281 * Check if session exist for specific session id
282 *
283 * @since 2.2.0
284 * @access public
285 *
286 * @return bool
287 */
288 public function has_session() {
289 return $this->has_cookie;
290 }
291
292 /**
293 * Set cookie name
294 *
295 * @since 2.2.0
296 * @access private
297 *
298 * @return void
299 */
300 private function set_cookie_name() {
301 /**
302 * Filter the cookie name
303 *
304 * @since 2.2.0
305 *
306 * @param string $cookie_name Cookie name.
307 * @param string $cookie_type Cookie type session or nonce.
308 */
309 $this->cookie_name = apply_filters(
310 'give_session_cookie',
311 'wp-give_session_' . COOKIEHASH, // Cookie name.
312 'session' // Cookie type.
313 );
314
315 $this->nonce_cookie_name = apply_filters(
316 'give_session_cookie',
317 'wp-give_session_reset_nonce_' . COOKIEHASH, // Cookie name.
318 'nonce' // Cookie type.
319 );
320 }
321
322 /**
323 * Get session donor id
324 *
325 * @since 2.10.0
326 * @access public
327 *
328 * @return int
329 */
330 public function get_donor_id() {
331 return $this->donor_id;
332 }
333
334 /**
335 * Get Session
336 *
337 * Retrieve session variable for a given session key.
338 *
339 * @since 1.0
340 * @access public
341 *
342 * @param string $key Session key.
343 * @param mixed $default default value.
344 *
345 * @return string|array Session variable.
346 */
347 public function get( $key, $default = false ) {
348 $key = sanitize_key( $key );
349
350 return isset( $this->session[ $key ] ) ? maybe_unserialize( $this->session[ $key ] ) : $default;
351 }
352
353 /**
354 * Set Session
355 *
356 * @since 1.0
357 * @access public
358 *
359 * @param string $key Session key.
360 * @param mixed $value Session variable.
361 *
362 * @return string Session variable.
363 */
364 public function set( $key, $value ) {
365 if ( $value !== $this->get( $key ) ) {
366 $this->session[ sanitize_key( $key ) ] = maybe_serialize( $value );
367 $this->session_data_changed = true;
368 }
369
370 return $this->session[ $key ];
371 }
372
373 /**
374 * Set Session Cookies
375 *
376 * Cookies are used to increase the session lifetime using the give setting. This is helpful for when a user closes
377 * their browser after making a donation and comes back to the site.
378 *
379 * @since 1.4
380 * @access public
381 *
382 * @param bool $set Flag to check if set cookie or not.
383 */
384 public function set_session_cookies( $set ) {
385 if ( $set ) {
386 $this->set_expiration_time();
387
388 $to_hash = $this->donor_id . '|' . $this->session_expiration;
389 $cookie_hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) );
390 $cookie_value = $this->donor_id . '||' . $this->session_expiration . '||' . $this->session_expiring . '||' . $cookie_hash;
391 $this->has_cookie = true;
392
393 give_setcookie( $this->cookie_name, $cookie_value, $this->session_expiration, apply_filters( 'give_session_use_secure_cookie', false ) );
394 give_setcookie( $this->nonce_cookie_name, '1', $this->session_expiration, apply_filters( 'give_session_use_secure_cookie', false ) );
395 }
396 }
397
398 /**
399 * Set Cookie Expiration
400 *
401 * Force the cookie expiration time if set, default to 24 hours.
402 *
403 * @since 1.0
404 * @access public
405 *
406 * @return int
407 */
408 public function set_expiration_time() {
409 $this->session_expiring = time() + intval( apply_filters( 'give_session_expiring', ( $this->exp_option - 3600 ) ) ); // Default 11 Hours.
410 $this->session_expiration = time() + intval( apply_filters( 'give_session_expiration', $this->exp_option ) ); // Default 12 Hours.
411
412 return $this->session_expiration;
413 }
414
415 /**
416 * Get Session Expiration
417 *
418 * Looks at the session cookies and returns the expiration date for this session if applicable
419 *
420 * @since 2.2.0
421 * @access public
422 *
423 * @return string|bool Formatted expiration date string.
424 */
425 public function get_session_expiration() {
426 return $this->has_session() ? $this->session_expiration : false;
427 }
428
429 /**
430 * Maybe Start Session
431 *
432 * Starts a new session if one hasn't started yet.
433 *
434 * @since 2.2.0
435 * @access public
436 *
437 * @return void
438 */
439 public function maybe_start_session() {
440 if (
441 ! headers_sent()
442 && empty( $this->session )
443 && ! $this->has_cookie
444 ) {
445 $this->set_session_cookies( true );
446 }
447 }
448
449 /**
450 * Setup donor session when authorized by WP user credentials
451 *
452 * @since 2.7.0
453 *
454 * @param WP_User $wpUser
455 * @param string $wpUserLogin
456 */
457 public function startSessionWhenLoginAsWPUser( $wpUserLogin, $wpUser ) {
458
459 $donor = Give()->donors->get_donor_by( 'user_id', $wpUser->ID );
460
461 // Setup session only if donor exist for specific WP user.
462 if ( $donor ) {
463 $this->maybe_start_session();
464 $this->set( 'give_email', $donor->email );
465 }
466 }
467
468 /**
469 * Generate a unique donor ID.
470 *
471 * Uses Portable PHP password hashing framework to generate a unique cryptographically strong ID.
472 *
473 * @since 2.2.0
474 * @access public
475 */
476 public function generate_donor_id() {
477 require_once ABSPATH . 'wp-includes/class-phpass.php';
478
479 $hasher = new PasswordHash( 8, false );
480 $this->donor_id = md5( $hasher->get_random_bytes( 32 ) );
481 }
482
483 /**
484 * Save donor session data
485 *
486 * @since 2.2.0
487 * @access public
488 */
489 public function save_data() {
490 // Dirty if something changed - prevents saving nothing new.
491 if ( $this->session_data_changed && $this->has_session() ) {
492 global $wpdb;
493
494 Give()->session_db->replace(
495 Give()->session_db->table_name,
496 [
497 'session_key' => $this->donor_id,
498 'session_value' => maybe_serialize( $this->session ),
499 'session_expiry' => $this->session_expiration,
500 ],
501 [
502 '%s',
503 '%s',
504 '%d',
505 ]
506 );
507
508 $this->session_data_changed = false;
509 }
510 }
511
512 /**
513 * Destroy all session data.
514 *
515 * @since 2.2.0
516 * @access public
517 */
518 public function destroy_session() {
519
520 give_setcookie( 'give_nl', '', time() - YEAR_IN_SECONDS, apply_filters( 'give_session_use_secure_cookie', false ) );
521 give_setcookie( $this->cookie_name, '', time() - YEAR_IN_SECONDS, apply_filters( 'give_session_use_secure_cookie', false ) );
522 give_setcookie( $this->nonce_cookie_name, '', time() - YEAR_IN_SECONDS, apply_filters( 'give_session_use_secure_cookie', false ) );
523
524 Give()->session_db->delete_session( $this->donor_id );
525
526 $this->session = [];
527 $this->session_data_changed = false;
528
529 $this->generate_donor_id();
530 }
531
532 /**
533 * Delete nonce cookie if generating fresh form html.
534 *
535 * @since 2.2.0
536 * @access public
537 *
538 * @return bool
539 */
540 public function is_delete_nonce_cookie() {
541 $value = false;
542
543 if ( Give()->session->has_session() ) {
544 $value = true;
545 }
546
547 return $value;
548 }
549
550 /**
551 * Get cookie names
552 *
553 * @since 2.2.0
554 * @access public
555 *
556 * @param string $type Nonce type.
557 *
558 * @return string Cookie name
559 */
560 public function get_cookie_name( $type = '' ) {
561 $name = '';
562
563 switch ( $type ) {
564 case 'nonce':
565 $name = $this->nonce_cookie_name;
566 break;
567
568 case 'session':
569 $name = $this->cookie_name;
570 break;
571 }
572
573 return $name;
574 }
575
576 /**
577 * When a user is logged out, ensure they have a unique nonce by using the donor/session ID.
578 * Note: for internal logic only.
579 *
580 * @since 4.9.0 rename function - PHP 8 compatibility
581 * @since 2.2.0
582 * @access public
583 *
584 * @param int $uid User ID.
585 *
586 * @return string
587 */
588 public function nonce_user_logged_out( $uid ) {
589 return $this->has_session() && $this->donor_id ? $this->donor_id : $uid;
590 }
591
592
593 /**
594 * Cleanup session data from the database and clear caches.
595 * Note: for internal logic only.
596 *
597 * @since 4.9.0 rename function - PHP 8 compatibility
598 * @since 2.2.0
599 * @access public
600 */
601 public function cleanup_sessions() { // @codingStandardsIgnoreLine
602 Give()->session_db->delete_expired_sessions();
603 }
604
605
606 /**
607 * Get Session ID
608 *
609 * Retrieve session ID.
610 *
611 * @since 1.0
612 * @return string Session ID.
613 * @deprecated 2.2.0
614 * @access public
615 *
616 */
617 public function get_id() {
618 return $this->get_cookie_name( 'session' );
619 }
620
621 /**
622 * Set Cookie Variant Time
623 *
624 * Force the cookie expiration variant time to custom expiration option, less and hour. defaults to 23 hours
625 * (set_expiration_variant_time used in WP_Session).
626 *
627 * @since 1.0
628 * @return int
629 * @deprecated 2.2.0
630 * @access public
631 *
632 */
633 public function set_expiration_variant_time() {
634
635 return ( ! empty( $this->exp_option ) ? ( intval( $this->exp_option ) - 3600 ) : 30 * 60 * 23 );
636 }
637
638 /**
639 * Starts a new session if one has not started yet.
640 *
641 * Checks to see if the server supports PHP sessions or if the GIVE_USE_PHP_SESSIONS constant is defined.
642 *
643 * @since 1.0
644 * @access public
645 * @return bool $ret True if we are using PHP sessions, false otherwise.
646 * @deprecated 2.2.0
647 *
648 */
649 public function use_php_sessions() {
650 $ret = false;
651
652 give_doing_it_wrong( __FUNCTION__, __( 'We are using database session logic instead of PHP session since GiveWP 2.2.0', 'give' ) );
653
654 return (bool) apply_filters( 'give_use_php_sessions', $ret );
655 }
656
657 /**
658 * Should Start Session
659 *
660 * Determines if we should start sessions.
661 *
662 * @since 1.4
663 * @access public
664 * @return bool
665 * @deprecated 2.2.0
666 *
667 */
668 public function should_start_session() {
669
670 $start_session = true;
671
672 give_doing_it_wrong( __FUNCTION__, __( 'We are using database session logic instead of PHP session since GiveWP 2.2.0', 'give' ) );
673
674 if ( ! empty( $_SERVER['REQUEST_URI'] ) ) { // @codingStandardsIgnoreLine
675
676 $blacklist = apply_filters(
677 'give_session_start_uri_blacklist',
678 [
679 'feed',
680 'feed',
681 'feed/rss',
682 'feed/rss2',
683 'feed/rdf',
684 'feed/atom',
685 'comments/feed/',
686 ]
687 );
688 $uri = ltrim( $_SERVER['REQUEST_URI'], '/' ); // // @codingStandardsIgnoreLine
689 $uri = untrailingslashit( $uri );
690 if ( in_array( $uri, $blacklist, true ) ) {
691 $start_session = false;
692 }
693 if ( false !== strpos( $uri, 'feed=' ) ) {
694 $start_session = false;
695 }
696 if ( is_admin() ) {
697 $start_session = false;
698 }
699 }
700
701 return apply_filters( 'give_start_session', $start_session );
702 }
703 }
704