JFIF $ d d 7 * Z qn )ZP 0 !1 A "#a$2Qr D8 a Ri [f \m I ykI w0 c u F c Rı?lO7 к _f˓ [C $殷WF< _W ԣ s Kc ëI zyQy /_LK ℂ ;C",p F A : /] =H ~ , l s / 9 ć: [=/#f ; ) x { ٛE Q )~ = 𘙲r*2~ a _V = ' ku m F D } KYYC )( { * g& f `툪 r y ` = ^ c J. I ]( * `wq 1dđ #̩ ͑ 0 ; H ] u 搂 @:~ ו K L N s h } O I R* 8 :2 ! lD JV o ( 3 = M ( z Ȱ+i *N A r6K n S l ) ! J J Ӂ* % ݉?|D } d5: eP0 R; {$X' x F @ .ÊB {,WJ uQ ɲRI ;9 Q E琯 6 2fT .DU J ;*c P A\IL Nj! J ۱+ O\ ͔ ] ޒ S J ȧ c%A N ol ՎprU L Zԛe r E2= X D Xg VQeӓ k y P7 U* o m Q I s ,K `) 6\G3t?pgjr m ۛجw luGt f h 9uyP 0D;Uڽ"OXl i f $ ) &|ML 0 Z rm1 [ H XP l P R0 'G=i 2N +0 e 2 ]] 9 VT P O 7 h(F * 癈 ' = Q VZD F,d ߬ ~ T X G[ `le 69C R(!S2! P < 0 x < !1AQ "Raq 02Br #S CTb ? Ζ "]mH5WR 7 k.ۛ ! } Q~ + yԏ z |@ T20 S~ K e k *zF f^2X *( @ 8 r ? C I uI|֓>^Ex LgNU Y+{.R Ѫ τV YT D I 6 2 '8Y2 7'\T P.6 d &˦ @V q i |8 -O Ε ] ʔ U= T L 8= ;6c | !qfF3 a ů& ~$ l} 'NW U s$U k^S V : U#6w + +s &r+n ڐ { @ 29gL u " T Ù M=6 (^ "7 r}=6Yݾ lC u hquymp Ǧ G jhs ǜNl ɻ} o 7 #S6 a w 4 ! OS r D 5 7 % | ?x> L | / nD 6?/8 w # [ ) L 7 +6〼T A T g ! %5 Mm Z /c -{1_Je "| ^$ 'O & ޱմ < H vNqϡQ$ < 6 &Nݛ ֨tǻN (9 n ru~'όN sMG& ,uH Kw *Ī 5@ u6 BԒ i YN * f 0 _ GhKW u lT <nj- 0{ M L~ | /a v\ E = ?1 \ɟuq Ђ Y O a K ޡP q $ H8o Q˼EV ~ k 0 h' L Pp M -M" m^ !6l nմ 쮝C U T . ! :vMǨb h ډ Vc r @~p # !1QAa q ? AL0L x LU 4 d ; x " 16ad0 7.\ߋ 0 = P l v/ " c A Ay A|2pO8"d MV #1] = \ " ˡ ] k v I9 d ۓ & q ) ǐq E ꞅ v "P )q X &Q З non]я u ג./ ; gZ$ M QР 2M ]h ni 0 P $ێ 3CɏGjώy : m c # S_ l@ '_ \m|C 2`K _ 1 cIvGc $? PCQ S+D ? K aײ k Fr b 8 ύ NEدg ĝ U 3 6 #Ik+ v { v i ( ވ ? a e) X xy/*@Q Ǽ Ծ ) $ IWO l c G; !i k{ gOŀ L ('x T rb $ w) R $ & N1E td U3Uȉ1p M"N* (DNy d96.(jQ) X 5 c QɎMy W ? Q *!R > 6=7)Xj 5`J ] e 8%t ! + ' ! 1Q 5 !1 AQaq ё #2 "0BRb ? G t^ ## .l lQ T $ v , ,m 㵜5u bV =sY+ @d { N ! dn O < .- B; _w J t 6;Q Jd. Q c%p{ 1 ,sND dF H I0 Гo X ш e黅X ۢ F :)[ F G X ƹ / w _c MeD ,ʡc c . W D tA $ j@ : ) - #u c1< @ۗ9F ) KJ- hpP] _ x [ q B lb p ʖ w q " LFGd ƶ * s +ډ_Zc " ? % t[I P 6 J ]# =ɺ V v v CGs Gh1 > )6 |e y ? L ӣ m,4 G W Ui ` ] uJVo VDG< SB 6ϏQ @ TiU l y O U 0 kfV ~ ~}S Z @ *WU Ui ## ; s /[ = ! 7}" W N ] ' (L ! ~ y5 g9T̅J kbM' +s :S +B) v @ M j e C f j E 0 Y\Qn z G 1 д~ W o{T 9?` Rm yhsy3 !HAD ] m c1 ~ 2 L S u7x T ;j$ `} 4-> L# vzŏ I L S ֭ T { r jGK C ; b pU= - ` Bs K. S F w4 M q] Z dH S 0 ) tLg
<?php
/**
* Cloud misc trait
*
* @package LiteSpeed
* @since 7.8
*/
namespace LiteSpeed;
defined( 'WPINC' ) || exit();
/**
* Trait Cloud_Misc
*
* Handles version check, news, usage, promo, and other misc features.
*/
trait Cloud_Misc {
/**
* Load QC status for dash usage.
* Format to translate: `<a href="{#xxx#}" class="button button-primary">xxxx</a><a href="{#xxx#}">xxxx2</a>`
*
* @since 7.0
*
* @param string $type Type.
* @param bool $force Force refresh.
* @return string
*/
public function load_qc_status_for_dash( $type, $force = false ) {
return Str::translate_qc_apis( $this->_load_qc_status_for_dash( $type, $force ) );
}
/**
* Internal: load QC status HTML for dash.
*
* @param string $type Type.
* @param bool $force Force refresh.
* @return string
*/
private function _load_qc_status_for_dash( $type, $force = false ) {
if (
! $force &&
! empty( $this->_summary['mini_html'] ) &&
isset( $this->_summary['mini_html'][ $type ] ) &&
! empty( $this->_summary['mini_html'][ 'ttl.' . $type ] ) &&
$this->_summary['mini_html'][ 'ttl.' . $type ] > time()
) {
return Str::safe_html( $this->_summary['mini_html'][ $type ] );
}
// Try to update dash content
$data = self::post( self::SVC_D_DASH, [ 'action2' => ( 'cdn_dash_mini' === $type ? 'cdn_dash' : $type ) ] );
if ( ! empty( $data['qc_activated'] ) ) {
// Sync conf as changed
if ( empty( $this->_summary['qc_activated'] ) || $this->_summary['qc_activated'] !== $data['qc_activated'] ) {
$msg = sprintf( __( 'Congratulations, %s successfully set this domain up for the online services with CDN service.', 'litespeed-cache' ), 'QUIC.cloud' );
Admin_Display::success( '🎊 ' . $msg );
$this->_clear_reset_qc_reg_msg();
// Turn on CDN option
$this->cls( 'Conf' )->update_confs( [ self::O_CDN_QUIC => true ] );
$this->cls( 'CDN\Quic' )->try_sync_conf( true );
}
$this->_summary['qc_activated'] = $data['qc_activated'];
$this->save_summary();
}
// Show the info
if ( isset( $this->_summary['mini_html'][ $type ] ) ) {
return Str::safe_html( $this->_summary['mini_html'][ $type ] );
}
return '';
}
/**
* Show latest commit version always if is on dev
*
* @since 3.0
*/
public function check_dev_version() {
if ( ! preg_match( '/[^\d\.]/', Core::VER ) ) {
return;
}
$last_check = empty( $this->_summary[ 'last_request.' . self::API_VER ] ) ? 0 : $this->_summary[ 'last_request.' . self::API_VER ];
if ( time() - $last_check > 86400 ) {
$auto_v = self::version_check( 'dev' );
if ( ! empty( $auto_v['dev'] ) ) {
self::save_summary( [ 'version.dev' => $auto_v['dev'] ] );
}
}
if ( empty( $this->_summary['version.dev'] ) ) {
return;
}
self::debug( 'Latest dev version ' . $this->_summary['version.dev'] );
if ( version_compare( $this->_summary['version.dev'], Core::VER, '<=' ) ) {
return;
}
// Show the dev banner
require_once LSCWP_DIR . 'tpl/banner/new_version_dev.tpl.php';
}
/**
* Check latest version
*
* @since 2.9
* @access public
*
* @param string|false $src Source.
* @return mixed
*/
public static function version_check( $src = false ) {
$req_data = [
'v' => defined( 'LSCWP_CUR_V' ) ? LSCWP_CUR_V : '',
'src' => $src,
'php' => phpversion(),
];
// If code ver is smaller than db ver, bypass
if ( ! empty( $req_data['v'] ) && version_compare( Core::VER, $req_data['v'], '<' ) ) {
return;
}
if ( defined( 'LITESPEED_ERR' ) ) {
$litespeed_err = constant( 'LITESPEED_ERR' );
$req_data['err'] = base64_encode( ! is_string( $litespeed_err ) ? wp_json_encode( $litespeed_err ) : $litespeed_err ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
}
$data = self::post( self::API_VER, $req_data );
return $data;
}
/**
* Show latest news
*
* @since 3.0
*/
public function news() {
$this->_update_news();
if ( empty( $this->_summary['news.new'] ) ) {
return;
}
if ( ! empty( $this->_summary['news.plugin'] ) && Activation::cls()->dash_notifier_is_plugin_active( $this->_summary['news.plugin'] ) ) {
return;
}
require_once LSCWP_DIR . 'tpl/banner/cloud_news.tpl.php';
}
/**
* Update latest news
*
* @since 2.9.9.1
*/
private function _update_news() {
if ( ! empty( $this->_summary['news.utime'] ) && time() - (int) $this->_summary['news.utime'] < 86400 * 7 ) {
return;
}
self::save_summary( [ 'news.utime' => time() ] );
$data = self::get( self::API_NEWS );
if ( empty( $data['id'] ) ) {
return;
}
// Save news
if ( ! empty( $this->_summary['news.id'] ) && (string) $this->_summary['news.id'] === (string) $data['id'] ) {
return;
}
$this->_summary['news.id'] = $data['id'];
$this->_summary['news.plugin'] = ! empty( $data['plugin'] ) ? $data['plugin'] : '';
$this->_summary['news.title'] = ! empty( $data['title'] ) ? $data['title'] : '';
$this->_summary['news.content'] = ! empty( $data['content'] ) ? $data['content'] : '';
$this->_summary['news.zip'] = ! empty( $data['zip'] ) ? $data['zip'] : '';
$this->_summary['news.new'] = 1;
if ( $this->_summary['news.plugin'] ) {
$plugin_info = Activation::cls()->dash_notifier_get_plugin_info( $this->_summary['news.plugin'] );
if ( $plugin_info && ! empty( $plugin_info->name ) ) {
$this->_summary['news.plugin_name'] = $plugin_info->name;
}
}
self::save_summary();
}
/**
* Check if contains a package in a service or not
*
* @since 4.0
*
* @param string $service Service.
* @param int $pkg Package flag.
* @return bool
*/
public function has_pkg( $service, $pkg ) {
if ( ! empty( $this->_summary[ 'usage.' . $service ]['pkgs'] ) && ( $this->_summary[ 'usage.' . $service ]['pkgs'] & $pkg ) ) {
return true;
}
return false;
}
/**
* Get allowance of current service
*
* @since 3.0
* @access private
*
* @param string $service Service.
* @param string|bool $err Error code by ref.
* @return int
*/
public function allowance( $service, &$err = false ) {
// Only auto sync usage at most one time per day
if ( empty( $this->_summary[ 'last_request.' . self::SVC_D_USAGE ] ) || time() - (int) $this->_summary[ 'last_request.' . self::SVC_D_USAGE ] > 86400 ) {
$this->sync_usage();
}
if ( in_array( $service, [ self::SVC_CCSS, self::SVC_UCSS, self::SVC_VPI ], true ) ) {
// @since 4.2
$service = self::SVC_PAGE_OPTM;
}
if ( empty( $this->_summary[ 'usage.' . $service ] ) ) {
return 0;
}
$usage = $this->_summary[ 'usage.' . $service ];
// Image optm is always free
$allowance_max = 0;
if ( self::SVC_IMG_OPTM === $service ) {
$allowance_max = self::IMG_OPTM_DEFAULT_GROUP;
}
$allowance = (int) $usage['quota'] - (int) $usage['used'];
$err = 'out_of_quota';
if ( $allowance > 0 ) {
if ( $allowance_max && $allowance_max < $allowance ) {
$allowance = $allowance_max;
}
// Daily limit @since 4.2
if ( isset( $usage['remaining_daily_quota'] ) && $usage['remaining_daily_quota'] >= 0 && $usage['remaining_daily_quota'] < $allowance ) {
$allowance = $usage['remaining_daily_quota'];
if ( ! $allowance ) {
$err = 'out_of_daily_quota';
}
}
return $allowance;
}
// Check Pay As You Go balance
if ( empty( $usage['pag_bal'] ) ) {
return $allowance_max;
}
if ( $allowance_max && $allowance_max < $usage['pag_bal'] ) {
return $allowance_max;
}
return (int) $usage['pag_bal'];
}
/**
* Sync Cloud usage summary data
*
* @since 3.0
* @access public
*/
public function sync_usage() {
$usage = $this->_post( self::SVC_D_USAGE );
if ( ! $usage ) {
return;
}
self::debug( 'sync_usage ' . wp_json_encode( $usage ) );
foreach ( self::$services as $v ) {
$this->_summary[ 'usage.' . $v ] = ! empty( $usage[ $v ] ) ? $usage[ $v ] : false;
}
self::save_summary();
return $this->_summary;
}
/**
* REST call: check if the error domain is valid call for auto alias purpose
*
* @since 5.0
* @param string|null $raw_body Verified request body.
* @return array
*/
public function rest_err_domains( $raw_body = null ) {
$payload = is_string( $raw_body ) ? json_decode( $raw_body, true, 32 ) : false;
if (
! is_array( $payload ) || empty( $payload['alias'] ) || ! is_string( $payload['alias'] ) ||
empty( $payload['main_domain'] ) || ! is_string( $payload['main_domain'] )
) {
return self::err( 'lack_of_param' );
}
$alias = sanitize_text_field( $payload['alias'] );
if ( ! $this->_is_err_domain( $alias ) ) {
return self::err( 'Not an alias req from here' );
}
$message = [];
foreach ( [ '_info', '_note', '_success' ] as $field ) {
if ( ! isset( $payload[ $field ] ) || ! is_string( $payload[ $field ] ) ) {
continue;
}
$len = strlen( $payload[ $field ] );
if ( $len > self::CALLBACK_MSG_MAX_BYTES ) {
// Oversized notices are ignored but logged.
self::debugErr( 'Dropped oversized callback message [field] ' . $field . ' [bytes] ' . $len );
continue;
}
$message[ $field ] = $payload[ $field ];
}
$this->extract_msg( $message, 'Quic.cloud', false, true );
if ( site_url() === $alias ) {
$this->_remove_domain_from_err_list( $alias );
}
return self::ok();
}
/**
* Remove a domain from err domain
*
* @since 5.0
*
* @param string $url URL to remove.
*/
private function _remove_domain_from_err_list( $url ) {
unset( $this->_summary['err_domains'][ $url ] );
self::save_summary();
}
/**
* Check if is err domain
*
* @since 5.0
*
* @param string $site_url Site URL.
* @return bool
*/
private function _is_err_domain( $site_url ) {
if ( empty( $this->_summary['err_domains'] ) ) {
return false;
}
if ( ! array_key_exists( $site_url, $this->_summary['err_domains'] ) ) {
return false;
}
// Auto delete if too long ago
if ( time() - (int) $this->_summary['err_domains'][ $site_url ] > 86400 * 10 ) {
$this->_remove_domain_from_err_list( $site_url );
return false;
}
if ( time() - (int) $this->_summary['err_domains'][ $site_url ] > 86400 ) {
return false;
}
return true;
}
/**
* Show promo from cloud
*
* @since 3.0
* @access public
*/
public function show_promo() {
if ( empty( $this->_summary['promo'] ) ) {
return;
}
require_once LSCWP_DIR . 'tpl/banner/cloud_promo.tpl.php';
}
/**
* Clear promo from cloud
*
* @since 3.0
* @access private
*/
private function _clear_promo() {
if ( count( $this->_summary['promo'] ) > 1 ) {
array_shift( $this->_summary['promo'] );
} else {
$this->_summary['promo'] = [];
}
self::save_summary();
}
/**
* Display a banner for dev env if using preview QC node.
*
* @since 7.0
*/
public function maybe_preview_banner() {
if ( false !== strpos( $this->_cloud_server, 'preview.' ) ) {
Admin_Display::note( __( 'Linked to QUIC.cloud preview environment, for testing purpose only.', 'litespeed-cache' ), true, true, 'litespeed-warning-bg' );
}
}
}