Open Journal Systems  3.3.0
DefaultCacheStorage.php
1 <?php
2 
3 namespace Guzzle\Plugin\Cache;
4 
12 
17 {
19  protected $keyPrefix;
20 
22  protected $cache;
23 
25  protected $defaultTtl;
26 
32  public function __construct($cache, $keyPrefix = '', $defaultTtl = 3600)
33  {
35  $this->defaultTtl = $defaultTtl;
36  $this->keyPrefix = $keyPrefix;
37  }
38 
39  public function cache(RequestInterface $request, Response $response)
40  {
41  $currentTime = time();
42 
43  $overrideTtl = $request->getParams()->get('cache.override_ttl');
44  if ($overrideTtl) {
45  $ttl = $overrideTtl;
46  } else {
47  $maxAge = $response->getMaxAge();
48  if ($maxAge !== null) {
49  $ttl = $maxAge;
50  } else {
51  $ttl = $this->defaultTtl;
52  }
53  }
54 
55  if ($cacheControl = $response->getHeader('Cache-Control')) {
56  $stale = $cacheControl->getDirective('stale-if-error');
57  if ($stale === true) {
58  $ttl += $ttl;
59  } else if (is_numeric($stale)) {
60  $ttl += $stale;
61  }
62  }
63 
64  // Determine which manifest key should be used
65  $key = $this->getCacheKey($request);
66  $persistedRequest = $this->persistHeaders($request);
67  $entries = array();
68 
69  if ($manifest = $this->cache->fetch($key)) {
70  // Determine which cache entries should still be in the cache
71  $vary = $response->getVary();
72  foreach (unserialize($manifest) as $entry) {
73  // Check if the entry is expired
74  if ($entry[4] < $currentTime) {
75  continue;
76  }
77  $entry[1]['vary'] = isset($entry[1]['vary']) ? $entry[1]['vary'] : '';
78  if ($vary != $entry[1]['vary'] || !$this->requestsMatch($vary, $entry[0], $persistedRequest)) {
79  $entries[] = $entry;
80  }
81  }
82  }
83 
84  // Persist the response body if needed
85  $bodyDigest = null;
86  if ($response->getBody() && $response->getBody()->getContentLength() > 0) {
87  $bodyDigest = $this->getBodyKey($request->getUrl(), $response->getBody());
88  $this->cache->save($bodyDigest, (string) $response->getBody(), $ttl);
89  }
90 
91  array_unshift($entries, array(
92  $persistedRequest,
93  $this->persistHeaders($response),
94  $response->getStatusCode(),
95  $bodyDigest,
96  $currentTime + $ttl
97  ));
98 
99  $this->cache->save($key, serialize($entries));
100  }
101 
102  public function delete(RequestInterface $request)
103  {
104  $key = $this->getCacheKey($request);
105  if ($entries = $this->cache->fetch($key)) {
106  // Delete each cached body
107  foreach (unserialize($entries) as $entry) {
108  if ($entry[3]) {
109  $this->cache->delete($entry[3]);
110  }
111  }
112  $this->cache->delete($key);
113  }
114  }
115 
116  public function purge($url)
117  {
118  foreach (array('GET', 'HEAD', 'POST', 'PUT', 'DELETE') as $method) {
119  $this->delete(new Request($method, $url));
120  }
121  }
122 
123  public function fetch(RequestInterface $request)
124  {
125  $key = $this->getCacheKey($request);
126  if (!($entries = $this->cache->fetch($key))) {
127  return null;
128  }
129 
130  $match = null;
131  $headers = $this->persistHeaders($request);
132  $entries = unserialize($entries);
133  foreach ($entries as $index => $entry) {
134  if ($this->requestsMatch(isset($entry[1]['vary']) ? $entry[1]['vary'] : '', $headers, $entry[0])) {
135  $match = $entry;
136  break;
137  }
138  }
139 
140  if (!$match) {
141  return null;
142  }
143 
144  // Ensure that the response is not expired
145  $response = null;
146  if ($match[4] < time()) {
147  $response = -1;
148  } else {
149  $response = new Response($match[2], $match[1]);
150  if ($match[3]) {
151  if ($body = $this->cache->fetch($match[3])) {
152  $response->setBody($body);
153  } else {
154  // The response is not valid because the body was somehow deleted
155  $response = -1;
156  }
157  }
158  }
159 
160  if ($response === -1) {
161  // Remove the entry from the metadata and update the cache
162  unset($entries[$index]);
163  if ($entries) {
164  $this->cache->save($key, serialize($entries));
165  } else {
166  $this->cache->delete($key);
167  }
168  return null;
169  }
170 
171  return $response;
172  }
173 
181  protected function getCacheKey(RequestInterface $request)
182  {
183  // Allow cache.key_filter to trim down the URL cache key by removing generate query string values (e.g. auth)
184  if ($filter = $request->getParams()->get('cache.key_filter')) {
185  $url = $request->getUrl(true);
186  foreach (explode(',', $filter) as $remove) {
187  $url->getQuery()->remove(trim($remove));
188  }
189  } else {
190  $url = $request->getUrl();
191  }
192 
193  return $this->keyPrefix . md5($request->getMethod() . ' ' . $url);
194  }
195 
204  protected function getBodyKey($url, EntityBodyInterface $body)
205  {
206  return $this->keyPrefix . md5($url) . $body->getContentMd5();
207  }
208 
218  private function requestsMatch($vary, $r1, $r2)
219  {
220  if ($vary) {
221  foreach (explode(',', $vary) as $header) {
222  $key = trim(strtolower($header));
223  $v1 = isset($r1[$key]) ? $r1[$key] : null;
224  $v2 = isset($r2[$key]) ? $r2[$key] : null;
225  if ($v1 !== $v2) {
226  return false;
227  }
228  }
229  }
230 
231  return true;
232  }
233 
241  private function persistHeaders(MessageInterface $message)
242  {
243  // Headers are excluded from the caching (see RFC 2616:13.5.1)
244  static $noCache = array(
245  'age' => true,
246  'connection' => true,
247  'keep-alive' => true,
248  'proxy-authenticate' => true,
249  'proxy-authorization' => true,
250  'te' => true,
251  'trailers' => true,
252  'transfer-encoding' => true,
253  'upgrade' => true,
254  'set-cookie' => true,
255  'set-cookie2' => true
256  );
257 
258  // Clone the response to not destroy any necessary headers when caching
259  $headers = $message->getHeaders()->getAll();
260  $headers = array_diff_key($headers, $noCache);
261  // Cast the headers to a string
262  $headers = array_map(function ($h) { return (string) $h; }, $headers);
263 
264  return $headers;
265  }
266 }
Guzzle\Cache\CacheAdapterInterface
Definition: CacheAdapterInterface.php:12
Guzzle\Http\Message\RequestInterface
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/RequestInterface.php:16
Guzzle\Plugin\Cache\DefaultCacheStorage\purge
purge($url)
Definition: DefaultCacheStorage.php:125
Guzzle\Http\Message\RequestInterface\getUrl
getUrl($asObject=false)
Guzzle\Http\EntityBodyInterface
Definition: EntityBodyInterface.php:10
Guzzle\Plugin\Cache
Definition: CacheKeyProviderInterface.php:3
Guzzle\Http\Message\MessageInterface
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/MessageInterface.php:8
Guzzle\Plugin\Cache\DefaultCacheStorage\__construct
__construct($cache, $keyPrefix='', $defaultTtl=3600)
Definition: DefaultCacheStorage.php:41
Guzzle\Http\Message\Response
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Response.php:17
Guzzle\Plugin\Cache\DefaultCacheStorage\cache
cache(RequestInterface $request, Response $response)
Definition: DefaultCacheStorage.php:48
Guzzle\Plugin\Cache\DefaultCacheStorage\$keyPrefix
$keyPrefix
Definition: DefaultCacheStorage.php:22
Guzzle\Plugin\Cache\DefaultCacheStorage
Definition: DefaultCacheStorage.php:16
Guzzle\Plugin\Cache\DefaultCacheStorage\getCacheKey
getCacheKey(RequestInterface $request)
Definition: DefaultCacheStorage.php:190
Guzzle\Http\EntityBodyInterface\getContentMd5
getContentMd5($rawOutput=false, $base64Encode=false)
Guzzle\Cache\CacheAdapterFactory\fromCache
static fromCache($cache)
Definition: CacheAdapterFactory.php:25
Guzzle\Plugin\Cache\DefaultCacheStorage\$defaultTtl
$defaultTtl
Definition: DefaultCacheStorage.php:34
Guzzle\Http\Message\Request
Definition: lib/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php:25
Guzzle\Http\Message\RequestInterface\getMethod
getMethod()
Guzzle\Cache\CacheAdapterFactory
Definition: CacheAdapterFactory.php:15
Guzzle\Http\Message\MessageInterface\getParams
getParams()
Guzzle\Plugin\Cache\DefaultCacheStorage\fetch
fetch(RequestInterface $request)
Definition: DefaultCacheStorage.php:132
Guzzle\Plugin\Cache\DefaultCacheStorage\$cache
$cache
Definition: DefaultCacheStorage.php:28
Guzzle\Plugin\Cache\CacheStorageInterface
Definition: CacheStorageInterface.php:11
Guzzle\Plugin\Cache\DefaultCacheStorage\getBodyKey
getBodyKey($url, EntityBodyInterface $body)
Definition: DefaultCacheStorage.php:213