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