Uname: Linux webm005.cluster107.gra.hosting.ovh.net 5.15.167-ovh-vps-grsec-zfs-classid #1 SMP Tue Sep 17 08:14:20 UTC 2024 x86_64
User: 6036 (villadal)
Group: 100 (users)
Disabled functions: NONE
Safe mode: On[ PHPinfo ]
//home/villadal/www/wp-content/plugins///wordfence///lib/      ( Reset | Go to )
File Name: wfLog.php
Edit
<?php
require_once(dirname(__FILE__) . '/wfDB.php');
require_once(
dirname(__FILE__) . '/wfUtils.php');
require_once(
dirname(__FILE__) . '/wfBrowscap.php');
class 
wfLog {
    public 
$canLogHit true;
    private 
$effectiveUserID 0;
    private 
$hitsTable '';
    private 
$apiKey '';
    private 
$wp_version '';
    private 
$db false;
    private 
$googlePattern '/\.(?:googlebot\.com|google\.[a-z]{2,3}|google\.[a-z]{2}\.[a-z]{2}|1e100\.net)$/i';
    private 
$loginsTable$statusTable;
    private static 
$gbSafeCache = array();

    
/**
     * @var wfRequestModel
     */
    
private $currentRequest;
    
    public static function 
shared() {
        static 
$_shared null;
        if (
$_shared === null) {
            
$_shared = new wfLog(wfConfig::get('apiKey'), wfUtils::getWPVersion());
        }
        return 
$_shared;
    }
    
    
/**
     * Returns whether or not we have a cached record identifying the visitor as human. This is used both by certain
     * rate limiting features and by Live Traffic.
     * 
     * @param bool|string $IP
     * @param bool|string $UA
     * @return bool
     */
    
public static function isHumanRequest($IP false$UA false) {
        global 
$wpdb;
        
        if (
$IP === false) {
            
$IP wfUtils::getIP();
        }
        
        if (
$UA === false || $UA === null) {
            
$UA = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
        }
        
        
$ipHex wfDB::binaryValueToSQLHex(wfUtils::inet_pton($IP));
        
$table wfDB::networkTable('wfLiveTrafficHuman');
        if (
$wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table} WHERE IP = {$ipHex} AND identifier = %s AND expiration >= UNIX_TIMESTAMP()"hash('sha256'$UAtrue)))) {
            return 
true;
        }
        return 
false;
    }
    
    
/**
     * Creates a cache record for the requester to tag it as human.
     * 
     * @param bool|string $IP
     * @param bool|string $UA
     * @return bool
     */
    
public static function cacheHumanRequester($IP false$UA false) {
        global 
$wpdb;
        
        if (
$IP === false) {
            
$IP wfUtils::getIP();
        }
        
        if (
$UA === false) {
            
$UA = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
        }
        
        
$ipHex wfDB::binaryValueToSQLHex(wfUtils::inet_pton($IP));
        
$table wfDB::networkTable('wfLiveTrafficHuman');
        if (
$wpdb->get_var($wpdb->prepare("INSERT IGNORE INTO {$table} (IP, identifier, expiration) VALUES ({$ipHex}, %s, UNIX_TIMESTAMP() + 86400)"hash('sha256'$UAtrue)))) {
            return 
true;
        }
    }
    
    
/**
     * Prunes any expired records from the human cache.
     */
    
public static function trimHumanCache() {
        global 
$wpdb;
        
$table wfDB::networkTable('wfLiveTrafficHuman');
        
$wpdb->query("DELETE FROM {$table} WHERE `expiration` < UNIX_TIMESTAMP()");
    }

    public function 
__construct($apiKey$wp_version){
        
$this->apiKey $apiKey;
        
$this->wp_version $wp_version;
        
$this->hitsTable wfDB::networkTable('wfHits');
        
$this->loginsTable wfDB::networkTable('wfLogins');
        
$this->statusTable wfDB::networkTable('wfStatus');
        
        
add_filter('determine_current_user', array($this'_userIDDetermined'), 991);
    }
    
    public function 
_userIDDetermined($userID) {
        
//Needed because the REST API will clear the authenticated user if it fails a nonce check on the request
        
$this->effectiveUserID = (int) $userID;
        return 
$userID;
    }

    public function 
initLogRequest() {
        if (
$this->currentRequest === null) {
            
$this->currentRequest = new wfRequestModel();

            
$this->currentRequest->ctime sprintf('%.6f'microtime(true));
            
$this->currentRequest->statusCode 200;
            
$this->currentRequest->isGoogle = (wfCrawl::isGoogleCrawler() ? 0);
            
$this->currentRequest->IP wfUtils::inet_pton(wfUtils::getIP());
            
$this->currentRequest->userID $this->getCurrentUserID();
            
$this->currentRequest->URL wfUtils::getRequestedURL();
            
$this->currentRequest->referer = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '');
            
$this->currentRequest->UA = (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');
            
$this->currentRequest->jsRun 0;
            
            
add_action('wp_loaded', array($this'actionSetRequestJSEnabled'));
            
add_action('init', array($this'actionSetRequestOnInit'), 9999);

            if (
function_exists('register_shutdown_function')) {
                
register_shutdown_function(array($this'logHit'));
            }
        }
    }

    public function 
actionSetRequestJSEnabled() {
        if (
get_current_user_id() > 0) {
            
$this->currentRequest->jsRun true;
            return;
        }
        
        
$IP wfUtils::getIP();
        
$UA $this->currentRequest->UA;
        
$this->currentRequest->jsRun wfLog::isHumanRequest($IP$UA);
    }

    
/**
     * CloudFlare's plugin changes $_SERVER['REMOTE_ADDR'] on init.
     */
    
public function actionSetRequestOnInit() {
        
$this->currentRequest->IP wfUtils::inet_pton(wfUtils::getIP());
        
$this->currentRequest->userID $this->getCurrentUserID();
    }

    
/**
     * @return wfRequestModel
     */
    
public function getCurrentRequest() {
        return 
$this->currentRequest;
    }
    
    public function 
