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