PluginProbe
RabbitLoader / 2.17.6
RabbitLoader v2.17.6
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.17.6, at inc/public.php

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