logLogin($action$fail$username){
        if(! 
$username){
            return;
        }
        
$user get_user_by('login'$username);
        
$userID 0;
        if(
$user){
            
$userID $user->ID;
            if(! 
$userID){
                return;
            }
        }
        else {
            
$user get_user_by('email'$username);
            if (
$user) {
                
$userID $user->ID;
                if (!
$userID) {
                    return;
                }
            }
        }
        
// change the action flag here if the user does not exist.
        
if ($action == 'loginFailValidUsername' && $userID == 0) {
            
$action 'loginFailInvalidUsername';
        }

        
$hitID 0;
        if (
$this->currentRequest !== null) {
            
$this->currentRequest->userID $userID;
            
$this->currentRequest->action $action;
            
$this->currentRequest->save();
            
$hitID $this->currentRequest->getPrimaryKey();
        }

        
//Else userID stays 0 but we do log this even though the user doesn't exist.
        
$ipHex wfDB::binaryValueToSQLHex(wfUtils::inet_pton(wfUtils::getIP()));
        
$this->getDB()->queryWrite("insert into " $this->loginsTable " (hitID, ctime, fail, action, username, userID, IP, UA) values (%d, %f, %d, '%s', '%s', %s, {$ipHex}, '%s')",
            
$hitID,
            
sprintf('%.6f'microtime(true)),
            
$fail,
            
$action,
            
$username,
            
$userID,
            (isset(
$_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '')
            );
    }
    private function 
getCurrentUserID(){
        if (!
function_exists('get_current_user_id') || !defined('AUTH_COOKIE')) { //If pluggable.php is loaded early by some other plugin on a multisite installation, it leads to an error because AUTH_COOKIE is undefined and WP doesn't check for it first
            
return 0;
        }
        
$id get_current_user_id();
        return 
$id $id 0;
    }
    public function 
logLeechAndBlock($type) { //404 or hit
        
if (!wfRateLimit::mightRateLimit($type)) {
            return;
        }
        
        
wfRateLimit::countHit($typewfUtils::getIP());
        
        if (
wfRateLimit::globalRateLimit()->shouldEnforce($type)) {
            
$this->takeBlockingAction('maxGlobalRequests'wfI18n::__("Exceeded the maximum global requests per minute for crawlers or humans."'wordfence'));
        }
        else if (
wfRateLimit::crawlerViewsRateLimit()->shouldEnforce($type)) {
            
$this->takeBlockingAction('maxRequestsCrawlers'wfI18n::__("Exceeded the maximum number of requests per minute for crawlers."'wordfence')); //may not exit
        
}
        else if (
wfRateLimit::crawler404sRateLimit()->shouldEnforce($type)) {
            
$this->takeBlockingAction('max404Crawlers'wfI18n::__("Exceeded the maximum number of page not found errors per minute for a crawler."'wordfence'));
        }
        else if (
wfRateLimit::humanViewsRateLimit()->shouldEnforce($type)) {
            
$this->takeBlockingAction('maxRequestsHumans'wfI18n::__("Exceeded the maximum number of page requests per minute for humans."'wordfence'));
        }
        else if (
wfRateLimit::human404sRateLimit()->shouldEnforce($type)) {
            
$this->takeBlockingAction('max404Humans'wfI18n::__("Exceeded the maximum number of page not found errors per minute for humans."'wordfence'));
        }
    }
    
    public function 
tagRequestForBlock($reason$wfsn false) {
        if (
$this->currentRequest !== null) {
            
$this->currentRequest->statusCode 403;
            
$this->currentRequest->action 'blocked:' . ($wfsn 'wfsn' 'wordfence');
            
$this->currentRequest->actionDescription $reason;
        }
    }
    
    public function 
tagRequestForLockout($reason) {
        if (
$this->currentRequest !== null) {
            
$this->currentRequest->statusCode 503;
            
$this->currentRequest->action 'lockedOut';
            
$this->currentRequest->actionDescription $reason;
        }
    }

    
/**
     * @return bool|int
     */
    
public function logHit() {
        
$liveTrafficEnabled wfConfig::liveTrafficEnabled();
        
$action $this->currentRequest->action;
        
$logHitOK $this->logHitOK();
        if (!
$logHitOK) {
            return 
false;
        }
        if (!
$liveTrafficEnabled && !$action) {
            return 
false;
        }
        if (
$this->currentRequest !== null) {
            if (
$this->currentRequest->save()) {
                return 
$this->currentRequest->getPrimaryKey();
            }
        }
        return 
false;
    }
    
    public function 
getHits($hitType /* 'hits' or 'logins' */$type$afterTime$limit 50$IP false){
        global 
$wpdb;
        
$IPSQL "";
        if(
$IP){
            
$ipHex wfDB::binaryValueToSQLHex(wfUtils::inet_pton($IP));
            
$IPSQL " and IP={$ipHex} ";
            
$sqlArgs = array($afterTime$limit);
        } else {
            
$sqlArgs = array($afterTime$limit);
        }
        if(
$hitType == 'hits'){
            
$securityOnly = !wfConfig::liveTrafficEnabled();
            
$delayedHumanBotFiltering false;
            
            if(
$type == 'hit'){
                
$typeSQL " ";
            } else if(
$type == 'crawler'){
                if (
$securityOnly) {
                    
$typeSQL " ";
                    
$delayedHumanBotFiltering true;
                }
                else {
                    
$now time();
                    
$typeSQL " and jsRun = 0 and {$now} - ctime > 30 ";
                }
            } else if(
$type == 'gCrawler'){
                
$typeSQL " and isGoogle = 1 ";
            } else if(
$type == '404'){
                
$typeSQL " and statusCode = 404 ";
            } else if(
$type == 'human'){
                if (
$securityOnly) {
                    
$typeSQL " ";
                    
$delayedHumanBotFiltering true;
                }
                else {
                    
$typeSQL " and jsRun = 1 ";
                }
            } else if(
$type == 'ruser'){
                
$typeSQL " and userID > 0 ";
            } else {
                
wordfence::status(1'error'sprintf(/* translators: Error message. */ __("Invalid log type to wfLog: %s"'wordfence'), $type));
                return 
false;
            }
            
array_unshift($sqlArgs"select h.*, u.display_name from {$this->hitsTable} h
                LEFT JOIN 
{$wpdb->users} u on h.userID = u.ID
                where ctime > %f 
$IPSQL $typeSQL order by ctime desc limit %d");
            
$results call_user_func_array(array($this->getDB(), 'querySelect'), $sqlArgs);
            
            if (
$delayedHumanBotFiltering) {
                
$browscap wfBrowscap::shared();
                foreach (
$results as $index => $res) {
                    if (
$res['UA']) {
                        
$b $browscap->getBrowser($res['UA']);
                        if (
$b && $b['Parent'] != 'DefaultProperties') {
                            
$jsRun wfUtils::truthyToBoolean($res['jsRun']);
                            if (!
wfConfig::liveTrafficEnabled() && !$jsRun) {
                                
$jsRun = !(isset($b['Crawler']) && $b['Crawler']);
                            }
                            
                            if (
$type == 'crawler' && $jsRun || $type == 'human' && !$jsRun) {
                                unset(
$results[$index]);
                            }
                        }
                    }
                }
            }

        } else if(
$hitType == 'logins'){
            
array_unshift($sqlArgs"select l.*, u.display_name from {$this->loginsTable} l
                LEFT JOIN 
{$wpdb->users} u on l.userID = u.ID
                where ctime > %f 
$IPSQL order by ctime desc limit %d");
            
$results call_user_func_array(array($this->getDB(), 'querySelect'), $sqlArgs ); 

        } else {
            
wordfence::status(1'error'sprintf(/* translators: Error message. */ __("getHits got invalid hitType: %s"'wordfence'), $hitType));
            return 
false;
        }
        
$this->processGetHitsResults($type$results);
        return 
$results;
    }

    private function 
processActionDescription($description) {
        switch (
$description) {
        case 
wfWAFIPBlocksController::WFWAF_BLOCK_UAREFIPRANGE:
            return 
__('UA/Hostname/Referrer/IP Range not allowed''wordfence');
        default:
            return 
$description;
        }
    }

    
/**
     * @param string $type
     * @param array $results
     * @throws Exception
     */
    
public function processGetHitsResults($type, &$results) {
        
$serverTime $this->getDB()->querySingle("select unix_timestamp()");

        
$this->resolveIPs($results);
        
$ourURL parse_url(site_url());
        
$ourHost strtolower($ourURL['host']);
        
$ourHost preg_replace('/^www\./i'''$ourHost);
        
$browscap wfBrowscap::shared();

        
$patternBlocks wfBlock::patternBlocks(true);

        foreach(
$results as &$res){
            
$res['type'] = $type;
            
$res['IP'] = wfUtils::inet_ntop($res['IP']);
            
$res['timeAgo'] = wfUtils::makeTimeAgo($serverTime $res['ctime']);
            
$res['blocked'] = false;
            
$res['rangeBlocked'] = false;
            
$res['ipRangeID'] = -1;
            if (
array_key_exists('actionDescription'$res))
                
$res['actionDescription'] = $this->processActionDescription($res['actionDescription']);
            
            
$ipBlock wfBlock::findIPBlock($res['IP']);
            if (
$ipBlock !== false) {
                
$res['blocked'] = true;
                
$res['blockID'] = $ipBlock->id;
            }
            
            foreach (
$patternBlocks as $b) {
                if (empty(
$b->ipRange)) { continue; }
                
$range = new wfUserIPRange($b->ipRange);
                if (
$range->isIPInRange($res['IP'])) {
                    
$res['rangeBlocked'] = true;
                    
$res['ipRangeID'] = $b->id;
                    break;
                }
            }
            
            
$res['extReferer'] = false;
            if(isset( 
$res['referer'] ) && $res['referer']){
                if(
wfUtils::hasXSS($res['referer'] )){ //filtering out XSS
                    
$res['referer'] = '';
                }
            }
            if( isset( 
$res['referer'] ) && $res['referer']){
                
$refURL parse_url($res['referer']);
                if(
is_array($refURL) && isset($refURL['host']) && $refURL['host']){
                    
$refHost strtolower(preg_replace('/^www\./i'''$refURL['host']));
                    if(
$refHost != $ourHost){
                        
$res['extReferer'] = true;
                        
//now extract search terms
                        
$q false;
                        if(
preg_match('/(?:google|bing|alltheweb|aol|ask)\./i'$refURL['host'])){
                            
$q 'q';
                        } else if(
stristr($refURL['host'], 'yahoo.')){
                            
$q 'p';
                        } else if(
stristr($refURL['host'], 'baidu.')){
                            
$q 'wd';
                        }
                        if(
$q){
                            
$queryVars = array();
                            if( isset( 
$refURL['query'] ) ) {
                                
parse_str($refURL['query'], $queryVars);
                                if(isset(
$queryVars[$q])){
                                    
$res['searchTerms'] = urlencode($queryVars[$q]);
                                }
                            }
                        }
                    }
                }
                if(
$res['extReferer']){
                    if ( isset( 
$referringPage ) && stristr$referringPage['host'], 'google.' ) )
                    {
                        
parse_str$referringPage['query'], $queryVars );
                        
// echo $queryVars['q']; // This is the search term used
                    
}
                }
            }
            
$res['browser'] = false;
            if(
$res['UA']){
                
$b $browscap->getBrowser($res['UA']);
                if(
$b && $b['Parent'] != 'DefaultProperties'){
                    
$res['browser'] = array(
                        
'browser'   => !empty($b['Browser']) ? $b['Browser'] : "",
                        
'version'   => !empty($b['Version']) ? $b['Version'] : "",
                        
'platform'  => !empty($b['Platform']) ? $b['Platform'] : "",
                        
'isMobile'  => !empty($b['isMobileDevice']) ? $b['isMobileDevice'] : "",
                        
'isCrawler' => !empty($b['Crawler']) ? $b['Crawler'] : "",
                    );
                    
                    if (isset(
$res['jsRun']) && !wfConfig::liveTrafficEnabled() && !wfUtils::truthyToBoolean($res['jsRun'])) {
                        
$res['jsRun'] = !(isset($b['Crawler']) && $b['Crawler']) ? '1' '0';
                    }
                }
                else {
                    
$IP wfUtils::getIP();
                    
$res['browser'] = array(
                        
'isCrawler' => !wfLog::isHumanRequest($IP$res['UA']) ? 'true' ''
                    
);
                }
            }


            if(
$res['userID']){
                
$ud get_userdata($res['userID']);
                if(
$ud){
                    
$res['user'] = array(
                        
'editLink' => wfUtils::editUserLink($res['userID']),
                        
'display_name' => $res['display_name'],
                        
'ID' => $res['userID']
                    );
                }
            } else {
                
$res['user'] = false;
            }
        }
    }

    public function 
resolveIPs(&$results){
        if(
sizeof($results) < 1){ return; }
        
$IPs = array();
        foreach(
$results as &$res){
            if(
$res['IP']){ //Can also be zero in case of non IP events
                
$IPs[] = $res['IP'];
            }
        }
        
$IPLocs wfUtils::getIPsGeo($IPs); //Creates an array with IP as key and data as value

        
foreach($results as &$res){
            
$ip_printable wfUtils::inet_ntop($res['IP']);
            if(isset(
$IPLocs[$ip_printable])){
                
$res['loc'] = $IPLocs[$ip_printable];
            } else {
                
$res['loc'] = false;
            }
        }
    }
    public function 
logHitOK(){
        if (!
$this->canLogHit) {
            return 
false;
        }
        if (
is_admin()) { return false; } //Don't log admin pageviews
        
if (isset($_SERVER['HTTP_USER_AGENT'])) {
            if (
preg_match('/WordPress\/' $this->wp_version '/i'$_SERVER['HTTP_USER_AGENT'])) { return false; } //Ignore regular requests generated by WP UA.
        
}
        
$userID get_current_user_id();
        if (!
$userID) {
            
$userID $this->effectiveUserID;
        }
        if (
$userID) {
            
$user = new WP_User($userID);
            if (
$user && $user->exists()) {
                if (
wfConfig::get('liveTraf_ignorePublishers') && ($user->has_cap('publish_posts') || $user->has_cap('publish_pages'))) {
                    return 
false;
                }
                
                if (
wfConfig::get('liveTraf_ignoreUsers')) {
                    
$ignored explode(','wfConfig::get('liveTraf_ignoreUsers'));
                    foreach (
$ignored as $entry) {
                        if(
$user->user_login == $entry){
                            return 
false;
                        }
                    }
                }
            }
        }
        if(
wfConfig::get('liveTraf_ignoreIPs')){
            
$IPs explode(','wfConfig::get('liveTraf_ignoreIPs'));
            
$IP wfUtils::getIP();
            foreach(
$IPs as $ignoreIP){
                if(
$ignoreIP == $IP){
                    return 
false;
                }
            }
        }
        if( isset(
$_SERVER['HTTP_USER_AGENT']) && wfConfig::get('liveTraf_ignoreUA') ){
            if(
$_SERVER['HTTP_USER_AGENT'] == wfConfig::get('liveTraf_ignoreUA')){
                return 
false;
            }
        }

        return 
true;
    }
    private function 
getDB(){
        if(! 
$this->db){
            
$this->db = new wfDB();
        }
        return 
$this->db;
    }
    public function 
firewallBadIPs() {
        
$IP wfUtils::getIP();
        if (
wfBlock::isWhitelisted($IP)) {
            return;
        }

        
//Range and UA pattern blocking
        
$patternBlocks wfBlock::patternBlocks(true);
        
$userAgent = !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        
$referrer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
        foreach (
$patternBlocks as $b) {
            if (
$b->matchRequest($IP$userAgent$referrer) !== wfBlock::MATCH_NONE) {
                
$b->recordBlock();
                
wfActivityReport::logBlockedIP($IPnull'advanced');
                
$this->currentRequest->actionDescription wfI18n::__('UA/Referrer/IP Range not allowed''wordfence');
                
$this->do503(3600wfI18n::__("Advanced blocking in effect."'wordfence')); //exits
            
}
        }

        
// Country blocking
        
$countryBlocks wfBlock::countryBlocks(true);
        foreach (
$countryBlocks as $b) {
            
$match $b->matchRequest($IPfalsefalse);
            if (
$match === wfBlock::MATCH_COUNTRY_REDIR_BYPASS) {
                
$bypassRedirDest wfConfig::get('cbl_bypassRedirDest''');
                
                
$this->initLogRequest();
                
$this->getCurrentRequest()->actionDescription __('redirected to bypass URL''wordfence');
                
$this->getCurrentRequest()->statusCode 302;
                
$this->currentRequest->action 'cbl:redirect';
                
$this->logHit();
                
                
wfUtils::doNotCache();
                
wp_redirect($bypassRedirDest302);
                exit();
            }
            else if (
$match === wfBlock::MATCH_COUNTRY_REDIR) {
                
$b->recordBlock();
                
wfConfig::inc('totalCountryBlocked');
                
                
$this->initLogRequest();
                
$this->getCurrentRequest()->actionDescription sprintf(/* translators: URL */ __('blocked access via country blocking and redirected to URL (%s)''wordfence'), wfConfig::get('cbl_redirURL'));
                
$this->getCurrentRequest()->statusCode 503;
                if (!
$this->getCurrentRequest()->action) {
                    
$this->currentRequest->action 'blocked:wordfence';
                }
                
$this->logHit();
                
                
wfActivityReport::logBlockedIP($IPnull'country');
                
                
wfUtils::doNotCache();
                
wp_redirect(wfConfig::get('cbl_redirURL'), 302);
                exit();
            }
            else if (
$match !== wfBlock::MATCH_NONE) {
                
$b->recordBlock();
                
$this->currentRequest->actionDescription __('blocked access via country blocking''wordfence');
                
wfConfig::inc('totalCountryBlocked');
                
wfActivityReport::logBlockedIP($IPnull'country');
                
$this->do503(3600wfI18n::__('Access from your area has been temporarily limited for security reasons''wordfence'));
            }
        }

        
//Specific IP blocks
        
$ipBlock wfBlock::findIPBlock($IP);
        if (
$ipBlock !== false) {
            
$ipBlock->recordBlock();
            
$secsToGo max(0$ipBlock->expiration time());
            if (
wfConfig::get('other_WFNet') && self::isAuthRequest()) { //It's an auth request and this IP has been blocked
                
$this->getCurrentRequest()->action 'blocked:wfsnrepeat';
                
wordfence::wfsnReportBlockedAttempt($IP'login');
            }
            
$reason $ipBlock->reason;
            if (
$ipBlock->type == wfBlock::TYPE_IP_MANUAL || $ipBlock->type == wfBlock::TYPE_IP_AUTOMATIC_PERMANENT) {
                
$reason wfI18n::__('Manual block by administrator''wordfence');
            }
            
$this->do503($secsToGo$reason); //exits
        
}
    }

    private function 
takeBlockingAction($configVar$reason) {
        if (
$this->googleSafetyCheckOK()) {
            
$action wfConfig::get($configVar '_action');
            if (!
$action) {
                return;
            }
            
            
$IP wfUtils::getIP();
            
$secsToGo 0;
            if (
$action == 'block') { //Rate limited - block temporarily
                
$secsToGo wfBlock::blockDuration();
                
wfBlock::createRateBlock($reason$IP$secsToGo);
                
wfActivityReport::logBlockedIP($IPnull'throttle');
                
$this->tagRequestForBlock($reason);

                
$alertCallback = array(new wfBlockAlert($IP$reason$secsToGo), 'send');

                
do_action('wordfence_security_event''block', array(
                    
'ip' => $IP,
                    
'reason' => $reason,
                    
'duration' => $secsToGo,
                ), 
$alertCallback);
                
wordfence::status(2'info'sprintf(/* translators: 1. IP address. 2. Description of firewall action. */ __('Blocking IP %1$s. %2$s''wordfence'), $IP$reason));
            }
            else if (
$action == 'throttle') { //Rate limited - throttle
                
$secsToGo wfBlock::rateLimitThrottleDuration();
                
wfBlock::createRateThrottle($reason$IP$secsToGo);
                
wfActivityReport::logBlockedIP($IPnull'throttle');

                
do_action('wordfence_security_event''throttle', array(
                    
'ip' => $IP,
                    
'reason' => $reason,
                    
'duration' => $secsToGo,
                ));
                
wordfence::status(2'info'sprintf(/* translators: 1. IP address. 2. Description of firewall action. */ __('Throttling IP %1$s. %2$s''wordfence'), $IP$reason));
                
wfConfig::inc('totalIPsThrottled');
            }
            
$this->do503($secsToGo$reasonfalse);
        }
        
        return;
    }
    
    
/**
     * Test if the current request is for wp-login.php or xmlrpc.php
     *
     * @return boolean
     */
    
private static function isAuthRequest() {
        if ((
strpos($_SERVER['REQUEST_URI'], '/wp-login.php') !== false)) {
            return 
true;
        }
        return 
false;
    }
    
    public function 
do503($secsToGo$reason$sendEventToCentral true){
        
$this->initLogRequest();

        if (
$sendEventToCentral) {
            
do_action('wordfence_security_event''block', array(
                
'ip' => wfUtils::inet_ntop($this->currentRequest->IP),
                
'reason' => $this->currentRequest->actionDescription $this->currentRequest->actionDescription $reason,
                
'duration' => $secsToGo,
            ));
        }

        
$this->currentRequest->statusCode 503;
        if (!
$this->currentRequest->action) {
            
$this->currentRequest->action 'blocked:wordfence';
        }
        if (!
$this->currentRequest->actionDescription) {
            
$this->currentRequest->actionDescription "blocked: " $reason;
        }
        
        
$this->logHit();

        
wfConfig::inc('total503s');
        
wfUtils::doNotCache();
        
header('HTTP/1.1 503 Service Temporarily Unavailable');
        
header('Status: 503 Service Temporarily Unavailable');
        if(
$secsToGo){
            
header('Retry-After: ' $secsToGo);
        }
        
$customText wpautop(wp_strip_all_tags(wfConfig::get('blockCustomText''')));
        require_once(
dirname(__FILE__) . '/wf503.php');
        exit();
    }
    private function 
redirect($URL){
        
wfUtils::doNotCache();
        
wp_redirect($URL302);
        exit();
    }
    private function 
googleSafetyCheckOK(){ //returns true if OK to block. Returns false if we must not block.
        
$cacheKey md5( (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '') . ' ' wfUtils::getIP());
        
//Cache so we can call this multiple times in one request
        
if(! isset(self::$gbSafeCache[$cacheKey])){
            
$nb wfConfig::get('neverBlockBG');
            if(
$nb == 'treatAsOtherCrawlers'){
                
self::$gbSafeCache[$cacheKey] = true//OK to block because we're treating google like everyone else
            
} else if($nb == 'neverBlockUA' || $nb == 'neverBlockVerified'){
                if(
wfCrawl::isGoogleCrawler()){ //Check the UA using regex
                    
if($nb == 'neverBlockVerified'){
                        if(
wfCrawl::isVerifiedGoogleCrawler(wfUtils::getIP())){ //UA check passed, now verify using PTR if configured to
                            
self::$gbSafeCache[$cacheKey] = false//This is a verified Google crawler, so no we can't block it
                        
} else {
                            
self::$gbSafeCache[$cacheKey] = true//This is a crawler claiming to be Google but it did not verify
                        
}
                    } else { 
//neverBlockUA
                        
self::$gbSafeCache[$cacheKey] = false//User configured us to only do a UA check and this claims to be google so don't block
                    
}
                } else {
                    
self::$gbSafeCache[$cacheKey] = true//This isn't a Google UA, so it's OK to block
                
}
            } else {
                
//error_log("Wordfence error: neverBlockBG option is not set.");
                
self::$gbSafeCache[$cacheKey] = false//Oops the config option is not set. This should never happen because it's set on install. So we return false to indicate it's not OK to block just for safety.
            
}
        }
        if(! isset(
self::$gbSafeCache[$cacheKey])){
            
//error_log("Wordfence assertion fail in googleSafetyCheckOK: cached value is not set.");
            
return false//for safety
        
}
        return 
self::$gbSafeCache[$cacheKey]; //return cached value
    
}
    public function 
addStatus($level$type$msg){
        
//$msg = '[' . sprintf('%.2f', memory_get_usage(true) / (1024 * 1024)) . '] ' . $msg;
        
$this->getDB()->queryWrite("insert into " $this->statusTable " (ctime, level, type, msg) values (%s, %d, '%s', '%s')"sprintf('%.6f'microtime(true)), $level$type$msg);
    }
    public function 
getStatusEvents($lastCtime){
        if(
$lastCtime 1){
            
$lastCtime $this->getDB()->querySingle("select ctime from " $this->statusTable " order by ctime desc limit 1000,1");
            if(! 
$lastCtime){
                
$lastCtime 0;
            }
        }
        
$results $this->getDB()->querySelect("select ctime, level, type, msg from " $this->statusTable " where ctime > %f order by ctime asc"$lastCtime);
        
$timeOffset 3600 get_option('gmt_offset');
        foreach(
$results as &$rec){
            
//$rec['timeAgo'] = wfUtils::makeTimeAgo(time() - $rec['ctime']);
            
$rec['date'] = date('M d H:i:s', (int) $rec['ctime'] + $timeOffset);
            
$rec['msg'] = wp_kses_data( (string) $rec['msg']);
        }
        return 
$results;
    }
    public function 
getSummaryEvents(){
        
$results $this->getDB()->querySelect("select ctime, level, type, msg from " $this->statusTable " where level = 10 order by ctime desc limit 100");
        
$timeOffset 3600 get_option('gmt_offset');
        foreach(
$results as &$rec){
            
$rec['date'] = date('M d H:i:s', (int) $rec['ctime'] + $timeOffset);
            if(
strpos($rec['msg'], 'SUM_PREP:') === 0){
                break;
            }
        }
        return 
array_reverse($results);
    }

    
/**
     * @return string
     */
    
public function getGooglePattern() {
        return 
$this->googlePattern;
    }

}

