PluginProbe
RabbitLoader / 2.18.2
RabbitLoader v2.18.2
4.0.2 4.0.1 4.0 3.2.0 3.1.1 3.1.0 3.0.5 3.0.3 3.0.4 2.17.1 2.17.2 2.17.3 2.17.4 2.17.5 2.17.6 2.17.7 2.18.0 2.18.1 2.18.2 2.18.3 2.18.4 2.18.5 2.18.6 2.18.7 2.18.8 All 129 releases
rabbit-loader / inc / public.php

public.php in RabbitLoader 2.18.2, at inc/public.php

451 lines 17.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class RabbitLoader_21_Public{
4
5 static $skip_reason = '';
6 const skip_reason_pm = "private-mode";
7 const skip_reason_or = "rl-origin";
8 const skip_reason_ep = "exclude-pattern";
9 const no_optimization = "rl-no-optimization";
10 static $wp_footer_called = false;
11 static $add_action_called = false;
12 static $is_origin = false;
13
14 public static function addActions(){
15 if(self::$add_action_called){
16 return;
17 }
18 self::$add_action_called = true;
19 //is_user_logged_in is a pluggable function and you could get a fatal error if you call it too early.
20 add_action('init', 'RabbitLoader_21_Public::init', 10);
21 add_action('shutdown', 'RabbitLoader_21_Public::shutdown', 10000);
22 add_filter('wp_redirect', 'RabbitLoader_21_Public::wp_redirect', 10, 2);
23 add_filter('redirect_canonical', 'RabbitLoader_21_Public::redirect_canonical', 10, 2);
24 add_filter('pre_handle_404','RabbitLoader_21_Public::pre_handle_404', 10, 2);
25 add_filter('paginate_links', 'RabbitLoader_21_Public::paginate_links', 10, 1);
26 add_filter('nonce_life', 'RabbitLoader_21_Public::nonce_life');
27 add_action('wp_footer', 'RabbitLoader_21_Public::wp_footer');
28 add_action('get_footer', 'RabbitLoader_21_Public::wp_footer');
29
30 RabbitLoader_21_CanonicalUrl::init();
31 RabbitLoader_21_Util_WP::init();
32
33 //Third party theme hooks
34 add_action('kirki_output_inline_styles', function($value){
35 #theme developed using kirki framework may generate lots of inline css referring to font files making the page load slow
36 #https://github.com/kirki-framework/kirki/blob/3a5d5093b1a99d1c7b813608479fe8fc9348b6a3/packages/kirki-framework/module-css/src/CSS.php
37 $value = false;
38 return $value;
39 }, -1);
40 }
41
42 public static function init()
43 {
44 if(!empty($_SERVER["HTTP_X_RL_PINGBACK_V2"])){
45 self::setup_endpoint();
46 return;
47 }
48
49 // try{
50 // if(!empty($_SERVER["HTTP_X_RL_SET_OPTION"]) && strcmp($_SERVER["HTTP_X_RL_SET_OPTION"], 'rabbitloader_field_disconnect_reason')===0){
51 // $responses = ['time'=>date('c')];
52 // try{
53 // global $wpdb;
54 // $responses['disconnect_reason'] = $wpdb->get_results("select option_id, option_name from $wpdb->options where option_name in ('rabbitloader_field_disconnect_reason', 'rabbitloader_field_update_time')");
55 // }catch(Throwable $e){
56 // RabbitLoader_21_Core::on_exception($e);
57 // }
58 // RabbitLoader_21_Core::sendJsonResponse($responses);
59 // }
60 // }catch(Throwable $e){
61 // RabbitLoader_21_Core::on_exception($e);
62 // }
63
64 if (current_user_can( 'manage_options' )) {
65 add_action('admin_bar_menu', 'RabbitLoader_21_Public::adminBarMenu', 50);
66 add_action('wp_enqueue_scripts', 'RabbitLoader_21_Public::adminBarScript');
67 }
68
69 RabbitLoader_21_CDN::init();
70 }
71
72 public static function shutdown($cache_served = false)
73 {
74 try{
75 if(!$cache_served){
76 self::optimized_version_missing();
77 RabbitLoader_21_Core::clean_orphaned_cached_files(300);
78 }else{
79 RabbitLoader_21_Core::clean_orphaned_cached_files(3600);
80 }
81 }catch(Throwable $e){
82 RabbitLoader_21_Core::on_exception($e);
83 }
84 }
85
86 private static function can_cache_request($request_uri){
87 if(!empty(self::$skip_reason)){
88 return false;
89 }
90 if(RabbitLoader_21_Util_Core::get_request_type()!='get'){
91 //Not a GET request, return
92 self::$skip_reason = 'method-'.RabbitLoader_21_Util_Core::get_request_type();
93 return false;
94 }
95
96 if(RabbitLoader_21_Util_WP::is_user_logged_in() || RabbitLoader_21_Util_WP::is_login_page()){
97 //we are not serving cached content to logged in users
98 self::$skip_reason = 'user-session';
99 return false;
100 }
101
102 if(RabbitLoader_21_Util_WP::is_ajax()){
103 self::$skip_reason = 'ajax';
104 return false;
105 }
106
107 if(!empty($_SERVER["HTTP_X_RL_PINGBACK"]) || RabbitLoader_21_Util_Core::isNoOptimization() || !empty($_SERVER["HTTP_X_RL_DIAGNOSIS"])){
108 //its origin pull form ur own server, let it get the original HTML
109 self::$skip_reason = self::skip_reason_or;
110 self::$is_origin = true;
111 return false;
112 }
113
114 if(!empty($_COOKIE['woocommerce_items_in_cart'])){
115 //TBD- user has some items in cart, in future version we will check how to serve a cached page with cart
116 self::$skip_reason = 'cart-items';
117 return false;
118 }
119
120 if(empty($_SERVER["HTTP_HOST"]) || RabbitLoader_21_Util_WP::is_cli() || !empty($_GET["mwprid"])){
121 self::$skip_reason = 'cli';
122 return false;
123 }
124
125 global $wp_query;
126 if (isset($wp_query) && $wp_query->is_404()) {
127 self::$skip_reason = '404-not-found';
128 return false;
129 }
130
131 if (RabbitLoader_21_Util_WP::is_search()) {
132 self::$skip_reason = 'search';
133 return false;
134 }
135
136 if(RabbitLoader_21_Util_WP::is_cart()){
137 self::$skip_reason = 'cart';
138 return false;
139 }
140
141 if(RabbitLoader_21_Util_WP::is_checkout()){
142 self::$skip_reason = 'checkout';
143 return false;
144 }
145
146 RabbitLoader_21_Core::getWpUserOption($user_options);
147
148 if(!empty($user_options['cart_uri']) && strcasecmp(RabbitLoader_21_Util_Core::serverURINoGet(), $user_options['cart_uri'])==0){
149 self::$skip_reason = 'cart';
150 return false;
151 }
152
153 if(!empty($user_options['checkout_uri']) && strcasecmp(RabbitLoader_21_Util_Core::serverURINoGet(), $user_options['checkout_uri'])==0){
154 self::$skip_reason = 'checkout';
155 return false;
156 }
157
158 if(!empty($user_options['exclude_patterns'])){
159 $exclude_patterns = explode("\n", $user_options['exclude_patterns']);
160 $matched = false;
161 if(!empty($exclude_patterns)){
162 foreach($exclude_patterns as $i=>$path_pattern){
163 if(!empty($path_pattern)){
164 $matched = fnmatch(trim($path_pattern), $request_uri);
165 if(!$matched){
166 $matched = fnmatch(trim($path_pattern), rawurldecode($request_uri));
167 }
168 if(!$matched){
169 $matched = fnmatch($path_pattern, rawurldecode($request_uri));
170 }
171 if($matched){break;}
172 }
173 }
174 }
175 if($matched){
176 self::$skip_reason = self::skip_reason_ep;
177 return false;
178 }
179 }
180 if(!empty($user_options['private_mode_val']) && empty($_GET['rltest'])){
181 self::$skip_reason = self::skip_reason_pm;
182 return false;
183 }
184
185 if(!empty(self::$skip_reason)){
186 self::$skip_reason = self::$skip_reason;
187 return false;
188 }
189
190 return true;
191 }
192
193 public static function getSkipReason(){
194 return self::$skip_reason;
195 }
196
197 public static function process_incoming_request($mode='ac'){
198 try{
199 RabbitLoader_21_Util_Core::get_requested_uri($request_uri, $request_url);
200
201 if(!self::can_cache_request($request_uri)){
202 if(empty(self::$skip_reason)){self::$skip_reason='unknown';}
203 RabbitLoader_21_Core::sendHeader('x-rl-cache: skipped-'.self::$skip_reason, true);
204 return;
205 }
206
207 if(!empty($request_uri) && $request_uri!="/favicon.ico"){
208
209 RabbitLoader_21_Core::get_cache_file_path($request_url, $cache_file);
210
211 if(self::serve_from_cache_if_available($cache_file)){
212 //ignore buffer and serve from cache
213 self::shutdown(true);
214 exit;
215 }
216
217 RabbitLoader_21_Core::sendHeader('x-rl-cache: miss/'.$mode, true);
218 }
219 }catch(Throwable $e){
220 RabbitLoader_21_Core::on_exception($e);
221 }
222 }
223
224 private static function optimized_version_missing(){
225
226 RabbitLoader_21_Util_Core::get_requested_uri($request_uri, $request_url);
227 if(self::can_cache_request($request_uri)){
228 $request_url.="\n";
229 RabbitLoader_21_Util_Core::fac('cache_missed', $request_url, WP_DEBUG);
230 }else if(strcmp(self::$skip_reason,self::skip_reason_pm)===0){
231 if(!RabbitLoader_21_Core::cache_exists_for_url($request_url, 0)){
232 $request_url.="\n";
233 RabbitLoader_21_Util_Core::fac('cache_missed', $request_url, WP_DEBUG);
234 }
235 }else{
236 //error_log($skip_reason.'=>'.$request_uri);
237 }
238 }
239
240 public static function setup_endpoint(){
241 if(empty($_SERVER["HTTP_X_RL_PINGBACK_V2"])){
242 return;
243 }
244
245 $response = [
246 'time'=>date('c')
247 ];
248
249 RabbitLoader_21_Core::getWpOption($rl_wp_options);
250 $api_key = empty($_SERVER["HTTP_X_RL_APIKEY"]) ? '' : trim($_SERVER["HTTP_X_RL_APIKEY"]);
251 $push_key = empty($_SERVER["HTTP_X_RL_PUSH_KEY"]) ? '' : trim($_SERVER["HTTP_X_RL_PUSH_KEY"]);
252
253 $isValidKey1 = (!empty($rl_wp_options['rabbitloader_field_apikey']) && ($rl_wp_options['rabbitloader_field_apikey'] == $api_key));
254 $isValidKey2 = (!empty($rl_wp_options['push_key']) && wp_check_password($push_key, $rl_wp_options['push_key']));
255 $isValidKey3 = (function_exists('get_option') && !empty($api_key) && ($api_key == get_option('rabbitloader_field_apikey')));
256 $isValidKey = $isValidKey1 || $isValidKey2 || $isValidKey3;
257
258 $rlaction = RabbitLoader_21_Util_Core::get_param('rlaction', true);
259
260 if(!$isValidKey){
261 $response['exception'] = 'key mismatch';
262 http_response_code(200);
263 echo json_encode($response);
264 return;
265 }
266
267 if(strcasecmp($rlaction, 'warmup')===0){
268 $queued_offset = intval($_POST['queued_offset']);
269 RabbitLoader_21_Core::run_warmup($queued_offset, $response);
270 }else if(strcasecmp($rlaction, 'purge')===0){
271 $tp_purge_count = 0;
272 RabbitLoader_21_Core::purge_all($purge_count, 'RL_PANEL', $tp_purge_count);
273 $response['purged'] = 1;
274 $response['purge_count'] = $purge_count;
275 $response['tp_purge_count'] = $tp_purge_count;
276 }else if(strcasecmp($rlaction, 'diagnosis')===0){
277 RabbitLoader_21_Core::run_diagnosis($response);
278 }else if(empty($rlaction) || strcasecmp($rlaction, 'savepage')===0){
279
280 $cur_id = RabbitLoader_21_Util_Core::get_param('cur_id', true);
281 $response['cur_id'] = $cur_id;
282
283 if(class_exists('ZipArchive')){
284 try{
285 $zip = new \ZipArchive();
286 if (!empty($cur_id) && !empty($_FILES["content_zip"]["tmp_name"]) && $zip->open($_FILES["content_zip"]["tmp_name"]) === TRUE) {
287 $dir = sys_get_temp_dir();
288 $zip->extractTo($dir);
289 $zip->close();
290 RabbitLoader_21_Core::get_cache_file_path($_POST['canonical_url'], $cache_file);
291
292 $saved_count = 0;
293 $tp_purge_count = 0;
294 $html_fn = "$dir/$cur_id.html";
295 if(file_exists($html_fn)){
296 $response['zip_opened'] = true;
297 if(self::hasValidClosingTag($html_fn)){
298 if(RabbitLoader_21_Util_Core::move($html_fn, $cache_file.'_c')){
299 ++$saved_count;
300 }
301 if(RabbitLoader_21_Util_Core::move("$dir/$cur_id.json", $cache_file.'_h')){
302 ++$saved_count;
303 }
304 }else{
305 $response['eof_missing'] = true;
306 }
307 if($saved_count>0){
308 RabbitLoader_21_TP::purge_url($_POST['canonical_url'], $tp_purge_count);
309 }
310
311 }else{
312 $response['zip_extract'] = "$html_fn not found";
313 }
314
315 $response['tmp_dir'] = $dir;
316 $response['saved_count'] = $saved_count;
317 $response['tp_purge_count'] = $tp_purge_count;
318 $response['cache_file'] = $cache_file;
319 $response['cache_filesize'] = filesize($cache_file.'_c');
320 $response['canonical_url'] = $_POST['canonical_url'];
321 }else{
322 $response['zip_opened'] = false;
323 }
324 }catch(\Throwable $e){
325 $response['exception'] = $e->getMessage();
326 }
327 }else{
328 $response['exception'] = 'ZipArchive not found';
329 }
330 }else{
331 $response['exception'] = 'invalid action '.$rlaction;
332 }
333 http_response_code(200);
334 echo json_encode($response);
335 exit;
336 }
337
338 private static function hasValidClosingTag(string $fn){
339 $valid = false;
340 $handle = fopen($fn, 'r');
341 fseek($handle, -8192, SEEK_END); //grab the last 8000 bytes to be safe
342 while (($buffer = fgets($handle)) !== false) {
343 if (stripos($buffer, '</html>') !== false || stripos($buffer, '</body>') !== false) {
344 $valid = true;
345 break;
346 }
347 }
348 fclose($handle);
349 return $valid;
350 }
351
352 private static function serve_from_cache_if_available($cache_file){
353 if(RabbitLoader_21_Core::cache_exists_for_hash($cache_file, 0)){
354 //ignore buffer and serve from cache
355 if(file_exists($cache_file.'_h')){
356 //header is optional
357 RabbitLoader_21_Util_Core::send_headers(file_get_contents($cache_file.'_h'));
358 }
359 RabbitLoader_21_Core::sendHeader('x-rl-cache: hit', true);
360 echo file_get_contents($cache_file.'_c');
361 return true;
362 }
363 }
364
365 public static function adminBarMenu($admin_bar){
366 $top_menu = array(
367 'id' => 'rabbitloader_top_menu',
368 'title' => 'RabbitLoader',
369 'href' => admin_url( 'options-general.php?page=rabbitloader' )
370 );
371
372 $list_menu = array(
373 'parent' => 'rabbitloader_top_menu',
374 'id' => 'rabbitloader_purge_page',
375 'title' => 'Purge cache for this page',
376 'href' => "#",
377 'meta' => array(
378 'class' => 'rabbitloader_purge_page',
379 )
380 );
381
382 $admin_bar->add_node($top_menu);
383 $admin_bar->add_node($list_menu);
384 }
385
386 public static function adminBarScript(){
387 global $post;
388
389 wp_enqueue_script('rabbitloader-index', RABBITLOADER_PLUG_URL . 'admin/js/index.js', ['jquery'], RABBITLOADER_PLUG_VERSION);
390 wp_localize_script( 'rabbitloader-index', 'rabbitloader_local_vars', [
391 'admin_ajax' => admin_url( 'admin-ajax.php' ),
392 'post_id' => empty($post) ? 0: $post->ID
393 ]);
394 }
395
396 public static function wp_redirect($location, $status){
397 if(!empty($location)){
398 self::$skip_reason = 'redirect-'.$status;
399 }
400 return $location;
401 }
402
403 public static function redirect_canonical($redirect_url, $requested_url){
404 if(!empty($redirect_url)){self::$skip_reason = 'redirect-canonical';}
405 return $redirect_url;
406 }
407
408 public static function pre_handle_404($preempt, $wp_query ){
409 if($preempt){self::$skip_reason = '404';}
410 return $preempt;
411 }
412
413 public static function paginate_links($link){
414 if(!empty($link)){
415 $link = str_ireplace('rl-no-optimization=1','', $link);
416 $link = rtrim($link, '?');
417 return $link;
418 }
419 }
420
421 public static function nonce_life($life){
422 $referer = empty($_SERVER["HTTP_REFERER"]) ? '' : $_SERVER["HTTP_REFERER"];
423 if(RabbitLoader_21_Util_WP::is_user_logged_in()){
424 return $life;
425 }elseif(intval($life)>RabbitLoader_21_Core::ORPHANED_LONG_AGE_SEC){
426 return $life;
427 }else if(self::$skip_reason==self::skip_reason_or || self::$is_origin){
428 //this also sets if no_optimization is passed
429 return RabbitLoader_21_Core::ORPHANED_LONG_AGE_SEC;
430 }else if(RabbitLoader_21_Util_WP::is_ajax() && (!empty($_COOKIE["rlCached"]) || stripos($referer, self::no_optimization)!==false)){
431 //for ajax, if cookie is set, the page was cached who called the ajax
432 //or the referer page had no_optimization that matched the previous else condition
433 return RabbitLoader_21_Core::ORPHANED_LONG_AGE_SEC;
434 }else{
435 //unhandled scenarios
436 }
437 return $life;
438 }
439
440 public static function wp_footer(){
441 if(self::$wp_footer_called){
442 return;
443 }
444 self::$wp_footer_called = true;
445 echo "<script data-rlskip='1'>let rlCached = window.rlPageData && window.rlPageData.rlCached;
446 document.cookie = 'rlCached=' + (rlCached ? '1' : '0') + '; path=/;';
447 </script>";
448 }
449 }
450
451 ?>