RedisSessionHandler.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. /**
  3. * This file is part of workerman.
  4. *
  5. * Licensed under The MIT License
  6. * For full copyright and license information, please see the MIT-LICENSE.txt
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @author walkor<walkor@workerman.net>
  10. * @copyright walkor<walkor@workerman.net>
  11. * @link http://www.workerman.net/
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. declare(strict_types=1);
  15. namespace Workerman\Protocols\Http\Session;
  16. use Redis;
  17. use RedisCluster;
  18. use RedisException;
  19. use RuntimeException;
  20. use Throwable;
  21. use Workerman\Protocols\Http\Session;
  22. use Workerman\Timer;
  23. /**
  24. * Class RedisSessionHandler
  25. * @package Workerman\Protocols\Http\Session
  26. */
  27. class RedisSessionHandler implements SessionHandlerInterface
  28. {
  29. /**
  30. * @var Redis|RedisCluster
  31. */
  32. protected Redis|RedisCluster $redis;
  33. /**
  34. * @var array
  35. */
  36. protected array $config;
  37. /**
  38. * RedisSessionHandler constructor.
  39. * @param array $config = [
  40. * 'host' => '127.0.0.1',
  41. * 'port' => 6379,
  42. * 'timeout' => 2,
  43. * 'auth' => '******',
  44. * 'database' => 2,
  45. * 'prefix' => 'redis_session_',
  46. * 'ping' => 55,
  47. * ]
  48. * @throws RedisException
  49. */
  50. public function __construct(array $config)
  51. {
  52. if (false === extension_loaded('redis')) {
  53. throw new RuntimeException('Please install redis extension.');
  54. }
  55. if (!isset($config['timeout'])) {
  56. $config['timeout'] = 2;
  57. }
  58. $this->config = $config;
  59. $this->connect();
  60. Timer::add($config['ping'] ?? 55, function () {
  61. $this->redis->get('ping');
  62. });
  63. }
  64. /**
  65. * @throws RedisException
  66. */
  67. public function connect()
  68. {
  69. $config = $this->config;
  70. $this->redis = new Redis();
  71. if (false === $this->redis->connect($config['host'], $config['port'], $config['timeout'])) {
  72. throw new RuntimeException("Redis connect {$config['host']}:{$config['port']} fail.");
  73. }
  74. if (!empty($config['auth'])) {
  75. $this->redis->auth($config['auth']);
  76. }
  77. if (!empty($config['database'])) {
  78. $this->redis->select($config['database']);
  79. }
  80. if (empty($config['prefix'])) {
  81. $config['prefix'] = 'redis_session_';
  82. }
  83. $this->redis->setOption(Redis::OPT_PREFIX, $config['prefix']);
  84. }
  85. /**
  86. * {@inheritdoc}
  87. */
  88. public function open(string $savePath, string $name): bool
  89. {
  90. return true;
  91. }
  92. /**
  93. * {@inheritdoc}
  94. * @param string $sessionId
  95. * @return string
  96. * @throws RedisException
  97. * @throws Throwable
  98. */
  99. public function read(string $sessionId): string
  100. {
  101. try {
  102. return $this->redis->get($sessionId);
  103. } catch (Throwable $e) {
  104. $msg = strtolower($e->getMessage());
  105. if ($msg === 'connection lost' || strpos($msg, 'went away')) {
  106. $this->connect();
  107. return $this->redis->get($sessionId);
  108. }
  109. throw $e;
  110. }
  111. }
  112. /**
  113. * {@inheritdoc}
  114. * @throws RedisException
  115. */
  116. public function write(string $sessionId, string $sessionData): bool
  117. {
  118. return true === $this->redis->setex($sessionId, Session::$lifetime, $sessionData);
  119. }
  120. /**
  121. * {@inheritdoc}
  122. * @throws RedisException
  123. */
  124. public function updateTimestamp(string $sessionId, string $data = ""): bool
  125. {
  126. return true === $this->redis->expire($sessionId, Session::$lifetime);
  127. }
  128. /**
  129. * {@inheritdoc}
  130. * @throws RedisException
  131. */
  132. public function destroy(string $sessionId): bool
  133. {
  134. $this->redis->del($sessionId);
  135. return true;
  136. }
  137. /**
  138. * {@inheritdoc}
  139. */
  140. public function close(): bool
  141. {
  142. return true;
  143. }
  144. /**
  145. * {@inheritdoc}
  146. */
  147. public function gc(int $maxLifetime): bool
  148. {
  149. return true;
  150. }
  151. }