/**
 *
 */
class wfUserIPRange {

    
/**
     * @var string|null
     */
    
private $ip_string;

    
/**
     * @param string|null $ip_string
     */
    
public function __construct($ip_string null) {
        
$this->setIPString($ip_string);
    }

    
/**
     * Check if the supplied IP address is within the user supplied range.
     *
     * @param string $ip
     * @return bool
     */
    
public function isIPInRange($ip) {
        
$ip_string $this->getIPString();
        
        if (
strpos($ip_string'/') !== false) { //CIDR range -- 127.0.0.1/24
            
return wfUtils::subnetContainsIP($ip_string$ip);
        }
        else if (
strpos($ip_string'[') !== false//Bracketed range -- 127.0.0.[1-100]
        
{
            
// IPv4 range
            
if (strpos($ip_string'.') !== false && strpos($ip'.') !== false) {
                
// IPv4-mapped-IPv6
                
if (preg_match('/:ffff:([^:]+)$/i'$ip_string$matches)) {
                    
$ip_string $matches[1];
                }
                if (
preg_match('/:ffff:([^:]+)$/i'$ip$matches)) {
                    
$ip $matches[1];
                }
                
                
// Range check
                
if (preg_match('/\[\d+\-\d+\]/'$ip_string)) {
                    
$IPparts explode('.'$ip);
                    
$whiteParts explode('.'$ip_string);
                    
$mismatch false;
                    if (
count($whiteParts) != || count($IPparts) != 4) {
                        return 
false;
                    }
                    
                    for (
$i 0$i <= 3$i++) {
                        if (
preg_match('/^\[(\d+)\-(\d+)\]$/'$whiteParts[$i], $m)) {
                            if (
$IPparts[$i] < $m[1] || $IPparts[$i] > $m[2]) {
                                
$mismatch true;
                            }
                        }
                        else if (
$whiteParts[$i] != $IPparts[$i]) {
                            
$mismatch true;
                        }
                    }
                    if (
$mismatch === false) {
                        return 
true// Is whitelisted because we did not get a mismatch
                    
}
                }
                else if (
$ip_string == $ip) {
                    return 
true;
                }
                
                
// IPv6 range
            
}
            else if (
strpos($ip_string':') !== false && strpos($ip':') !== false) {
                
$ip strtolower(wfUtils::expandIPv6Address($ip));
                
$ip_string strtolower(self::expandIPv6Range($ip_string));
                if (
preg_match('/\[[a-f0-9]+\-[a-f0-9]+\]/i'$ip_string)) {
                    
$IPparts explode(':'$ip);
                    
$whiteParts explode(':'$ip_string);
                    
$mismatch false;
                    if (
count($whiteParts) != || count($IPparts) != 8) {
                        return 
false;
                    }
                    
                    for (
$i 0$i <= 7$i++) {
                        if (
preg_match('/^\[([a-f0-9]+)\-([a-f0-9]+)\]$/i'$whiteParts[$i], $m)) {
                            
$ip_group hexdec($IPparts[$i]);
                            
$range_group_from hexdec($m[1]);
                            
$range_group_to hexdec($m[2]);
                            if (
$ip_group $range_group_from || $ip_group $range_group_to) {
                                
$mismatch true;
                                break;
                            }
                        }
                        else if (
$whiteParts[$i] != $IPparts[$i]) {
                            
$mismatch true;
                            break;
                        }
                    }
                    if (
$mismatch === false) {
                        return 
true// Is whitelisted because we did not get a mismatch
                    
}
                }
                else if (
$ip_string == $ip) {
                    return 
true;
                }
            }
        }
        else if (
strpos($ip_string'-') !== false) { //Linear range -- 127.0.0.1 - 127.0.1.100
            
list($ip1$ip2) = explode('-'$ip_string);
            
$ip1N wfUtils::inet_pton($ip1);
            
$ip2N wfUtils::inet_pton($ip2);
            
$ipN wfUtils::inet_pton($ip);
            return (
strcmp($ip1N$ipN) <= && strcmp($ip2N$ipN) >= 0);
        }
        else { 
//Treat as a literal IP
            
$ip1 wfUtils::inet_pton($ip_string);
            
$ip2 wfUtils::inet_pton($ip);
            if (
$ip1 !== false && $ip1 == $ip2) {
                return 
true;
            }
        }
        
        return 
false;
    }

    private static function 
repeatString($string$count) {
        if (
$count <= 0)
            return 
'';
        return 
str_repeat($string$count);
    }

    
/**
     * Expand a compressed printable range representation of an IPv6 address.
     *
     * @todo Hook up exceptions for better error handling.
     * @todo Allow IPv4 mapped IPv6 addresses (::ffff:192.168.1.1).
     * @param string $ip_range
     * @return string
     */
    
public static function expandIPv6Range($ip_range) {
        
$colon_count substr_count($ip_range':');
        
$dbl_colon_count substr_count($ip_range'::');
        if (
$dbl_colon_count 1) {
            return 
false;
        }
        
$dbl_colon_pos strpos($ip_range'::');
        if (
$dbl_colon_pos !== false) {
            
$ip_range str_replace('::'self::repeatString(':0000',
                    ((
$dbl_colon_pos === || $dbl_colon_pos === strlen($ip_range) - 2) ? 8) - $colon_count) . ':'$ip_range);
            
$ip_range trim($ip_range':');
        }
        
$colon_count substr_count($ip_range':');
        if (
$colon_count != 7) {
            return 
false;
        }

        
$groups explode(':'$ip_range);
        
$expanded '';
        foreach (
$groups as $group) {
            if (
preg_match('/\[([a-f0-9]{1,4})\-([a-f0-9]{1,4})\]/i'$group$matches)) {
                
$expanded .= sprintf('[%s-%s]'str_pad(strtolower($matches[1]), 4'0'STR_PAD_LEFT), str_pad(strtolower($matches[2]), 4'0'STR_PAD_LEFT)) . ':';
            } else if (
preg_match('/[a-f0-9]{1,4}/i'$group)) {
                
$expanded .= str_pad(strtolower($group), 4'0'STR_PAD_LEFT) . ':';
            } else {
                return 
false;
            }
        }
        return 
trim($expanded':');
    }

    
/**
     * @return bool
     */
    
public function isValidRange() {
        return 
$this->isValidCIDRRange() || $this->isValidBracketedRange() || $this->isValidLinearRange() || wfUtils::isValidIP($this->getIPString());
    }
    
    public function 
isValidCIDRRange() { //e.g., 192.0.2.1/24
        
$ip_string $this->getIPString();
        if (
preg_match('/[^0-9a-f:\/\.]/i'$ip_string)) { return false; }
        return 
wfUtils::isValidCIDRRange($ip_string);
    }
    
    public function 
isValidBracketedRange() { //e.g., 192.0.2.[1-10]
        
$ip_string $this->getIPString();
        if (
preg_match('/[^0-9a-f:\.\[\]\-]/i'$ip_string)) { return false; }
        if (
strpos($ip_string'.') !== false) { //IPv4
            
if (preg_match_all('/(\d+)/'$ip_string$matches) > 0) {
                foreach (
$matches[1] as $match) {
                    
$group = (int) $match;
                    if (
$group 255 || $group 0) {
                        return 
false;
                    }
                }
            }
            
            
$group_regex '([0-9]{1,3}|\[[0-9]{1,3}\-[0-9]{1,3}\])';
            return 
preg_match('/^' str_repeat("{$group_regex}\\."3) . $group_regex '$/i'$ip_string) > 0;
        }
        
        
//IPv6
        
if (strpos($ip_string'::') !== false) {
            
$ip_string self::expandIPv6Range($ip_string);
        }
        if (!
$ip_string) {
            return 
false;
        }
        
$group_regex '([a-f0-9]{1,4}|\[[a-f0-9]{1,4}\-[a-f0-9]{1,4}\])';
        return 
preg_match('/^' str_repeat("$group_regex:"7) . $group_regex '$/i'$ip_string) > 0;
    }
    
    public function 
isValidLinearRange() { //e.g., 192.0.2.1-192.0.2.100
        
$ip_string $this->getIPString();
        if (
preg_match('/[^0-9a-f:\.\-]/i'$ip_string)) { return false; }
        list(
$ip1$ip2) = explode("-"$ip_string);
        
        if (!
wfUtils::isValidIP($ip1) || !wfUtils::isValidIP($ip2)) {
            return 
false;
        }
        
        
$ip1N wfUtils::inet_pton($ip1);
        
$ip2N wfUtils::inet_pton($ip2);
        
        if (
$ip1N === false || $ip2N === false) {
            return 
false;
        }
        
        return 
strcmp($ip1N$ip2N) <= 0;
    }
    
    public function 
isMixedRange() { //e.g., 192.0.2.1-2001:db8::ffff
        
$ip_string $this->getIPString();
        if (
preg_match('/[^0-9a-f:\.\-]/i'$ip_string)) { return false; }
        list(
$ip1$ip2) = explode("-"$ip_string);
        
        
$ipv4Count 0;
        
$ipv4Count += filter_var($ip1FILTER_VALIDATE_IPFILTER_FLAG_IPV4) !== false 0;
        
$ipv4Count += filter_var($ip2FILTER_VALIDATE_IPFILTER_FLAG_IPV4) !== false 0;
        
        
$ipv6Count 0;
        
$ipv6Count += filter_var($ip1FILTER_VALIDATE_IPFILTER_FLAG_IPV6) !== false 0;
        
$ipv6Count += filter_var($ip2FILTER_VALIDATE_IPFILTER_FLAG_IPV6) !== false 0;
        
        if (
$ipv4Count != && $ipv6Count != 2) { 
            return 
true;
        }
        
        return 
false;
    }

    protected function 
_sanitizeIPRange($ip_string) {
        if (!
is_string($ip_string))
            return 
null;
        
$ip_string preg_replace('/\s/'''$ip_string); //Strip whitespace
        
$ip_string preg_replace('/[\\x{2013}-\\x{2015}]/u''-'$ip_string); //Non-hyphen dashes to hyphen
        
$ip_string strtolower($ip_string);
        
        if (
preg_match('/^\d+-\d+$/'$ip_string)) { //v5 32 bit int style format
            
list($start$end) = explode('-'$ip_string);
            
$start long2ip($start);
            
$end long2ip($end);
            
$ip_string "{$start}-{$end}";
        }
        
        return 
$ip_string;
    }

    
/**
     * @return string|null
     */
    
public function getIPString() {
        return 
$this->ip_string;
    }

    
/**
     * @param string|null $ip_string
     */
    
public function setIPString($ip_string) {
        
$this->ip_string $this->_sanitizeIPRange($ip_string);
    }
}

/**
 * The function of this class is to detect admin users created via direct access to the database (in other words, not
 * through WordPress).
 */
class wfAdminUserMonitor {

