PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.17.0
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.17.0
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / classes / Feature / SubrequestCache.php
nitropack / classes / Feature Last commit date
AjaxShortcodes.php 1 year ago SubrequestCache.php 2 years ago
SubrequestCache.php
189 lines
1 <?php
2 namespace NitroPack\Feature;
3
4 use NitroPack\Util\CacheStreamWrapper;
5 use NitroPack\Interfaces\CacheManager;
6 use NitroPack\SDK\NitroPack as NitroPackSDK;
7
8 class SubrequestCache implements CacheManager {
9 const STAGE = "very_early";
10
11 private $allowList = array();
12 private $blockList = array();
13
14 private $cache = array();
15 private $cacheDir = NULL;
16 private $cacheTtl = 3600;
17
18 public function init($stage) {
19 if ($stage != self::STAGE) {
20 return;
21 }
22
23 if (!defined("NITROPACK_SUBREQUEST_CACHE_ALLOW_LIST") || !NITROPACK_SUBREQUEST_CACHE_ALLOW_LIST) {
24 return;
25 }
26
27 if (null === $nitro = get_nitropack_sdk()) {
28 return;
29 }
30
31 $this->allowList = explode(";", NITROPACK_SUBREQUEST_CACHE_ALLOW_LIST);
32 $this->blockList = array();
33
34 if (defined("NITROPACK_SUBREQUEST_CACHE_BLOCK_LIST") && NITROPACK_SUBREQUEST_CACHE_BLOCK_LIST) {
35 $this->blockList = explode(";", NITROPACK_SUBREQUEST_CACHE_BLOCK_LIST);
36 }
37
38 if (defined("NITROPACK_SUBREQUEST_CACHE_TTL") && NITROPACK_SUBREQUEST_CACHE_TTL >= 0) {
39 $this->cacheTtl = NITROPACK_SUBREQUEST_CACHE_TTL;
40 }
41
42 add_action('nitropack_execute_purge_all', [$this, 'purgeCache']);
43
44 $this->cacheDir = nitropack_trailingslashit(NITROPACK_DATA_DIR) . nitropack_trailingslashit("subrequest-cache");
45
46 CacheStreamWrapper::setCacheManager($this);
47 CacheStreamWrapper::init();
48
49 add_filter('pre_http_request', array($this, "interceptRequest"), 10, 3);
50 add_action('http_api_debug', array($this, "interceptResponse"), 10, 5);
51 }
52
53 public function interceptRequest($resp, $args, $url) {
54 if (!empty($args["method"]) && $args["method"] != "GET") {
55 return $resp;
56 }
57
58 if (!$this->isCacheAllowed($url)) {
59 return $resp;
60 }
61
62 $key = "wpremote-" . $url;
63 if ($this->hasCache($key)) {
64 return unserialize($this->getCache($key));
65 }
66
67 return $resp;
68 }
69
70 public function interceptResponse($response, $context, $class, $parsed_args, $url) {
71 if (is_wp_error($response)) {
72 return;
73 }
74
75 if (!empty($parsed_args["method"]) && $parsed_args["method"] != "GET") {
76 return;
77 }
78
79 if (!$this->isCacheAllowed($url)) {
80 return;
81 }
82
83 $key = "wpremote-" . $url;
84 $this->setCache($key, serialize($response));
85 }
86
87 public function purgeCache($key = NULL) {
88 if (!$this->cacheDir || !is_dir($this->cacheDir)) return;
89
90 if ($key) {
91 $cacheFile = $this->getCacheFile($key);
92 if (file_exists($cacheFile)) {
93 unlink($cacheFile);
94 }
95
96 $cacheFileWp = $this->getCacheFile("wpremote-" . $key);
97 if (file_exists($cacheFileWp)) {
98 unlink($cacheFileWp);
99 }
100 return;
101 }
102
103 $dh = opendir($this->cacheDir);
104 while (($entry = readdir($dh)) !== false) {
105 if ($entry == "." || $entry == "..") continue;
106
107 $cacheFile = $this->cacheDir . $entry;
108 if (!is_file($cacheFile)) continue;
109 unlink($cacheFile);
110 }
111 closedir($dh);
112 rmdir($this->cacheDir);
113 }
114
115 public function hasCache($key) {
116 if(!empty($this->cache[$key])) {
117 return true;
118 }
119
120 $cacheFile = $this->getCacheFile($key);
121 if (file_exists($cacheFile) && time() - filemtime($cacheFile) <= $this->cacheTtl) {
122 return true;
123 }
124
125 return false;
126 }
127
128 public function getCache($key) {
129 if(empty($this->cache[$key])) {
130 $cacheFile = $this->getCacheFile($key);
131 if (file_exists($cacheFile) && time() - filemtime($cacheFile) <= $this->cacheTtl) {
132 $this->cache[$key] = file_get_contents($cacheFile);
133 }
134 }
135
136 if(!empty($this->cache[$key])) {
137 return $this->cache[$key];
138 }
139
140 return NULL;
141 }
142
143 public function setCache($key, $content) {
144 $this->cache[$key] = $content;
145
146 if (!$this->cacheDir) {
147 return;
148 }
149
150 if (!is_dir($this->cacheDir) && !mkdir($this->cacheDir, 0755, true)) {
151 return;
152 }
153
154 file_put_contents($this->getCacheFile($key), $content);
155 }
156
157 private function getCacheFile($key) {
158 if (!$this->cacheDir) {
159 return;
160 }
161
162 return $this->cacheDir . md5($key);
163 }
164
165 public function isCacheAllowed($key) {
166 // Exact match search. Exact matches have higher priority than wildcard matches.
167 foreach ($this->allowList as $pattern) {
168 if ($pattern == $key) {
169 return true;
170 }
171 }
172
173 // Block list patterns have higher priority than allow list ones
174 foreach ($this->blockList as $pattern) {
175 if (preg_match("/" . NitroPackSDK::wildcardToRegex($pattern) . "/", $key)) {
176 return false;
177 }
178 }
179
180 foreach ($this->allowList as $pattern) {
181 if (preg_match("/" . NitroPackSDK::wildcardToRegex($pattern) . "/", $key)) {
182 return true;
183 }
184 }
185
186 return false;
187 }
188 }
189