1<?php 2 3namespace OAuth\Common\Storage; 4 5use OAuth\Common\Token\TokenInterface; 6use OAuth\Common\Storage\Exception\TokenNotFoundException; 7use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException; 8use Predis\Client as Predis; 9 10/* 11 * Stores a token in a Redis server. Requires the Predis library available at https://github.com/nrk/predis 12 */ 13class Redis implements TokenStorageInterface 14{ 15 /** 16 * @var string 17 */ 18 protected $key; 19 20 protected $stateKey; 21 22 /** 23 * @var object|\Redis 24 */ 25 protected $redis; 26 27 /** 28 * @var object|TokenInterface 29 */ 30 protected $cachedTokens; 31 32 /** 33 * @var object 34 */ 35 protected $cachedStates; 36 37 /** 38 * @param Predis $redis An instantiated and connected redis client 39 * @param string $key The key to store the token under in redis 40 * @param string $stateKey The key to store the state under in redis. 41 */ 42 public function __construct(Predis $redis, $key, $stateKey) 43 { 44 $this->redis = $redis; 45 $this->key = $key; 46 $this->stateKey = $stateKey; 47 $this->cachedTokens = array(); 48 $this->cachedStates = array(); 49 } 50 51 /** 52 * {@inheritDoc} 53 */ 54 public function retrieveAccessToken($service) 55 { 56 if (!$this->hasAccessToken($service)) { 57 throw new TokenNotFoundException('Token not found in redis'); 58 } 59 60 if (isset($this->cachedTokens[$service])) { 61 return $this->cachedTokens[$service]; 62 } 63 64 $val = $this->redis->hget($this->key, $service); 65 66 return $this->cachedTokens[$service] = unserialize($val); 67 } 68 69 /** 70 * {@inheritDoc} 71 */ 72 public function storeAccessToken($service, TokenInterface $token) 73 { 74 // (over)write the token 75 $this->redis->hset($this->key, $service, serialize($token)); 76 $this->cachedTokens[$service] = $token; 77 78 // allow chaining 79 return $this; 80 } 81 82 /** 83 * {@inheritDoc} 84 */ 85 public function hasAccessToken($service) 86 { 87 if (isset($this->cachedTokens[$service]) 88 && $this->cachedTokens[$service] instanceof TokenInterface 89 ) { 90 return true; 91 } 92 93 return $this->redis->hexists($this->key, $service); 94 } 95 96 /** 97 * {@inheritDoc} 98 */ 99 public function clearToken($service) 100 { 101 $this->redis->hdel($this->key, $service); 102 unset($this->cachedTokens[$service]); 103 104 // allow chaining 105 return $this; 106 } 107 108 /** 109 * {@inheritDoc} 110 */ 111 public function clearAllTokens() 112 { 113 // memory 114 $this->cachedTokens = array(); 115 116 // redis 117 $keys = $this->redis->hkeys($this->key); 118 $me = $this; // 5.3 compat 119 120 // pipeline for performance 121 $this->redis->pipeline( 122 function ($pipe) use ($keys, $me) { 123 foreach ($keys as $k) { 124 $pipe->hdel($me->getKey(), $k); 125 } 126 } 127 ); 128 129 // allow chaining 130 return $this; 131 } 132 133 /** 134 * {@inheritDoc} 135 */ 136 public function retrieveAuthorizationState($service) 137 { 138 if (!$this->hasAuthorizationState($service)) { 139 throw new AuthorizationStateNotFoundException('State not found in redis'); 140 } 141 142 if (isset($this->cachedStates[$service])) { 143 return $this->cachedStates[$service]; 144 } 145 146 $val = $this->redis->hget($this->stateKey, $service); 147 148 return $this->cachedStates[$service] = unserialize($val); 149 } 150 151 /** 152 * {@inheritDoc} 153 */ 154 public function storeAuthorizationState($service, $state) 155 { 156 // (over)write the token 157 $this->redis->hset($this->stateKey, $service, $state); 158 $this->cachedStates[$service] = $state; 159 160 // allow chaining 161 return $this; 162 } 163 164 /** 165 * {@inheritDoc} 166 */ 167 public function hasAuthorizationState($service) 168 { 169 if (isset($this->cachedStates[$service]) 170 && null !== $this->cachedStates[$service] 171 ) { 172 return true; 173 } 174 175 return $this->redis->hexists($this->stateKey, $service); 176 } 177 178 /** 179 * {@inheritDoc} 180 */ 181 public function clearAuthorizationState($service) 182 { 183 $this->redis->hdel($this->stateKey, $service); 184 unset($this->cachedStates[$service]); 185 186 // allow chaining 187 return $this; 188 } 189 190 /** 191 * {@inheritDoc} 192 */ 193 public function clearAllAuthorizationStates() 194 { 195 // memory 196 $this->cachedStates = array(); 197 198 // redis 199 $keys = $this->redis->hkeys($this->stateKey); 200 $me = $this; // 5.3 compat 201 202 // pipeline for performance 203 $this->redis->pipeline( 204 function ($pipe) use ($keys, $me) { 205 foreach ($keys as $k) { 206 $pipe->hdel($me->getKey(), $k); 207 } 208 } 209 ); 210 211 // allow chaining 212 return $this; 213 } 214 215 /** 216 * @return Predis $redis 217 */ 218 public function getRedis() 219 { 220 return $this->redis; 221 } 222 223 /** 224 * @return string $key 225 */ 226 public function getKey() 227 { 228 return $this->key; 229 } 230} 231