forked from codeigniter4/CodeIgniter4
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathResponseCache.php
More file actions
157 lines (130 loc) · 4.46 KB
/
ResponseCache.php
File metadata and controls
157 lines (130 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<?php
declare(strict_types=1);
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\Cache;
use CodeIgniter\Exceptions\RuntimeException;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\Header;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\ResponseInterface;
use Config\Cache as CacheConfig;
/**
* Web Page Caching
*
* @see \CodeIgniter\Cache\ResponseCacheTest
*/
final class ResponseCache
{
/**
* Whether to take the URL query string into consideration when generating
* output cache files. Valid options are:
*
* false = Disabled
* true = Enabled, take all query parameters into account.
* Please be aware that this may result in numerous cache
* files generated for the same page over and over again.
* array('q') = Enabled, but only take into account the specified list
* of query parameters.
*
* @var bool|list<string>
*/
private array|bool $cacheQueryString = false;
/**
* Cache time to live (TTL) in seconds.
*/
private int $ttl = 0;
public function __construct(CacheConfig $config, private readonly CacheInterface $cache)
{
$this->cacheQueryString = $config->cacheQueryString;
}
public function setTtl(int $ttl): self
{
$this->ttl = $ttl;
return $this;
}
/**
* Generates the cache key to use from the current request.
*
* @internal for testing purposes only
*/
public function generateCacheKey(CLIRequest|IncomingRequest $request): string
{
if ($request instanceof CLIRequest) {
return md5($request->getPath());
}
$uri = clone $request->getUri();
$query = (bool) $this->cacheQueryString
? $uri->getQuery(is_array($this->cacheQueryString) ? ['only' => $this->cacheQueryString] : [])
: '';
return md5($request->getMethod() . ':' . $uri->setFragment('')->setQuery($query));
}
/**
* Caches the response.
*/
public function make(CLIRequest|IncomingRequest $request, ResponseInterface $response): bool
{
if ($this->ttl === 0) {
return true;
}
$headers = [];
foreach ($response->headers() as $name => $value) {
if ($value instanceof Header) {
$headers[$name] = $value->getValueLine();
} else {
foreach ($value as $header) {
$headers[$name][] = $header->getValueLine();
}
}
}
return $this->cache->save(
$this->generateCacheKey($request),
serialize([
'headers' => $headers,
'output' => $response->getBody(),
'status' => $response->getStatusCode(),
'reason' => $response->getReasonPhrase(),
]),
$this->ttl,
);
}
/**
* Gets the cached response for the request.
*/
public function get(CLIRequest|IncomingRequest $request, ResponseInterface $response): ?ResponseInterface
{
$cachedResponse = $this->cache->get($this->generateCacheKey($request));
if (is_string($cachedResponse) && $cachedResponse !== '') {
$cachedResponse = unserialize($cachedResponse);
if (
! is_array($cachedResponse)
|| ! isset($cachedResponse['output'])
|| ! isset($cachedResponse['headers'])
) {
throw new RuntimeException('Error unserializing page cache');
}
$headers = $cachedResponse['headers'];
$output = $cachedResponse['output'];
$status = $cachedResponse['status'] ?? 200;
$reason = $cachedResponse['reason'] ?? '';
// Clear all default headers
foreach (array_keys($response->headers()) as $key) {
$response->removeHeader($key);
}
// Set cached headers
foreach ($headers as $name => $value) {
$response->setHeader($name, $value);
}
$response->setBody($output);
$response->setStatusCode($status, $reason);
return $response;
}
return null;
}
}