    protected 
$currentAdminList = array();

    public function 
isEnabled() {
        
$options wfScanner::shared()->scanOptions();
        
$enabled $options['scansEnabled_suspiciousAdminUsers'];
        if (
$enabled && is_multisite()) {
            if (!
function_exists('wp_is_large_network')) {
                require_once(
ABSPATH WPINC '/ms-functions.php');
            }
            
$enabled = !wp_is_large_network('sites') && !wp_is_large_network('users');
        }
        return 
$enabled;
    }

    
/**
     *
     */
    
public function createInitialList() {
        
$admins $this->getCurrentAdmins();
        
$adminUserList = array();
        foreach (
$admins as $id => $user) {
            
$adminUserList[$id] = 1;
        }
        
wfConfig::set_ser('adminUserList'$adminUserList);
    }

    
/**
     * @param int $userID
     */
    
public function grantSuperAdmin($userID null) {
        if (
$userID) {
            
$this->addAdmin($userID);
        }
    }

    
/**
     * @param int $userID
     */
    
public function revokeSuperAdmin($userID null) {
        if (
$userID) {
            
$this->removeAdmin($userID);
        }
    }

    
/**
     * @param int $ID
     * @param mixed $role
     * @param mixed $old_roles
     */
    
public function updateToUserRole($ID null$role null$old_roles null) {
        
$admins $this->getLoggedAdmins();
        if (
$role !== 'administrator' && array_key_exists($ID$admins)) {
            
$this->removeAdmin($ID);
        } else if (
$role === 'administrator') {
            
$this->addAdmin($ID);
        }
    }

    
/**
     * @return array|bool
     */
    
public function checkNewAdmins() {
        
$loggedAdmins $this->getLoggedAdmins();
        
$admins $this->getCurrentAdmins();
        
$suspiciousAdmins = array();
        foreach (
$admins as $adminID => $v) {
            if (!
array_key_exists($adminID$loggedAdmins)) {
                
$suspiciousAdmins[] = $adminID;
            }
        }
        return 
$suspiciousAdmins $suspiciousAdmins false;
    }

    
/**
     * Checks if the supplied user ID is suspicious.
     *
     * @param int $userID
     * @return bool
     */
    
public function isAdminUserLogged($userID) {
        
$loggedAdmins $this->getLoggedAdmins();
        return 
array_key_exists($userID$loggedAdmins);
    }

    
/**
     * @param bool $forceReload
     * @return array
     */
    
public function getCurrentAdmins($forceReload false) {
        if (empty(
$this->currentAdminList) || $forceReload) {
            require_once(
ABSPATH WPINC '/user.php');
            if (
is_multisite()) {
                if (
function_exists("get_sites")) {
                    
$sites get_sites(array(
                        
'network_id' => null,
                    ));
                }
                else {
                    
$sites wp_get_sites(array(
                        
'network_id' => null,
                    ));
                }
            } else {
                
$sites = array(array(
                    
'blog_id' => get_current_blog_id(),
                ));
            }

            
// not very efficient, but the WordPress API doesn't provide a good way to do this.
            
$this->currentAdminList = array();
            foreach (
$sites as $siteRow) {
                
$siteRowArray = (array) $siteRow;
                
$user_query = new WP_User_Query(array(
                    
'blog_id' => $siteRowArray['blog_id'],
                    
'role'    => 'administrator',
                ));
                
$users $user_query->get_results();
                if (
is_array($users)) {
                    
/** @var WP_User $user */
                    
foreach ($users as $user) {
                        
$this->currentAdminList[$user->ID] = $user;
                    }
                }
            }

            
// Add any super admins that aren't also admins on a network
            
$superAdmins get_super_admins();
            foreach (
$superAdmins as $userLogin) {
                
$user get_user_by('login'$userLogin);
                if (
$user) {
                    
$this->currentAdminList[$user->ID] = $user;
                }
            }
        }

        return 
$this->currentAdminList;
    }

