/wp-content/plugins/loco-translate/src/data/Session.php

https://gitlab.com/campus-academy/krowkaramel · PHP · 196 lines · 102 code · 31 blank · 63 comment · 18 complexity · ed470d15ce2de9f937b06c8cb99b7f61 MD5 · raw file

  1. <?php
  2. /**
  3. * Abstracts session data access using WP_Session_Tokens
  4. */
  5. class Loco_data_Session extends Loco_data_Serializable {
  6. /**
  7. * @var Loco_data_Session
  8. */
  9. private static $current;
  10. /**
  11. * Value from wp_get_session_token
  12. * @var string
  13. */
  14. private $token;
  15. /**
  16. * @var WP_User_Meta_Session_Tokens
  17. */
  18. private $manager;
  19. /**
  20. * Dirty flag: TODO abstract into array access setters
  21. * @var bool
  22. */
  23. private $dirty = false;
  24. /**
  25. * @return Loco_data_Session
  26. */
  27. public static function get(){
  28. if( ! self::$current ){
  29. new Loco_data_Session;
  30. }
  31. return self::$current;
  32. }
  33. /**
  34. * Trash data and remove from memory
  35. */
  36. public static function destroy(){
  37. if( self::$current ){
  38. try {
  39. self::$current->clear();
  40. }
  41. catch( Exception $e ){
  42. // probably no session to destroy
  43. }
  44. self::$current = null;
  45. }
  46. }
  47. /**
  48. * Commit current session data to WordPress storage and remove from memory
  49. */
  50. public static function close(){
  51. if( self::$current && self::$current->dirty ){
  52. self::$current->persist();
  53. self::$current = null;
  54. }
  55. }
  56. /**
  57. * @internal
  58. */
  59. final public function __construct( array $raw = [] ){
  60. $this->token = wp_get_session_token();
  61. if( ! $this->token ){
  62. throw new Loco_error_Exception('Failed to get session token');
  63. }
  64. parent::__construct( [] );
  65. $this->manager = WP_Session_Tokens::get_instance( get_current_user_id() );
  66. // populate object from stored session data
  67. $data = $this->getRaw();
  68. if( isset($data['loco']) ){
  69. $this->setUnserialized( $data['loco'] );
  70. }
  71. // any initial arbitrary data can be merged on top
  72. foreach( $raw as $prop => $value ){
  73. $this[$prop] = $value;
  74. }
  75. // enforce single instance
  76. self::$current = $this;
  77. // ensure against unclean shutdown
  78. if( loco_debugging() ){
  79. register_shutdown_function( [$this,'_on_shutdown'] );
  80. }
  81. }
  82. /**
  83. * @internal
  84. * Ensure against unclean use of session storage
  85. */
  86. public function _on_shutdown(){
  87. if( $this->dirty ){
  88. trigger_error('Unclean session shutdown: call either Loco_data_Session::destroy or Loco_data_Session::close');
  89. }
  90. }
  91. /**
  92. * Get raw session data held by WordPress
  93. * @return array
  94. */
  95. private function getRaw(){
  96. $data = $this->manager->get( $this->token );
  97. // session data will exist if WordPress login is valid
  98. if( ! $data || ! is_array($data) ){
  99. throw new Loco_error_Exception('Invalid session');
  100. }
  101. return $data;
  102. }
  103. /**
  104. * Persist object in WordPress usermeta table
  105. * @return Loco_data_Session
  106. */
  107. public function persist(){
  108. $data = $this->getRaw();
  109. $data['loco'] = $this->getSerializable();
  110. $this->manager->update( $this->token, $data );
  111. $this->dirty = false;
  112. return $this;
  113. }
  114. /**
  115. * Clear object data and remove our key from WordPress usermeta record
  116. * @return Loco_data_Session
  117. */
  118. public function clear(){
  119. $data = $this->getRaw();
  120. if( isset($data['loco']) ){
  121. unset( $data['loco'] );
  122. $this->manager->update( $this->token, $data );
  123. }
  124. $this->exchangeArray( [] );
  125. $this->dirty = false;
  126. return $this;
  127. }
  128. /**
  129. * @param string name of messages bag, e.g. "errors"
  130. * @param string optionally put message in rather than getting data out
  131. * @return mixed
  132. */
  133. public function flash( $bag, $data = null ){
  134. if( isset($data) ){
  135. $this->dirty = true;
  136. $this[$bag][] = $data;
  137. }
  138. // else get first object in bag and remove before returning
  139. else if( isset($this[$bag]) ){
  140. if( $data = array_shift($this[$bag]) ){
  141. $this->dirty = true;
  142. return $data;
  143. }
  144. }
  145. return null;
  146. }
  147. /**
  148. * {@inheritDoc}
  149. */
  150. public function offsetSet( $index, $newval ){
  151. if( ! isset($this[$index]) || $newval !== $this[$index] ){
  152. $this->dirty = true;
  153. parent::offsetSet( $index, $newval );
  154. }
  155. }
  156. /**
  157. * {@inheritDoc}
  158. */
  159. public function offsetUnset( $index ){
  160. if( isset($this[$index]) ){
  161. $this->dirty = true;
  162. parent::offsetUnset( $index );
  163. }
  164. }
  165. }