session.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * Created by PhpStorm.
  5. * User: stanley-king
  6. * Date: 16/1/30
  7. * Time: 下午3:43
  8. */
  9. class session
  10. {
  11. static $stInstance = NULL;
  12. private $fdestroy = false;
  13. private $sessid = '';
  14. const prefix = 'MPHPSESSID';
  15. const session_name = 'MPHPSESSID';
  16. static public function instance()
  17. {
  18. if (self::$stInstance == NULL) {
  19. self::$stInstance = new session();
  20. }
  21. return self::$stInstance;
  22. }
  23. private function __construct()
  24. {
  25. }
  26. public function init()
  27. {
  28. session_set_save_handler(
  29. [$this, 'onOpen'],
  30. [$this, 'onClose'],
  31. [$this, 'onRead'],
  32. [$this, 'onWrite'],
  33. [$this, 'onDestroy'],
  34. [$this, 'onGc']);
  35. }
  36. public function start()
  37. {
  38. $this->fdestroy = false;
  39. session_start();
  40. $_SESSION['MPHPSESSID'] = $this->sessid;
  41. }
  42. public function end($need_close = true)
  43. {
  44. // 会触发write 和 close 函数
  45. if($need_close) {
  46. session_write_close();
  47. }
  48. foreach ($_SESSION as $key => $value) {
  49. unset($_SESSION[$key]);
  50. }
  51. foreach ($_COOKIE as $key => $value) {
  52. unset($_COOKIE[$key]);
  53. }
  54. foreach ($_POST as $key => $value) {
  55. unset($_POST[$key]);
  56. }
  57. foreach ($_GET as $key => $value) {
  58. unset($_GET[$key]);
  59. }
  60. request_helper::clear_server();
  61. $this->sessid = '';
  62. }
  63. public function destroy()
  64. {
  65. $this->fdestroy = true;
  66. $sid = $this->sessid;
  67. fcgi_setcookie("MPHPSESSID", "{$sid}", -3600, '/', COOKIE_DOMAIN);
  68. }
  69. public function onOpen()
  70. {
  71. return true;
  72. }
  73. public function onRead($rsid)
  74. {
  75. //这段代码为了确保内置H5,直接使用客户端的session 状态。
  76. $client = strtolower(trim($_SERVER['HTTP_CLIENT_TYPE']));
  77. if ($client == 'ios' || $client == 'android') {
  78. $sid = $_COOKIE[self::session_name];
  79. Log::record("MPHPSESSID = {$sid}", Log::DEBUG);
  80. return $this->from_certain($sid);
  81. } else {
  82. $sid = $_COOKIE[self::session_name];
  83. Log::record("MPHPSESSID = {$sid}", Log::DEBUG);
  84. if (isset($_POST['HPHPSESSID']) && !empty($_POST['HPHPSESSID'])) {
  85. $hsid = $_POST['HPHPSESSID'];
  86. $this->sessid = $hsid;
  87. if ($sid == $hsid) {
  88. return $this->from_certain($sid);
  89. } else {
  90. return $this->from_uncertain($hsid);
  91. }
  92. } else {
  93. return $this->from_certain($sid);
  94. }
  95. }
  96. }
  97. private function from_uncertain($sid)
  98. {
  99. $this->set_cookie($sid);
  100. if (empty($sid)) {
  101. return '';
  102. } else {
  103. $data = rcache($sid, self::prefix);
  104. if (empty($data)) {
  105. return '';
  106. } else {
  107. $this->sessid = $sid;
  108. return $data[self::session_name];
  109. }
  110. }
  111. }
  112. private function from_certain($sid)
  113. {
  114. if (empty($sid)) {
  115. $sid = session_create_id('');
  116. if (!empty($sid)) {
  117. $this->set_cookie($sid);
  118. $this->sessid = $sid;
  119. } else {
  120. Log::record("session_create_id error.", Log::ERR);
  121. }
  122. return '';
  123. } else {
  124. $data = rcache($sid, self::prefix);
  125. if (empty($data)) {
  126. dcache($sid, self::prefix);
  127. $sid = session_create_id('');
  128. if ($sid == true) {
  129. $this->set_cookie($sid);
  130. $this->sessid = $sid;
  131. } else {
  132. Log::record("session_create_id error.", Log::ERR);
  133. }
  134. return '';
  135. } else {
  136. $this->sessid = $sid;
  137. return $data[self::session_name];
  138. }
  139. }
  140. }
  141. public function onClose()
  142. {
  143. return true;
  144. }
  145. public function onWrite($sid, $data)
  146. {
  147. if ($this->fdestroy) {
  148. dcache($this->sessid, self::prefix);
  149. } else {
  150. wcache($this->sessid, [self::session_name => $data], self::prefix, self::expire_min());
  151. }
  152. return true;
  153. }
  154. public function onDestroy($sid)
  155. {
  156. return dcache($this->sessid, self::prefix);
  157. }
  158. public function onGc($expire)
  159. {
  160. return true;
  161. }
  162. public function set_cookie($sid)
  163. {
  164. $expire_time = time() + self::expire_min() * 60;
  165. fcgi_setcookie("MPHPSESSID", "{$sid}", $expire_time, '/', COOKIE_DOMAIN);
  166. Log::record("set_cookie MPHPSESSID={$sid}", Log::DEBUG);
  167. }
  168. private static function expire_min()
  169. {
  170. if (is_debug()) {
  171. return 43200;
  172. } else {
  173. return 43200;
  174. }
  175. }
  176. static public function read_other_session($sid)
  177. {
  178. $data = rcache($sid, self::prefix);
  179. $org = $_SESSION;
  180. $_SESSION = [];
  181. if (session_decode($data[self::session_name]) == true) {
  182. $data = $_SESSION;
  183. $_SESSION = $org;
  184. return $data;
  185. } else {
  186. $_SESSION = $org;
  187. return false;
  188. }
  189. }
  190. static public function write_other_session($sid, $data)
  191. {
  192. $org = $_SESSION;
  193. $_SESSION = $data;
  194. $data = session_encode();
  195. wcache($sid, [self::session_name => $data], self::prefix, self::expire_min());
  196. $_SESSION = $org;
  197. }
  198. }