    public function 
getLoggedAdmins() {
        
$loggedAdmins wfConfig::get_ser('adminUserList'false);
        if (!
is_array($loggedAdmins)) {
            
$this->createInitialList();
            
$loggedAdmins wfConfig::get_ser('adminUserList'false);
        }
        if (!
is_array($loggedAdmins)) {
            
$loggedAdmins = array();
        }
        return 
$loggedAdmins;
    }

    
/**
     * @param int $userID
     */
    
public function addAdmin($userID) {
        
$loggedAdmins $this->getLoggedAdmins();
        if (!
array_key_exists($userID$loggedAdmins)) {
            
$loggedAdmins[$userID] = 1;
            
wfConfig::set_ser('adminUserList'$loggedAdmins);
        }
    }

    
/**
     * @param int $userID
     */
    
public function removeAdmin($userID) {
        
$loggedAdmins $this->getLoggedAdmins();
        if (
array_key_exists($userID$loggedAdmins) && !array_key_exists($userID$this->getCurrentAdmins())) {
            unset(
$loggedAdmins[$userID]);
            
wfConfig::set_ser('adminUserList'$loggedAdmins);
        }
    }
}

/**
 * Represents a request record
 * 
 * @property int $id
 * @property float $attackLogTime
 * @property float $ctime
 * @property string $IP
 * @property bool $jsRun
 * @property int $statusCode
 * @property bool $isGoogle
 * @property int $userID
 * @property string $URL
 * @property string $referer
 * @property string $UA
 * @property string $action
 * @property string $actionDescription
 * @property string $actionData
 */
class wfRequestModel extends wfModel {

