PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.12.0
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.12.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 / classes / Integration / Server / LiteSpeed.php
nitropack / classes / Integration / Server Last commit date
Cloudflare.php 3 years ago Fastly.php 4 years ago LiteSpeed.php 3 years ago Sucuri.php 4 years ago
LiteSpeed.php
183 lines
1 <?php
2
3 namespace NitroPack\Integration\Server;
4 use NitroPack\WordPress\NitroPack;
5 use NitroPack\Url\Url;
6 use NitroPack\SDK\Device;
7 use NitroPack\Integration\Hosting\WPX;
8
9 class LiteSpeed {
10 const STAGE = "very_early";
11
12 public static function detect() {
13 return !empty($_SERVER["X-LSCACHE"]) || ( !empty($_SERVER["SERVER_SOFTWARE"]) && strtolower($_SERVER["SERVER_SOFTWARE"]) == "litespeed" );
14 }
15
16 public static function isCacheEnabled() {
17 return
18 !empty($_SERVER["X-LSCACHE"]) &&
19 in_array("on", array_map("trim", explode(",", $_SERVER["X-LSCACHE"]))) &&
20 !empty($_SERVER['LSCACHE_VARY_VALUE']) &&
21 in_array($_SERVER['LSCACHE_VARY_VALUE'], array("nitrodesktop", "nitrotablet", "nitromobile"));
22 }
23
24 public static function sendCacheHeader($maxAge = NULL) {
25 if (!$maxAge) {
26 nitropack_header("X-LiteSpeed-Cache-Control: public");
27 } else if (is_numeric($maxAge)) {
28 nitropack_header("X-LiteSpeed-Cache-Control: public,max-age=" . (int)$maxAge);
29 }
30 }
31
32 public static function purge($url = NULL, $tag = NULL) {
33 if ($url || $tag) {
34 $headerValues = [];
35
36 if ($url) {
37 $urlObj = new Url((new Url($url))->getNormalized());
38 if (!$urlObj->getQuery()) {
39 $headerValues[] = "uri=" . md5($urlObj->getPath());
40 } else {
41 $headerValues[] = "uri=" . md5($urlObj->getPath() . "?" . $urlObj->getQuery());
42 }
43 }
44
45 if ($tag) {
46 $headerValues[] = $tag;
47 }
48
49 nitropack_header("X-LiteSpeed-Purge: " . implode(", ", $headerValues), false);
50 } else {
51 nitropack_header("X-LiteSpeed-Purge: *", false);
52 }
53 }
54
55 public function init($stage) {
56 if (self::detect()) {
57 add_filter('nitropack_should_modify_htaccess', function() { return true; });
58 add_filter('nitropack_htaccess_rules', [$this, 'getHtaccessRules'], 10);
59
60 if (self::isCacheEnabled()) {
61 add_action('nitropack_integration_purge_url', [$this, 'purgeUrl']);
62 add_action('nitropack_integration_purge_all', [$this, 'purgeAll']);
63 add_action('nitropack_early_cache_headers', [$this, 'setupVary']);
64 add_action('nitropack_early_cache_headers', [$this, 'preventProxyCache']);
65 add_action('nitropack_cacheable_cache_headers', [$this, 'allowProxyCache']);
66 add_filter('nocache_headers', function($headers) {
67 $headers["X-LiteSpeed-Cache-Control"] = "no-cache";
68 return $headers;
69 });
70 } else {
71 add_filter('nitropack_needs_htaccess_changes', function() { return true; });
72 }
73 }
74 }
75
76 public function purgeUrl($url) {
77 self::purge($url);
78 }
79
80 public function purgeAll() {
81 self::purge();
82 }
83
84 public function setupVary() {
85 $cookies = []; // Configure vary based on NitroPack's variation cookies.
86
87 $nitro = get_nitropack()->getSdk();
88 if ($nitro && !empty($nitro->getConfig()->PageCache->SupportedCookies)) {
89 $cookies = $nitro->getConfig()->PageCache->SupportedCookies;
90 }
91
92 $deviceStr = "nitrodesktop";
93 if ( ! empty($_SERVER["HTTP_USER_AGENT"]) ) {
94 $device = new Device($_SERVER["HTTP_USER_AGENT"]);
95
96 if ($device->isMobile()) {
97 $deviceStr = "nitromobile";
98 } else if ($device->isTablet()) {
99 $deviceStr = "nitrotablet";
100 }
101 }
102
103 $varyStr = "";
104
105 if ($cookies) {
106 $varyStr = implode(",", array_map(function($name) { return "cookie=$name"; }, $cookies)); // Vary on multiple cookies should look like this: cookie=name1,cookie=name2
107 }
108
109 $varyStr .= ($varyStr ? ", " : "") . "value=$deviceStr";
110
111 nitropack_header("X-LiteSpeed-Vary: $varyStr");
112 }
113
114 public function preventProxyCache() {
115 nitropack_header("X-LiteSpeed-Cache-Control: no-cache");
116 }
117
118 public function allowProxyCache() {
119 self::sendCacheHeader(3600);
120 $urlObj = new Url(NitroPack::getInstance()->getSdk()->getUrl());
121 if (!$urlObj->getQuery()) {
122 $uri = md5($urlObj->getPath());
123 } else {
124 $uri = md5($urlObj->getPath() . "?" . $urlObj->getQuery());
125 }
126
127 nitropack_header("X-LiteSpeed-Tag: uri=$uri");
128
129 // TODO: Add LSC-Cookie headers for variation cookies - https://docs.litespeedtech.com/lscache/devguide/controls/#lsc-cookie
130 }
131
132 public function getHtaccessRules($ruleLines) {
133 $rules = "
134 <IfModule LiteSpeed>
135 RewriteEngine on
136 CacheLookup on
137
138 RewriteRule .* - [E=NitroPackHtaccessVersion:NITROPACK_VERSION]
139 RewriteRule .* - [E=Cache-Control:vary=nitrodesktop]
140
141 RewriteCond %{HTTP_USER_AGENT} Android|iPad|RIM\ Tablet|hp-tablet|Kindle\ Fire [NC]
142 RewriteRule .* - [E=Cache-Control:vary=nitrotablet]
143
144 RewriteCond %{HTTP_USER_AGENT} iPod|iPhone|MobileSafari|webOS|BlackBerry|windows\ phone|symbian|vodafone|opera\ mini|windows\ ce|smartphone|palm|midp [NC,OR]
145 RewriteCond %{HTTP_USER_AGENT} Android.*Mobile [NC,OR]
146 RewriteCond %{HTTP_USER_AGENT} Mobile.*Android [NC]
147 RewriteRule .* - [E=Cache-Control:vary=nitromobile]
148
149 RewriteCond %{HTTP_COOKIE} COOKIEBYPASS
150 RewriteRule .* - [E=Cache-Control:no-cache]
151
152 # QSDROP
153
154 </IfModule>
155 ";
156
157 $rules = str_replace("NITROPACK_VERSION", NITROPACK_VERSION, $rules);
158
159 $nitro = get_nitropack()->getSdk();
160
161 $bypassCookies = ["wordpress_logged_in", "comment_author", "wp-postpass_", "woocommerce_items_in_cart="];
162 if (defined('NITROPACK_LOGGED_IN_COOKIE') || defined('LOGGED_IN_COOKIE')) {
163 $bypassCookies[] = (defined('NITROPACK_LOGGED_IN_COOKIE') ? NITROPACK_LOGGED_IN_COOKIE : (defined('LOGGED_IN_COOKIE') ? LOGGED_IN_COOKIE : '')) . "="; // Add "=" for exact match
164 }
165 if ($nitro && !!$nitro->getConfig()->ExcludedCookies->Status && !empty($nitro->getConfig()->ExcludedCookies->Cookies)) {
166 foreach ($nitro->getConfig()->ExcludedCookies->Cookies as $excludedCookie) {
167 if ($excludedCookie->values) {
168 $bypassCookies[] = $excludedCookie->name . "=(" . implode("|", $excludedCookie->values) . ')\s*(;|$)';
169 } else {
170 $bypassCookies[] = $excludedCookie->name . "=";
171 }
172 }
173 }
174 $rules = str_replace("COOKIEBYPASS", "(" . implode("|", array_map(function($cookie){ return "(^|\;\s*)$cookie"; }, $bypassCookies)) . ")", $rules);
175
176 if ($nitro && !empty($nitro->getConfig()->IgnoredParams)) {
177 $rules = str_replace("# QSDROP", implode("\n", array_map(function($param) { return "CacheKeyModify -qs:$param"; }, array_filter($nitro->getConfig()->IgnoredParams, function($param) { return $param != "ignorenitro"; }))), $rules);
178 }
179
180 return array_merge($ruleLines, explode("\n", $rules));
181 }
182 }
183