class-wp-session-tokens.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. * Abstract class for managing user session tokens.
  11. *
  12. * @since 4.0.0
  13. */
  14. #[AllowDynamicProperties]
  15. abstract class WP_Session_Tokens {
  16. /**
  17. * User ID.
  18. *
  19. * @since 4.0.0
  20. * @var int User ID.
  21. */
  22. protected $user_id;
  23. /**
  24. * Protected constructor. Use the `get_instance()` method to get the instance.
  25. *
  26. * @since 4.0.0
  27. *
  28. * @param int $user_id User whose session to manage.
  29. */
  30. protected function __construct( $user_id ) {
  31. $this->user_id = $user_id;
  32. }
  33. /**
  34. * Retrieves a session manager instance for a user.
  35. *
  36. * This method contains a {@see 'session_token_manager'} filter, allowing a plugin to swap out
  37. * the session manager for a subclass of `WP_Session_Tokens`.
  38. *
  39. * @since 4.0.0
  40. *
  41. * @param int $user_id User whose session to manage.
  42. * @return WP_Session_Tokens The session object, which is by default an instance of
  43. * the `WP_User_Meta_Session_Tokens` class.
  44. */
  45. final public static function get_instance( $user_id ) {
  46. /**
  47. * Filters the class name for the session token manager.
  48. *
  49. * @since 4.0.0
  50. *
  51. * @param string $session Name of class to use as the manager.
  52. * Default 'WP_User_Meta_Session_Tokens'.
  53. */
  54. $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
  55. return new $manager( $user_id );
  56. }
  57. /**
  58. * Hashes the given session token for storage.
  59. *
  60. * @since 4.0.0
  61. *
  62. * @param string $token Session token to hash.
  63. * @return string A hash of the session token (a verifier).
  64. */
  65. private function hash_token( $token ) {
  66. // If ext/hash is not present, use sha1() instead.
  67. if ( function_exists( 'hash' ) ) {
  68. return hash( 'sha256', $token );
  69. } else {
  70. return sha1( $token );
  71. }
  72. }
  73. /**
  74. * Retrieves a user's session for the given token.
  75. *
  76. * @since 4.0.0
  77. *
  78. * @param string $token Session token.
  79. * @return array|null The session, or null if it does not exist.
  80. */
  81. final public function get( $token ) {
  82. $verifier = $this->hash_token( $token );
  83. return $this->get_session( $verifier );
  84. }
  85. /**
  86. * Validates the given session token for authenticity and validity.
  87. *
  88. * Checks that the given token is present and hasn't expired.
  89. *
  90. * @since 4.0.0
  91. *
  92. * @param string $token Token to verify.
  93. * @return bool Whether the token is valid for the user.
  94. */
  95. final public function verify( $token ) {
  96. $verifier = $this->hash_token( $token );
  97. return (bool) $this->get_session( $verifier );
  98. }
  99. /**
  100. * Generates a session token and attaches session information to it.
  101. *
  102. * A session token is a long, random string. It is used in a cookie
  103. * to link that cookie to an expiration time and to ensure the cookie
  104. * becomes invalidated when the user logs out.
  105. *
  106. * This function generates a token and stores it with the associated
  107. * expiration time (and potentially other session information via the
  108. * {@see 'attach_session_information'} filter).
  109. *
  110. * @since 4.0.0
  111. *
  112. * @param int $expiration Session expiration timestamp.
  113. * @return string Session token.
  114. */
  115. final public function create( $expiration ) {
  116. /**
  117. * Filters the information attached to the newly created session.
  118. *
  119. * Can be used to attach further information to a session.
  120. *
  121. * @since 4.0.0
  122. *
  123. * @param array $session Array of extra data.
  124. * @param int $user_id User ID.
  125. */
  126. $session = apply_filters( 'attach_session_information', array(), $this->user_id );
  127. $session['expiration'] = $expiration;
  128. // IP address.
  129. if ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
  130. $session['ip'] = $_SERVER['REMOTE_ADDR'];
  131. }
  132. // User-agent.
  133. if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
  134. $session['ua'] = wp_unslash( $_SERVER['HTTP_USER_AGENT'] );
  135. }
  136. // Timestamp.
  137. $session['login'] = time();
  138. $token = wp_generate_password( 43, false, false );
  139. $this->update( $token, $session );
  140. return $token;
  141. }
  142. /**
  143. * Updates the data for the session with the given token.
  144. *
  145. * @since 4.0.0
  146. *
  147. * @param string $token Session token to update.
  148. * @param array $session Session information.
  149. */
  150. final public function update( $token, $session ) {
  151. $verifier = $this->hash_token( $token );
  152. $this->update_session( $verifier, $session );
  153. }
  154. /**
  155. * Destroys the session with the given token.
  156. *
  157. * @since 4.0.0
  158. *
  159. * @param string $token Session token to destroy.
  160. */
  161. final public function destroy( $token ) {
  162. $verifier = $this->hash_token( $token );
  163. $this->update_session( $verifier, null );
  164. }
  165. /**
  166. * Destroys all sessions for this user except the one with the given token (presumably the one in use).
  167. *
  168. * @since 4.0.0
  169. *
  170. * @param string $token_to_keep Session token to keep.
  171. */
  172. final public function destroy_others( $token_to_keep ) {
  173. $verifier = $this->hash_token( $token_to_keep );
  174. $session = $this->get_session( $verifier );
  175. if ( $session ) {
  176. $this->destroy_other_sessions( $verifier );
  177. } else {
  178. $this->destroy_all_sessions();
  179. }
  180. }
  181. /**
  182. * Determines whether a session is still valid, based on its expiration timestamp.
  183. *
  184. * @since 4.0.0
  185. *
  186. * @param array $session Session to check.
  187. * @return bool Whether session is valid.
  188. */
  189. final protected function is_still_valid( $session ) {
  190. return $session['expiration'] >= time();
  191. }
  192. /**
  193. * Destroys all sessions for a user.
  194. *
  195. * @since 4.0.0
  196. */
  197. final public function destroy_all() {
  198. $this->destroy_all_sessions();
  199. }
  200. /**
  201. * Destroys all sessions for all users.
  202. *
  203. * @since 4.0.0
  204. */
  205. final public static function destroy_all_for_all_users() {
  206. /** This filter is documented in wp-includes/class-wp-session-tokens.php */
  207. $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
  208. call_user_func( array( $manager, 'drop_sessions' ) );
  209. }
  210. /**
  211. * Retrieves all sessions for a user.
  212. *
  213. * @since 4.0.0
  214. *
  215. * @return array Sessions for a user.
  216. */
  217. final public function get_all() {
  218. return array_values( $this->get_sessions() );
  219. }
  220. /**
  221. * Retrieves all sessions of the user.
  222. *
  223. * @since 4.0.0
  224. *
  225. * @return array Sessions of the user.
  226. */
  227. abstract protected function get_sessions();
  228. /**
  229. * Retrieves a session based on its verifier (token hash).
  230. *
  231. * @since 4.0.0
  232. *
  233. * @param string $verifier Verifier for the session to retrieve.
  234. * @return array|null The session, or null if it does not exist.
  235. */
  236. abstract protected function get_session( $verifier );
  237. /**
  238. * Updates a session based on its verifier (token hash).
  239. *
  240. * Omitting the second argument destroys the session.
  241. *
  242. * @since 4.0.0
  243. *
  244. * @param string $verifier Verifier for the session to update.
  245. * @param array $session Optional. Session. Omitting this argument destroys the session.
  246. */
  247. abstract protected function update_session( $verifier, $session = null );
  248. /**
  249. * Destroys all sessions for this user, except the single session with the given verifier.
  250. *
  251. * @since 4.0.0
  252. *
  253. * @param string $verifier Verifier of the session to keep.
  254. */
  255. abstract protected function destroy_other_sessions( $verifier );
  256. /**
  257. * Destroys all sessions for the user.
  258. *
  259. * @since 4.0.0
  260. */
  261. abstract protected function destroy_all_sessions();
  262. /**
  263. * Destroys all sessions for all users.
  264. *
  265. * @since 4.0.0
  266. */
  267. public static function drop_sessions() {}
  268. }