1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) exit;
4
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 class WC_Session_Handler extends WC_Session {
21
22
23 private $_cookie;
24
25
26 private $_session_expiring;
27
28
29 private $_session_expiration;
30
31
32 private $_has_cookie = false;
33
34 35 36 37 38 39
40 public function __construct() {
41 $this->_cookie = 'wp_woocommerce_session_' . COOKIEHASH;
42
43 if ( $cookie = $this->get_session_cookie() ) {
44 $this->_customer_id = $cookie[0];
45 $this->_session_expiration = $cookie[1];
46 $this->_session_expiring = $cookie[2];
47 $this->_has_cookie = true;
48
49
50 if ( time() > $this->_session_expiring ) {
51 $this->set_session_expiration();
52 $session_expiry_option = '_wc_session_expires_' . $this->_customer_id;
53
54 if ( false === get_option( $session_expiry_option ) ) {
55 add_option( $session_expiry_option, $this->_session_expiration, '', 'no' );
56 } else {
57 update_option( $session_expiry_option, $this->_session_expiration );
58 }
59 }
60
61 } else {
62 $this->set_session_expiration();
63 $this->_customer_id = $this->generate_customer_id();
64 }
65
66 $this->_data = $this->get_session_data();
67
68
69 add_action( 'woocommerce_set_cart_cookies', array( $this, 'set_customer_session_cookie' ), 10 );
70 add_action( 'woocommerce_cleanup_sessions', array( $this, 'cleanup_sessions' ), 10 );
71 add_action( 'shutdown', array( $this, 'save_data' ), 20 );
72 }
73
74 75 76 77 78 79 80
81 public function set_customer_session_cookie( $set ) {
82 if ( $set ) {
83
84 $to_hash = $this->_customer_id . $this->_session_expiration;
85 $cookie_hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) );
86 $cookie_value = $this->_customer_id . '||' . $this->_session_expiration . '||' . $this->_session_expiring . '||' . $cookie_hash;
87 $this->_has_cookie = true;
88
89
90 wc_setcookie( $this->_cookie, $cookie_value, $this->_session_expiration, apply_filters( 'wc_session_use_secure_cookie', false ) );
91 }
92 }
93
94 95 96 97
98 public function has_session() {
99 return isset( $_COOKIE[ $this->_cookie ] ) || $this->_has_cookie || is_user_logged_in();
100 }
101
102 103 104 105 106 107
108 public function set_session_expiration() {
109 $this->_session_expiring = time() + intval( apply_filters( 'wc_session_expiring', 60 * 60 * 47 ) );
110 $this->_session_expiration = time() + intval( apply_filters( 'wc_session_expiration', 60 * 60 * 48 ) );
111 }
112
113 114 115 116 117 118 119 120
121 public function generate_customer_id() {
122 if ( is_user_logged_in() ) {
123 return get_current_user_id();
124 } else {
125 require_once( ABSPATH . 'wp-includes/class-phpass.php');
126 $hasher = new PasswordHash( 8, false );
127 return md5( $hasher->get_random_bytes( 32 ) );
128 }
129 }
130
131 132 133 134 135 136
137 public function get_session_cookie() {
138 if ( empty( $_COOKIE[ $this->_cookie ] ) ) {
139 return false;
140 }
141
142 list( $customer_id, $session_expiration, $session_expiring, $cookie_hash ) = explode( '||', $_COOKIE[ $this->_cookie ] );
143
144
145 $to_hash = $customer_id . $session_expiration;
146 $hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) );
147
148 if ( $hash != $cookie_hash ) {
149 return false;
150 }
151
152 return array( $customer_id, $session_expiration, $session_expiring, $cookie_hash );
153 }
154
155 156 157 158 159 160
161 public function get_session_data() {
162 return (array) get_option( '_wc_session_' . $this->_customer_id, array() );
163 }
164
165 166 167 168 169 170
171 public function save_data() {
172
173 if ( $this->_dirty && $this->has_session() ) {
174
175 $session_option = '_wc_session_' . $this->_customer_id;
176 $session_expiry_option = '_wc_session_expires_' . $this->_customer_id;
177
178 if ( false === get_option( $session_option ) ) {
179 add_option( $session_option, $this->_data, '', 'no' );
180 add_option( $session_expiry_option, $this->_session_expiration, '', 'no' );
181 } else {
182 update_option( $session_option, $this->_data );
183 }
184 }
185 }
186
187 188 189 190 191 192
193 public function cleanup_sessions() {
194 global $wpdb;
195
196 if ( ! defined( 'WP_SETUP_CONFIG' ) && ! defined( 'WP_INSTALLING' ) ) {
197 $now = time();
198 $expired_sessions = array();
199 $wc_session_expires = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE option_name LIKE '_wc_session_expires_%'" );
200
201 foreach ( $wc_session_expires as $wc_session_expire ) {
202 if ( $now > intval( $wc_session_expire->option_value ) ) {
203 $session_id = substr( $wc_session_expire->option_name, 20 );
204 $expired_sessions[] = $wc_session_expire->option_name;
205 $expired_sessions[] = "_wc_session_$session_id";
206 }
207 }
208
209 if ( ! empty( $expired_sessions ) ) {
210 $expired_sessions_chunked = array_chunk( $expired_sessions, 100 );
211 foreach ( $expired_sessions_chunked as $chunk ) {
212 $option_names = implode( "','", $chunk );
213 $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name IN ('$option_names')" );
214 }
215 }
216 }
217 }
218 }