2013-01-15 19:51:19 +00:00
< ? php
2014-09-20 18:59:26 +00:00
if ( ! defined ( 'ABSPATH' ) ) {
2015-01-23 11:11:27 +00:00
exit ;
2014-09-20 18:59:26 +00:00
}
2013-02-20 17:14:46 +00:00
2013-01-15 19:51:19 +00:00
/**
* Handle data for the current customers session .
* Implements the WC_Session abstract class
*
* Long term plan will be , if https :// github . com / ericmann / wp - session - manager / gains traction
* in WP core , this will be switched out to use it and maintain backwards compatibility : )
*
* Partly based on WP SESSION by Eric Mann .
*
* @ class WC_Session_Handler
* @ version 2.0 . 0
* @ package WooCommerce / Classes
2013-02-20 17:14:46 +00:00
* @ category Class
2013-01-15 19:51:19 +00:00
* @ author WooThemes
*/
class WC_Session_Handler extends WC_Session {
/** cookie name */
private $_cookie ;
2013-01-16 11:05:50 +00:00
/** session due to expire timestamp */
private $_session_expiring ;
2013-01-15 19:51:19 +00:00
/** session expiration timestamp */
private $_session_expiration ;
2014-05-08 09:36:19 +00:00
/** Bool based on whether a cookie exists **/
private $_has_cookie = false ;
2013-01-15 19:51:19 +00:00
/**
* Constructor for the session class .
*/
public function __construct () {
2013-10-17 14:29:39 +00:00
$this -> _cookie = 'wp_woocommerce_session_' . COOKIEHASH ;
2013-01-15 19:51:19 +00:00
if ( $cookie = $this -> get_session_cookie () ) {
$this -> _customer_id = $cookie [ 0 ];
2013-01-16 11:05:50 +00:00
$this -> _session_expiration = $cookie [ 1 ];
$this -> _session_expiring = $cookie [ 2 ];
2014-05-08 09:36:19 +00:00
$this -> _has_cookie = true ;
2013-01-15 19:51:19 +00:00
// Update session if its close to expiring
2013-01-16 11:05:50 +00:00
if ( time () > $this -> _session_expiring ) {
$this -> set_session_expiration ();
2014-04-08 07:35:04 +00:00
$session_expiry_option = '_wc_session_expires_' . $this -> _customer_id ;
// Check if option exists first to avoid auloading cleaned up sessions
if ( false === get_option ( $session_expiry_option ) ) {
add_option ( $session_expiry_option , $this -> _session_expiration , '' , 'no' );
} else {
update_option ( $session_expiry_option , $this -> _session_expiration );
}
2013-01-15 19:51:19 +00:00
}
} else {
2013-01-16 11:05:50 +00:00
$this -> set_session_expiration ();
2013-01-15 19:51:19 +00:00
$this -> _customer_id = $this -> generate_customer_id ();
}
$this -> _data = $this -> get_session_data ();
// Actions
2013-10-17 14:29:39 +00:00
add_action ( 'woocommerce_set_cart_cookies' , array ( $this , 'set_customer_session_cookie' ), 10 );
2013-01-16 09:53:08 +00:00
add_action ( 'woocommerce_cleanup_sessions' , array ( $this , 'cleanup_sessions' ), 10 );
2013-01-15 19:51:19 +00:00
add_action ( 'shutdown' , array ( $this , 'save_data' ), 20 );
2014-05-20 09:01:26 +00:00
add_action ( 'clear_auth_cookie' , array ( $this , 'destroy_session' ) );
if ( ! is_user_logged_in () ) {
add_action ( 'woocommerce_thankyou' , array ( $this , 'destroy_session' ) );
}
2013-01-15 19:51:19 +00:00
}
2013-10-17 14:29:39 +00:00
/**
* Sets the session cookie on - demand ( usually after adding an item to the cart ) .
*
* Since the cookie name ( as of 2.1 ) is prepended with wp , cache systems like batcache will not cache pages when set .
*
* Warning : Cookies will only be set if this is called before the headers are sent .
*/
public function set_customer_session_cookie ( $set ) {
if ( $set ) {
// Set/renew our cookie
2014-05-08 09:36:19 +00:00
$to_hash = $this -> _customer_id . $this -> _session_expiration ;
$cookie_hash = hash_hmac ( 'md5' , $to_hash , wp_hash ( $to_hash ) );
$cookie_value = $this -> _customer_id . '||' . $this -> _session_expiration . '||' . $this -> _session_expiring . '||' . $cookie_hash ;
$this -> _has_cookie = true ;
2013-10-17 14:29:39 +00:00
// Set the cookie
2014-03-19 09:16:26 +00:00
wc_setcookie ( $this -> _cookie , $cookie_value , $this -> _session_expiration , apply_filters ( 'wc_session_use_secure_cookie' , false ) );
2013-10-17 14:29:39 +00:00
}
}
2014-05-08 09:36:19 +00:00
/**
* Return true if the current user has an active session , i . e . a cookie to retrieve values
* @ return boolean
*/
public function has_session () {
return isset ( $_COOKIE [ $this -> _cookie ] ) || $this -> _has_cookie || is_user_logged_in ();
}
2013-01-15 19:51:19 +00:00
/**
2013-01-16 11:05:50 +00:00
* set_session_expiration function .
2013-01-15 19:51:19 +00:00
*/
2013-09-13 12:39:46 +00:00
public function set_session_expiration () {
2013-01-16 11:05:50 +00:00
$this -> _session_expiring = time () + intval ( apply_filters ( 'wc_session_expiring' , 60 * 60 * 47 ) ); // 47 Hours
$this -> _session_expiration = time () + intval ( apply_filters ( 'wc_session_expiration' , 60 * 60 * 48 ) ); // 48 Hours
2013-01-15 19:51:19 +00:00
}
/**
2014-09-20 18:59:26 +00:00
* Generate a unique customer ID for guests , or return user ID if logged in .
*
2014-05-20 10:08:31 +00:00
* Uses Portable PHP password hashing framework to generate a unique cryptographically strong ID .
2013-01-15 19:51:19 +00:00
*
2014-05-20 10:08:31 +00:00
* @ return int | string
2013-01-15 19:51:19 +00:00
*/
2013-09-13 12:39:46 +00:00
public function generate_customer_id () {
2014-05-08 09:36:19 +00:00
if ( is_user_logged_in () ) {
2013-01-15 19:51:19 +00:00
return get_current_user_id ();
2014-05-08 09:36:19 +00:00
} else {
2014-05-20 10:08:31 +00:00
require_once ( ABSPATH . 'wp-includes/class-phpass.php' );
$hasher = new PasswordHash ( 8 , false );
return md5 ( $hasher -> get_random_bytes ( 32 ) );
2014-05-08 09:36:19 +00:00
}
2013-01-15 19:51:19 +00:00
}
/**
* get_session_cookie function .
*
2015-01-23 11:11:27 +00:00
* @ return bool | array
2013-01-15 19:51:19 +00:00
*/
2013-09-13 12:39:46 +00:00
public function get_session_cookie () {
2014-05-08 09:36:19 +00:00
if ( empty ( $_COOKIE [ $this -> _cookie ] ) ) {
2013-01-15 19:51:19 +00:00
return false ;
2014-05-08 09:36:19 +00:00
}
2013-01-15 19:51:19 +00:00
2013-01-16 11:05:50 +00:00
list ( $customer_id , $session_expiration , $session_expiring , $cookie_hash ) = explode ( '||' , $_COOKIE [ $this -> _cookie ] );
2013-01-15 19:51:19 +00:00
// Validate hash
2013-01-16 11:05:50 +00:00
$to_hash = $customer_id . $session_expiration ;
2013-01-15 19:51:19 +00:00
$hash = hash_hmac ( 'md5' , $to_hash , wp_hash ( $to_hash ) );
2014-05-08 09:36:19 +00:00
if ( $hash != $cookie_hash ) {
2013-01-15 19:51:19 +00:00
return false ;
2014-05-08 09:36:19 +00:00
}
2013-01-15 19:51:19 +00:00
2013-01-16 11:05:50 +00:00
return array ( $customer_id , $session_expiration , $session_expiring , $cookie_hash );
2013-01-15 19:51:19 +00:00
}
/**
* get_session_data function .
*
* @ return array
*/
2013-09-13 12:39:46 +00:00
public function get_session_data () {
2015-01-23 11:13:16 +00:00
return $this -> has_session () ? ( array ) get_option ( '_wc_session_' . $this -> _customer_id , array () ) : array ();
2013-01-15 19:51:19 +00:00
}
/**
* save_data function .
*/
public function save_data () {
// Dirty if something changed - prevents saving nothing new
2014-05-08 09:36:19 +00:00
if ( $this -> _dirty && $this -> has_session () ) {
2013-01-16 11:05:50 +00:00
2014-05-08 09:36:19 +00:00
$session_option = '_wc_session_' . $this -> _customer_id ;
$session_expiry_option = '_wc_session_expires_' . $this -> _customer_id ;
2013-01-16 11:05:50 +00:00
if ( false === get_option ( $session_option ) ) {
2013-04-09 08:40:23 +00:00
add_option ( $session_option , $this -> _data , '' , 'no' );
add_option ( $session_expiry_option , $this -> _session_expiration , '' , 'no' );
2013-01-15 19:51:19 +00:00
} else {
2013-01-16 11:05:50 +00:00
update_option ( $session_option , $this -> _data );
2013-01-15 19:51:19 +00:00
}
2015-02-21 07:55:24 +00:00
// Mark session clean after saving
$this -> _dirty = false ;
2013-01-15 19:51:19 +00:00
}
}
2013-01-16 09:53:08 +00:00
2014-05-20 09:01:26 +00:00
/**
* Destroy all session data
*/
public function destroy_session () {
// Clear cookie
wc_setcookie ( $this -> _cookie , '' , time () - YEAR_IN_SECONDS , apply_filters ( 'wc_session_use_secure_cookie' , false ) );
// Delete session
$session_option = '_wc_session_' . $this -> _customer_id ;
$session_expiry_option = '_wc_session_expires_' . $this -> _customer_id ;
delete_option ( $session_option );
delete_option ( $session_expiry_option );
// Clear cart
wc_empty_cart ();
2014-09-20 18:59:26 +00:00
2014-05-20 09:01:26 +00:00
// Clear data
$this -> _data = array ();
$this -> _dirty = false ;
$this -> _customer_id = $this -> generate_customer_id ();
}
2013-01-16 09:53:08 +00:00
/**
* cleanup_sessions function .
*/
public function cleanup_sessions () {
global $wpdb ;
2014-01-13 10:45:31 +00:00
if ( ! defined ( 'WP_SETUP_CONFIG' ) && ! defined ( 'WP_INSTALLING' ) ) {
$now = time ();
$expired_sessions = array ();
2014-12-08 21:16:40 +00:00
$wc_session_expires = $wpdb -> get_col ( " SELECT option_name FROM $wpdb->options WHERE option_name LIKE ' \ _wc \ _session \ _expires \ _%' AND option_value < ' $now ' " );
2014-01-13 10:45:31 +00:00
2014-12-08 21:16:40 +00:00
foreach ( $wc_session_expires as $option_name ) {
$session_id = substr ( $option_name , 20 );
$expired_sessions [] = $option_name ; // Expires key
2014-12-08 21:07:12 +00:00
$expired_sessions [] = " _wc_session_ $session_id " ; // Session key
2014-01-13 10:45:31 +00:00
}
if ( ! empty ( $expired_sessions ) ) {
2014-04-01 13:51:41 +00:00
$expired_sessions_chunked = array_chunk ( $expired_sessions , 100 );
foreach ( $expired_sessions_chunked as $chunk ) {
2014-12-07 22:04:55 +00:00
if ( wp_using_ext_object_cache () ) {
// delete from object cache first, to avoid cached but deleted options
foreach ( $chunk as $option ) {
wp_cache_delete ( $option , 'options' );
}
2014-12-06 07:43:56 +00:00
}
// delete from options table
2014-04-01 13:51:41 +00:00
$option_names = implode ( " ',' " , $chunk );
$wpdb -> query ( " DELETE FROM $wpdb->options WHERE option_name IN (' $option_names ') " );
}
2014-01-13 10:45:31 +00:00
}
}
2013-01-16 09:53:08 +00:00
}
2014-09-20 18:59:26 +00:00
}