    private static 
$actionDataEncodedParams = array(
        
'paramKey',
        
'paramValue',
        
'path',
    );

    
/**
     * @param $actionData
     * @return mixed|string|void
     */
    
public static function serializeActionData($actionData$optionalKeys = array(), $maxLength 65535) {
        if (
is_array($actionData)) {
            foreach (
self::$actionDataEncodedParams as $key) {
                if (
array_key_exists($key$actionData)) {
                    
$actionData[$key] = base64_encode($actionData[$key]);
                }
            }
        }
        do {
            
$serialized json_encode($actionDataJSON_UNESCAPED_SLASHES);
            
$length strlen($serialized);
            if (
$length <= $maxLength)
                return 
$serialized;
            
$excess $length $maxLength;
            
$truncated false;
            foreach (
$optionalKeys as $key) {
                if (
array_key_exists($key$actionData)) {
                    
$fieldValue $actionData[$key];
                    
$fieldLength strlen($fieldValue);
                    
$truncatedLength min($fieldLength$excess);
                    
$truncated true;
                    if (
$truncatedLength 0) {
                        
$actionData[$key] = substr($fieldValue0, -$truncatedLength);
                        
$excess -= $truncatedLength;
                    }
                    else {
                        unset(
$actionData[$key]);
                        break;
                    }
                }
            }
        } while (
$truncated);
        return 
null;
    }

    
/**
     * @param $actionDataJSON
     * @return mixed|string|void
     */
    
public static function unserializeActionData($actionDataJSON) {
        
$actionData json_decode($actionDataJSONtrue);
        if (
is_array($actionData)) {
            foreach (
self::$actionDataEncodedParams as $key) {
                if (
array_key_exists($key$actionData)) {
                    
$actionData[$key] = base64_decode($actionData[$key]);
                }
            }
        }
        else {
            
$actionData = array();
        }
        return 
$actionData;
    }

    private 
$columns = array(
        
'id',
        
'attackLogTime',
        
'ctime',
        
'IP',
        
'jsRun',
        
'statusCode',
        
'isGoogle',
        
'userID',
        
'URL',
        
'referer',
        
'UA',
        
'action',
        
'actionDescription',
        
'actionData',
    );

    public function 
getIDColumn() {
        return 
'id';
    }

    public function 
getTable() {
        return 
wfDB::networkTable('wfHits');
    }

    public function 
hasColumn($column) {
        return 
in_array($column$this->columns);
    }
    
