PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.19.3
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.19.3
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 5 months ago vendor 3 months ago autoload.php 1 year ago bootstrap.php 5 months ago nitro.start.php 1 year ago
bootstrap.php
461 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
201 $doAction = ! empty( $_POST['useInvalidate'] )
202 ? static function ( $url = null ) {
203 nitropack_sdk_invalidate_local( $url );
204 }
205 : static function ( $url = null ) {
206 nitropack_sdk_purge_local( $url );
207 };
208
209 if (!empty($_POST["url"])) {
210 $urls = is_array($_POST["url"]) ? $_POST["url"] : array($_POST["url"]);
211 foreach ($urls as $url) {
212 $sanitizedUrl = nitropack_sanitize_url_input($url);
213 $doAction($sanitizedUrl);
214 }
215 } else {
216 $doAction();
217 nitropack_sdk_delete_backlog();
218 }
219 break;
220 }
221 }
222 exit;
223 }
224
225 function nitropack_sanitize_url_input($url) {
226 $result = NULL;
227 $sanitizedUrl = filter_var($url, FILTER_SANITIZE_URL);
228 $urlObj = new \NitroPack\Url\Url($url);
229 if ($sanitizedUrl !== false && $urlObj->isValid() !== false) {
230 $result = $sanitizedUrl;
231 }
232
233 return $result;
234 }
235
236 function nitropack_sdk_invalidate_local($url = NULL, $tag = NULL, $reason = NULL) {
237 if (null !== $nitro = nitropack_get_instance()) {
238 try {
239 if ($tag) {
240 if (is_array($tag)) {
241 $tag = array_map('nitropack_filter_tag', $tag);
242 } else {
243 $tag = nitropack_filter_tag($tag);
244 }
245 }
246
247 if ($tag != "pageType:home") {
248 $nitro->invalidateCache(NITROPACK_HOME_URL, "pageType:home", $reason);
249 }
250
251 $nitro->invalidateCache($url, $tag, $reason);
252 } catch (\Exception $e) {
253 return false;
254 }
255
256 return true;
257 }
258
259 return false;
260 }
261
262 /**
263 * @deprecated For SDK version >= 0.56.2 use nitropack_sdk_invalidate_local instead.
264 */
265 function nitropack_sdk_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
266 return nitropack_sdk_invalidate_local($url = NULL, $tag = NULL, $reason = NULL);
267 }
268
269 function nitropack_sdk_purge($url = NULL, $tag = NULL, $reason = NULL, $type = \NitroPack\SDK\PurgeType::COMPLETE) {
270 if (null !== $nitro = nitropack_get_instance()) {
271 try {
272 if ($tag) {
273 if (is_array($tag)) {
274 $tag = array_map('nitropack_filter_tag', $tag);
275 } else {
276 $tag = nitropack_filter_tag($tag);
277 }
278 }
279
280 if ($tag != "pageType:home") {
281 $nitro->invalidateCache(NITROPACK_HOME_URL, "pageType:home", $reason);
282 }
283
284 $nitro->purgeCache($url, $tag, $type, $reason);
285 } catch (\Exception $e) {
286 return false;
287 }
288
289 return true;
290 }
291
292 return false;
293 }
294
295 function nitropack_sdk_purge_local($url = NULL) {
296 if (null !== $nitro = nitropack_get_instance()) {
297 try {
298 if ($url) {
299 $nitro->purgeLocalUrlCache($url);
300 } else {
301 $nitro->purgeLocalCache(NITROPACK_USE_QUICK_PURGE);
302 }
303 } catch (\Exception $e) {
304 return false;
305 }
306
307 return true;
308 }
309
310 return false;
311 }
312
313 function nitropack_sdk_delete_backlog() {
314 if (null !== $nitro = nitropack_get_instance()) {
315 try {
316 if ($nitro->backlog->exists()) {
317 $nitro->backlog->delete();
318 }
319 } catch (\Exception $e) {
320 return false;
321 }
322
323 return true;
324 }
325
326 return false;
327 }
328
329 function nitropack_filter_tag($tag) {
330 return preg_replace("/[^a-zA-Z0-9:]/", ":", $tag);
331 }
332
333 function nitropack_is_warmup_request() {
334 return !empty($_SERVER["HTTP_X_NITRO_WARMUP"]);
335 }
336
337 function nitropack_is_lighthouse_request() {
338 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "lighthouse") !== false;
339 }
340
341 function nitropack_is_gtmetrix_request() {
342 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "gtmetrix") !== false;
343 }
344
345 function nitropack_is_pingdom_request() {
346 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "pingdom") !== false;
347 }
348
349 function nitropack_is_optimizer_request() {
350 return isset($_SERVER["HTTP_X_NITROPACK_REQUEST"]);
351 }
352
353 function nitropack_add_tag($tag = NULL, $flush = false) {
354 static $addedTags = [];
355
356 if ($tag) {
357 $addedTags[] = $tag;
358 }
359
360 if ($flush) {
361 if (null !== $nitro = nitropack_get_instance()) {
362 try {
363 // Check whether this is the home page and tag this URL with pageType:home
364 $nitro->getApi()->tagUrl($nitro->getUrl(), array_map("nitropack_filter_tag", $addedTags));
365 } catch (\Exception $e) {}
366 }
367 }
368 }
369
370 function nitropack_get_beacon_script() {
371 if (null !== $nitro = nitropack_get_instance() ) {
372 $url = $nitro->getUrl();
373 $cookiesJson = json_encode($nitro->supportedCookiesFilter(NitroPack\SDK\NitroPack::getCookies()));
374
375 if (function_exists("hash_hmac") && function_exists("hash_equals")) {
376 $hash = hash_hmac("sha512", $url.$cookiesJson, NITROPACK_SITE_SECRET);
377 } else {
378 $hash = "";
379 }
380 $url = base64_encode($url); // We want only ASCII
381 $cookiesb64 = base64_encode($cookiesJson);
382
383 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>";
384 }
385 }
386
387 function nitropack_init_webhooks() {
388 $webhookFile = dirname(__FILE__) . "/nitropack_webhooks";
389
390 if (!NitroPack\SDK\Filesystem::fileExists($webhookFile)) {
391 NitroPack\SDK\Filesystem::filePutContents($webhookFile, time());
392 if (null !== $nitro = nitropack_get_instance() ) {
393 try {
394 $configUrl = new Url(NITROPACK_HOME_URL . "?nitroWebhook=config&token=" . NITROPACK_WEBHOOK_TOKEN);
395 $cacheClearUrl = new Url(NITROPACK_HOME_URL . "?nitroWebhook=cache_clear&token=" . NITROPACK_WEBHOOK_TOKEN);
396 $cacheReadyUrl = new Url(NITROPACK_HOME_URL . "?nitroWebhook=cache_ready&token=" . NITROPACK_WEBHOOK_TOKEN);
397
398 $nitro->getApi()->setWebhook("config", $configUrl);
399 $nitro->getApi()->setWebhook("cache_clear", $cacheClearUrl);
400 $nitro->getApi()->setWebhook("cache_ready", $cacheReadyUrl);
401 } catch (\Exception $e) {}
402 }
403 }
404 }
405
406 nitropack_handle_request();
407 if ( null !== $nitro = nitropack_get_instance() ) {
408 if ($nitro->isAllowedUrl($nitro->getUrl()) && $nitro->isAllowedRequest(true)) {
409 nitropack_init_webhooks();
410 ob_start(function($buffer) {
411 $isGzipped = substr($buffer, 0, 3) === "\x1f\x8b\x08";
412 if ($isGzipped && (!function_exists("gzdecode") || !function_exists("gzencode"))) {
413 return $buffer;
414 }
415
416 if (nitropack_is_optimizer_request()) {
417 nitropack_add_tag(NULL, true); // Flush registered tags
418 }
419
420 // Get the content type
421 $respHeaders = headers_list();
422 $contentType = NULL;
423 foreach ($respHeaders as $respHeader) {
424 if (stripos(trim($respHeader), 'Content-Type:') === 0) {
425 $contentType = $respHeader;
426 }
427 }
428
429 // If the content type header was detected and it's value does not contain 'text/html',
430 // don't attach the beacon script.
431 if ($contentType !== NULL && stripos($contentType, 'text/html') === false) {
432 return $buffer;
433 }
434
435 if ($isGzipped) {
436 // Make a copy to return later in case something goes wrong
437 $bufferCopy = $buffer;
438 $buffer = gzdecode($buffer);
439 }
440
441 // Remove BOM from output
442 $bom = pack('H*','EFBBBF');
443 $buffer = preg_replace("/^($bom)*/", '', $buffer);
444
445 if (!preg_match("/<html.*?\s(amp|⚡)(\s|=|>)/", $buffer)) {
446 $buffer = str_replace("</body", nitropack_get_beacon_script() . "</body", $buffer);
447 }
448
449 if ($isGzipped) {
450 $buffer = gzencode($buffer);
451 if (empty($buffer)) {
452 return $bufferCopy;
453 }
454 }
455
456 return $buffer;
457 }, 0, PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE);
458 } else {
459 header("X-Nitro-Disabled: 1");
460 }
461 }