WC_Session_Handler

Handle data for the current customers session.

Defined (1)

The class is defined in the following location(s).

/includes/class-wc-session-handler.php  
  1. class WC_Session_Handler extends WC_Session { 
  2.  
  3. /** @var string cookie name */ 
  4. private $_cookie; 
  5.  
  6. /** @var string session due to expire timestamp */ 
  7. private $_session_expiring; 
  8.  
  9. /** @var string session expiration timestamp */ 
  10. private $_session_expiration; 
  11.  
  12. /** $var bool Bool based on whether a cookie exists **/ 
  13. private $_has_cookie = false; 
  14.  
  15. /** @var string Custom session table name */ 
  16. private $_table; 
  17.  
  18. /** 
  19. * Constructor for the session class. 
  20. */ 
  21. public function __construct() { 
  22. global $wpdb; 
  23.  
  24. $this->_cookie = 'wp_woocommerce_session_' . COOKIEHASH; 
  25. $this->_table = $wpdb->prefix . 'woocommerce_sessions'; 
  26.  
  27. if ( $cookie = $this->get_session_cookie() ) { 
  28. $this->_customer_id = $cookie[0]; 
  29. $this->_session_expiration = $cookie[1]; 
  30. $this->_session_expiring = $cookie[2]; 
  31. $this->_has_cookie = true; 
  32.  
  33. // Update session if its close to expiring 
  34. if ( time() > $this->_session_expiring ) { 
  35. $this->set_session_expiration(); 
  36. $this->update_session_timestamp( $this->_customer_id, $this->_session_expiration ); 
  37. } else { 
  38. $this->set_session_expiration(); 
  39. $this->_customer_id = $this->generate_customer_id(); 
  40.  
  41. $this->_data = $this->get_session_data(); 
  42.  
  43. // Actions 
  44. add_action( 'woocommerce_set_cart_cookies', array( $this, 'set_customer_session_cookie' ), 10 ); 
  45. add_action( 'woocommerce_cleanup_sessions', array( $this, 'cleanup_sessions' ), 10 ); 
  46. add_action( 'shutdown', array( $this, 'save_data' ), 20 ); 
  47. add_action( 'wp_logout', array( $this, 'destroy_session' ) ); 
  48. if ( ! is_user_logged_in() ) { 
  49. add_filter( 'nonce_user_logged_out', array( $this, 'nonce_user_logged_out' ) ); 
  50.  
  51. /** 
  52. * Sets the session cookie on-demand (usually after adding an item to the cart). 
  53. * Since the cookie name (as of 2.1) is prepended with wp, cache systems like batcache will not cache pages when set. 
  54. * Warning: Cookies will only be set if this is called before the headers are sent. 
  55. */ 
  56. public function set_customer_session_cookie( $set ) { 
  57. if ( $set ) { 
  58. // Set/renew our cookie 
  59. $to_hash = $this->_customer_id . '|' . $this->_session_expiration; 
  60. $cookie_hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) ); 
  61. $cookie_value = $this->_customer_id . '||' . $this->_session_expiration . '||' . $this->_session_expiring . '||' . $cookie_hash; 
  62. $this->_has_cookie = true; 
  63.  
  64. // Set the cookie 
  65. wc_setcookie( $this->_cookie, $cookie_value, $this->_session_expiration, apply_filters( 'wc_session_use_secure_cookie', false ) ); 
  66.  
  67. /** 
  68. * Return true if the current user has an active session, i.e. a cookie to retrieve values. 
  69. * @return bool 
  70. */ 
  71. public function has_session() { 
  72. return isset( $_COOKIE[ $this->_cookie ] ) || $this->_has_cookie || is_user_logged_in(); 
  73.  
  74. /** 
  75. * Set session expiration. 
  76. */ 
  77. public function set_session_expiration() { 
  78. $this->_session_expiring = time() + intval( apply_filters( 'wc_session_expiring', 60 * 60 * 47 ) ); // 47 Hours. 
  79. $this->_session_expiration = time() + intval( apply_filters( 'wc_session_expiration', 60 * 60 * 48 ) ); // 48 Hours. 
  80.  
  81. /** 
  82. * Generate a unique customer ID for guests, or return user ID if logged in. 
  83. * Uses Portable PHP password hashing framework to generate a unique cryptographically strong ID. 
  84. * @return int|string 
  85. */ 
  86. public function generate_customer_id() { 
  87. if ( is_user_logged_in() ) { 
  88. return get_current_user_id(); 
  89. } else { 
  90. require_once( ABSPATH . 'wp-includes/class-phpass.php' ); 
  91. $hasher = new PasswordHash( 8, false ); 
  92. return md5( $hasher->get_random_bytes( 32 ) ); 
  93.  
  94. /** 
  95. * Get session cookie. 
  96. * @return bool|array 
  97. */ 
  98. public function get_session_cookie() { 
  99. if ( empty( $_COOKIE[ $this->_cookie ] ) || ! is_string( $_COOKIE[ $this->_cookie ] ) ) { 
  100. return false; 
  101.  
  102. list( $customer_id, $session_expiration, $session_expiring, $cookie_hash ) = explode( '||', $_COOKIE[ $this->_cookie ] ); 
  103.  
  104. // Validate hash 
  105. $to_hash = $customer_id . '|' . $session_expiration; 
  106. $hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) ); 
  107.  
  108. if ( empty( $cookie_hash ) || ! hash_equals( $hash, $cookie_hash ) ) { 
  109. return false; 
  110.  
  111. return array( $customer_id, $session_expiration, $session_expiring, $cookie_hash ); 
  112.  
  113. /** 
  114. * Get session data. 
  115. * @return array 
  116. */ 
  117. public function get_session_data() { 
  118. return $this->has_session() ? (array) $this->get_session( $this->_customer_id, array() ) : array(); 
  119.  
  120. /** 
  121. * Gets a cache prefix. This is used in session names so the entire cache can be invalidated with 1 function call. 
  122. * @return string 
  123. */ 
  124. private function get_cache_prefix() { 
  125. return WC_Cache_Helper::get_cache_prefix( WC_SESSION_CACHE_GROUP ); 
  126.  
  127. /** 
  128. * Save data. 
  129. */ 
  130. public function save_data() { 
  131. // Dirty if something changed - prevents saving nothing new 
  132. if ( $this->_dirty && $this->has_session() ) { 
  133. global $wpdb; 
  134.  
  135. $wpdb->replace( 
  136. $this->_table,  
  137. array( 
  138. 'session_key' => $this->_customer_id,  
  139. 'session_value' => maybe_serialize( $this->_data ),  
  140. 'session_expiry' => $this->_session_expiration,  
  141. ),  
  142. array( 
  143. '%s',  
  144. '%s',  
  145. '%d',  
  146. ); 
  147.  
  148. // Set cache 
  149. wp_cache_set( $this->get_cache_prefix() . $this->_customer_id, $this->_data, WC_SESSION_CACHE_GROUP, $this->_session_expiration - time() ); 
  150.  
  151. // Mark session clean after saving 
  152. $this->_dirty = false; 
  153.  
  154. /** 
  155. * Destroy all session data. 
  156. */ 
  157. public function destroy_session() { 
  158. // Clear cookie 
  159. wc_setcookie( $this->_cookie, '', time() - YEAR_IN_SECONDS, apply_filters( 'wc_session_use_secure_cookie', false ) ); 
  160.  
  161. $this->delete_session( $this->_customer_id ); 
  162.  
  163. // Clear cart 
  164. wc_empty_cart(); 
  165.  
  166. // Clear data 
  167. $this->_data = array(); 
  168. $this->_dirty = false; 
  169. $this->_customer_id = $this->generate_customer_id(); 
  170.  
  171. /** 
  172. * When a user is logged out, ensure they have a unique nonce by using the customer/session ID. 
  173. * @return string 
  174. */ 
  175. public function nonce_user_logged_out( $uid ) { 
  176. return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid; 
  177.  
  178. /** 
  179. * Cleanup sessions. 
  180. */ 
  181. public function cleanup_sessions() { 
  182. global $wpdb; 
  183.  
  184. if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) { 
  185.  
  186. // Delete expired sessions 
  187. $wpdb->query( $wpdb->prepare( "DELETE FROM $this->_table WHERE session_expiry < %d", time() ) ); 
  188.  
  189. // Invalidate cache 
  190. WC_Cache_Helper::incr_cache_prefix( WC_SESSION_CACHE_GROUP ); 
  191.  
  192. /** 
  193. * Returns the session. 
  194. * @param string $customer_id 
  195. * @param mixed $default 
  196. * @return string|array 
  197. */ 
  198. public function get_session( $customer_id, $default = false ) { 
  199. global $wpdb; 
  200.  
  201. if ( defined( 'WP_SETUP_CONFIG' ) ) { 
  202. return false; 
  203.  
  204. // Try get it from the cache, it will return false if not present or if object cache not in use 
  205. $value = wp_cache_get( $this->get_cache_prefix() . $customer_id, WC_SESSION_CACHE_GROUP ); 
  206.  
  207. if ( false === $value ) { 
  208. $value = $wpdb->get_var( $wpdb->prepare( "SELECT session_value FROM $this->_table WHERE session_key = %s", $customer_id ) ); 
  209.  
  210. if ( is_null( $value ) ) { 
  211. $value = $default; 
  212.  
  213. wp_cache_add( $this->get_cache_prefix() . $customer_id, $value, WC_SESSION_CACHE_GROUP, $this->_session_expiration - time() ); 
  214.  
  215. return maybe_unserialize( $value ); 
  216.  
  217. /** 
  218. * Delete the session from the cache and database. 
  219. * @param int $customer_id 
  220. */ 
  221. public function delete_session( $customer_id ) { 
  222. global $wpdb; 
  223.  
  224. wp_cache_delete( $this->get_cache_prefix() . $customer_id, WC_SESSION_CACHE_GROUP ); 
  225.  
  226. $wpdb->delete( 
  227. $this->_table,  
  228. array( 
  229. 'session_key' => $customer_id,  
  230. ); 
  231.  
  232. /** 
  233. * Update the session expiry timestamp. 
  234. * @param string $customer_id 
  235. * @param int $timestamp 
  236. */ 
  237. public function update_session_timestamp( $customer_id, $timestamp ) { 
  238. global $wpdb; 
  239.  
  240. $wpdb->update( 
  241. $this->_table,  
  242. array( 
  243. 'session_expiry' => $timestamp,  
  244. ),  
  245. array( 
  246. 'session_key' => $customer_id,  
  247. ),  
  248. array( 
  249. '%d' 
  250. );