WordPress 4.7
[autoinstalls/wordpress.git] / wp-includes / class-wp-session-tokens.php
1 <?php
2 /**
3  * Session API: WP_Session_Tokens class
4  *
5  * @package WordPress
6  * @subpackage Session
7  * @since 4.7.0
8  */
9
10 /**
11  * Abstract class for managing user session tokens.
12  *
13  * @since 4.0.0
14  */
15 abstract class WP_Session_Tokens {
16
17         /**
18          * User ID.
19          *
20          * @since 4.0.0
21          * @access protected
22          * @var int User ID.
23          */
24         protected $user_id;
25
26         /**
27          * Protected constructor.
28          *
29          * @since 4.0.0
30          *
31          * @param int $user_id User whose session to manage.
32          */
33         protected function __construct( $user_id ) {
34                 $this->user_id = $user_id;
35         }
36
37         /**
38          * Get a session token manager instance for a user.
39          *
40          * This method contains a filter that allows a plugin to swap out
41          * the session manager for a subclass of WP_Session_Tokens.
42          *
43          * @since 4.0.0
44          * @access public
45          * @static
46          *
47          * @param int $user_id User whose session to manage.
48          */
49         final public static function get_instance( $user_id ) {
50                 /**
51                  * Filters the session token manager used.
52                  *
53                  * @since 4.0.0
54                  *
55                  * @param string $session Name of class to use as the manager.
56                  *                        Default 'WP_User_Meta_Session_Tokens'.
57                  */
58                 $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
59                 return new $manager( $user_id );
60         }
61
62         /**
63          * Hashes a session token for storage.
64          *
65          * @since 4.0.0
66          * @access private
67          *
68          * @param string $token Session token to hash.
69          * @return string A hash of the session token (a verifier).
70          */
71         final private function hash_token( $token ) {
72                 // If ext/hash is not present, use sha1() instead.
73                 if ( function_exists( 'hash' ) ) {
74                         return hash( 'sha256', $token );
75                 } else {
76                         return sha1( $token );
77                 }
78         }
79
80         /**
81          * Get a user's session.
82          *
83          * @since 4.0.0
84          * @access public
85          *
86          * @param string $token Session token
87          * @return array User session
88          */
89         final public function get( $token ) {
90                 $verifier = $this->hash_token( $token );
91                 return $this->get_session( $verifier );
92         }
93
94         /**
95          * Validate a user's session token as authentic.
96          *
97          * Checks that the given token is present and hasn't expired.
98          *
99          * @since 4.0.0
100          * @access public
101          *
102          * @param string $token Token to verify.
103          * @return bool Whether the token is valid for the user.
104          */
105         final public function verify( $token ) {
106                 $verifier = $this->hash_token( $token );
107                 return (bool) $this->get_session( $verifier );
108         }
109
110         /**
111          * Generate a session token and attach session information to it.
112          *
113          * A session token is a long, random string. It is used in a cookie
114          * link that cookie to an expiration time and to ensure the cookie
115          * becomes invalidated upon logout.
116          *
117          * This function generates a token and stores it with the associated
118          * expiration time (and potentially other session information via the
119          * {@see 'attach_session_information'} filter).
120          *
121          * @since 4.0.0
122          * @access public
123          *
124          * @param int $expiration Session expiration timestamp.
125          * @return string Session token.
126          */
127         final public function create( $expiration ) {
128                 /**
129                  * Filters the information attached to the newly created session.
130                  *
131                  * Could be used in the future to attach information such as
132                  * IP address or user agent to a session.
133                  *
134                  * @since 4.0.0
135                  *
136                  * @param array $session Array of extra data.
137                  * @param int   $user_id User ID.
138                  */
139                 $session = apply_filters( 'attach_session_information', array(), $this->user_id );
140                 $session['expiration'] = $expiration;
141
142                 // IP address.
143                 if ( !empty( $_SERVER['REMOTE_ADDR'] ) ) {
144                         $session['ip'] = $_SERVER['REMOTE_ADDR'];
145                 }
146
147                 // User-agent.
148                 if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
149                         $session['ua'] = wp_unslash( $_SERVER['HTTP_USER_AGENT'] );
150                 }
151
152                 // Timestamp
153                 $session['login'] = time();
154
155                 $token = wp_generate_password( 43, false, false );
156
157                 $this->update( $token, $session );
158
159                 return $token;
160         }
161
162         /**
163          * Update a session token.
164          *
165          * @since 4.0.0
166          * @access public
167          *
168          * @param string $token Session token to update.
169          * @param array  $session Session information.
170          */
171         final public function update( $token, $session ) {
172                 $verifier = $this->hash_token( $token );
173                 $this->update_session( $verifier, $session );
174         }
175
176         /**
177          * Destroy a session token.
178          *
179          * @since 4.0.0
180          * @access public
181          *
182          * @param string $token Session token to destroy.
183          */
184         final public function destroy( $token ) {
185                 $verifier = $this->hash_token( $token );
186                 $this->update_session( $verifier, null );
187         }
188
189         /**
190          * Destroy all session tokens for this user,
191          * except a single token, presumably the one in use.
192          *
193          * @since 4.0.0
194          * @access public
195          *
196          * @param string $token_to_keep Session token to keep.
197          */
198         final public function destroy_others( $token_to_keep ) {
199                 $verifier = $this->hash_token( $token_to_keep );
200                 $session = $this->get_session( $verifier );
201                 if ( $session ) {
202                         $this->destroy_other_sessions( $verifier );
203                 } else {
204                         $this->destroy_all_sessions();
205                 }
206         }
207
208         /**
209          * Determine whether a session token is still valid,
210          * based on expiration.
211          *
212          * @since 4.0.0
213          * @access protected
214          *
215          * @param array $session Session to check.
216          * @return bool Whether session is valid.
217          */
218         final protected function is_still_valid( $session ) {
219                 return $session['expiration'] >= time();
220         }
221
222         /**
223          * Destroy all session tokens for a user.
224          *
225          * @since 4.0.0
226          * @access public
227          */
228         final public function destroy_all() {
229                 $this->destroy_all_sessions();
230         }
231
232         /**
233          * Destroy all session tokens for all users.
234          *
235          * @since 4.0.0
236          * @access public
237          * @static
238          */
239         final public static function destroy_all_for_all_users() {
240                 $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
241                 call_user_func( array( $manager, 'drop_sessions' ) );
242         }
243
244         /**
245          * Retrieve all sessions of a user.
246          *
247          * @since 4.0.0
248          * @access public
249          *
250          * @return array Sessions of a user.
251          */
252         final public function get_all() {
253                 return array_values( $this->get_sessions() );
254         }
255
256         /**
257          * This method should retrieve all sessions of a user, keyed by verifier.
258          *
259          * @since 4.0.0
260          * @access protected
261          *
262          * @return array Sessions of a user, keyed by verifier.
263          */
264         abstract protected function get_sessions();
265
266         /**
267          * This method should look up a session by its verifier (token hash).
268          *
269          * @since 4.0.0
270          * @access protected
271          *
272          * @param string $verifier Verifier of the session to retrieve.
273          * @return array|null The session, or null if it does not exist.
274          */
275         abstract protected function get_session( $verifier );
276
277         /**
278          * This method should update a session by its verifier.
279          *
280          * Omitting the second argument should destroy the session.
281          *
282          * @since 4.0.0
283          * @access protected
284          *
285          * @param string $verifier Verifier of the session to update.
286          * @param array  $session  Optional. Session. Omitting this argument destroys the session.
287          */
288         abstract protected function update_session( $verifier, $session = null );
289
290         /**
291          * This method should destroy all session tokens for this user,
292          * except a single session passed.
293          *
294          * @since 4.0.0
295          * @access protected
296          *
297          * @param string $verifier Verifier of the session to keep.
298          */
299         abstract protected function destroy_other_sessions( $verifier );
300
301         /**
302          * This method should destroy all sessions for a user.
303          *
304          * @since 4.0.0
305          * @access protected
306          */
307         abstract protected function destroy_all_sessions();
308
309         /**
310          * This static method should destroy all session tokens for all users.
311          *
312          * @since 4.0.0
313          * @access public
314          * @static
315          */
316         public static function drop_sessions() {}
317 }