PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.7.0
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.7.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 / 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
418 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 if ($sanitizedUrl !== false && filter_var($sanitizedUrl, FILTER_VALIDATE_URL) !== false) {
220 $result = $sanitizedUrl;
221 }
222
223 return $result;
224 }
225
226 function nitropack_sdk_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
227 if (null !== $nitro = nitropack_get_instance()) {
228 try {
229 if ($tag) {
230 if (is_array($tag)) {
231 $tag = array_map('nitropack_filter_tag', $tag);
232 } else {
233 $tag = nitropack_filter_tag($tag);
234 }
235 }
236
237 if ($tag != "pageType:home") {
238 $nitro->invalidateCache(NITROPACK_HOME_URL, "pageType:home", $reason);
239 }
240
241 $nitro->invalidateCache($url, $tag, $reason);
242 } catch (\Exception $e) {
243 return false;
244 }
245
246 return true;
247 }
248
249 return false;
250 }
251
252 function nitropack_sdk_purge($url = NULL, $tag = NULL, $reason = NULL, $type = \NitroPack\SDK\PurgeType::COMPLETE) {
253 if (null !== $nitro = nitropack_get_instance()) {
254 try {
255 if ($tag) {
256 if (is_array($tag)) {
257 $tag = array_map('nitropack_filter_tag', $tag);
258 } else {
259 $tag = nitropack_filter_tag($tag);
260 }
261 }
262
263 if ($tag != "pageType:home") {
264 $nitro->invalidateCache(NITROPACK_HOME_URL, "pageType:home", $reason);
265 }
266
267 $nitro->purgeCache($url, $tag, $type, $reason);
268 } catch (\Exception $e) {
269 return false;
270 }
271
272 return true;
273 }
274
275 return false;
276 }
277
278 function nitropack_sdk_purge_local($url = NULL) {
279 if (null !== $nitro = nitropack_get_instance()) {
280 try {
281 if ($url) {
282 $nitro->purgeLocalUrlCache($url);
283 } else {
284 $nitro->purgeLocalCache(NITROPACK_USE_QUICK_PURGE);
285 }
286 } catch (\Exception $e) {
287 return false;
288 }
289
290 return true;
291 }
292
293 return false;
294 }
295
296 function nitropack_sdk_delete_backlog() {
297 if (null !== $nitro = nitropack_get_instance()) {
298 try {
299 if ($nitro->backlog->exists()) {
300 $nitro->backlog->delete();
301 }
302 } catch (\Exception $e) {
303 return false;
304 }
305
306 return true;
307 }
308
309 return false;
310 }
311
312 function nitropack_filter_tag($tag) {
313 return preg_replace("/[^a-zA-Z0-9:]/", ":", $tag);
314 }
315
316 function nitropack_is_warmup_request() {
317 return !empty($_SERVER["HTTP_X_NITRO_WARMUP"]);
318 }
319
320 function nitropack_is_lighthouse_request() {
321 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "lighthouse") !== false;
322 }
323
324 function nitropack_is_gtmetrix_request() {
325 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "gtmetrix") !== false;
326 }
327
328 function nitropack_is_pingdom_request() {
329 return !empty($_SERVER["HTTP_USER_AGENT"]) && stripos($_SERVER["HTTP_USER_AGENT"], "pingdom") !== false;
330 }
331
332 function nitropack_is_optimizer_request() {
333 return isset($_SERVER["HTTP_X_NITROPACK_REQUEST"]);
334 }
335
336 function nitropack_add_tag($tag = NULL, $flush = false) {
337 static $addedTags = [];
338
339 if ($tag) {
340 $addedTags[] = $tag;
341 }
342
343 if ($flush) {
344 if (null !== $nitro = nitropack_get_instance()) {
345 try {
346 // Check whether this is the home page and tag this URL with pageType:home
347 $nitro->getApi()->tagUrl($nitro->getUrl(), array_map("nitropack_filter_tag", $addedTags));
348 } catch (\Exception $e) {}
349 }
350 }
351 }
352
353 function nitropack_get_beacon_script() {
354 if (null !== $nitro = nitropack_get_instance() ) {
355 $url = $nitro->getUrl();
356 $cookiesJson = json_encode($nitro->supportedCookiesFilter(NitroPack\SDK\NitroPack::getCookies()));
357
358 if (function_exists("hash_hmac") && function_exists("hash_equals")) {
359 $hash = hash_hmac("sha512", $url.$cookiesJson, NITROPACK_SITE_SECRET);
360 } else {
361 $hash = "";
362 }
363 $url = base64_encode($url); // We want only ASCII
364 $cookiesb64 = base64_encode($cookiesJson);
365
366 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>";
367 }
368 }
369
370 function nitropack_init_webhooks() {
371 $webhookFile = dirname(__FILE__) . "/nitropack_webhooks";
372
373 if (!NitroPack\SDK\Filesystem::fileExists($webhookFile)) {
374 NitroPack\SDK\Filesystem::filePutContents($webhookFile, time());
375 if (null !== $nitro = nitropack_get_instance() ) {
376 try {
377 $configUrl = new Url(NITROPACK_HOME_URL . "?nitroWebhook=config&token=" . NITROPACK_WEBHOOK_TOKEN);
378 $cacheClearUrl = new Url(NITROPACK_HOME_URL . "?nitroWebhook=cache_clear&token=" . NITROPACK_WEBHOOK_TOKEN);
379 $cacheReadyUrl = new Url(NITROPACK_HOME_URL . "?nitroWebhook=cache_ready&token=" . NITROPACK_WEBHOOK_TOKEN);
380
381 $nitro->getApi()->setWebhook("config", $configUrl);
382 $nitro->getApi()->setWebhook("cache_clear", $cacheClearUrl);
383 $nitro->getApi()->setWebhook("cache_ready", $cacheReadyUrl);
384 } catch (\Exception $e) {}
385 }
386 }
387 }
388
389 nitropack_handle_request();
390 if ( null !== $nitro = nitropack_get_instance() ) {
391 if ($nitro->isAllowedUrl($nitro->getUrl()) && $nitro->isAllowedRequest(true)) {
392 nitropack_init_webhooks();
393 ob_start();
394 register_shutdown_function(function() {
395 $buffer = ob_get_clean();
396
397 if (nitropack_is_optimizer_request()) {
398 nitropack_add_tag(NULL, true); // Flush registered tags
399 }
400
401 // Remove BOM from output
402 $bom = pack('H*','EFBBBF');
403 $buffer = preg_replace("/^($bom)*/", '', $buffer);
404
405 if (stripos($buffer, "</body>") !== FALSE) {
406 // Append before </body>
407 $buffer = str_replace("</body>", nitropack_get_beacon_script() . "</body>", $buffer);
408 } else {
409 // Append at the end of the output
410 $buffer .= nitropack_get_beacon_script();
411 }
412
413 echo $buffer;
414 });
415 } else {
416 header("X-Nitro-Disabled: 1");
417 }
418 }