PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
← All changes | inc/class-lp-session-handler.php +282 -321 4.1.6.9.24.4.8 View file →
@@ -1,15 +1,16 @@
1 1 <?php
2 2
3 3 /**
4 4 * Class LP_Session_Handler
5 + *
6 + * Only set COOKIE for user guest
5 7 */
6 -class LP_Session_Handler implements ArrayAccess {
7 -
8 +class LP_Session_Handler {
8 9 /**
9 - * @var int $_customer_id
10 + * @var string $_customer_id
10 11 */
11 - protected $_customer_id;
12 + public $_customer_id = '';
12 13
13 14 /**
14 15 * @var array $_data
15 16 */
@@ -22,378 +23,343 @@
22 23
23 24 /**
24 25 * @var string cookie name
25 26 */
26 - private $_cookie;
27 + private $_cookie = 'lp_session_guest';
27 28
28 29 /**
29 - * @var string session expiration timestamp
30 + * @var int session expiration timestamp
30 31 */
31 - private $_session_expiration;
32 + private $_session_expiration = 0;
32 33
33 34 /**
34 - * $var bool Bool based on whether a cookie exists
35 - */
36 - private $_has_cookie = false;
37 -
38 - /**
39 - * @since 3.2.2
40 - *
41 - * @var bool
42 - */
43 - private $_has_browser_cookie = true;
44 -
45 - /**
46 - * @var string Custom session table name
47 - */
48 - private $_table;
49 -
50 - /**
51 35 * @var null
52 36 */
53 37 private static $_instance = null;
54 38
55 39 /**
56 - * __get function.
40 + * LP_Session_Handler constructor.
57 41 *
58 - * @param mixed $key
59 - *
60 - * @return mixed
42 + * @version 3.2.2
61 43 */
62 - public function __get( $key ) {
63 - return $this->get( $key );
44 + protected function __construct() {
45 + $this->init_hooks();
46 + if ( is_admin() ) {
47 + return;
48 + }
49 +
50 + $this->init();
64 51 }
65 52
66 - /**
67 - * __set function.
68 - *
69 - * @param mixed $key
70 - * @param mixed $value
71 - */
72 - public function __set( $key, $value ) {
73 - // if ( $key === 'order_awaiting_payment' ) {
74 -
75 - // }
76 - $this->set( $key, $value );
53 + protected function init_hooks() {
54 + add_action( 'wp_login', [ $this, 'handle_when_user_login_success' ], 10, 2 );
55 + add_action( 'wp_logout', array( $this, 'destroy_session' ) );
77 56 }
78 57
79 58 /**
80 - * __isset function.
59 + * Set COOKIE for only user guest
60 + * Set data: customer_id, session_expiration
81 61 *
82 - * @param mixed $key
83 - *
84 - * @return bool
62 + * @return self
63 + * @since 3.0.0
64 + * @version 4.0.3
65 + * @modify Tungnx
85 66 */
86 - public function __isset( $key ) {
87 - return isset( $this->_data[ sanitize_key( $key ) ] );
88 - }
67 + protected function init(): LP_Session_Handler {
68 + $expire_time_for_guest = DAY_IN_SECONDS;
69 + $expire_time_for_user = 6 * DAY_IN_SECONDS;
89 70
90 - /**
91 - * __unset function.
92 - *
93 - * @param mixed $key
94 - */
95 - public function __unset( $key ) {
96 - if ( isset( $this->_data[ $key ] ) ) {
97 - unset( $this->_data[ $key ] );
98 - $this->_changed = true;
71 + // Set data for user Guest.
72 + if ( ! is_user_logged_in() ) { // Generate data and set cookie for guest
73 + $this->set_session_expiration( $expire_time_for_guest );
74 +
75 + if ( LP_Settings::is_store_ip_customer() ) {
76 + $this->_customer_id = LP_Helper::get_client_ip();
77 + } else { // Store data in COOKIE
78 + $cookie = $this->get_cookie_data();
79 + // If cookie exists, set data from cookie for guest
80 + if ( empty( $cookie ) ) {
81 + // Create new cookie and session for user Guest.
82 + $this->_customer_id = apply_filters( 'lp/cookie/guest-id', 'g-' . uniqid() );
83 + $this->set_customer_session_cookie();
84 + } else {
85 + $this->_customer_id = $cookie;
86 + }
87 + }
88 + } else { // Set data for user logged.
89 + $this->set_session_expiration( $expire_time_for_user );
90 + $this->_customer_id = get_current_user_id();
99 91 }
92 +
93 + // Get session data from DB.
94 + $this->_data = $this->get_session_data();
95 +
96 + return $this;
100 97 }
101 98
102 - protected $schedule_id = 'learn-press/clear-expired-session';
103 -
104 99 /**
105 - * LP_Session_Handler constructor.
100 + * Handle when user logged in.
106 101 *
107 - * @version 3.2.2
102 + * @param $user_name
103 + * @param $user
104 + *
105 + * @return void
108 106 */
109 - public function __construct() {
110 - $this->init();
111 - $this->init_hooks();
112 - }
107 + public function handle_when_user_login_success( $user_name, $user ) {
108 + // Remove COOKIE for user guest.
109 + learn_press_remove_cookie( $this->_cookie );
113 110
114 - protected function init_hooks() {
115 - add_action( 'learn_press_set_cart_cookies', array( $this, 'set_customer_session_cookie' ), 10 );
116 - add_action( 'learn_press_cleanup_sessions', array( $this, 'cleanup_sessions' ), 10 );
117 - add_action( 'shutdown', array( $this, 'save_data' ), 20 );
118 - add_action( 'wp_logout', array( $this, 'destroy_session' ) );
119 - //add_action( 'wp', array( $this, 'schedule_event' ) );
120 - //add_action( $this->schedule_id, array( $this, 'cleanup_sessions' ), 10 );
121 - }
111 + /**
112 + * Must set wp_set_current_user to get_current_user_id and is_user_logged_in work correctly.
113 + * Because WP note must do that.
114 + * Read more @see wp_signon
115 + * If version WP after run correctly, remove wp_set_current_user.
116 + */
117 + wp_set_current_user( $user->ID );
118 + $user_id = get_current_user_id();
122 119
123 - protected function init() {
124 - global $wpdb;
125 - $this->_cookie = '_learn_press_session_' . COOKIEHASH;
126 - $this->_table = $wpdb->prefix . 'learnpress_sessions';
127 -
128 - // Check cookie ...
129 - if ( ! isset( $_COOKIE ) || sizeof( $_COOKIE ) == 0 ) {
130 - $this->_has_browser_cookie = false;
131 - }
132 -
133 - // ...and user-agent to ensure user a viewing in a web browser
134 - if ( empty( $_SERVER['HTTP_USER_AGENT'] ) || strpos( $_SERVER['HTTP_USER_AGENT'], 'Mozilla' ) === false ) {
135 - $this->_has_browser_cookie = false;
136 - }
137 -
138 - $cookie = $this->get_session_cookie();
139 - if ( $cookie ) {
140 - $this->_customer_id = $cookie[0];
141 - $this->_session_expiration = $cookie[1];
142 - $this->_has_cookie = true;
143 - if ( time() > $this->_session_expiration - HOUR_IN_SECONDS ) {
144 - $this->set_session_expiration();
145 - $this->update_session_timestamp( $this->_customer_id, $this->_session_expiration );
120 + /**
121 + * Delete session of user guest before.
122 + */
123 + if ( $user_id ) {
124 + $customer_id = $this->get_customer_id();
125 + $user_before = get_user_by( 'ID', $customer_id );
126 + if ( ! $user_before ) {
127 + $this->delete_session( $customer_id );
146 128 }
147 - } else {
148 - $this->set_session_expiration();
149 - $this->_customer_id = $this->generate_customer_id();
150 129
130 + $this->_customer_id = $user_id;
151 131 }
152 - $this->_data = $this->get_session_data();
153 132 }
154 133
155 - /*public function schedule_event() {
156 - if ( ! wp_next_scheduled( $this->schedule_id ) ) {
157 - wp_schedule_event( time(), 'hourly', $this->schedule_id );
134 + /**
135 + * Set cookie for user guest.
136 + *
137 + * @return LP_Session_Handler
138 + */
139 + public function set_customer_session_cookie(): LP_Session_Handler {
140 + // Set the cookie
141 + if ( ! isset( $_COOKIE[ $this->_cookie ] ) ) {
142 + learn_press_setcookie( $this->_cookie, $this->_customer_id, $this->_session_expiration );
158 143 }
159 - }*/
160 144
161 - public function set_customer_session_cookie( $set ) {
162 - if ( $set ) {
163 - // Set/renew our cookie
164 - $to_hash = $this->_customer_id . '|' . $this->_session_expiration;
165 - $cookie_hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) );
166 - $cookie_value = $this->_customer_id . '||' . $this->_session_expiration . '||' . $cookie_hash;
167 - $this->_has_cookie = true;
168 -
169 - // Set the cookie
170 - if ( ! isset( $_COOKIE[ $this->_cookie ] ) || $_COOKIE[ $this->_cookie ] !== $cookie_value ) {
171 - learn_press_setcookie( $this->_cookie, $cookie_value, $this->_session_expiration, apply_filters( 'learn_press_session_use_secure_cookie', false ), true );
172 - }
173 - }
145 + return $this;
174 146 }
175 147
176 - public function has_cookie() {
177 - return $this->_has_cookie && $this->_has_browser_cookie;
178 - }
148 + /**
149 + * Set session expiration.
150 + *
151 + * @param int $duration
152 + *
153 + * @return LP_Session_Handler
154 + */
155 + public function set_session_expiration( int $duration = 0 ): LP_Session_Handler {
156 + $this->_session_expiration = time() + $duration;
179 157
180 - public function has_session() {
181 - return isset( $_COOKIE[ $this->_cookie ] ) || $this->_has_cookie || is_user_logged_in();
158 + return $this;
182 159 }
183 160
184 - public function set_session_expiration() {
185 - $this->_session_expiration = time() + intval( apply_filters( 'learn_press_session_expiration', 60 * 60 * 48 ) );
186 - }
187 -
188 - public function generate_customer_id() {
189 - if ( is_user_logged_in() ) {
190 - return get_current_user_id();
191 - } else {
192 - require_once ABSPATH . 'wp-includes/class-phpass.php';
193 - $hasher = new PasswordHash( 12, false );
194 -
195 - return md5( $hasher->get_random_bytes( 32 ) );
196 - }
197 - }
198 -
199 - public function get_session_cookie() {
200 -
161 + /**
162 + * Get cookie of guest.
163 + *
164 + * @return string
165 + */
166 + public function get_cookie_data(): string {
201 167 if ( empty( $_COOKIE[ $this->_cookie ] ) || ! is_string( $_COOKIE[ $this->_cookie ] ) ) {
202 - return false;
168 + return '';
203 169 }
204 170
205 - list( $customer_id, $session_expiration, $cookie_hash ) = explode( '||', $_COOKIE[ $this->_cookie ] );
206 -
207 - $to_hash = $customer_id . '|' . $session_expiration;
208 - $hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) );
209 -
210 - // LP_Debug::instance()->add( array(
211 - // $this->_customer_id,
212 - // $_COOKIE,
213 - // $_REQUEST,
214 - // $_POST,
215 - // $_GET,
216 - // $_SERVER
217 - // ), 'sessions-cookie' );
218 -
219 - if ( empty( $cookie_hash ) || ! hash_equals( $hash, $cookie_hash ) ) {
220 - return false;
221 - }
222 -
223 - return array( $customer_id, $session_expiration, $cookie_hash );
171 + return $_COOKIE[ $this->_cookie ];
224 172 }
225 173
226 - public function get_session_data() {
227 - return $this->has_session() ? (array) $this->get_session( $this->_customer_id, array() ) : array();
228 - }
229 -
230 - public function get_cache_prefix( $group = LP_SESSION_CACHE_GROUP ) {
231 - $prefix = LP_Object_Cache::get( 'learn_press_' . $group . '_cache_prefix', $group );
232 -
233 - if ( false === $prefix ) {
234 - $prefix = 1;
235 - LP_Object_Cache::set( 'learn_press_' . $group . '_cache_prefix', $prefix, $group );
174 + /**
175 + * Get session data
176 + *
177 + * @return array
178 + */
179 + public function get_session_data(): array {
180 + if ( is_user_logged_in() ) {
181 + $customer_id = get_current_user_id();
182 + } else {
183 + $customer_id = $this->get_customer_id();
236 184 }
237 185
238 - return 'learn_press_cache_' . $prefix . '_';
186 + return (array) $this->get_session_by_customer_id( (string) $customer_id );
239 187 }
240 188
241 189 /**
242 - * Increment group cache prefix (invalidates cache).
190 + * Save session data to the database.
243 191 *
244 - * @param string $group
192 + * @return bool
193 + * @version 4.0.1
194 + * @since 3.0.0
245 195 */
246 - public function incr_cache_prefix( $group ) {
247 - wp_cache_incr( 'learn_press_' . $group . '_cache_prefix', 1, $group );
248 - }
196 + public function save_data(): bool {
197 + $res = false;
249 198
199 + try {
200 + $lp_session_db = LP_Sessions_DB::getInstance();
250 201
251 - public function save_data() {
252 - // var_dump($this->_changed , $this->has_session() , $this->has_cookie() );
253 - if ( $this->_changed && $this->has_session() && $this->has_cookie() ) {
254 - global $wpdb;
255 - $wpdb->replace(
256 - $this->_table,
257 - array(
258 - 'session_key' => $this->_customer_id,
259 - 'session_value' => maybe_serialize( $this->_data ),
260 - 'session_expiry' => $this->_session_expiration,
261 - ),
262 - array(
263 - '%s',
264 - '%s',
265 - '%d',
266 - )
267 - );
268 - // LP_Debug::instance()->add( array(
269 - // $this->_customer_id,
270 - // $_COOKIE,
271 - // $_REQUEST,
272 - // $_POST,
273 - // $_GET,
274 - // $_SERVER
275 - // ), __FUNCTION__ );
202 + // Check exists on DB.
203 + $filter = new LP_Session_filter();
204 + $filter->collection = $lp_session_db->tb_lp_sessions;
205 + $filter->field_count = 'session_id';
206 + $filter->limit = 1;
207 + $filter->where[] = $lp_session_db->wpdb->prepare( 'AND session_key = %s', $this->_customer_id );
208 + $get = $lp_session_db->execute( $filter );
276 209
277 - // Set cache
278 - LP_Object_Cache::set( $this->get_cache_prefix() . $this->_customer_id, $this->_data, LP_SESSION_CACHE_GROUP, $this->_session_expiration - time() );
210 + $data = [
211 + 'session_key' => (string) $this->_customer_id,
212 + 'session_value' => maybe_serialize( $this->_data ),
213 + 'session_expiry' => $this->_session_expiration,
214 + ];
215 + if ( ! empty( $get ) ) {
216 + // Update
217 + $lp_session_db->wpdb->update(
218 + $lp_session_db->tb_lp_sessions,
219 + $data,
220 + [ 'session_key' => $this->_customer_id ],
221 + [ '%s', '%s', '%d' ],
222 + [ '%s' ]
223 + );
224 + } else {
225 + // Insert
226 + $lp_session_db->wpdb->insert(
227 + $lp_session_db->tb_lp_sessions,
228 + $data,
229 + [ '%s', '%s', '%d' ]
230 + );
231 + }
279 232
280 - // Mark session clean after saving
281 - $this->_changed = false;
233 + // Clear cache.
234 + LP_Session_Cache::instance()->clear( $this->_customer_id );
235 +
236 + $res = true;
237 + } catch ( Throwable $e ) {
238 + error_log( $e->getMessage() );
282 239 }
240 +
241 + return $res;
283 242 }
284 243
244 + /**
245 + * Destroy session.
246 + */
285 247 public function destroy_session() {
286 - $id = $this->get( 'temp_user' );
287 - if ( $id ) {
288 - delete_user_meta( $id, '_lp_expiration' );
248 + // Clear cookie.
249 + if ( ! empty( $this->_cookie ) ) {
250 + learn_press_remove_cookie( $this->_cookie );
289 251 }
290 252
291 - // Clear cookie
292 - learn_press_setcookie( $this->_cookie, '', time() - YEAR_IN_SECONDS, apply_filters( 'learn_press_session_secure_cookie', false ) );
253 + // Clear session expire.
254 + $this->cleanup_sessions_expire();
293 255
294 - $this->delete_session( $this->_customer_id );
295 -
296 - // Clear cart
297 - $this->set( 'cart', '' );
298 - $this->set( 'temp_user', '' );
299 -
300 - // Clear data
301 - $this->_data = array();
302 - $this->_changed = false;
303 - $this->_customer_id = $this->generate_customer_id();
304 -
305 - $logout_redirect_page_id = LP_Settings::get_option( 'logout_redirect_page_id', false );
256 + $logout_redirect_page_id = LP_Settings::get_option( 'logout_redirect_page_id' );
306 257 if ( $logout_redirect_page_id ) {
307 -
308 258 wp_safe_redirect( get_the_permalink( $logout_redirect_page_id ) );
309 259 die;
310 260 }
311 261 }
312 262
313 - public function cleanup_sessions() {
314 - global $wpdb;
263 + /**
264 + * Clear session expired.
265 + *
266 + * @return bool
267 + */
268 + public function cleanup_sessions_expire(): bool {
269 + $res = true;
270 + $lp_session_db = LP_Sessions_DB::getInstance();
315 271
316 - if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
272 + try {
273 + // Get session expired.
274 + $filter_get = new LP_Session_Filter();
275 + $filter_get->where[] = $lp_session_db->wpdb->prepare( 'AND session_expiry < %d', time() );
276 + $sessions = $lp_session_db->get_sessions( $filter_get );
277 + // Clear cache.
278 + foreach ( $sessions as $session ) {
279 + LP_Session_Cache::instance()->clear( $session->session_key );
280 + }
317 281
318 - // Delete expired sessions
319 - $wpdb->query( $wpdb->prepare( "DELETE FROM $this->_table WHERE session_expiry < %d", time() ) ); // phpcs:ignore
282 + // Delete session expired.
283 + $filter = new LP_Session_Filter();
284 + $filter->collection = $lp_session_db->tb_lp_sessions;
285 + $filter->where[] = $lp_session_db->wpdb->prepare( 'AND session_expiry < %d', time() );
286 + $lp_session_db->delete_execute( $filter );
287 + } catch ( Throwable $e ) {
288 + $res = false;
289 + error_log( $e->getMessage() );
290 + }
320 291
321 - // Invalidate cache
322 - $this->incr_cache_prefix( LP_SESSION_CACHE_GROUP );
323 - }
292 + return $res;
324 293 }
325 294
326 - public function get_session( $customer_id, $default = false ) {
327 - global $wpdb;
295 + /**
296 + * Get session on DB.
297 + *
298 + * @param string $customer_id
299 + *
300 + * @return false|mixed|string
301 + * @Todo - Tungnx should handle data when save type json instead serialize.
302 + */
303 + public function get_session_by_customer_id( string $customer_id = '' ) {
304 + $lp_session_db = LP_Sessions_DB::getInstance();
305 + $session = [];
328 306
329 - if ( defined( 'WP_SETUP_CONFIG' ) ) {
330 - return false;
331 - }
307 + try {
308 + // Get cache.
309 + $session_cache = LP_Session_Cache::instance();
310 + $key_cache = $customer_id;
311 + $session = $session_cache->get_cache( $key_cache );
312 + if ( $session !== false ) {
313 + return $session;
314 + }
332 315
333 - // Try get it from the cache, it will return false if not present or if object cache not in use
334 - $value = LP_Object_Cache::get( $this->get_cache_prefix() . $customer_id, LP_SESSION_CACHE_GROUP );
335 - // echo "KEY:" . $this->get_cache_prefix() . $customer_id . "]";
336 -
337 - if ( false === $value && $wpdb->get_var( "SHOW TABLES LIKE '$this->_table'" ) == $this->_table ) {
338 - $q = $wpdb->prepare( "SELECT session_value FROM $this->_table WHERE session_key = %s", $customer_id ); // phpcs:ignore
339 - $value = $wpdb->get_var( $q );
340 -
341 - if ( is_null( $value ) ) {
342 - $value = $default;
316 + $filter = new LP_Session_Filter();
317 + $filter->session_key = $customer_id;
318 + $filter->only_fields = [ 'session_key', 'session_value' ];
319 + $filter->field_count = 'session_key';
320 + $filter->run_query_count = false;
321 + $filter->limit = 1;
322 + $res = $lp_session_db->get_sessions( $filter );
323 + if ( ! empty( $res ) ) {
324 + $session = $res[0]->session_value;
343 325 }
344 326
345 - wp_cache_add( $this->get_cache_prefix() . $customer_id, $value, LP_SESSION_CACHE_GROUP, $this->_session_expiration - time() );
327 + $session = LP_Helper::maybe_unserialize( $session );
328 + // Set cache.
329 + $session_cache->set_cache( $key_cache, $session );
330 + } catch ( Throwable $e ) {
331 + error_log( $e->getMessage() );
346 332 }
347 333
348 - return LP_Helper::maybe_unserialize( $value );
334 + return $session;
349 335 }
350 336
351 - public function delete_session( $customer_id ) {
352 - global $wpdb;
353 -
354 - wp_cache_delete( $this->get_cache_prefix() . $customer_id, LP_SESSION_CACHE_GROUP );
355 -
356 - $wpdb->delete(
357 - $this->_table,
358 - array(
359 - 'session_key' => $customer_id,
360 - )
361 - );
362 - }
363 -
364 - public function update_session_timestamp( $customer_id, $timestamp ) {
365 - global $wpdb;
366 - $wpdb->update(
367 - $this->_table,
368 - array(
369 - 'session_expiry' => $timestamp,
370 - ),
371 - array(
372 - 'session_key' => $customer_id,
373 - ),
374 - array(
375 - '%d',
376 - )
377 - );
378 - // LP_Debug::instance()->add( $customer_id, __FUNCTION__ );
379 - }
380 -
381 337 /**
382 - * Remove a value from session by key.
338 + * Delete session by customer_id on DB.
383 339 *
384 - * @param string $key
385 - * @param bool $force_change
340 + * @param string $customer_id
341 + *
342 + * @return bool
386 343 */
387 - public function remove( $key, $force_change = false ) {
388 - if ( ! array_key_exists( $key, $this->_data ) ) {
389 - return;
344 + public function delete_session( string $customer_id ): bool {
345 + global $wpdb;
346 + $rs = true;
347 +
348 + try {
349 + $wpdb->delete(
350 + LP_Sessions_DB::getInstance()->tb_lp_sessions,
351 + [ 'session_key' => $customer_id ],
352 + [ '%s' ]
353 + );
354 + // Clear cache.
355 + LP_Session_Cache::instance()->clear( $customer_id );
356 + } catch ( Throwable $e ) {
357 + $rs = false;
358 + error_log( $e->getMessage() );
390 359 }
391 - unset( $this->_data[ $key ] );
392 - $this->_changed = true;
393 - if ( $force_change ) {
394 - $this->save_data();
395 - }
360 +
361 + return $rs;
396 362 }
397 363
398 364 /**
399 365 * Get session value.
@@ -402,11 +368,9 @@
402 368 * @param mixed $default
403 369 *
404 370 * @return mixed|null
405 371 */
406 - public function get( $key, $default = null ) {
407 - $key = sanitize_key( $key );
408 -
372 + public function get( string $key, $default = null ) {
409 373 return isset( $this->_data[ $key ] ) ? LP_Helper::maybe_unserialize( $this->_data[ $key ] ) : $default;
410 374 }
411 375
412 376 /**
@@ -412,52 +376,49 @@
412 376 /**
413 377 * Set session value.
414 378 *
415 379 * @param string $key
416 - * @param mixed $value
417 - * @param bool $force_change
380 + * @param mixed $value
381 + * @param bool $force_change
418 382 */
419 - public function set( $key, $value, $force_change = false ) {
420 - if ( $value !== $this->get( $key ) ) {
421 - $this->_data[ sanitize_key( $key ) ] = maybe_serialize( $value );
422 - $this->_changed = true;
383 + public function set( string $key, $value, bool $force_change = false ) {
384 + $this->_data[ sanitize_key( $key ) ] = maybe_serialize( $value );
423 385
424 - if ( $force_change ) {
425 - $this->save_data();
426 - }
386 + if ( $force_change ) {
387 + $this->save_data();
427 388 }
428 389 }
429 390
430 - public function get_customer_id() {
431 - return $this->_customer_id;
391 + /**
392 + * Remove a value from session by key.
393 + *
394 + * @param string $key
395 + * @param bool $force_change
396 + */
397 + public function remove( string $key, bool $force_change = false ) {
398 + if ( ! array_key_exists( $key, $this->_data ) ) {
399 + return;
400 + }
401 + unset( $this->_data[ $key ] );
402 +
403 + if ( $force_change ) {
404 + $this->save_data();
405 + }
432 406 }
433 407
434 - public function get_session_expiration() {
435 - return $this->_session_expiration;
408 + /**
409 + * Get customer id.
410 + */
411 + public function get_customer_id(): string {
412 + return (string) $this->_customer_id;
436 413 }
437 414
438 415 public static function instance() {
439 - if ( ! self::$_instance ) {
416 + if ( is_null( self::$_instance ) ) {
440 417 self::$_instance = new self();
441 418 }
442 419
443 420 return self::$_instance;
444 - }
445 -
446 - public function offsetExists( $offset ) {
447 - return array_key_exists( $offset, $this->_data );
448 - }
449 -
450 - public function offsetGet( $offset ) {
451 - return $this->get( $offset );
452 - }
453 -
454 - public function offsetUnset( $offset ) {
455 - $this->remove( $offset );
456 - }
457 -
458 - public function offsetSet( $offset, $value ) {
459 - $this->set( $offset, $value );
460 421 }
461 422 }
462 423
463 424 /**