    public function 
save() {
        
$sapi = @php_sapi_name();
        if (
$sapi == "cli") {
            return 
false;
        }
        
        return 
parent::save();
    }
}


class 
wfLiveTrafficQuery {

    protected 
$validParams = array(
        
'id' => 'h.id',
        
'ctime' => 'h.ctime',
        
'ip' => 'h.ip',
        
'jsrun' => 'h.jsrun',
        
'statuscode' => 'h.statuscode',
        
'isgoogle' => 'h.isgoogle',
        
'userid' => 'h.userid',
        
'url' => 'h.url',
        
'referer' => 'h.referer',
        
'ua' => 'h.ua',
        
'action' => 'h.action',
        
'actiondescription' => 'h.actiondescription',
        
'actiondata' => 'h.actiondata',

        
// wfLogins
        
'user_login' => 'u.user_login',
        
'username' => 'l.username',
    );

    
/** @var wfLiveTrafficQueryFilterCollection */
    
private $filters = array();

    
/** @var wfLiveTrafficQueryGroupBy */
    
private $groupBy;
    
/**
     * @var float|null
     */
    
private $startDate;
    
/**
     * @var float|null
     */
    
private $endDate;
    
/**
     * @var int
     */
    
private $limit;
    
/**
     * @var int
     */
    
private $offset;

    private 
$tableName;

    
/** @var wfLog */
    
private $wfLog;

    
/**
     * wfLiveTrafficQuery constructor.
     *
     * @param wfLog $wfLog
     * @param wfLiveTrafficQueryFilterCollection $filters
     * @param wfLiveTrafficQueryGroupBy $groupBy
     * @param float $startDate
     * @param float $endDate
     * @param int $limit
     * @param int $offset
     */
    
public function __construct($wfLog$filters null$groupBy null$startDate null$endDate null$limit 20$offset 0) {
        
$this->wfLog $wfLog;
        
$this->filters $filters;
        
$this->groupBy $groupBy;
        
$this->startDate $startDate;
        
$this->endDate $endDate;
        
$this->limit $limit;
        
$this->offset $offset;
    }

    
/**
     * @return array|null|object
     */
    
public function execute() {
        global 
$wpdb;
        
$delayedHumanBotFiltering false;
        
$humanOnly false;
        
$sql $this->buildQuery($delayedHumanBotFiltering$humanOnly);
        
$results $wpdb->get_results($sqlARRAY_A);
        
        if (
$delayedHumanBotFiltering) {
            
$browscap wfBrowscap::shared();
            foreach (
$results as $index => $res) {
                if (
$res['UA']) {
                    
$b $browscap->getBrowser($res['UA']);
                    
$jsRun wfUtils::truthyToBoolean($res['jsRun']);
                    if (
$b && $b['Parent'] != 'DefaultProperties') {
                        
$jsRun wfUtils::truthyToBoolean($res['jsRun']);
                        if (!
wfConfig::liveTrafficEnabled() && !$jsRun) {
                            
$jsRun = !(isset($b['Crawler']) && $b['Crawler']);
                        }
                    }
                    
                    if (!
$humanOnly && $jsRun || $humanOnly && !$jsRun) {
                        unset(
$results[$index]);
                    }
                }
            }
        }
        
        
$this->getWFLog()->processGetHitsResults(''$results);
        
        
$verifyCrawlers false;
        if (
$this->filters !== null && count($this->filters->getFilters()) > 0) {
            
$filters $this->filters->getFilters();
            foreach (
$filters as $f) {
                if (
strtolower($f->getParam()) == "isgoogle") {
                    
$verifyCrawlers true;
                    break;
                }
            }
        }
        
        foreach (
$results as $key => &$row) {
            if (
$row['isGoogle'] && $verifyCrawlers) {
                if (!
wfCrawl::isVerifiedGoogleCrawler($row['IP'], $row['UA'])) {
                    unset(
$results[$key]); //foreach copies $results and iterates on the copy, so it is safe to mutate $results within the loop
                    
continue;
                }
            }

            
$row['actionData'] = $row['actionData'] === null ? array() : (array) json_decode($row['actionData'], true);
        }
        return 
array_values($results);
    }

    
/**
     * @param mixed $delayedHumanBotFiltering Whether or not human/bot filtering should be applied in PHP rather than SQL.
     * @param mixed $humanOnly When using delayed filtering, whether to show only humans or only bots.
     * 
     * @return string
     * @throws wfLiveTrafficQueryException
     */
    
public function buildQuery(&$delayedHumanBotFiltering, &$humanOnly) {
        global 
$wpdb;
        
$filters $this->getFilters();
        
$groupBy $this->getGroupBy();
        
$startDate $this->getStartDate();
        
$endDate $this->getEndDate();
        
$limit absint($this->getLimit());
        
$offset absint($this->getOffset());

        
$wheres = array("h.action != 'logged:waf'""h.action != 'scan:detectproxy'");
        if (
$startDate) {
            
$wheres[] = $wpdb->prepare('h.ctime > %f'$startDate);
        }
        if (
$endDate) {
            
$wheres[] = $wpdb->prepare('h.ctime < %f'$endDate);
        }

        if (
$filters instanceof wfLiveTrafficQueryFilterCollection) {
            if (!
wfConfig::liveTrafficEnabled()) {
                
$individualFilters $filters->getFilters();
                foreach (
$individualFilters as $index => $f) {
                    if (
$f->getParam() == 'jsRun' && $delayedHumanBotFiltering !== null && $humanOnly !== null) {
                        
$humanOnly wfUtils::truthyToBoolean($f->getValue());
                        if (
$f->getOperator() == '!=') {
                            
$humanOnly = !$humanOnly;
                        }
                        
$delayedHumanBotFiltering true;
                        unset(
$individualFilters[$index]);
                    }
                }
                
$filters->setFilters($individualFilters);
            }
            
            
$filtersSQL $filters->toSQL();
            if (
$filtersSQL) {
                
$wheres[] = $filtersSQL;
            }
        }

        
$orderBy 'ORDER BY h.ctime DESC';
        
$select ', l.username';
        
$groupBySQL '';
        if (
$groupBy && $groupBy->validate()) {
            
$groupBySQL "GROUP BY {$groupBy->getParam()}";
            
$orderBy 'ORDER BY hitCount DESC';
            
$select .= ', COUNT(h.id) as hitCount, MAX(h.ctime) AS lastHit, u.user_login AS username';
            
            if (
$groupBy->getParam() == 'user_login') {
                
$wheres[] = 'user_login IS NOT NULL';
            }
            else if (
$groupBy->getParam() == 'action') {
                
$wheres[] = '(statusCode = 403 OR statusCode = 503)';
            }
        }
        
        
$where join(' AND '$wheres);
        if (
$where) {
            
$where 'WHERE ' $where;
        }
        if (!
$limit || $limit 1000) {
            
$limit 20;
        }
        
$limitSQL $wpdb->prepare('LIMIT %d, %d'$offset$limit);
        
        
$table_wfLogins wfDB::networkTable('wfLogins');
        
$sql = <<<SQL
SELECT h.*, u.display_name{$select} FROM {$this->getTableName()} h
LEFT JOIN 
{$wpdb->users} u on h.userID = u.ID
LEFT JOIN 
{$table_wfLogins} l on h.id = l.hitID
$where
$groupBySQL
$orderBy
$limitSQL
SQL;

        return 
$sql;
    }

    
/**
     * @param $param
     * @return bool
     */
    
public function isValidParam($param) {
        return 
array_key_exists(strtolower($param), $this->validParams);
    }

    
/**
     * @param $getParam
     * @return bool|string
     */
    
public function getColumnFromParam($getParam) {
        
$getParam strtolower($getParam);
        if (
array_key_exists($getParam$this->validParams)) {
            return 
$this->validParams[$getParam];
        }
        return 
false;
    }

    
/**
     * @return wfLiveTrafficQueryFilterCollection
     */
    
public function getFilters() {
        return 
$this->filters;
    }

    
/**
     * @param wfLiveTrafficQueryFilterCollection $filters
     */
    
public function setFilters($filters) {
        
$this->filters $filters;
    }

    
/**
     * @return float|null
     */
    
public function getStartDate() {
        return 
$this->startDate;
    }

    
/**
     * @param float|null $startDate
     */
    
public function setStartDate($startDate) {
        
$this->startDate $startDate;
    }

    
/**
     * @return float|null
     */
    
public function getEndDate() {
        return 
$this->endDate;
    }

    
/**
     * @param float|null $endDate
     */
    
public function setEndDate($endDate) {
        
$this->endDate $endDate;
    }

    
/**
     * @return wfLiveTrafficQueryGroupBy
     */
    
public function getGroupBy() {
        return 
$this->groupBy;
    }

    
/**
     * @param wfLiveTrafficQueryGroupBy $groupBy
     */
    
public function setGroupBy($groupBy) {
        
$this->groupBy $groupBy;
    }

    
/**
     * @return int
     */
    
public function getLimit() {
        return 
$this->limit;
    }

    
/**
     * @param int $limit
     */
    
public function setLimit($limit) {
        
$this->limit $limit;
    }

    
/**
     * @return int
     */
    
public function getOffset() {
        return 
$this->offset;
    }

    
/**
     * @param int $offset
     */
    
public function setOffset($offset) {
        
$this->offset $offset;
    }

    
/**
     * @return string
     */
    
public function getTableName() {
        if (
$this->tableName === null) {
            
$this->tableName wfDB::networkTable('wfHits');
        }
        return 
$this->tableName;
    }

    
/**
     * @param string $tableName
     */
    
public function setTableName($tableName) {
        
$this->tableName $tableName;
    }

    
/**
     * @return wfLog
     */
    
public function getWFLog() {
        return 
$this->wfLog;
    }

    
/**
     * @param wfLog $wfLog
     */
    
public function setWFLog($wfLog) {
        
$this->wfLog $wfLog;
    }
}

class 
wfLiveTrafficQueryFilterCollection {

    private 
$filters = array();

    
/**
     * wfLiveTrafficQueryFilterCollection constructor.
     *
     * @param array $filters
     */
    
public function __construct($filters = array()) {
        
$this->filters $filters;
    }

    public function 
toSQL() {
        
$params = array();
        
$sql '';
        
$filters $this->getFilters();
        if (
$filters) {
            
/** @var wfLiveTrafficQueryFilter $filter */
            
foreach ($filters as $filter) {
                
$params[$filter->getParam()][] = $filter;
            }
        }

        foreach (
$params as $param => $filters) {
            
// $sql .= '(';
            
$filtersSQL '';
            foreach (
$filters as $filter) {
                
$filterSQL $filter->toSQL();
                if (
$filterSQL) {
                    
$filtersSQL .= $filterSQL ' OR ';
                }
            }
            if (
$filtersSQL) {
                
$sql .= '(' substr($filtersSQL0, -4) . ') AND ';
            }
        }
        if (
$sql) {
            
$sql substr($sql0, -5);
        }
        return 
$sql;
    }

    public function 
addFilter($filter) {
        
$this->filters[] = $filter;
    }

    
/**
     * @return array
     */
    
public function getFilters() {
        return 
$this->filters;
    }

    
/**
     * @param array $filters
     */
    
public function setFilters($filters) {
        
$this->filters $filters;
    }
}

class 
wfLiveTrafficQueryFilter {

    private 
$param;
    private 
$operator;
    private 
$value;

    protected 
$validOperators = array(
        
'=',
        
'!=',
        
'contains',
        
'match',
        
'hregexp',
        
'hnotregexp',
    );

    
/**
     * @var wfLiveTrafficQuery
     */
    
private $query;

    
/**
     * wfLiveTrafficQueryFilter constructor.
     *
     * @param wfLiveTrafficQuery $query
     * @param string $param
     * @param string $operator
     * @param string $value
     */
    
public function __construct($query$param$operator$value) {
        
$this->query $query;
        
$this->param $param;
        
$this->operator $operator;
        
$this->value $value;
    }

    
/**
     * @return string|void
     */
    
public function toSQL() {
        
$sql '';
        if (
$this->validate()) {
            
/** @var wpdb $wpdb */
            
global $wpdb;
            
$operator $this->getOperator();
            
$param $this->getQuery()->getColumnFromParam($this->getParam());
            if (!
$param) {
                return 
$sql;
            }
            
$value $this->getValue();
            switch (
$operator) {
                case 
'contains':
                    
$like addcslashes($value'_%\\');
                    
$sql $wpdb->prepare("$param LIKE %s""%$like%");
                    break;

                case 
'match':
                    
$sql $wpdb->prepare("$param LIKE %s"$value);
                    break;
                
                case 
'hregexp':
                    
$sql $wpdb->prepare("HEX($param) REGEXP %s"$value);
                    break;
                
                case 
'hnotregexp':
                    
$sql $wpdb->prepare("HEX($param) NOT REGEXP %s"$value);
                    break;

                default:
                    
$sql $wpdb->prepare("$param $operator %s"$value);
                    break;
            }
        }
        return 
$sql;
    }

    
/**
     * @return bool
     */
    
public function validate() {
        
$valid $this->isValidParam($this->getParam()) && $this->isValidOperator($this->getOperator());
        if (
defined('WP_DEBUG') && WP_DEBUG) {
            if (!
$valid) {
                throw new 
wfLiveTrafficQueryException("Invalid param/operator [{$this->getParam()}]/[{$this->getOperator()}] passed to " get_class($this));
            }
            return 
true;
        }
        return 
$valid;
    }

    
/**
     * @param string $param
     * @return bool
     */
    
public function isValidParam($param) {
        return 
$this->getQuery() && $this->getQuery()->isValidParam($param);
    }

    
/**
     * @param string $operator
     * @return bool
     */
    
public function isValidOperator($operator) {
        return 
in_array($operator$this->validOperators);
    }

    
/**
     * @return mixed
     */
    
public function getParam() {
        return 
$this->param;
    }

    
/**
     * @param mixed $param
     */
    
public function setParam($param) {
        
$this->param $param;
    }

    
/**
     * @return mixed
     */
    
public function getOperator() {
        return 
$this->operator;
    }

    
/**
     * @param mixed $operator
     */
    
public function setOperator($operator) {
        
$this->operator $operator;
    }

    
/**
     * @return mixed
     */
    
public function getValue() {
        return 
$this->value;
    }

    
/**
     * @param mixed $value
     */
    
public function setValue($value) {
        
$this->value $value;
    }

    
/**
     * @return wfLiveTrafficQuery
     */
    
public function getQuery() {
        return 
$this->query;
    }

    
/**
     * @param wfLiveTrafficQuery $query
     */
    
public function setQuery($query) {
        
$this->query $query;
    }
}

class 
wfLiveTrafficQueryGroupBy {

    private 
$param;

    
/**
     * @var wfLiveTrafficQuery
     */
    
private $query;

    
/**
     * wfLiveTrafficQueryGroupBy constructor.
     *
     * @param wfLiveTrafficQuery $query
     * @param string $param
     */
    
public function __construct($query$param) {
        
$this->query $query;
        
$this->param $param;
    }

    
/**
     * @return bool
     * @throws wfLiveTrafficQueryException
     */
    
public function validate() {
        
$valid $this->isValidParam($this->getParam());
        if (
defined('WP_DEBUG') && WP_DEBUG) {
            if (!
$valid) {
                throw new 
wfLiveTrafficQueryException("Invalid param [{$this->getParam()}] passed to " get_class($this));
            }
            return 
true;
        }
        return 
$valid;
    }

    
/**
     * @param string $param
     * @return bool
     */
    
public function isValidParam($param) {
        return 
$this->getQuery() && $this->getQuery()->isValidParam($param);
    }

    
/**
     * @return wfLiveTrafficQuery
     */
    
public function getQuery() {
        return 
$this->query;
    }

    
/**
     * @param wfLiveTrafficQuery $query
     */
    
public function setQuery($query) {
        
$this->query $query;
    }

    
/**
     * @return mixed
     */
    
public function getParam() {
        return 
$this->param;
    }

    
/**
     * @param mixed $param
     */
    
public function setParam($param) {
        
$this->param $param;
    }

}


class 
wfLiveTrafficQueryException extends Exception {

}

class 
wfErrorLogHandler {
    public static function 
getErrorLogs($deepSearch false) {
        static 
$errorLogs null;
        
        if (
$errorLogs === null) {
            
$searchPaths = array(ABSPATHABSPATH 'wp-admin'ABSPATH 'wp-content');
            
            
$homePath wfUtils::getHomePath();
            if (!
in_array($homePath$searchPaths)) {
                
$searchPaths[] = $homePath;
            }
            
            
$errorLogPath ini_get('error_log');
            if (!empty(
$errorLogPath) && !in_array($errorLogPath$searchPaths)) {
                
$searchPaths[] = $errorLogPath;
            }
            
            
$errorLogs = array();
            foreach (
$searchPaths as $s) {
                
$errorLogs array_merge($errorLogsself::_scanForLogs($s$deepSearch));
            }
        }
        return 
$errorLogs;
    }
    
    private static function 
_scanForLogs($path$deepSearch false) {
        static 
$processedFolders = array(); //Protection for endless loops caused by symlinks
        
if (is_file($path)) {
            
$file basename($path);
            if (
preg_match('#(?:^php_errorlog$|error_log(\-\d+)?$|\.log$)#i'$file)) {
                return array(
$path => is_readable($path));
            }
            return array();
        }
        
        
$path untrailingslashit($path);
        if (empty(
$path)) {
            return array();
        }
        
        
$contents = @scandir($path);
        if (!
is_array($contents)) {
            return array();
        }
        
        
$processedFolders[$path] = true;
        
$errorLogs = array();
        foreach (
$contents as $name) {
            if (
$name == '.' || $name == '..') { continue; }
            
$testPath $path DIRECTORY_SEPARATOR $name;
            if (!
array_key_exists($testPath$processedFolders)) {
                if ((
is_dir($testPath) && $deepSearch) || !is_dir($testPath)) {
                    
$errorLogs array_merge($errorLogsself::_scanForLogs($testPath$deepSearch));
                }
            }
        }
        return 
$errorLogs;
    }
    
    public static function 
outputErrorLog($path) {
        
$errorLogs self::getErrorLogs();
        if (!isset(
$errorLogs[$path])) { //Only allow error logs we've identified
            
global $wp_query;
            
$wp_query->set_404();
            
status_header(404);
            
nocache_headers();
            
            
$template get_404_template();
            if (
$template && file_exists($template)) {
                include(
$template);
            }
            exit;
        }
        
        
$fh = @fopen($path'r');
        if (!
$fh) {
            
status_header(503);
            
nocache_headers();
            echo 
"503 Service Unavailable";
            exit;
        }
        
        
$headersOutputted false;
        while (!
feof($fh)) {
            
$data fread($fh1024 1024); //read 1 megs max per chunk
            
if ($data === false) { //Handle the error where the file was reported readable but we can't actually read it
                
status_header(503);
                
nocache_headers();
                echo 
"503 Service Unavailable";
                exit;
            }
        
            if (!
$headersOutputted) {
                
header('Content-Type: text/plain');
                
header('Content-Disposition: attachment; filename="' basename($path));
                
$headersOutputted true;
            }
            echo 
$data;
        }
        exit;
    }
}

All system for education purposes only. For more tools: Telegram @jackleet

Mr.X Private Shell

Logo
-
New File | New Folder
Command
SQL