PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.5.11
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.5.11
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 / nitropack-sdk / bootstrap.php
nitropack / nitropack-sdk Last commit date
NitroPack 4 years ago vendor 4 years ago autoload.php 6 years ago bootstrap.php 4 years ago nitro.start.php 4 years ago
bootstrap.php
407 lines
1 <?php
2
3 require_once dirname(__FILE__) . "/autoload.php";
4
5 class NitroPack_CookieStore {
6 static $cookies = array();
7 }
8
9 NitroPack_CookieStore::$cookies = $_COOKIE;
10 /* You must define these constants before requiring this file for easier installation of SDK updates
11 define("NITROPACK_HOME_URL", "Your home page URL");
12 define("NITROPACK_SITE_ID", "your site ID");
13 define("NITROPACK_SITE_SECRET", "your site secret");
14 */
15 if (!defined("NITROPACK_ENABLE_COMPRESSION")) define("NITROPACK_ENABLE_COMPRESSION", false); // Set this to true to enable compression. Only do this if your server does not already have compression enabled
16 if (!defined("NITROPACK_WEBHOOK_TOKEN")) define("NITROPACK_WEBHOOK_TOKEN", md5(__FILE__)); // Feel free to set this to a value of your liking
17 if (!defined("NITROPACK_USE_QUICK_PURGE")) define("NITROPACK_USE_QUICK_PURGE", false); // Feel free to set this to a value of your liking
18 if (!defined("NITROPACK_USE_REDIS")) define("NITROPACK_USE_REDIS", false); // Set this to true to enable storing cache in Redis
19 if (!defined("NITROPACK_REDIS_HOST")) define("NITROPACK_REDIS_HOST", "127.0.0.1"); // Set this to the IP of your Redis server
20 if (!defined("NITROPACK_REDIS_PORT")) define("NITROPACK_REDIS_PORT", 6379); // Set this to the port of your Redis server
21 if (!defined("NITROPACK_REDIS_PASS")) define("NITROPACK_REDIS_PASS", NULL); // Set this to the password of your redis server if authentication is needed
22 if (!defined("NITROPACK_REDIS_DB")) define("NITROPACK_REDIS_DB", NULL); // Set this to the number of the Redis DB if you'd like to not use the default one
23 if (!defined("NITROPACK_DATA_DIR")) define("NITROPACK_DATA_DIR", NULL); // Set this to the number of the Redis DB if you'd like to not use the default one
24 if (!defined("NITROPACK_DISABLE_BACKLOG")) define("NITROPACK_DISABLE_BACKLOG", true); // Only allow backlog use if you've prepared a way to replay backlogged entries. Otherwise you might end up with a permanently disabled cache layer and an infinitely growing backlog file
25
26 if (NITROPACK_USE_REDIS) {
27 NitroPack\SDK\Filesystem::setStorageDriver(new NitroPack\SDK\StorageDriver\Redis(
28 NITROPACK_REDIS_HOST,
29 NITROPACK_REDIS_PORT,
30 NITROPACK_REDIS_PASS,
31 NITROPACK_REDIS_DB
32 ));
33 }
34
35 function nitropack_filter_non_original_cookies(&$cookies) {
36 $ogNames = is_array(NitroPack_CookieStore::$cookies) ? array_keys(NitroPack_CookieStore::$cookies) : array();
37 foreach ($cookies as $name=>$val) {
38 if (!in_array($name, $ogNames)) {
39 unset($cookies[$name]);
40 }
41 }
42 }
43
44 function nitropack_get_instance($siteId = NULL, $siteSecret = NULL, $url = NULL) {
45 static $instances = [];
46 $key = $url ? $url : "auto";
47 if (empty($instances[$key])) {
48 try {
49 NitroPack\SDK\NitroPack::addCookieFilter("nitropack_filter_non_original_cookies");
50 $siteId = $siteId !== NULL ? $siteId : NITROPACK_SITE_ID;
51 $siteSecret = $siteSecret !== NULL ? $siteSecret : NITROPACK_SITE_SECRET;
52 if (NITROPACK_DATA_DIR) {
53 $instances[$key] = new NitroPack\SDK\NitroPack($siteId, $siteSecret, NULL, $url, NITROPACK_DATA_DIR);
54 } else {
55 $instances[$key] = new NitroPack\SDK\NitroPack($siteId, $siteSecret, NULL, $url);
56 }
57 } catch(\Exception $e) {
58 $instances[$key] = NULL;
59 }
60 }
61
62 return $instances[$key];
63 }
64
65 function nitropack_handle_request() {
66 if (isset($_GET["ignorenitro"])) {
67 unset($_GET["ignorenitro"]);
68 }
69
70 header('Cache-Control: no-cache');
71 header('X-Nitro-Cache: MISS');
72 if ( !empty($_SERVER["HTTP_HOST"]) && !empty($_SERVER["REQUEST_URI"]) ) {
73 try {
74 if (is_valid_nitropack_webhook()) {
75 nitropack_handle_webhook();
76 } else {
77 if (is_valid_nitropack_beacon()) {
78 nitropack_handle_beacon();
79 } else {
80 if ( null !== $nitro = nitropack_get_instance() ) {
81 if ($nitro->isCacheAllowed()) {
82 if (NITROPACK_ENABLE_COMPRESSION) {
83 $nitro->enableCompression();
84 }
85
86 if ($nitro->hasLocalCache()) {
87 header('X-Nitro-Cache: HIT');
88 setcookie("nitroCache", "HIT", time() + 10);
89 $nitro->pageCache->readfile();
90 exit;
91 } else {
92 // We need the following if..else block to handle bot requests which will not be firing our beacon
93 if (nitropack_is_warmup_request()) {
94 $nitro->hasRemoteCache("default"); // Only ping the API letting our service know that this page must be cached.
95 exit; // No need to continue handling this request. The response is not important.
96 } else if (nitropack_is_lighthouse_request() || nitropack_is_gtmetrix_request() || nitropack_is_pingdom_request()) {
97 $nitro->hasRemoteCache("default"); // Ping the API letting our service know that this page must be cached.
98 }
99
100 $nitro->pageCache->useInvalidated(true);
101 if ($nitro->hasLocalCache()) {
102 header('X-Nitro-Cache: STALE');
103 $nitro->pageCache->readfile();
104 exit;
105 } else {
106 $nitro->pageCache->useInvalidated(false);
107 }
108 }
109 }
110 }
111 }
112 }
113 } catch (\Exception $e) {
114 // Fail silently
115 }
116 }
117 }
118
119 function nitropack_validate_webhook_token($token) {
120 return preg_match("/^([abcdef0-9]{32})$/", strtolower($token)) && $token == NITROPACK_WEBHOOK_TOKEN;
121 }
122
123 function is_valid_nitropack_webhook() {
124 return !empty($_GET["nitroWebhook"]) && !empty($_GET["token"]) && nitropack_validate_webhook_token($_GET["token"]);
125 }
126
127 function is_valid_nitropack_beacon() {
128 if (!isset($_POST["nitroBeaconUrl"]) || !isset($_POST["nitroBeaconHash"])) return false;
129
130 if (function_exists("hash_hmac") && function_exists("hash_equals")) {
131 $url = base64_decode($_POST["nitroBeaconUrl"]);
132 $cookiesJson = !empty($_POST["nitroBeaconCookies"]) ? base64_decode($_POST["nitroBeaconCookies"]) : ""; // We need to fall back to empty string to remain backwards compatible. Otherwise cache files invalidated before an upgrade will never get updated :(
133 $localHash = hash_hmac("sha512", $url.$cookiesJson, NITROPACK_SITE_SECRET);
134 return hash_equals($_POST["nitroBeaconHash"], $localHash);
135 } else {
136 return !empty($_POST["nitroBeaconUrl"]);
137 }
138 }
139
140 function nitropack_handle_beacon() {
141 if (!empty($_POST["nitroBeaconUrl"])) {
142 $url = base64_decode($_POST["nitroBeaconUrl"]);
143
144 if (!empty($_POST["nitroBeaconCookies"])) {
145 NitroPack_CookieStore::$cookies = json_decode(base64_decode($_POST["nitroBeaconCookies"]), true);
146 }
147
148 if (null !== $nitro = nitropack_get_instance(NITROPACK_SITE_ID, NITROPACK_SITE_SECRET, $url) ) {
149 try {
150 if (!$nitro->hasLocalCache(false)) {
151 header("X-Nitro-Beacon: FORWARD");
152 $hasCache = $nitro->hasRemoteCache("default", false); // Download the new cache file
153 $nitro->purgeProxyCache($url);
154 printf("Cache %s", $hasCache ? "fetched" : "requested");
155 } else {
156 header("X-Nitro-Beacon: SKIP");
157 printf("Cache exists already");
158 }
159 } catch (Exception $e) {
160 // not a critical error, do nothing
161 }
162 }
163 }
164 exit;
165 }
166
167 function nitropack_handle_webhook() {
168 if (NITROPACK_WEBHOOK_TOKEN == $_GET["token"]) {
169 switch($_GET["nitroWebhook"]) {
170 case "config":
171 if (null !== $nitro = nitropack_get_instance() ) {
172 try {
173 $nitro->fetchConfig();
174 } catch (\Exception $e) {}
175 }
176 break;
177 case "cache_ready":
178 if (!empty($_POST["url"])) {
179 $readyUrl = nitropack_sanitize_url_input($_POST["url"]);
180
181 if ($readyUrl && null !== $nitro = nitropack_get_instance(NITROPACK_SITE_ID, NITROPACK_SITE_SECRET, $readyUrl) ) {
182 $hasCache = $nitro->hasRemoteCache("default", false); // Download the new cache file
183 $nitro->purgeProxyCache($readyUrl);
184 }
185 }
186 break;
187 case "cache_clear":
188 if (!empty($_POST["url"])) {
189 $urls = is_array($_POST["url"]) ? $_POST["url"] : array($_POST["url"]);
190 foreach ($urls as $url) {
191 $sanitizedUrl = nitropack_sanitize_url_input($url);
192 nitropack_sdk_purge_local($sanitizedUrl);
193 }
194 } else {
195 nitropack_sdk_purge_local();
196 nitropack_sdk_delete_backlog();
197 }
198 break;
199 }
200 }
201 exit;
202 }
203
204 function nitropack_sanitize_url_input($url) {
205 $result = NULL;
206 $sanitizedUrl = filter_var($url, FILTER_SANITIZE_URL);
207 if ($sanitizedUrl !== false && filter_var($sanitizedUrl, FILTER_VALIDATE_URL) !== false) {
208 $result = $sanitizedUrl;
209 }
210
211 return $result;
212 }
213
214 function nitropack_sdk_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
215 if (null !== $nitro = nitropack_get_instance()) {
216 try {
217 if ($tag) {
218 if (is_array($tag)) {
219 $tag = array_map('nitropack_filter_tag', $tag);
220 } else {
221 $tag = nitropack_filter_tag($tag);
222 }
223 }
224
225 if ($tag != "pageType:home") {
226 $nitro->invalidateCache(NITROPACK_HOME_URL, "pageType:home", $reason);
227 }
228
229 $nitro->invalidateCache($url, $tag, $reason);
230 } catch (\Exception $e) {
231 return false;
232 }
233
234 return true;
235 }
236
237 return false;
238 }
239
240 function nitropack_sdk_purge($url = NULL, $tag = NULL, $reason = NULL, $type = \NitroPack\SDK\PurgeType::COMPLETE) {
241 if (null !== $nitro = nitropack_get_instance()) {
242 try {
243 if ($tag) {
244 if (is_array($tag)) {
245 $tag = array_map('nitropack_filter_tag', $tag);
246 } else {
247 $tag = nitropack_filter_tag($tag);
248 }
249 }
250
251 if ($tag != "pageType:home") {
252 $nitro->invalidateCache(NITROPACK_HOME_URL, "pageType:home", $reason);
253 }
254
255 $nitro->purgeCache($url, $tag, $type, $reason);
256 } catch (\Exception $e) {
257 return false;
258 }
259
260 return true;
261 }
262
263 return false;
264 }
265
266 function nitropack_sdk_purge_local($url = NULL) {
267 if (null !== $nitro = nitropack_get_instance()) {
268 try {
269 if ($url) {
270 $nitro->purgeLocalUrlCache($url);
271 } else {
272 $nitro->purgeLocalCache(NITROPACK_USE_QUICK_PURGE);
273 }
274 } catch (\Exception $e) {
275 return false;
276 }
277
278 return true;
279 }
280
281 return false;
282 }
283
284 function nitropack_sdk_delete_backlog() {
285 if (null !== $nitro = nitropack_get_instance()) {
286 try {
287 if ($nitro->backlog->exists()) {
288 $nitro->backlog->delete();
289 }
290 } catch (\Exception $e) {
291 return false;
292 }
293
294 return true;
295 }
296
297 return false;
298 }
299
300 function nitropack_filter_tag($tag) {
301 return preg_replace("/[^a-zA-Z0-9:]/", ":", $tag);
302 }
303
304 function nitropack_is_warmup_request() {
305 return !empty($_SERVER["HTTP_X_NITRO_WARMUP"]);
306 }
307
308 function nitropack_is_lighthouse_request() {
309 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "lighthouse") !== false;
310 }
311
312 function nitropack_is_gtmetrix_request() {
313 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "gtmetrix") !== false;
314 }
315
316 function nitropack_is_pingdom_request() {
317 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "pingdom") !== false;
318 }
319
320 function nitropack_is_optimizer_request() {
321 return isset($_SERVER["HTTP_X_NITROPACK_REQUEST"]);
322 }
323
324 function nitropack_add_tag($tag = NULL, $flush = false) {
325 static $addedTags = [];
326
327 if ($tag) {
328 $addedTags[] = $tag;
329 }
330
331 if ($flush) {
332 if (null !== $nitro = nitropack_get_instance()) {
333 try {
334 // Check whether this is the home page and tag this URL with pageType:home
335 $nitro->getApi()->tagUrl($nitro->getUrl(), array_map("nitropack_filter_tag", $addedTags));
336 } catch (\Exception $e) {}
337 }
338 }
339 }
340
341 function nitropack_get_beacon_script() {
342 if (null !== $nitro = nitropack_get_instance() ) {
343 $url = $nitro->getUrl();
344 $cookiesJson = json_encode($nitro->supportedCookiesFilter(NitroPack\SDK\NitroPack::getCookies()));
345
346 if (function_exists("hash_hmac") && function_exists("hash_equals")) {
347 $hash = hash_hmac("sha512", $url.$cookiesJson, NITROPACK_SITE_SECRET);
348 } else {
349 $hash = "";
350 }
351 $url = base64_encode($url); // We want only ASCII
352 $cookiesb64 = base64_encode($cookiesJson);
353
354 return "<script nitro-exclude>if (document.cookie.indexOf('nitroCache=HIT') == -1) {var nitroData = new FormData(); nitroData.append('nitroBeaconUrl', '$url'); nitroData.append('nitroBeaconCookies', '$cookiesb64'); nitroData.append('nitroBeaconHash', '$hash'); navigator.sendBeacon(location.href, nitroData);} document.cookie = 'nitroCache=HIT; expires=Thu, 01 Jan 1970 00:00:01 GMT;';</script>";
355 }
356 }
357
358 function nitropack_init_webhooks() {
359 $webhookFile = dirname(__FILE__) . "/nitropack_webhooks";
360
361 if (!NitroPack\SDK\Filesystem::fileExists($webhookFile)) {
362 NitroPack\SDK\Filesystem::filePutContents($webhookFile, time());
363 if (null !== $nitro = nitropack_get_instance() ) {
364 try {
365 $configUrl = new \NitroPack\Url(NITROPACK_HOME_URL . "?nitroWebhook=config&token=" . NITROPACK_WEBHOOK_TOKEN);
366 $cacheClearUrl = new \NitroPack\Url(NITROPACK_HOME_URL . "?nitroWebhook=cache_clear&token=" . NITROPACK_WEBHOOK_TOKEN);
367 $cacheReadyUrl = new \NitroPack\Url(NITROPACK_HOME_URL . "?nitroWebhook=cache_ready&token=" . NITROPACK_WEBHOOK_TOKEN);
368
369 $nitro->getApi()->setWebhook("config", $configUrl);
370 $nitro->getApi()->setWebhook("cache_clear", $cacheClearUrl);
371 $nitro->getApi()->setWebhook("cache_ready", $cacheReadyUrl);
372 } catch (\Exception $e) {}
373 }
374 }
375 }
376
377 nitropack_handle_request();
378 if ( null !== $nitro = nitropack_get_instance() ) {
379 if ($nitro->isAllowedUrl($nitro->getUrl()) && $nitro->isAllowedRequest(true)) {
380 nitropack_init_webhooks();
381 ob_start();
382 register_shutdown_function(function() {
383 $buffer = ob_get_clean();
384
385 if (nitropack_is_optimizer_request()) {
386 nitropack_add_tag(NULL, true); // Flush registered tags
387 }
388
389 // Remove BOM from output
390 $bom = pack('H*','EFBBBF');
391 $buffer = preg_replace("/^($bom)*/", '', $buffer);
392
393 if (stripos($buffer, "</body>") !== FALSE) {
394 // Append before </body>
395 $buffer = str_replace("</body>", nitropack_get_beacon_script() . "</body>", $buffer);
396 } else {
397 // Append at the end of the output
398 $buffer .= nitropack_get_beacon_script();
399 }
400
401 echo $buffer;
402 });
403 } else {
404 header("X-Nitro-Disabled: 1");
405 }
406 }
407