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: wfUtils.php
Edit
<?php
require_once(dirname(__FILE__) . '/wfConfig.php');
class 
wfUtils {
    const 
DEFAULT_MAX_SERIALIZED_INPUT_LENGTH 65536;
    const 
DEFAULT_MAX_SERIALIZED_ARRAY_LENGTH 1024;
    const 
DEFAULT_MAX_SERIALIZED_ARRAY_DEPTH 5;
    
    
//Flags for wfUtils::parse_version
    
const VERSION_MAJOR 'major';
    const 
VERSION_MINOR 'minor';
    const 
VERSION_PATCH 'patch';
    const 
VERSION_PRE_RELEASE 'pre-release';
    const 
VERSION_BUILD 'build';
    
    
//Flags for array_diff_assoc
    
const ARRAY_DIFF_ORDERED_ARRAYS 1//When specified, non-associative arrays are treated as if the ordering matters. The default is to ignore the ordering and only care about the content
    
    
private static $isWindows false;
    public static 
$scanLockFH false;
    private static 
$lastErrorReporting false;
    private static 
$lastDisplayErrors false;
    public static function 
patternToRegex($pattern$mod 'i'$sep '/') {
        
$pattern preg_quote(trim($pattern), $sep);
        
$pattern str_replace(' ''\s'$pattern);
        return 
$sep '^' str_replace('\*''.*'$pattern) . '$' $sep $mod;
    }
    public static function 
versionedAsset($subpath) {
        
$version WORDFENCE_BUILD_NUMBER;
        if (
$version != 'WORDFENCE_BUILD_NUMBER' && preg_match('/^(.+?)(\.[^\.]+)$/'$subpath$matches)) {
            
$prefix $matches[1];
            
$suffix $matches[2];
            return 
$prefix '.' $version $suffix;
        }
        
        return 
$subpath;
    }
    public static function 
makeTimeAgo($secs$noSeconds false) {
        if(
$secs 1){
            return 
__("a moment"'wordfence');
        }
        
        if (
function_exists('date_diff')) {
            
$now = new DateTime();
            
$utc = new DateTimeZone('UTC');
            
$dtStr gmdate("c", (int) ($now->getTimestamp() + $secs)); //Have to do it this way because of PHP 5.2
            
$then = new DateTime($dtStr$utc);
            
            
$diff $then->diff($now);
            
$years $diff->y;
            
$months $diff->m;
            
$days $diff->d;
            
$hours $diff->h;
            
$minutes $diff->i;
        }
        else {
            
$years 0;
            
$months floor($secs / (86400 30));
            
$days floor($secs 86400);
            
$hours floor($secs 3600);
            
$minutes floor($secs 60);
            
            if (
$months) {
                
$days -= $months 30;
            }
            else if (
$days) {
                
$hours -= $days 24;
            }
            else if (
$hours) {
                
$minutes -= $hours 60;
            }
        }
        
        if (
$years) {
            return 
$years ' ' _n('year''years'$years'wordfence') .
                (
is_numeric($months) ? ' ' $months ' ' _n('month''months'$months'wordfence') : '');
        }
        else if (
$months) {
            return 
$months ' ' _n('month''months'$months'wordfence') .
                (
is_numeric($days) ? ' ' $days ' ' _n('day''days'$days'wordfence') : '');
        }
        else if (
$days) {
            return 
$days ' ' _n('day''days'$days'wordfence') .
                (
is_numeric($hours) ? ' ' $hours ' ' _n('hour''hours'$hours'wordfence') : '');
        }
        else if (
$hours) {
            return 
$hours ' ' _n('hour''hours'$hours'wordfence') .
                (
is_numeric($minutes) ? ' ' $minutes ' ' _n('minute''minutes'$minutes'wordfence') : '');
        }
        else if (
$minutes) {
            return 
$minutes ' ' _n('minute''minutes'$minutes'wordfence');
        }
        else {
            if(
$noSeconds){
                return 
__("less than a minute"'wordfence');
            } else {
                return 
sprintf(/* translators: Number of seconds. */ __("%d seconds"'wordfence'), floor($secs));
            }
        }
    }
    public static function 
makeDuration($secs$createExact false) {
        
$components = array();
        
        
$months floor($secs / (86400 30)); $secs -= $months 86400 30;
        
$days floor($secs 86400); $secs -= $days 86400;
        
$hours floor($secs 3600); $secs -= $hours 3600;
        
$minutes floor($secs 60); $secs -= $minutes 60;
        
        if (
$months) {
            
$components[] = $months ' ' _n('month''months'$months'wordfence');
            if (!
$createExact) {
                
$hours $minutes $secs 0;
            }
        }
        if (
$days) {
            
$components[] = $days ' ' _n('day''days'$days'wordfence');
            if (!
$createExact) {
                
$minutes $secs 0;
            }
        }
        if (
$hours) {
            
$components[] = $hours ' ' _n('hour''hours'$hours'wordfence');
            if (!
$createExact) {
                
$secs 0;
            }
        }
        if (
$minutes) {
            
$components[] = $minutes ' ' _n('minute''minutes'$minutes'wordfence');
        }
        if (
$secs && $secs >= 1) {
            
$components[] = $secs ' ' _n('second''seconds'$secs'wordfence');
        }
        
        if (empty(
$components)) {
            
$components[] = __('less than 1 second''wordfence');
        }
        
        return 
implode(' '$components);
    }
    public static function 
pluralize($m1$m1Singular$m1Plural$m2 false$m2Singular false$m2Plural false) {
        
$m1Text _n($m1Singular$m1Plural$m1'wordfence');
        if (
is_numeric($m2)) {
            
$m2Text _n($m2Singular$m2Plural$m2'wordfence');
            return 
"$m1 $m1Text $m2 $m2Text";
        } else {
            return 
"$m1 $m1Text";
        }
    }
    public static function 
formatBytes($bytes$precision 2) {
        
$units = array('B''KB''MB''GB''TB');

        
$bytes max($bytes0);
        
$pow floor(($bytes log($bytes) : 0) / log(1024));
        
$pow min($powcount($units) - 1);

        
// Uncomment one of the following alternatives
        
$bytes /= pow(1024$pow);
        
// $bytes /= (1 << (10 * $pow)); 

        
return round($bytes$precision) . ' ' $units[$pow];
    }
    
    
/**
     * Returns the PHP version formatted for display, stripping off the build information when present.
     * 
     * @return string
     */
    
public static function cleanPHPVersion() {
        
$version phpversion();
        if (
preg_match('/^(\d+\.\d+\.\d+)/'$version$matches)) {
            return 
$matches[1];
        }
        return 
$version;
    }
    
    
/**
     * Safe unserialize() replacement
     * - accepts a strict subset of PHP's native serialized representation
     * - does not unserialize objects
     *
     * @param string $str
     * @return mixed
     */
    
public static function _safe_unserialize($str$limit_input_length self::DEFAULT_MAX_SERIALIZED_INPUT_LENGTH$limit_array_length self::DEFAULT_MAX_SERIALIZED_ARRAY_LENGTH$limit_array_depth self::DEFAULT_MAX_SERIALIZED_ARRAY_DEPTH) {
        if (empty(
$str) || !is_string($str)) { return false; }
        if (
strlen($str) > $limit_input_length) { return false; }
        if (!
is_serialized($str)) { return false; }
        
        
$stack = array();
        
$expected = array();
        
        
/*
         * states:
         *   0 - initial state, expecting a single value or array
         *   1 - terminal state
         *   2 - in array, expecting end of array or a key
         *   3 - in array, expecting value or another array
         */
        
$state 0;
        while (
$state != 1) {
            
$type = isset($str[0]) ? $str[0] : '';
            if (
$type == '}') {
                
$str substr($str1);
            } else if (
$type == 'N' && $str[1] == ';') {
                
$value null;
                
$str substr($str2);
            } else if (
$type == 'b' && preg_match('/^b:([01]);/'$str$matches)) {
                
$value $matches[1] == '1' true false;
                
$str substr($str4);
            } else if (
$type == 'i' && preg_match('/^i:(-?[0-9]+);(.*)/s'$str$matches)) {
                
$value = (int) $matches[1];
                
$str $matches[2];
            } else if (
$type == 'd' && preg_match('/^d:(-?[0-9]+\.?[0-9]*(E[+-][0-9]+)?);(.*)/s'$str$matches)) {
                
$value = (float) $matches[1];
                
$str $matches[3];
            } else if (
$type == 's' && preg_match('/^s:([0-9]+):"(.*)/s'$str$matches) && substr($matches[2], (int) $matches[1], 2) == '";') {
                
$value substr($matches[2], 0, (int) $matches[1]);
                
$str substr($matches[2], (int) $matches[1] + 2);
            } else if (
$type == 'a' && preg_match('/^a:([0-9]+):{(.*)/s'$str$matches) && $matches[1] < $limit_array_length) {
                
$expectedLength = (int) $matches[1];
                
$str $matches[2];
            } else {
                
// object or unknown/malformed type
                
return false;
            }
            
            switch (
$state) {
                case 
3// in array, expecting value or another array
                    
if ($type == 'a') {
                        if (
count($stack) >= $limit_array_depth) { return false; }
                        
                        
$stack[] = &$list;
                        
$list[$key] = array(); //$key is set in state 2
                        
$list = &$list[$key];
                        
$expected[] = $expectedLength;
                        
$state 2;
                        break;
                    }
                    if (
$type != '}') {
                        
$list[$key] = $value;
                        
$state 2;
                        break;
                    }
                    
                    
// missing array value
                    
return false;
                
                case 
2// in array, expecting end of array or a key
                    
if ($type == '}') {
                        if (
count($list) < end($expected)) {
                            
// array size less than expected
                            
return false;
                        }
                        
                        unset(
$list);
                        
$list = &$stack[count($stack) - 1];
                        
array_pop($stack);
                        
                        
// go to terminal state if we're at the end of the root array
                        
array_pop($expected);
                        if (
count($expected) == 0) {
                            
$state 1;
                        }
                        break;
                    }
                    if (
$type == 'i' || $type == 's') {
                        if (
count($list) >= $limit_array_length) { return false; }
                        if (
count($list) >= end($expected)) { return false; }
                        
                        
$key $value;
                        
$state 3;
                        break;
                    }
                    
                    
// illegal array index type
                    
return false;
                
                case 
0// expecting array or value
                    
if ($type == 'a') {
                        if (
count($stack) >= $limit_array_depth) { return false; }
                        
                        
$data = array();
                        
$list = &$data;
                        
$expected[] = $expectedLength;
                        
$state 2;
                        break;
                    }
                    if (
$type != '}') {
                        
$data $value;
                        
$state 1;
                        break;
                    }
                    
                    
// not in array
                    
return false;
            }
        }
        
        if (!empty(
$str)) { return false; } // trailing data in input
        
return $data;
    }
    
    
/**
     * Wrapper for _safe_unserialize() that handles multibyte encoding issues
     *
     * @param string $str
     * @return mixed
     */
    
public static function safe_unserialize($str) {
        
// ensure we use the byte count for strings even when strlen() is overloaded by mb_strlen()
        
if (function_exists('mb_internal_encoding') && (((int) ini_get('mbstring.func_overload')) & 2)) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
            
$mbIntEnc mb_internal_encoding();
            
mb_internal_encoding('ASCII');
        }
        
        
$out self::_safe_unserialize($str);
        
        if (isset(
$mbIntEnc)) {
            
mb_internal_encoding($mbIntEnc);
        }
        return 
$out;
    }
    
    
/**
     * If $value is not null, this returns $value unchanged. Otherwise it returns one of two values:
     * 1. If $orCallable is a valid callable, it returns the result
     * 2. Otherwise it returns $default 
     * 
     * @param mixed $value
     * @param mixed $default
     * @param callable|null $orCallable
     * @return mixed
     */
    
public static function ifnull($value$default ''$orCallable null) {
        if (
is_null($value)) {
            if (
is_callable($orCallable)) {
                return 
$orCallable();
            }
            return 
$default;
        }
        return 
$value;
    }
    
    
/**
     * Returns a diff on the passed arrays. The behavior varies based on the content of the arrays themselves and any
     * flags passed. The resulting structure will be some variant of:
     * 
     * ['added' => [...], 'removed' => [...]]
     * 
     * 1. If both $a and $b are non-associative arrays, the result will not include keys in `added` and `removed`.
     * 2. If either or both of $a and $b are associative arrays, the result will include keys that are also factored
     *    into the comparison.
     * 
     * @param array $a
     * @param array $b
     * @param int $flags
     * @return array
     */
    
public static function array_diff($a$b$flags 0) {
        
$result = array();
        if (!
self::is_assoc($a) && !self::is_assoc($b)) {
            
$result['added'] = array_diff($b$a);
            
$result['removed'] = array_diff($a$b);
        }
        else {
            
$result['added'] = self::array_diff_assoc($b$a);
            
$result['removed'] = self::array_diff_assoc($a$b);
        }
        return 
$result;
    }
    
    
/**
     * Improved version of array_diff_assoc that handles multidimensional arrays. The resulting array will contain all 
     * key/values from $a that are not present in $b.
     * 
     * For nested arrays, the behavior for inequality is this:
     *     - If $a[key] contains values $b[key] does not, an array of those missing values is set for `key` in the result
     *     - If $b[key] contains values $a[key] does not, `key` is not present in the result
     * 
     * @param array $a
     * @param array $b
     * @param int $flags
     * @return array
     */
    
public static function array_diff_assoc($a$b$flags 0) {
        if (!(
$flags self::ARRAY_DIFF_ORDERED_ARRAYS)) { //Treat $a and $b as unordered if they're non-associative
            
if (!self::is_assoc($a) && !self::is_assoc($b)) {
                
sort($a);
                
sort($b);
            }
        }
        
        
$result = array();
        foreach (
$a as $k => $v) {
            if (
array_key_exists($k$b)) {
                if (
$a[$k] == $b[$k]) {
                    continue;
                }
                
                if (
is_array($a[$k]) && is_array($b[$k])) {
                    
$diff self::array_diff($a[$k], $b[$k]);
                    if (!empty(
$diff['removed'])) {
                        
$result[$k] = $diff['removed'];
                    }
                    
                    continue;
                }
            }
            
            
$result[$k] = $v;
        }
        return 
$result;
    }
    
    
/**
     * Returns the items from $array whose keys are in $keys.
     * 
     * @param array $array
     * @param array|string $keys
     * @param bool $single Return single-value as-is instead of a one-element array.
     * @param mixed|null $default Value to return when $single is true and nothing is found.
     * @return array|mixed
     */
    
public static function array_choose($array$keys$single false$default null) {
        if (!
is_array($keys)) {
            
$keys = array($keys);
        }
        
        if (
is_object($array) && (
            
$array instanceof ArrayAccess ||
                
$array instanceof Traversable ||
                
$array instanceof Serializable ||
                
$array instanceof Countable)) {
            
$array = (array) $array;
        }
        
        
$matches array_filter($array, function($k) use ($keys) {
            return 
in_array($k$keys);
        }, 
ARRAY_FILTER_USE_KEY);
        if (
$single) {
            
$key self::array_first($keys);
            if (
$key !== null && isset($matches[$key])) {
                return 
$matches[$key];
            }
            
            return 
$default;
        }
        return 
$matches;
    }
    
    
/**
     * Convenience function for `array_choose` in its single return value mode for better code readability.
     * 
     * @param array $array
     * @param string $key
     * @param mixed|null $default
     * @return mixed
     */
    
public static function array_get($array$key$default null) {
        return 
self::array_choose($array$keytrue$default);
    }
    
    
/**
     * Polyfill for array_key_first.
     * 
     * @param array $array
     * @return mixed|null
     */
    
public static function array_key_first($array) {
        if (
function_exists('array_key_first')) {
            return 
array_key_first($array);
        }
        
        if (!
count($array)) {
            return 
null;
        }
        
        
$keys array_keys($array);
        return 
$keys[0];
    }
    
    
/**
     * Polyfill for array_key_last.
     *
     * @param array $array
     * @return mixed|null
     */
    
public static function array_key_last($array) {
        if (
function_exists('array_key_last')) {
            return 
array_key_last($array);
        }
        
        if (!
count($array)) {
            return 
null;
        }
        
        
$keys array_keys($array);
        return 
$keys[count($keys) - 1];
    }
    
    
/**
     * Performs an array_map but then converts the response into an associative array. $callable is expected to return
     * [$key => $value] rather than just $value as a normal array_map call would. The resulting array will be as if each
     * were merged in, preserving the $value under $key. Each $key _should_ generally be unique, but if there are 
     * duplicates, the last key/value pair mapped for a given $key will be the final value in the array.
     * 
     * @param callable $callable
     * @param array $array
     * @return array
     */
    
public static function array_kmap($callable$array) {
        
$intermediate array_map($callable$array);
        
$result = array();
        foreach (
$intermediate as $i) { //Can't use array_merge because it discards numerical keys
            
$k self::array_key_first($i);
            
$v $i[$k];
            
$result[$k] = $v;
        }
        return 
$result;
    }
    
    
    
/**
     * Returns whether or not $a is an associative-array. It is considered associative only when the array keys are not
     * sequential integers starting at 0.
     * 
     * @param array $a
     * @return bool
     */
    
public static function is_assoc($a) {
        if (!
is_array($a)) { return false; }
        for (
$i 0$i count($a); $i++) {
            if (!isset(
$a[$i])) {
                return 
true;
            }
        }
        return 
false;
    }
    
    
/**
     * Returns the raw HTTP POST body if possible. This is functionally identical to the implementation in wfWAFUtils 
     * but present here to avoid complications with nested install WAF optimization. 
     * 
     * @return string
     */
    
public static function rawPOSTBody() {
        
// phpcs:ignore PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved
        
global $HTTP_RAW_POST_DATA;
        
// phpcs:ignore PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved
        
if (empty($HTTP_RAW_POST_DATA)) { //Defined if always_populate_raw_post_data is on, PHP < 7, and the encoding type is not multipart/form-data
            
$avoidPHPInput wfWAFConfig::get('avoid_php_input'false);
            if (
$avoidPHPInput) { //Some custom PHP builds break reading from php://input
                //Reconstruct the best possible approximation of it from $_POST if populated -- won't help JSON or other raw payloads
                
$data http_build_query($_POST'''&');
            }
            else {
                
$data file_get_contents('php://input'); //Available if the encoding type is not multipart/form-data; it can only be read once prior to PHP 5.6 so we save it in $HTTP_RAW_POST_DATA for WP Core and others
                
                //For our purposes, we don't currently need the raw POST body if it's multipart/form-data since the data will be in $_POST/$_FILES. If we did, we could reconstruct the body here.
                
                // phpcs:ignore PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved
                
$HTTP_RAW_POST_DATA $data;
            }
        }
        else {
            
// phpcs:ignore PHPCompatibility.Variables.RemovedPredefinedGlobalVariables.http_raw_post_dataDeprecatedRemoved
            
$data =& $HTTP_RAW_POST_DATA;
        }
        return 
$data;
    }
    
    
/**
     * Check if an IP address is in a network block
     *
     * @param string    $subnet    Single IP or subnet in CIDR notation (e.g. '192.168.100.0' or '192.168.100.0/22')
     * @param string    $ip        IPv4 or IPv6 address in dot or colon notation
     * @return boolean
     */
    
public static function subnetContainsIP($subnet$ip) {
        static 
$_network_cache = array();
        static 
$_ip_cache = array();
        static 
$_masks = array(
            
=> "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
=> "\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
10 => "\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
11 => "\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
12 => "\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
13 => "\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
14 => "\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
15 => "\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
16 => "\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
17 => "\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
18 => "\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
19 => "\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
20 => "\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
21 => "\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
22 => "\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
23 => "\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
24 => "\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
25 => "\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
26 => "\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
27 => "\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
28 => "\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
29 => "\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
30 => "\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
31 => "\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
32 => "\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
33 => "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
34 => "\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
35 => "\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
36 => "\xff\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
37 => "\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
38 => "\xff\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
39 => "\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
40 => "\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
41 => "\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
42 => "\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
43 => "\xff\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
44 => "\xff\xff\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
45 => "\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
46 => "\xff\xff\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
47 => "\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
48 => "\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
49 => "\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
50 => "\xff\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
51 => "\xff\xff\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
52 => "\xff\xff\xff\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
53 => "\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
54 => "\xff\xff\xff\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
55 => "\xff\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
56 => "\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00",
            
57 => "\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00\x00",
            
58 => "\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00",
            
59 => "\xff\xff\xff\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00",
            
60 => "\xff\xff\xff\xff\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00",
            
61 => "\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00",
            
62 => "\xff\xff\xff\xff\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00",
            
63 => "\xff\xff\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00",
            
64 => "\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00",
            
65 => "\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00",
            
66 => "\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00",
            
67 => "\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00",
            
68 => "\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00",
            
69 => "\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00",
            
70 => "\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00",
            
71 => "\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00",
            
72 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00",
            
73 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00",
            
74 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00\x00",
            
75 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00",
            
76 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00",
            
77 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00",
            
78 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00",
            
79 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00",
            
80 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00",
            
81 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00",
            
82 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00\x00",
            
83 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00",
            
84 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\x00\x00\x00\x00",
            
85 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00\x00",
            
86 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00\x00\x00\x00\x00",
            
87 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00",
            
88 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00",
            
89 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00\x00",
            
90 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x00\x00\x00",
            
91 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\x00\x00\x00",
            
92 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\x00\x00\x00",
            
93 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00\x00",
            
94 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00\x00\x00\x00",
            
95 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x00\x00\x00\x00",
            
96 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00",
            
97 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x00",
            
98 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x00\x00",
            
99 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\x00\x00",
            
100 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\x00\x00",
            
101 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00\x00",
            
102 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00\x00\x00",
            
103 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x00\x00\x00",
            
104 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00",
            
105 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00",
            
106 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x00",
            
107 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\x00",
            
108 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\x00",
            
109 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00\x00",
            
110 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00\x00",
            
111 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x00\x00",
            
112 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00",
            
113 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00",
            
114 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00",
            
115 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00",
            
116 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00",
            
117 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8\x00",
            
118 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00",
            
119 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x00",
            
120 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00",
            
121 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x80",
            
122 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0",
            
123 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xe0",
            
124 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf0",
            
125 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf8",
            
126 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfc",
            
127 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe",
            
128 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
        );
        
/*
         * The above is generated by:
         * 
           function gen_mask($prefix, $size = 128) {
                //Workaround to avoid overflow, split into four pieces            
                $mask_1 = (pow(2, $size / 4) - 1) ^ (pow(2, min($size / 4, max(0, 1 * $size / 4 - $prefix))) - 1);
                $mask_2 = (pow(2, $size / 4) - 1) ^ (pow(2, min($size / 4, max(0, 2 * $size / 4 - $prefix))) - 1);
                $mask_3 = (pow(2, $size / 4) - 1) ^ (pow(2, min($size / 4, max(0, 3 * $size / 4 - $prefix))) - 1);
                $mask_4 = (pow(2, $size / 4) - 1) ^ (pow(2, min($size / 4, max(0, 4 * $size / 4 - $prefix))) - 1);
                return ($mask_1 ? pack('N', $mask_1) : "\0\0\0\0") . ($mask_2 ? pack('N', $mask_2) : "\0\0\0\0") . ($mask_3 ? pack('N', $mask_3) : "\0\0\0\0") . ($mask_4 ? pack('N', $mask_4) : "\0\0\0\0");
            }
            
            $masks = array();
            for ($i = 0; $i <= 128; $i++) {
                $mask = gen_mask($i);
                $chars = str_split($mask);
                $masks[] = implode('', array_map(function($c) { return '\\x' . bin2hex($c); }, $chars));
            }
            
            echo 'array(' . "\n";
            foreach ($masks as $index => $m) {
                echo "\t{$index} => \"{$m}\",\n";
            }
            echo ')';
         *
         */
        
        
if (isset($_network_cache[$subnet])) {
            list(
$bin_network$prefix$masked_network) = $_network_cache[$subnet];
            
$mask $_masks[$prefix];
        }
        else {
            list(
$network$prefix) = array_pad(explode('/'$subnet2), 2null);
            if (
filter_var($networkFILTER_VALIDATE_IPFILTER_FLAG_IPV4)) {
                
// If no prefix was supplied, 32 is implied for IPv4
                
if ($prefix === null) {
                    
$prefix 32;
                }
                
                
// Validate the IPv4 network prefix
                
if ($prefix || $prefix 32) {
                    return 
false;
                }
                
                
// Increase the IPv4 network prefix to work in the IPv6 address space
                
$prefix += 96;
            }
            else {
                
// If no prefix was supplied, 128 is implied for IPv6
                
if ($prefix === null) {
                    
$prefix 128;
                }
                
                
// Validate the IPv6 network prefix
                
if ($prefix || $prefix 128) {
                    return 
false;
                }
            }
            
$mask $_masks[$prefix];
            
$bin_network self::inet_pton($network);
            
$masked_network $bin_network $mask;
            
$_network_cache[$subnet] = array($bin_network$prefix$masked_network);
        }
        
        if (isset(
$_ip_cache[$ip]) && isset($_ip_cache[$ip][$prefix])) {
            list(
$bin_ip$masked_ip) = $_ip_cache[$ip][$prefix];
        }
        else {
            
$bin_ip self::inet_pton($ip);
            
$masked_ip $bin_ip $mask;
            if (!isset(
$_ip_cache[$ip])) {
                
$_ip_cache[$ip] = array();
            }
            
$_ip_cache[$ip][$prefix] = array($bin_ip$masked_ip);
        }
        
        return (
$masked_ip === $masked_network);
    }

    
/**
     * Convert CIDR notation to a wfUserIPRange object
     *
     * @param string $cidr
     * @return wfUserIPRange
     */
    
public static function CIDR2wfUserIPRange($cidr) {
        list(
$network$prefix) = array_pad(explode('/'$cidr2), 2null);
        
$ip_range = new wfUserIPRange();

        if (
filter_var($networkFILTER_VALIDATE_IPFILTER_FLAG_IPV4)) {
            
// If no prefix was supplied, 32 is implied for IPv4
            
if ($prefix === null) {
                
$prefix 32;
            }

            
// Validate the IPv4 network prefix
            
if ($prefix || $prefix 32) {
                return 
$ip_range;
            }

            
// Increase the IPv4 network prefix to work in the IPv6 address space
            
$prefix += 96;
        } else {
            
// If no prefix was supplied, 128 is implied for IPv6
            
if ($prefix === null) {
                
$prefix 128;
            }

            
// Validate the IPv6 network prefix
            
if ($prefix || $prefix 128) {
                return 
$ip_range;
            }
        }

        
// Convert human readable address to 128 bit (IPv6) binary string
        // Note: self::inet_pton converts IPv4 addresses to IPv6 compatible versions
        
$binary_network self::inet_pton($network);
        
$binary_mask wfHelperBin::str2bin(str_pad(str_repeat('1'$prefix), 128'0'STR_PAD_RIGHT));

        
// Calculate first and last address
        
$binary_first $binary_network $binary_mask;
        
$binary_last $binary_network | ~ $binary_mask;

        
// Convert binary addresses back to human readable strings
        
$first self::inet_ntop($binary_first);
        
$last self::inet_ntop($binary_last);

        if (
filter_var($networkFILTER_VALIDATE_IPFILTER_FLAG_IPV6)) {
            
$first self::expandIPv6Address($first);
            
$last self::expandIPv6Address($last);
        }

        
// Split addresses into segments
        
$first_array preg_split('/[\.\:]/'$first);
        
$last_array preg_split('/[\.\:]/'$last);

        
// Make sure arrays are the same size. IPv6 '::' could cause problems otherwise.
        // The strlen filter should leave zeros in place
        
$first_array array_pad(array_filter($first_array'strlen'), count($last_array), '0');

        
$range_segments = array();

        foreach (
$first_array as $index => $segment) {
            if (
$segment === $last_array[$index]) {
                
$range_segments[] = str_pad(ltrim($segment'0'), 1'0');
            } else if (
$segment === '' || $last_array[$index] === '') {
                
$range_segments[] = '';
            } else {
                
$range_segments[] = "["str_pad(ltrim($segment'0'), 1'0') . "-" .
                    
str_pad(ltrim($last_array[$index], '0'), 1'0') . "]";
            }
        }

        
$delimiter filter_var($networkFILTER_VALIDATE_IPFILTER_FLAG_IPV4) ? '.' ':';

        
$ip_range->setIPString(implode($delimiter$range_segments));

        return 
$ip_range;
    }

    
/**
     * Return dot notation of IPv4 address.
     *
     * @param int $ip
     * @return string|bool
     */
    
public static function inet_ntoa($ip) {
        
$long 4294967295 - ($ip 1);
        return 
long2ip(-$long);
    }

    
/**
     * Return string representation of 32 bit int of the IP address.
     *
     * @param string $ip
     * @return string
     */
    
public static function inet_aton($ip) {
        
$ip preg_replace('/(?<=^|\.)0+([1-9])/''$1'$ip);
        return 
sprintf("%u"ip2long($ip));
    }

    
/**
     * Return dot or colon notation of IPv4 or IPv6 address.
     *
     * @param string $ip
     * @return string|bool
     */
    
public static function inet_ntop($ip) {
        
// trim this to the IPv4 equiv if it's in the mapped range
        
if (strlen($ip) == 16 && substr($ip012) == "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff") {
            
$ip substr($ip124);
        }
        return 
self::hasIPv6Support() ? @inet_ntop($ip) : self::_inet_ntop($ip);
    }

    
/**
     * Return the packed binary string of an IPv4 or IPv6 address.
     *
     * @param string $ip
     * @return string
     */
    
public static function inet_pton($ip) {
        
// convert the 4 char IPv4 to IPv6 mapped version.
        
$pton str_pad(self::hasIPv6Support() ? @inet_pton($ip) : self::_inet_pton($ip), 16,
            
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00"STR_PAD_LEFT);
        return 
$pton;
    }

    
/**
     * Added compatibility for hosts that do not have inet_pton.
     *
     * @param $ip
     * @return bool|string
     */
    
public static function _inet_pton($ip) {
        
// IPv4
        
if (preg_match('/^(?:\d{1,3}(?:\.|$)){4}/'$ip)) {
            
$octets explode('.'$ip);
            
$bin chr($octets[0]) . chr($octets[1]) . chr($octets[2]) . chr($octets[3]);
            return 
$bin;
        }

        
// IPv6
        
if (preg_match('/^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/i'$ip)) {
            if (
$ip === '::') {
                return 
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
            }
            
$colon_count substr_count($ip':');
            
$dbl_colon_pos strpos($ip'::');
            if (
$dbl_colon_pos !== false) {
                
$ip str_replace('::'str_repeat(':0000',
                        ((
$dbl_colon_pos === || $dbl_colon_pos === strlen($ip) - 2) ? 8) - $colon_count) . ':'$ip);
                
$ip trim($ip':');
            }

            
$ip_groups explode(':'$ip);
            
$ipv6_bin '';
            foreach (
$ip_groups as $ip_group) {
                
$ipv6_bin .= pack('H*'str_pad($ip_group4'0'STR_PAD_LEFT));
            }

            return 
strlen($ipv6_bin) === 16 $ipv6_bin false;
        }

        
// IPv4 mapped IPv6
        
if (preg_match('/^(?:\:(?:\:0{1,4}){0,4}\:|(?:0{1,4}\:){5})ffff\:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i'$ip$matches)) {
            
$octets explode('.'$matches[1]);
            return 
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" chr($octets[0]) . chr($octets[1]) . chr($octets[2]) . chr($octets[3]);
        }

        return 
false;
    }

    
/**
     * Added compatibility for hosts that do not have inet_ntop.
     *
     * @param $ip
     * @return bool|string
     */
    
public static function _inet_ntop($ip) {
        
// IPv4
        
if (strlen($ip) === 4) {
            return 
ord($ip[0]) . '.' ord($ip[1]) . '.' ord($ip[2]) . '.' ord($ip[3]);
        }

        
// IPv6
        
if (strlen($ip) === 16) {

            
// IPv4 mapped IPv6
            
if (substr($ip012) == "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff") {
                return 
"::ffff:" ord($ip[12]) . '.' ord($ip[13]) . '.' ord($ip[14]) . '.' ord($ip[15]);
            }

            
$hex bin2hex($ip);
            
$groups str_split($hex4);
            
$in_collapse false;
            
$done_collapse false;
            foreach (
$groups as $index => $group) {
                if (
$group == '0000' && !$done_collapse) {
                    if (
$in_collapse) {
                        
$groups[$index] = '';
                        continue;
                    }
                    
$groups[$index] = ':';
                    
$in_collapse true;
                    continue;
                }
                if (
$in_collapse) {
                    
$done_collapse true;
                }
                
$groups[$index] = ltrim($groups[$index], '0');
                if (
strlen($groups[$index]) === 0) {
                    
$groups[$index] = '0';
                }
            }
            
$ip join(':'array_filter($groups'strlen'));
            
$ip str_replace(':::''::'$ip);
            return 
$ip == ':' '::' $ip;
        }

        return 
false;
    }

    
/**
     * Verify PHP was compiled with IPv6 support.
     *
     * Some hosts appear to not have inet_ntop, and others appear to have inet_ntop but are unable to process IPv6 addresses.
     *
     * @return bool
     */
    
public static function hasIPv6Support() {
        static 
$hasSupport null;
        if (
$hasSupport === null) {
            
$hasSupport defined('AF_INET6') && self::funcEnabled('inet_ntop') && self::funcEnabled('inet_pton');
        }
        return 
$hasSupport;
    }

    public static function 
hasLoginCookie(){
        if(isset(
$_COOKIE)){
            if(
is_array($_COOKIE)){
                foreach(
$_COOKIE as $key => $val){
                    if(
strpos($key'wordpress_logged_in') === 0){
                        return 
true;
                    }
                }
            }
        }
        return 
false;
    }
    public static function 
getBaseURL(){
        return 
plugins_url(''WORDFENCE_FCPATH) . '/';
    }
    public static function 
getPluginBaseDir(){
        if(
function_exists('wp_normalize_path')){ //Older WP versions don't have this func and we had many complaints before this check.
            
if(defined('WP_PLUGIN_DIR')) {
                return 
wp_normalize_path(WP_PLUGIN_DIR '/');
            }
            return 
wp_normalize_path(WP_CONTENT_DIR '/plugins/');
        } else {
            if(
defined('WP_PLUGIN_DIR')) {
                return 
WP_PLUGIN_DIR '/';
            }
            return 
WP_CONTENT_DIR '/plugins/';
        }
    }
    public static function 
makeRandomIP(){
        return 
rand(11,230) . '.' rand(0,255) . '.' rand(0,255) . '.' rand(0,255);
    }
    
    
/**
     * Converts a truthy value to a boolean, checking in this order:
     * - already a boolean
     * - is null => false
     * - numeric (0 => false, otherwise true)
     * - 'false', 'f', 'no', 'n', or 'off' => false
     * - 'true', 't', 'yes', 'y', or 'on' => true
     * - empty value => false, otherwise true
     * 
     * @param $value
     * @return bool
     */
    
public static function truthyToBoolean($value) {
        if (
$value === true || $value === false) {
            return 
$value;
        }
        
        if (
is_null($value)) {
            return 
false;
        }
        
        if (
is_numeric($value)) {
            return !!
$value;
        }
        
        if (
preg_match('/^(?:f(?:alse)?|no?|off)$/i'$value)) {
            return 
false;
        }
        else if (
preg_match('/^(?:t(?:rue)?|y(?:es)?|on)$/i'$value)) {
            return 
true;
        }
        
        return !empty(
$value);
    }
    
    
/**
     * Converts a truthy value to 1 or 0.
     * 
     * @see wfUtils::truthyToBoolean
     * 
     * @param $value
     * @return int
     */
    
public static function truthyToInt($value) {
        return 
self::truthyToBoolean($value) ? 0;
    }
    
    
/**
     * Returns the whitelist presets, which first grabs the bundled list and then merges the dynamic list into it.
     * 
     * @return array
     */
    
public static function whitelistPresets() {
        static 
$_cachedPresets null;
        if (
$_cachedPresets === null) {
            include(
dirname(__FILE__) . '/wfIPWhitelist.php'); /** @var array $wfIPWhitelist */
            
$currentPresets wfConfig::getJSON('whitelistPresets', array());
            if (
is_array($currentPresets)) {
                
$_cachedPresets array_merge($wfIPWhitelist$currentPresets);
            }
            else {
                
$_cachedPresets $wfIPWhitelist;
            }
        }
        return 
$_cachedPresets;
    }
    
    
/**
     * Returns an array containing all whitelisted service IPs/ranges. The returned array is grouped by service
     * tag: array('service1' => array('range1', 'range2', range3', ...), ...)
     * 
     * @param array|null $whitelistedServices If provided, use this service list for enabled/disabled resolution
     * @return array
     */
    
public static function whitelistedServiceIPs($whitelistedServices null) {
        
$result = array();
        
$whitelistPresets self::whitelistPresets();
        if (
$whitelistedServices === null) {
            
$whitelistedServices wfConfig::getJSON('whitelistedServices', array());
        }
        foreach (
$whitelistPresets as $tag => $preset) {
            if (!isset(
$preset['n'])) { //Just an array of IPs/ranges
                
$result[$tag] = $preset;
                continue;
            }
            
            if ((isset(
$preset['h']) && $preset['h']) || (isset($preset['f']) && $preset['f'])) { //Forced
                
$result[$tag] = $preset['r'];
                continue;
            }
            
            if ((!isset(
$whitelistedServices[$tag]) && isset($preset['d']) && $preset['d']) || (isset($whitelistedServices[$tag]) && $whitelistedServices[$tag])) {
                
$result[$tag] = $preset['r'];
            }
        }
        return 
$result;
    }

    
/**
     * Get the list of whitelisted IPs and networks, which is a combination of preset IPs/ranges and user-entered
     * IPs/ranges.
     *
     * @param string    $filter    Group name to filter whitelist by
     * @return array
     */
    
public static function getIPWhitelist($filter null) {
        static 
$wfIPWhitelist;

        if (!isset(
$wfIPWhitelist)) {
            
$wfIPWhitelist self::whitelistedServiceIPs();
            
            
//Append user ranges
            
$wfIPWhitelist['user'] = array();
            foreach (
array_filter(explode(','wfConfig::get('whitelisted'))) as $ip) {
                
$wfIPWhitelist['user'][] = new wfUserIPRange($ip);
            }
        }

        
$whitelist = array();
        foreach (
$wfIPWhitelist as $group => $values) {
            if (
$filter === null || $group === $filter) {
                
$whitelist array_merge($whitelist$values);
            }
        }

        return 
$whitelist;
    }

    
/**
     * @param string $addr Should be in dot or colon notation (127.0.0.1 or ::1)
     * @return bool
     */
    
public static function isPrivateAddress($addr) {
        
// Run this through the preset list for IPv4 addresses.
        
if (filter_var($addrFILTER_VALIDATE_IPFILTER_FLAG_IPV4) !== false) {
            foreach (
self::getIPWhitelist('private') as $a) {
                if (
self::subnetContainsIP($a$addr)) {
                    return 
true;
                }
            }
        }

        return 
filter_var($addrFILTER_VALIDATE_IPFILTER_FLAG_IPV4 FILTER_FLAG_IPV6) !== false
            
&& filter_var($addrFILTER_VALIDATE_IPFILTER_FLAG_IPV4 FILTER_FLAG_IPV6 FILTER_FLAG_NO_PRIV_RANGE FILTER_FLAG_NO_RES_RANGE) === false;
    }

    
/**
     * Expects an array of items. The items are either IP's or IP's separated by comma, space or tab. Or an array of IP's.
     * We then examine all IP's looking for a public IP and storing private IP's in an array. If we find no public IPs we return the first private addr we found.
     *
     * @param array $arr
     * @return bool|mixed
     */
    
private static function getCleanIP($arr){
        
$privates = array(); //Store private addrs until end as last resort.
        
for($i 0$i count($arr); $i++){
            
$item $arr[$i];
            if(
is_array($item)){
                foreach(
$item as $j){
                    
// try verifying the IP is valid before stripping the port off
                    
if (!self::isValidIP($j)) {
                        
$j preg_replace('/:\d+$/'''$j); //Strip off port
                    
}
                    if (
self::isValidIP($j)) {
                        if (
self::isPrivateAddress($j)) {
                            
$privates[] = $j;
                        } else {
                            return 
$j;
                        }
                    }
                }
                continue; 
//This was an array so we can skip to the next item
            
}
            
$skipToNext false;
            foreach(array(
','' '"\t") as $char){
                if(
strpos($item$char) !== false){
                    
$sp explode($char$item);
                    
$sp array_reverse($sp);
                    foreach(
$sp as $j){
                        
$j trim($j);
                        if (!
self::isValidIP($j)) {
                            
$j preg_replace('/:\d+$/'''$j); //Strip off port
                        
}
                        if(
self::isValidIP($j)){
                            if(
self::isPrivateAddress($j)){
                                
$privates[] = $j;
                            } else {
                                return 
$j;
                            }
                        }
                    }
                    
$skipToNext true;
                    break;
                }
            }
            if(
$skipToNext){ continue; } //Skip to next item because this one had a comma, space or tab so was delimited and we didn't find anything.

            
if (!self::isValidIP($item)) {
                
$item preg_replace('/:\d+$/'''$item); //Strip off port
            
}
            if(
self::isValidIP($item)){
                if(
self::isPrivateAddress($item)){
                    
$privates[] = $item;
                } else {
                    return 
$item;
                }
            }
        }
        if(
sizeof($privates) > 0){
            return 
$privates[0]; //Return the first private we found so that we respect the order the IP's were passed to this function.
        
} else {
            return 
false;
        }
    }

    
/**
     * Expects an array of items. The items are either IP's or IP's separated by comma, space or tab. Or an array of IP's.
     * We then examine all IP's looking for a public IP and storing private IP's in an array. If we find no public IPs we return the first private addr we found.
     *
     * @param array $arr
     * @return bool|mixed
     */
    
private static function getCleanIPAndServerVar($arr$trustedProxies null) {
        
$privates = array(); //Store private addrs until end as last resort.
        
for($i 0$i count($arr); $i++){
            list(
$item$var) = $arr[$i];
            if(
is_array($item)){
                foreach(
$item as $j){
                    
// try verifying the IP is valid before stripping the port off
                    
if (!self::isValidIP($j)) {
                        
$j preg_replace('/:\d+$/'''$j); //Strip off port
                    
}
                    if (
self::isValidIP($j)) {
                        if (
self::isIPv6MappedIPv4($j)) {
                            
$j self::inet_ntop(self::inet_pton($j));
                        }

                        if (
self::isPrivateAddress($j)) {
                            
$privates[] = array($j$var);
                        } else {
                            return array(
$j$var);
                        }
                    }
                }
                continue; 
//This was an array so we can skip to the next item
            
}
            
$skipToNext false;
            if (
$trustedProxies === null) {
                
$trustedProxies self::unifiedTrustedProxies();
            }
            foreach(array(
','' '"\t") as $char){
                if(
strpos($item$char) !== false){
                    
$sp explode($char$item);
                    
$sp array_reverse($sp);
                    foreach(
$sp as $index => $j){
                        
$j trim($j);
                        if (!
self::isValidIP($j)) {
                            
$j preg_replace('/:\d+$/'''$j); //Strip off port
                        
}
                        if(
self::isValidIP($j)){
                            if (
self::isIPv6MappedIPv4($j)) {
                                
$j self::inet_ntop(self::inet_pton($j));
                            }
                            
                            foreach (
$trustedProxies as $proxy) {
                                if (!empty(
$proxy)) {
                                    if (
self::subnetContainsIP($proxy$j) && $index count($sp) - 1) {
                                        continue 
2;
                                    }
                                }
                            }

                            if(
self::isPrivateAddress($j)){
                                
$privates[] = array($j$var);
                            } else {
                                return array(
$j$var);
                            }
                        }
                    }
                    
$skipToNext true;
                    break;
                }
            }
            if(
$skipToNext){ continue; } //Skip to next item because this one had a comma, space or tab so was delimited and we didn't find anything.

            
if (!self::isValidIP($item)) {
                
$item preg_replace('/:\d+$/'''$item); //Strip off port
            
}
            if(
self::isValidIP($item)){
                if (
self::isIPv6MappedIPv4($item)) {
                    
$item self::inet_ntop(self::inet_pton($item));
                }

                if(
self::isPrivateAddress($item)){
                    
$privates[] = array($item$var);
                } else {
                    return array(
$item$var);
                }
            }
        }
        if(
sizeof($privates) > 0){
            return 
$privates[0]; //Return the first private we found so that we respect the order the IP's were passed to this function.
        
} else {
            return 
false;
        }
    }
    
    
/**
     * Returns an array of all trusted proxies, combining both the user-entered ones and those from the selected preset.
     * 
     * @return string[]
     */
    
public static function unifiedTrustedProxies() {
        
$trustedProxies explode("\n"wfConfig::get('howGetIPs_trusted_proxies'''));
        
        
$preset wfConfig::get('howGetIPs_trusted_proxy_preset');
        
$presets wfConfig::getJSON('ipResolutionList', array());
        if (
is_array($presets) && isset($presets[$preset])) {
            
$testIPs array_merge($presets[$preset]['ipv4'], $presets[$preset]['ipv6']);
            foreach (
$testIPs as $val) {
                if (
strlen($val) > 0) {
                    if (
wfUtils::isValidIP($val) || wfUtils::isValidCIDRRange($val)) {
                        
$trustedProxies[] = $val;
                    }
                }
            }
        }
        return 
$trustedProxies;
    }

    
/**
     * @param string $ip
     * @return bool
     */
    
public static function isIPv6MappedIPv4($ip) {
        return 
preg_match('/^(?:\:(?:\:0{1,4}){0,4}\:|(?:0{1,4}\:){5})ffff\:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i'$ip) > 0;
    }

    public static function 
extractHostname($str){
        if(
preg_match('/https?:\/\/([a-zA-Z0-9\.\-]+)(?:\/|$)/i'$str$matches)){
            return 
strtolower($matches[1]);
        } else {
            return 
false;
        }
    }
    
    
/**
     * Returns the known server IPs, ordered by those as the best match for outgoing requests.
     * 
     * @param bool $refreshCache
     * @return string[]
     */
    
public static function serverIPs($refreshCache false) {
        static 
$cachedServerIPs null;
        if (isset(
$cachedServerIPs) && !$refreshCache) {
            return 
$cachedServerIPs;
        }
        
        
$serverIPs = array();
        
$storedIP wfConfig::get('serverIP');
        if (
preg_match('/^(\d+);(.+)$/'$storedIP$matches)) { //Format is 'timestamp;ip'
            
$serverIPs[] = $matches[2];
        }
        
        if (
function_exists('dns_get_record')) {
            
$storedDNS wfConfig::get('serverDNS');
            
$usingCache false;
            if (
preg_match('/^(\d+);(\d+);(.+)$/'$storedDNS$matches)) { //Format is 'timestamp;ttl;ip'
                
$timestamp $matches[1];
                
$ttl $matches[2];
                if (
$timestamp max($ttl86400) > time()) {
                    
$serverIPs[] = $matches[3];
                    
$usingCache true;
                }
            }
            
            if (!
$usingCache) {
                
$home get_home_url();
                if (
preg_match('/^https?:\/\/([^\/]+)/i'$home$matches)) {
                    
$host strtolower($matches[1]);
                    
$cnameRaw = @dns_get_record($hostDNS_CNAME);
                    
$cnames = array();
                    
$cnamesTargets = array();
                    if (
$cnameRaw && is_array($cnameRaw)) {
                        foreach (
$cnameRaw as $elem) {
                            if (
is_array($elem) && 
                                
array_key_exists('host'$elem) && 
                                
array_key_exists('target'$elem) && 
                                
$elem['host'] == $host
                            
) {
                                
$cnames[] = $elem;
                                
$cnamesTargets[] = $elem['target'];
                            }
                        }
                    }
                    
                    
$aRaw = @dns_get_record($hostDNS_A);
                    
$a = array();
                    if (
$aRaw && is_array($aRaw)) {
                        foreach (
$aRaw as $elem) {
                            if (
is_array($elem) && 
                                
array_key_exists('host'$elem) &&
                                
array_key_exists('ttl'$elem) &&
                                
array_key_exists('ip'$elem) &&
                                (
$elem['host'] == $host || in_array($elem['host'], $cnamesTargets))
                            ) {
                                
$a[] = $elem;
                            }
                        }
                    }
                    
                    
$firstA wfUtils::array_first($a);
                    if (
$firstA !== null) {
                        
$serverIPs[] = $firstA['ip'];
                        
wfConfig::set('serverDNS'time() . ';' $firstA['ttl'] . ';' $firstA['ip']);
                    }
                }
            }
        }
        
        if (isset(
$_SERVER['SERVER_ADDR']) && wfUtils::isValidIP($_SERVER['SERVER_ADDR'])) {
            
$serverIPs[] = $_SERVER['SERVER_ADDR'];
        }
        
        
$serverIPs array_unique($serverIPs);
        
$cachedServerIPs $serverIPs;
        return 
$serverIPs;
    }
    
    public static function 
getIP($refreshCache false) {
        static 
$theIP null;
        if (isset(
$theIP) && !$refreshCache) {
            return 
$theIP;
        }
        
//For debugging. 
        //return '54.232.205.132';
        //return self::makeRandomIP();

        // if no REMOTE_ADDR, it's probably running from the command line
        
$ip self::getIPAndServerVariable();
        if (
is_array($ip)) {
            list(
$IP$variable) = $ip;
            
$theIP $IP;
            return 
$IP;
        }
        return 
false;
    }
    
    public static function 
getIPForField($field$trustedProxies null) {
        
$ip self::getIPAndServerVariable($field$trustedProxies);
        if (
is_array($ip)) {
            list(
$IP$variable) = $ip;
            return 
$IP;
        }
        return 
false;
    }

    public static function 
getAllServerVariableIPs()
    {
        
$variables = array('REMOTE_ADDR''HTTP_CF_CONNECTING_IP''HTTP_X_REAL_IP''HTTP_X_FORWARDED_FOR');
        
$ips = array();

        foreach (
$variables as $variable) {
            
$ip = isset($_SERVER[$variable]) ? $_SERVER[$variable] : false;

            if (
$ip && strpos($ip',') !== false) {
                
$ips[$variable] = preg_replace('/[\s,]/'''explode(','$ip));
            } else {
                
$ips[$variable] = $ip;
            }
        }

        return 
$ips;
    }

    public static function 
getIPAndServerVariable($howGet null$trustedProxies null) {
        
$connectionIP array_key_exists('REMOTE_ADDR'$_SERVER) ? array($_SERVER['REMOTE_ADDR'], 'REMOTE_ADDR') : array('127.0.0.1''REMOTE_ADDR');

        if (
$howGet === null) {
            
$howGet wfConfig::get('howGetIPs'false);
        }
        
        if(
$howGet){
            if(
$howGet == 'REMOTE_ADDR'){
                return 
self::getCleanIPAndServerVar(array($connectionIP), $trustedProxies);
            } else {
                
$ipsToCheck = array(
                    array((isset(
$_SERVER[$howGet]) ? $_SERVER[$howGet] : ''), $howGet),
                    
$connectionIP,
                );
                return 
self::getCleanIPAndServerVar($ipsToCheck$trustedProxies);
            }
        } else {
            
$ipsToCheck = array();
            
            
$recommendedField wfConfig::get('detectProxyRecommendation'''); //Prioritize the result from our proxy check if done
            
if (!empty($recommendedField) && $recommendedField != 'UNKNOWN' && $recommendedField != 'DEFERRED') {
                if (isset(
$_SERVER[$recommendedField])) {
                    
$ipsToCheck[] = array($_SERVER[$recommendedField], $recommendedField);
                }
            }
            
$ipsToCheck[] = $connectionIP;
            if (isset(
$_SERVER['HTTP_X_FORWARDED_FOR'])) {
                
$ipsToCheck[] = array($_SERVER['HTTP_X_FORWARDED_FOR'], 'HTTP_X_FORWARDED_FOR');
            }
            if (isset(
$_SERVER['HTTP_X_REAL_IP'])) {
                
$ipsToCheck[] = array($_SERVER['HTTP_X_REAL_IP'], 'HTTP_X_REAL_IP');
            }
            return 
self::getCleanIPAndServerVar($ipsToCheck$trustedProxies);
        }
        return 
false//Returns an array with a valid IP and the server variable, or false.
    
}
    public static function 
getIPPreview($howGet null$trustedProxies null) {
        
$ip self::getIPAndServerVariable($howGet$trustedProxies);
        if (
is_array($ip)) {
            list(
$IP$variable) = $ip;
            if (isset(
$_SERVER[$variable]) && strpos($_SERVER[$variable], ',') !== false) {
                
$items preg_replace('/[\s,]/'''explode(','$_SERVER[$variable]));
                
$output '';
                foreach (
$items as $i) {
                    if (
$IP == $i) {
                        
$output .= ', <strong>' esc_html($i) . '</strong>';
                    }
                    else {
                        
$output .= ', ' esc_html($i); 
                    }
                }
                
                return 
substr($output2);
            }
            return 
'<strong>' esc_html($IP) . '</strong>';
        }
        return 
false;
    }
    public static function 
isValidIP($IP){
        return 
filter_var($IPFILTER_VALIDATE_IP) !== false;
    }
    public static function 
isValidCIDRRange($range) {
        
$components explode('/'$range);
        if (
count($components) != 2) { return false; }
        
        list(
$ip$prefix) = $components;
        if (!
self::isValidIP($ip)) { return false; }
        
        if (!
preg_match('/^\d+$/'$prefix)) { return false; }
        
        if (
filter_var($ipFILTER_VALIDATE_IPFILTER_FLAG_IPV4)) {
            if (
$prefix || $prefix 32) { return false; }
        }
        else {
            if (
$prefix || $prefix 128) { return false; }
        }
        
        return 
true;
    }
    public static function 
isValidEmail($email$strict false) {
        if (empty(
$email)) {
            return 
false;
        }
        
        
//We don't default to strict, full validation because poorly-configured servers can crash due to the regex PHP uses in filter_var($email, FILTER_VALIDATE_EMAIL)
        
if ($strict) {
            return (
filter_var($emailFILTER_VALIDATE_EMAIL) !== false);
        }
        
        return 
preg_match('/^[^@\s]+@[^@\s]+\.[^@\s]+$/i'$email) === 1;
    }
    public static function 
getRequestedURL() {
        if (isset(
$_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST']) {
            
$host $_SERVER['HTTP_HOST'];
        } else if (isset(
$_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME']) {
            
$host $_SERVER['SERVER_NAME'];
        }
        else {
            return 
null;
        }
        
$prefix 'http';
        if (
is_ssl()) {
            
$prefix 'https';
        }
        return 
$prefix '://' $host $_SERVER['REQUEST_URI'];
    }

    public static function 
editUserLink($userID){
        return 
get_admin_url() . 'user-edit.php?user_id=' $userID;
    }
    public static function 
tmpl($file$data){
        
extract($data);
        
ob_start();
        include 
dirname(__FILE__) . DIRECTORY_SEPARATOR $file;
        return 
ob_get_contents() . (ob_end_clean() ? "" "");
    }
    public static function 
bigRandomHex(){
        return 
bin2hex(wfWAFUtils::random_bytes(16));
    }
    public static function 
encrypt($str){
        
$key wfConfig::get('encKey');
        if(! 
$key){
            
wordfence::status(1'error'__("Wordfence error: No encryption key found!"'wordfence'));
            return 
false;
        }
        
$db = new wfDB();
        return 
$db->querySingle("select HEX(AES_ENCRYPT('%s', '%s')) as val"$str$key);
    }
    public static function 
decrypt($str){
        
$key wfConfig::get('encKey');
        if(! 
$key){
            
wordfence::status(1'error'__("Wordfence error: No encryption key found!"'wordfence'));
            return 
false;
        }
        
$db = new wfDB();
        return 
$db->querySingle("select AES_DECRYPT(UNHEX('%s'), '%s') as val"$str$key);
    }
    public static function 
lcmem(){
        
$trace=debug_backtrace();
        
$caller=array_shift($trace);
        
$mem memory_get_usage(true);
        
error_log("$mem at " $caller['file'] . " line " $caller['line']);
    }
    public static function 
logCaller(){
        
$trace=debug_backtrace();
        
$caller=array_shift($trace);
        
$c2 array_shift($trace);
        
error_log("Caller for " $caller['file'] . " line " $caller['line'] . " is " $c2['file'] . ' line ' $c2['line']);
    }
    public static function 
getWPVersion($forceRecheck false){
        if (
$forceRecheck) {
            require(
ABSPATH 'wp-includes/version.php'); //defines $wp_version
            
return $wp_version;
        }
        
        if(
wordfence::$wordfence_wp_version){
            return 
wordfence::$wordfence_wp_version;
        } else {
            global 
$wp_version;
            return 
$wp_version;
        }
    }
    
    public static function 
parse_version($version$component null) {
        
$major 0;
        
$minor 0;
        
$patch 0;
        
$prerelease '';
        
$build '';
        
        if (
preg_match('/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/'$version$matches)) { //semver
            
$major $matches[1];
            
$minor $matches[2];
            
$patch $matches[3];
            
            if (
preg_match('/^([^\+]+)\+(.*)$/'$version$matches)) {
                
$version $matches[1];
                
$build $matches[2];
            }
            
            if (
preg_match('/^([^\-]+)\-(.*)$/'$version$matches)) {
                
$version $matches[1];
                
$prerelease $matches[2];
            }
        }
        else { 
//Parse as "PHP-standardized" (see version_compare docs: "The function first replaces _, - and + with a dot . in the version strings and also inserts dots . before and after any non number so that for example '4.3.2RC1' becomes '4.3.2.RC.1'.")
            
$version trim(preg_replace('/\.\.+/''.'preg_replace('/([^0-9\.]+)/''.$1.'preg_replace('/[_\-\+]+/''.'$version))), '.');
            
$components explode('.'$version);
            
$i 0;
            if (isset(
$components[$i]) && is_numeric($components[$i])) { $major $components[$i]; $i++; }
            if (isset(
$components[$i]) && is_numeric($components[$i])) { $minor $components[$i]; $i++; }
            if (isset(
$components[$i]) && is_numeric($components[$i])) { $patch $components[$i]; $i++; }
            while (isset(
$components[$i]) && is_numeric($components[$i])) {
                if (!empty(
$build)) {
                    
$build .= '.';
                }
                
$build .= $components[$i];
                
$i++;
            }
            while (isset(
$components[$i])) {
                if (!empty(
$prerelease)) {
                    
$prerelease .= '.';
                }
                
                if (
preg_match('/^(?:dev|alpha|a|beta|b|rc|#|pl|p)$/i'$components[$i])) {
                    
$prerelease .= strtolower($components[$i]);
                    if (isset(
$components[$i 1])) {
                        if (!
preg_match('/^(?:a|b|rc|#|pl|p)$/i'$components[$i])) {
                            
$prerelease .= '-';
                        }
                        
$i++;
                    }
                }
                
                
$prerelease .= $components[$i];
                
$i++;
            }
        }
        
        
$version = array(
            
self::VERSION_MAJOR => $major,
            
self::VERSION_MINOR => $minor,
            
self::VERSION_PATCH => $patch,
            
self::VERSION_PRE_RELEASE => $prerelease,
            
self::VERSION_BUILD => $build,
        );
        
        
$version array_filter($version, function($v) {
            return 
$v !== '';
        });
        
        if (
$component === null) {
            return 
$version;
        }
        else if (isset(
$version[$component])) {
            return 
$version[$component];
        }
        
        return 
null;
    }
    
    public static function 
isAdminPageMU(){
        if(
preg_match('/^[\/a-zA-Z0-9\-\_\s\+\~\!\^\.]*\/wp-admin\/network\//'$_SERVER['REQUEST_URI'])){
            return 
true;
        }
        return 
false;
    }
    public static function 
getSiteBaseURL(){
        return 
rtrim(site_url(), '/') . '/';
    }
    public static function 
longestLine($data){
        
$lines preg_split('/[\r\n]+/'$data);
        
$max 0;
        foreach(
$lines as $line){
            
$len strlen($line);
            if(
$len $max){
                
$max $len;
            }
        }
        return 
$max;
    }
    public static function 
longestNospace($data){
        
$lines preg_split('/[\r\n\s\t]+/'$data);
        
$max 0;
        foreach(
$lines as $line){
            
$len strlen($line);
            if(
$len $max){
                
$max $len;
            }
        }
        return 
$max;
    }
    
    
/**
     * Returns the current PHP memory limit in bytes.
     * 
     * Note: This is duplicated in wordfence.php to avoid needing to include this class early.
     * 
     * @return int
     */
    
public static function memoryLimit() {
        
$maxMemory ini_get('memory_limit');
        if (!(
is_string($maxMemory) || is_numeric($maxMemory)) || !preg_match('/^\s*\d+[GMK]?\s*$/i'$maxMemory)) { $maxMemory '128M'; } //Invalid or unreadable value, default to our minimum
        
$last strtolower(substr($maxMemory, -1));
        
$maxMemory = (int) $maxMemory;
        
        if (
$last == 'g') { $maxMemory $maxMemory 1024 1024 1024; }
        else if (
$last == 'm') { $maxMemory $maxMemory 1024 1024; }
        else if (
$last == 'k') { $maxMemory $maxMemory 1024; }
        return 
floor($maxMemory);
    }
    
    public static function 
requestMaxMemory() {
        
$maxMem wfConfig::getInt('maxMem'256);
        if (
$maxMem <= 0) {
            
$maxMem 256;
        }
        
        if (
self::funcEnabled('memory_get_usage') && self::memoryLimit() < ($maxMem 1024 1024)){
            
self::iniSet('memory_limit'$maxMem 'M');
        }
    }
    
    public static function 
isAdmin($user false){
        if(
$user){
            if(
is_multisite()){
                if(
user_can($user'manage_network')){
                    return 
true;
                }
            } else {
                if(
user_can($user'manage_options')){
                    return 
true;
                }
            }
        } else {
            if(
is_multisite()){
                if(
current_user_can('manage_network')){
                    return 
true;
                }
            } else {
                if(
current_user_can('manage_options')){
                    return 
true;
                }
            }
        }
        return 
false;
    }
    public static function 
hasTwoFactorEnabled($user false) {
        if (!
$user) {
            
$user get_user_by('ID'get_current_user_id());
        }
        
        if (!
$user) {
            return 
false;
        }
        
        
$twoFactorUsers wfConfig::get_ser('twoFactorUsers', array());
        
$hasActivatedTwoFactorUser false;
        foreach (
$twoFactorUsers as &$t) {
            if (
$t[3] == 'activated') {
                
$userID $t[0];
                if (
$userID == $user->ID && wfUtils::isAdmin($user)) {
                    
$hasActivatedTwoFactorUser true;
                }
            }
        }
        
        return 
$hasActivatedTwoFactorUser;
    }
    public static function 
isWindows(){
        if(! 
self::$isWindows){
            if(
preg_match('/^win/i'PHP_OS)){
                
self::$isWindows 'yes';
            } else {
                
self::$isWindows 'no';
            }
        }
        return 
self::$isWindows == 'yes' true false;
    }
    public static function 
cleanupOneEntryPerLine($string) {
        
$string = !is_string($string) ? '' $string;
        
$string str_replace(",""\n"$string); // fix old format
        
return implode("\n"array_unique(array_filter(array_map('trim'explode("\n"$string)))));
    }

    public static function 
afterProcessingFile() {
        if (
wfScanner::shared()->useLowResourceScanning()) {
            
usleep(10000); //10 ms
        
}
    }

    public static function 
getScanLock(){
        
//Windows does not support non-blocking flock, so we use time.
        
$scanRunning wfConfig::get('wf_scanRunning');
        if(
$scanRunning && time() - $scanRunning WORDFENCE_MAX_SCAN_LOCK_TIME){
            return 
false;
        }
        
wfConfig::set('wf_scanRunning'time());
        return 
true;
    }
    public static function 
clearScanLock(){
        global 
$wpdb;
        
$wfdb = new wfDB();
        
$wfdb->truncate(wfDB::networkTable('wfHoover'));

        
wfConfig::set('wf_scanRunning''');
        
wfIssues::updateScanStillRunning(false);
        if (
wfCentral::isConnected()) {
            
wfCentral::updateScanStatus();
        }
    }
    public static function 
getIPGeo($IP){ //Works with int or dotted

        
$locs self::getIPsGeo(array($IP));
        if(isset(
$locs[$IP])){
            return 
$locs[$IP];
        } else {
            return 
false;
        }
    }
    public static function 
getIPsGeo($IPs){ //works with int or dotted. Outputs same format it receives.
        
$IPs array_unique($IPs);
        
$toResolve = array();
        
$db = new wfDB();
        
$locsTable wfDB::networkTable('wfLocs');
        
$IPLocs = array();
        foreach(
$IPs as $IP){
            
$isBinaryIP = !self::isValidIP($IP);
            if (
$isBinaryIP) {
                
$ip_printable wfUtils::inet_ntop($IP);
                
$ip_bin $IP;
            } else {
                
$ip_printable $IP;
                
$ip_bin wfUtils::inet_pton($IP);
            }
            
            
$ipHex wfDB::binaryValueToSQLHex($ip_bin);
            
$row $db->querySingleRec("select IP, ctime, failed, city, region, countryName, countryCode, lat, lon, unix_timestamp() - ctime as age from " $locsTable " where IP={$ipHex}");
            if(
$row){
                if(
$row['age'] > WORDFENCE_MAX_IPLOC_AGE){
                    
$ipHex wfDB::binaryValueToSQLHex($row['IP']);
                    
$db->queryWrite("delete from " $locsTable " where IP={$ipHex}");
                } else {
                    if(
$row['failed'] == 1){
                        
$IPLocs[$ip_printable] = false;
                    } else {
                        
$row['IP'] = self::inet_ntop($row['IP']);
                        
$row['region'] = wfUtils::shouldDisplayRegion($row['countryName']) ? $row['region'] : '';
                        
$IPLocs[$ip_printable] = $row;
                    }
                }
            }
            if(! isset(
$IPLocs[$ip_printable])){
                
$toResolve[] = $ip_printable;
            }
        }
        if(
sizeof($toResolve) > 0){
            if (
wfConfig::get('enableRemoteIpLookup'true)) {
                
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
                try {
                    
$freshIPs $api->call('resolve_ips', array(), array(
                        
'ips' => implode(','$toResolve)
                        ));
                } catch(
Exception $e){
                    
wordfence::status(2'error'sprintf(/* translators: Error message. */ __("Call to Wordfence API to resolve IPs failed: %s"'wordfence'), $e->getMessage()));
                    return array();
                }
            }
            else {
                require_once(
__DIR__ '/wfIpLocator.php');
                
$locator wfIpLocator::getInstance();
                
$freshIPs = array();
                
$locale get_locale();
                foreach (
$toResolve as $ip) {
                    
$record $locator->locate($ip);
                    if (
$record !== null) {
                        
$countryCode $record->getCountryCode();
                        if (
$countryCode !== null) {
                            
$countryName $record->getCountryName($locale);
                            if (
$countryName === null)
                                
$countryName $countryCode;
                            
$freshIPs[$ip] = array($countryCode$countryName);
                            continue;
                        }
                    }
                    
$freshIPs[$ip] = 'failed';
                }
            }
            if(
is_array($freshIPs)){
                foreach(
$freshIPs as $IP => $value){
                    
$IP_bin wfUtils::inet_pton($IP);
                    
$ipHex wfDB::binaryValueToSQLHex($IP_bin);
                    if(
$value == 'failed'){
                        
$db->queryWrite("insert IGNORE into " $locsTable " (IP, ctime, failed) values ({$ipHex}, unix_timestamp(), 1)");
                        
$IPLocs[$IP] = false;
                    } else if(
is_array($value)){
                        for(
$i 0$i <= 5$i++){
                            
//Prevent warnings in debug mode about uninitialized values
                            
if(! isset($value[$i])){ $value[$i] = ''; }
                        }
                        
$db->queryWrite("insert IGNORE into " $locsTable " (IP, ctime, failed, city, region, countryName, countryCode, lat, lon) values ({$ipHex}, unix_timestamp(), 0, '%s', '%s', '%s', '%s', %s, %s)",
                            
$value[3], //city
                            
$value[2], //region
                            
$value[1], //countryName
                            
$value[0],//countryCode
                            
$value[4],//lat
                            
$value[5]//lon
                            
);
                        
$IPLocs[$IP] = array(
                            
'IP' => $IP,
                            
'city' => $value[3],
                            
'region' => wfUtils::shouldDisplayRegion($value[1]) ? $value[2] : '',
                            
'countryName' => $value[1],
                            
'countryCode' => $value[0],
                            
'lat' => $value[4],
                            
'lon' => $value[5]
                            );
                    }
                }
            }
        }
        return 
$IPLocs;
    }

    public static function 
reverseLookup($IP) {
        static 
$_memoryCache = array();
        if (isset(
$_memoryCache[$IP])) {
            return 
$_memoryCache[$IP];
        }
        
        
$db = new wfDB();
        
$reverseTable wfDB::networkTable('wfReverseCache');
        
$IPn wfUtils::inet_pton($IP);
        
$ipHex wfDB::binaryValueToSQLHex($IPn);
        
$host $db->querySingle("select host from " $reverseTable " where IP={$ipHex} and unix_timestamp() - lastUpdate < %d"WORDFENCE_REVERSE_LOOKUP_CACHE_TIME);
        if (!
$host) {
            
// This function works for IPv4 or IPv6
            
if (function_exists('gethostbyaddr')) {
                
$host = @gethostbyaddr($IP);
            }
            if (!
$host) {
                
$ptr false;
                if (
filter_var($IPFILTER_VALIDATE_IPFILTER_FLAG_IPV4) !== false) {
                    
$ptr implode("."array_reverse(explode("."$IP))) . ".in-addr.arpa";
                } else if (
filter_var($IPFILTER_VALIDATE_IPFILTER_FLAG_IPV6) !== false) {
                    
$ptr implode("."array_reverse(str_split(bin2hex($IPn)))) . ".ip6.arpa";
                }

                if (
$ptr && function_exists('dns_get_record')) {
                    
$host = @dns_get_record($ptrDNS_PTR);
                    if (
$host && is_array($host) && count($host)) {
                        
$host wfUtils::array_get($host[0], 'target');
                    }
                }
            }
            
$_memoryCache[$IP] = $host;
            if (!
$host) {
                
$host 'NONE';
            }
            
$db->queryWrite("insert into " $reverseTable " (IP, host, lastUpdate) values ({$ipHex}, '%s', unix_timestamp()) ON DUPLICATE KEY UPDATE host='%s', lastUpdate=unix_timestamp()"$host$host);
        }
        if (
$host == 'NONE') {
            
$_memoryCache[$IP] = '';
            return 
'';
        } else {
            
$_memoryCache[$IP] = $host;
            return 
$host;
        }
    }
    public static function 
errorsOff(){
        
self::$lastErrorReporting = @ini_get('error_reporting');
        @
error_reporting(0);
        
self::$lastDisplayErrors = @ini_get('display_errors');
        
self::iniSet('display_errors'0);
        if(
class_exists('wfScan')){ wfScan::$errorHandlingOn false; }
    }
    public static function 
errorsOn(){
        @
error_reporting(self::$lastErrorReporting);
        
self::iniSet('display_errors'self::$lastDisplayErrors);
        if(
class_exists('wfScan')){ wfScan::$errorHandlingOn true; }
    }
    
//Note this function may report files that are too big which actually are not too big but are unseekable and throw an error on fseek(). But that's intentional
    
public static function fileTooBig($file, &$size false, &$handle false){ //Deals with files > 2 gigs on 32 bit systems which are reported with the wrong size due to integer overflow
        
if (!@is_file($file) || !@is_readable($file)) { return false; } //Only apply to readable files
        
wfUtils::errorsOff();
        
$fh = @fopen($file'rb');
        
wfUtils::errorsOn();
        if(! 
$fh){ return false; }
        try {
            if(@
fseek($fhWORDFENCE_MAX_FILE_SIZE_OFFSETSEEK_SET) === && !empty(fread($fh1))){
                return 
true;
            } 
//Otherwise we couldn't seek there so it must be smaller
            
if ($size !== false && @fseek($fh0SEEK_END) === 0) {
                
$size = @ftell($fh);
                if (
$size === false)
                    
$size 0// Assume 0 if unable to determine file size
            
}
            return 
false;
        } catch(
Exception $e){
            return 
true//If we get an error don't scan this file, report it's too big.
        
} finally {
            if (
$handle === false) {
                
fclose($fh);
            }
            else {
                
$handle $fh;
            }
        }
    }
    public static function 
fileOver2Gigs($file){ //Surround calls to this func with try/catch because fseek may throw error.
        
$fh = @fopen($file'rb');
        if(! 
$fh){ return false; }
        
$offset 2147483647;
        
$tooBig false;
        
//My throw an error so surround calls to this func with try/catch
        
if(@fseek($fh$offsetSEEK_SET) === 0){
            if(
strlen(fread($fh1)) === 1){
                
$tooBig true;
            }
        } 
//Otherwise we couldn't seek there so it must be smaller
        
@fclose($fh);
        return 
$tooBig;
    }
    public static function 
countryCode2Name($code){
        require(
dirname(__FILE__) . '/wfBulkCountries.php'); /** @var array $wfBulkCountries */
        
if(isset($wfBulkCountries[$code])){
            return 
$wfBulkCountries[$code];
        } else {
            return 
'';
        }
    }
    public static function 
shouldDisplayRegion($country) {
        
$countries_to_show_for = array('united states''canada''australia');
        return 
in_array(strtolower($country), $countries_to_show_for);
    }
    public static function 
extractBareURI($URL){
        
$URL preg_replace('/^https?:\/\/[^\/]+/i'''$URL); //strip of method and host
        
$URL preg_replace('/\#.*$/'''$URL); //strip off fragment
        
$URL preg_replace('/\?.*$/'''$URL); //strip off query string
        
return $URL;
    }
    public static function 
requireIpLocator() {
        
/**
         * This is also used in the WAF so in certain site setups (i.e. nested sites in subdirectories)
         * it's possible for this to already have been loaded from a different installation of the
         * plugin and hence require_once doesn't help as it's a different file path. There is no guarantee
         * that the two plugin installations are the same version, so should the wfIpLocator class or any
         * of its dependencies change in a manner that is not backwards compatible, this may need to be
         * handled differently.
         */
        
if (!class_exists('wfIpLocator'))
            require_once(
__DIR__ '/wfIpLocator.php');
    }
    public static function 
IP2Country($ip){
        
self::requireIpLocator();
        return 
wfIpLocator::getInstance()->getCountryCode($ip);
    }
    public static function 
geoIPVersion() {
        
self::requireIpLocator();
        
$version wfIpLocator::getInstance()->getDatabaseVersion();
        return 
$version === null $version;
    }
    public static function 
siteURLRelative(){
        if(
is_multisite()){
            
$URL network_site_url();
        } else {
            
$URL site_url();
        }
        
$URL preg_replace('/^https?:\/\/[^\/]+/i'''$URL);
        
$URL rtrim($URL'/') . '/';
        return 
$URL;
    }
    public static function 
localHumanDate(){
        return 
date('l jS \of F Y \a\t h:i:s A'time() + (3600 get_option('gmt_offset')));
    }
    public static function 
localHumanDateShort(){
        return 
date('D jS F \@ h:i:sA'time() + (3600 get_option('gmt_offset')));
    }
    public static function 
funcEnabled($func){
        if (!
function_exists($func)){ return false; }
        if (!
is_callable($func)) { return false; }
        
$disabled explode(','ini_get('disable_functions'));
        if (
in_array($func$disabled)) {
            return 
false;
        }
        return 
true;
    }
    public static function 
iniSet($key$val){
        if(
self::funcEnabled('ini_set')){
            @
ini_set($key$val);
        }
    }
    public static function 
doNotCache(){
        
header("Pragma: no-cache");
        
header("Cache-Control: no-cache, must-revalidate, private, max-age=0");
        
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); //In the past
        
if(! defined('DONOTCACHEPAGE')){ define('DONOTCACHEPAGE'true); }
        if(! 
defined('DONOTCACHEDB')){ define('DONOTCACHEDB'true); }
        if(! 
defined('DONOTCDN')){ define('DONOTCDN'true); }
        if(! 
defined('DONOTCACHEOBJECT')){ define('DONOTCACHEOBJECT'true); }
        
wfCache::doNotCache();
    }
    public static function 
isUABlocked($uaPattern){ // takes a pattern using asterisks as wildcards, turns it into regex and checks it against the visitor UA returning true if blocked
        
return fnmatch($uaPattern, !empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''FNM_CASEFOLD);
    }
    public static function 
isRefererBlocked($refPattern){
        return 
fnmatch($refPattern, !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''FNM_CASEFOLD);
    }
    
    public static function 
error_clear_last() {
        if (
function_exists('error_clear_last')) {
            
error_clear_last();
        }
        else {
            
// set error_get_last() to defined state by forcing an undefined variable error
            
set_error_handler('wfUtils::_resetErrorsHandler'0);
            @
$undefinedVariable;
            
restore_error_handler();
        }
    }
    
    
/**
     * Logs the error given or the last PHP error to our log, rate limiting if needed.
     * 
     * @param string $limiter_key
     * @param string $label
     * @param null|string $error The error to log. If null, it will be the result of error_get_last
     * @param int $rate Logging will only occur once per $rate seconds.
     */
    
public static function check_and_log_last_error($limiter_key$label$error null$rate 3600 /* 1 hour */) {
        if (
$error === null) {
            
$error error_get_last();
            if (
$error === null) {
                return;
            }
            else if (
$error['file'] === __FILE__) {
                return;
            }
            
$error $error['message'];
        }
        
        
$rateKey 'lastError_rate_' $limiter_key;
        
$previousKey 'lastError_prev_' $limiter_key;
        
$previousError wfConfig::getJSON($previousKey, array(0false));
        if (
$previousError[1] != $error) {
            if (
wfConfig::getInt($rateKey) < time() - $rate) {
                
wfConfig::set($rateKeytime());
                
wfConfig::setJSON($previousKey, array(time(), $error));
                
wordfence::status(2'error'$label ' ' $error);
            }
        }
    }
    
    public static function 
last_error($limiter_key) {
        
$previousKey 'lastError_prev_' $limiter_key;
        
$previousError wfConfig::getJSON($previousKey, array(0false));
        if (
$previousError[1]) {
            return 
wfUtils::formatLocalTime(get_option('date_format') . ' ' get_option('time_format'), $previousError[0]) . ': ' $previousError[1];
        }
        return 
false;
    }
    
    public static function 
_resetErrorsHandler($errno$errstr$errfile$errline) {
        
//Do nothing
    
}

    
/**
     * @param $startIP
     * @param $endIP
     * @return array
     */
    
public static function rangeToCIDRs($startIP$endIP){
        
$start_ip_printable wfUtils::inet_ntop($startIP);
        if (
filter_var($start_ip_printableFILTER_VALIDATE_IPFILTER_FLAG_IPV4)) {
            return 
self::rangeToCIDRsIPv4(current(unpack('N'substr($startIP124))), current(unpack('N'substr($endIP124))));
        }
        
$startIPBin str_pad(wfHelperBin::bin2str($startIP), 128'0'STR_PAD_LEFT);
        
$endIPBin str_pad(wfHelperBin::bin2str($endIP), 128'0'STR_PAD_LEFT);
        
$IPIncBin $startIPBin;
        
$CIDRs = array();
        while (
strcmp($IPIncBin$endIPBin) <= 0) {
            
$longNetwork 128;
            
$IPNetBin $IPIncBin;
            while ((
$IPIncBin[$longNetwork 1] == '0') && (strcmp(substr_replace($IPNetBin'1'$longNetwork 11), $endIPBin) <= 0)) {
                
$IPNetBin[$longNetwork 1] = '1';
                
$longNetwork--;
            }
            
$CIDRs[] = self::inet_ntop(str_pad(wfHelperBin::str2bin($IPIncBin), 16"\x00"STR_PAD_LEFT)) . ($longNetwork 128 '/' $longNetwork '');
            
$IPIncBin str_pad(wfHelperBin::bin2str(wfHelperBin::addbin2bin(chr(1), wfHelperBin::str2bin($IPNetBin))), 128'0'STR_PAD_LEFT);
        }
        return 
$CIDRs;
    }

    public static function 
rangeToCIDRsIPv4($startIP$endIP){
        
$startIPBin sprintf('%032b'$startIP);
        
$endIPBin sprintf('%032b'$endIP);
        
$IPIncBin $startIPBin;
        
$CIDRs = array();
        while(
strcmp($IPIncBin$endIPBin) <= 0){
            
$longNetwork 32;
            
$IPNetBin $IPIncBin;
            while((
$IPIncBin[$longNetwork 1] == '0') && (strcmp(substr_replace($IPNetBin'1'$longNetwork 11), $endIPBin) <= 0)){
                
$IPNetBin[$longNetwork 1] = '1';
                
$longNetwork--;
            }
            
$CIDRs[] = long2ip(bindec($IPIncBin)) . ($longNetwork 32 '/' $longNetwork '');
            
$IPIncBin sprintf('%032b'bindec($IPNetBin) + 1);
        }
        return 
$CIDRs;
    }
    
    
/**
     * This is a convenience function for sending a JSON response and ensuring that execution stops after sending
     * since wp_die() can be interrupted.
     * 
     * @param $response
     * @param int|null $status_code
     */
    
public static function send_json($response$status_code null) {
        
wp_send_json($response$status_code);
        die();
    }

    public static function 
setcookie($name$value ''$expire 0$path ''$domain ''$secure false$httpOnly false) {
        if (empty(
$path)) { $path COOKIEPATH; }
        if (empty(
$domain)) { $domain COOKIE_DOMAIN; }
        if (
version_compare(PHP_VERSION'5.2.0') >= 0) {
            
setcookie($name$value$expire$path$domain$secure$httpOnly);
        }
        else {
            
setcookie($name$value$expire$path);
        }
    }
    public static function 
isNginx(){
        
$sapi php_sapi_name();
        
$serverSoft $_SERVER['SERVER_SOFTWARE'];
        if(
$sapi == 'fpm-fcgi' && stripos($serverSoft'nginx') !== false){
            return 
true;
        }
    }
    public static function 
getLastError(){
        
$err error_get_last();
        if(
is_array($err)){
            return 
$err['message'];
        }
        return 
'';
    }
    public static function 
hostNotExcludedFromProxy($url){
        if(! 
defined('WP_PROXY_BYPASS_HOSTS')){
            return 
true//No hosts are excluded
        
}
        
$hosts explode(','WP_PROXY_BYPASS_HOSTS);
        
$url preg_replace('/^https?:\/\//i'''$url);
        
$url preg_replace('/\/.*$/'''$url);
        
$url strtolower($url);
        foreach(
$hosts as $h){
            if(
strtolower(trim($h)) == $url){
                return 
false;
            }
        }
        return 
true;
    }
    public static function 
hasXSS($URL){
        if(! 
preg_match('/^https?:\/\/[a-z0-9\.\-]+\/[^\':<>\"\\\]*$/i'$URL)){
            return 
true;
        } else {
            return 
false;
        }
    }

    
/**
     * @param string $host
     * @return array
     */
    
public static function resolveDomainName($host$ipVersion null) {
        if (!
function_exists('dns_get_record')) {
            if (
$ipVersion === || $ipVersion === null) {
                
$ips gethostbynamel($host);
                if (
$ips !== false)
                    return 
$ips;
            }
            return array();
        }
        
$recordTypes = array();
        if (
$ipVersion === || $ipVersion === null)
            
$recordTypes[DNS_A] = 'ip';
        if (
$ipVersion === || $ipVersion === null)
            
$recordTypes[DNS_AAAA] = 'ipv6';
        
$ips = array();
        foreach (
$recordTypes as $type => $key) {
            
$records = @dns_get_record($host$type);
            if (
$records !== false && is_array($records)) {
                foreach (
$records as $record) {
                    if (
array_key_exists($key$record)) {
                        
$ips[] = $record[$key];
                    }
                }
            }
        }
        return 
$ips;
    }

    
/**
     * Expand a compressed printable representation of an IPv6 address.
     *
     * @param string $ip
     * @return string
     */
    
public static function expandIPv6Address($ip) {
        
$hex bin2hex(self::inet_pton($ip));
        
$ip substr(preg_replace("/([a-f0-9]{4})/i""$1:"$hex), 0, -1);
        return 
$ip;
    }

    public static function 
set_html_content_type() {
        return 
'text/html';
    }

    public static function 
htmlEmail($to$subject$body) {
        
add_filter'wp_mail_content_type''wfUtils::set_html_content_type' );
        
$result wp_mail($to$subject$body);
        
remove_filter'wp_mail_content_type''wfUtils::set_html_content_type' );
        return 
$result;
    }

    
/**
     * @param string $readmePath
     * @return bool
     */
    
public static function hideReadme($readmePath null) {
        if (
$readmePath === null) {
            
$readmePath ABSPATH 'readme.html';
        }

        if (
file_exists($readmePath)) {
            
$readmePathInfo pathinfo($readmePath);
            require_once(
ABSPATH WPINC '/pluggable.php');
            
$hiddenReadmeFile $readmePathInfo['filename'] . '.' wp_hash('readme') . '.' $readmePathInfo['extension'];
            return @
rename($readmePath$readmePathInfo['dirname'] . '/' $hiddenReadmeFile);
        }
        return 
false;
    }

    
/**
     * @param string $readmePath
     * @return bool
     */
    
public static function showReadme($readmePath null) {
        if (
$readmePath === null) {
            
$readmePath ABSPATH 'readme.html';
        }
        
$readmePathInfo pathinfo($readmePath);
        require_once(
ABSPATH WPINC '/pluggable.php');
        
$hiddenReadmeFile $readmePathInfo['dirname'] . '/' $readmePathInfo['filename'] . '.' wp_hash('readme') . '.' $readmePathInfo['extension'];
        if (
file_exists($hiddenReadmeFile)) {
            return @
rename($hiddenReadmeFile$readmePath);
        }
        return 
false;
    }

    public static function 
htaccessAppend($code)
    {
        
$htaccess wfCache::getHtaccessPath();
        
$content  self::htaccess();
        if (
wfUtils::isNginx() || !is_writable($htaccess)) {
            return 
false;
        }

        if (
strpos($content$code) === false) {
            
// make sure we write this once
            
file_put_contents($htaccess$content "\n" trim($code), LOCK_EX);
        }

        return 
true;
    }
    
    public static function 
htaccessPrepend($code)
    {
        
$htaccess wfCache::getHtaccessPath();
        
$content  self::htaccess();
        if (
wfUtils::isNginx() || !is_writable($htaccess)) {
            return 
false;
        }
        
        if (
strpos($content$code) === false) {
            
// make sure we write this once
            
file_put_contents($htaccesstrim($code) . "\n" $contentLOCK_EX);
        }
        
        return 
true;
    }

    public static function 
htaccess() {
        
$htaccess wfCache::getHtaccessPath();
        if (
is_readable($htaccess) && !wfUtils::isNginx()) {
            return 
file_get_contents($htaccess);
        }
        return 
"";
    }

    
/**
     * @param array $array
     * @param mixed $oldKey
     * @param mixed $newKey
     * @return array
     * @throws Exception
     */
    
public static function arrayReplaceKey($array$oldKey$newKey) {
        
$keys array_keys($array);
        if ((
$index array_search($oldKey$keys)) === false) {
            throw new 
Exception(sprintf('Key "%s" does not exist'$oldKey));
        }
        
$keys[$index] = $newKey;
        return 
array_combine($keysarray_values($array));
    }
    
    
/**
     * Takes a string that may have characters that will be interpreted as invalid UTF-8 byte sequences and translates them into a string of the equivalent hex sequence.
     * 
     * @param $string
     * @param bool $inline
     * @return string
     */
    
public static function potentialBinaryStringToHTML($string$inline false$allowmb4 false) {
        
$output '';
        
        if (!
defined('ENT_SUBSTITUTE')) {
            
define('ENT_SUBSTITUTE'0);
        }
        
        
$span '<span class="wf-hex-sequence">';
        if (
$inline) {
            
$span '<span style="color:#587ECB">';
        }
        
        for (
$i 0$i wfUtils::strlen($string); $i++) {
            
$c $string[$i];
            
$b ord($c);
            if (
$b 0x20) {
                
$output .= $span '\x' str_pad(dechex($b), 2'0'STR_PAD_LEFT) . '</span>';
            }
            else if (
$b 0x80) {
                
$output .= htmlspecialchars($cENT_QUOTES'ISO-8859-1');
            }
            else { 
//Assume multi-byte UTF-8
                
$bytes 0;
                
$test $b;
                
                while ((
$test 0x80) > 0) {
                    
$bytes++;
                    
$test = (($test << 1) & 0xff);
                }
                
                
$brokenUTF8 = ($i $bytes wfUtils::strlen($string) || $bytes == 1);
                if (!
$brokenUTF8) { //Make sure we have all the bytes
                    
for ($n 1$n $bytes$n++) {
                        
$c2 $string[$i $n];
                        
$b2 ord($c2);
                        if ((
$b2 0xc0) != 0x80) {
                            
$brokenUTF8 true;
                            
$bytes $n;
                            break;
                        }
                    }
                }
                
                if (!
$brokenUTF8) { //Ensure the byte sequences are within the accepted ranges: https://tools.ietf.org/html/rfc3629
                    /*
                     * UTF8-octets = *( UTF8-char )
                        * UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
                        * UTF8-1      = %x00-7F
                        * UTF8-2      = %xC2-DF UTF8-tail
                        * UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
                        *               %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
                        * UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
                        *               %xF4 %x80-8F 2( UTF8-tail )
                        * UTF8-tail   = %x80-BF
                     */
                    
                    
$testString wfUtils::substr($string$i$bytes);
                    
$regex '/^(?:' .
                        
'[\xc2-\xdf][\x80-\xbf]' //UTF8-2
                        
'|' '\xe0[\xa0-\xbf][\x80-\xbf]' //UTF8-3
                        
'|' '[\xe1-\xec][\x80-\xbf]{2}' .
                        
'|' '\xed[\x80-\x9f][\x80-\xbf]' .
                        
'|' '[\xee-\xef][\x80-\xbf]{2}';
                    if (
$allowmb4) {
                        
$regex .= '|' '\xf0[\x90-\xbf][\x80-\xbf]{2}' //UTF8-4
                            
'|' '[\xf1-\xf3][\x80-\xbf]{3}' .
                            
'|' '\xf4[\x80-\x8f][\x80-\xbf]{2}';
                    }
                    
$regex  .= ')$/';
                    if (!
preg_match($regex$testString)) {
                        
$brokenUTF8 true;
                    }
                }
                
                if (
$brokenUTF8) {
                    
$bytes min($bytesstrlen($string) - $i);
                    for (
$n 0$n $bytes$n++) {
                        
$c2 $string[$i $n];
                        
$b2 ord($c2);
                        
$output .= $span '\x' str_pad(dechex($b2), 2'0'STR_PAD_LEFT) . '</span>';
                    }
                    
$i += ($bytes 1);
                }
                else {
                    
$output .= htmlspecialchars(wfUtils::substr($string$i$bytes), ENT_QUOTES ENT_SUBSTITUTE'ISO-8859-1');
                    
$i += ($bytes 1);
                }
            }
        }
        return 
$output;
    }
    
    public static function 
requestDetectProxyCallback($timeout 2$blocking true$forceCheck false) {
        
$currentRecommendation wfConfig::get('detectProxyRecommendation''');
        if (!
$forceCheck) {
            
$detectProxyNextCheck wfConfig::get('detectProxyNextCheck'false);
            if (
$detectProxyNextCheck !== false && time() < $detectProxyNextCheck) {
                if (empty(
$currentRecommendation)) {
                    
wfConfig::set('detectProxyRecommendation''DEFERRED'wfConfig::DONT_AUTOLOAD);
                }
                return; 
//Let it pull the currently-stored value
            
}
        }

        try {
            
$waf wfWAF::getInstance();
            if (
$waf->getStorageEngine()->getConfig('attackDataKey'false) === false) {
                
$waf->getStorageEngine()->setConfig('attackDataKey'mt_rand(00xfff));
            }
            
$response wp_remote_get(sprintf(WFWAF_API_URL_SEC "proxy-check/%d.txt"$waf->getStorageEngine()->getConfig('attackDataKey')), array('headers' => array('Referer' => false)));
            
            if (!
is_wp_error($response)) {
                
$okToSendBody wp_remote_retrieve_body($response);
                if (
preg_match('/^(ok|wait),\s*(\d+)$/i'$okToSendBody$matches)) {
                    
$command $matches[1];
                    
$ttl $matches[2];
                    if (
$command == 'wait') {
                        
wfConfig::set('detectProxyNextCheck'time() + $ttlwfConfig::DONT_AUTOLOAD);
                        if (empty(
$currentRecommendation) || $currentRecommendation == 'UNKNOWN') {
                            
wfConfig::set('detectProxyRecommendation''DEFERRED'wfConfig::DONT_AUTOLOAD);
                        }
                        return;
                    }
                    
                    
wfConfig::set('detectProxyNextCheck'time() + $ttlwfConfig::DONT_AUTOLOAD);
                }
                else { 
//Unknown response
                    
wfConfig::set('detectProxyNextCheck'falsewfConfig::DONT_AUTOLOAD);
                    if (empty(
$currentRecommendation) || $currentRecommendation == 'UNKNOWN') {
                        
wfConfig::set('detectProxyRecommendation''DEFERRED'wfConfig::DONT_AUTOLOAD);
                    }
                    return;
                }
            }
        }
        catch (
Exception $e) {
            return;
        }
        
        
$nonce bin2hex(wfWAFUtils::random_bytes(32));
        
$callback self::getSiteBaseURL() . '?_wfsf=detectProxy';
        
        
wfConfig::set('detectProxyNonce'$noncewfConfig::DONT_AUTOLOAD);
        
wfConfig::set('detectProxyRecommendation'''wfConfig::DONT_AUTOLOAD);
        
        
$payload = array(
            
'nonce' => $nonce,
            
'callback' => $callback,
        );
        
        
$homeurl wfUtils::wpHomeURL();
        
$siteurl wfUtils::wpSiteURL();
        
        try {
            
$response wp_remote_post(WFWAF_API_URL_SEC "?" http_build_query(array(
                    
'action' => 'detect_proxy',
                    
'k'      => wfConfig::get('apiKey'),
                    
's'      => $siteurl,
                    
'h'         => $homeurl,
                    
't'         => microtime(true),
                    
'lang'   => get_site_option('WPLANG'),
                ), 
'''&'),
                array(
                    
'body'    => json_encode($payload),
                    
'headers' => array(
                        
'Content-Type' => 'application/json',
                        
'Referer' => false,
                    ),
                    
'timeout' => $timeout,
                    
'blocking' => $blocking,
                ));
        
            if (!
is_wp_error($response)) {
                
$jsonResponse wp_remote_retrieve_body($response);
                
$decoded = @json_decode($jsonResponsetrue);
                if (
is_array($decoded) && isset($decoded['data']) && is_array($decoded['data']) && isset($decoded['data']['ip']) && wfUtils::isValidIP($decoded['data']['ip'])) {
                    
wfConfig::set('serverIP'time() . ';' $decoded['data']['ip']);
                }
            }
        }
        catch (
Exception $e) {
            return;
        }
    }
    
    
/**
     * @return bool Returns false if the payload is invalid, true if it processed the callback (even if the IP wasn't found).
     */
    
public static function processDetectProxyCallback() {
        
$nonce wfConfig::get('detectProxyNonce''');
        
$testNonce = (isset($_POST['nonce']) ? $_POST['nonce'] : '');
        if (empty(
$nonce) || empty($testNonce)) {
            return 
false;
        }
        
        if (!
hash_equals($nonce$testNonce)) {
            return 
false;
        }
        
        
$ips = (isset($_POST['ips']) ? $_POST['ips'] : array());
        if (empty(
$ips)) {
            return 
false;
        }
        
        
$expandedIPs = array();
        foreach (
$ips as $ip) {
            
$expandedIPs[] = self::inet_pton($ip);
        }
        
        
$checks = array('HTTP_CF_CONNECTING_IP''HTTP_X_REAL_IP''REMOTE_ADDR''HTTP_X_FORWARDED_FOR');
        foreach (
$checks as $key) {
            if (!isset(
$_SERVER[$key])) {
                continue;
            }
            
            
$testIP self::getCleanIPAndServerVar(array(array($_SERVER[$key], $key)));
            if (
$testIP === false) {
                continue;
            }
            
            
$testIP self::inet_pton($testIP[0]);
            if (
in_array($testIP$expandedIPs)) {
                
wfConfig::set('detectProxyRecommendation'$keywfConfig::DONT_AUTOLOAD);
                
wfConfig::set('detectProxyNonce'''wfConfig::DONT_AUTOLOAD);
                return 
true;
            }
        }
        
        
wfConfig::set('detectProxyRecommendation''UNKNOWN'wfConfig::DONT_AUTOLOAD);
        
wfConfig::set('detectProxyNonce'''wfConfig::DONT_AUTOLOAD);
        return 
true;
    }
    
    
/**
     * Returns a v4 UUID.
     * 
     * @return string
     */
    
public static function uuid() {
        return 
sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            
// 32 bits for "time_low"
            
wfWAFUtils::random_int(00xffff), wfWAFUtils::random_int(00xffff),
            
            
// 16 bits for "time_mid"
            
wfWAFUtils::random_int(00xffff),
            
            
// 16 bits for "time_hi_and_version",
            // four most significant bits holds version number 4
            
wfWAFUtils::random_int(00x0fff) | 0x4000,
            
            
// 16 bits, 8 bits for "clk_seq_hi_res",
            // 8 bits for "clk_seq_low",
            // two most significant bits holds zero and one for variant DCE1.1
            
wfWAFUtils::random_int(00x3fff) | 0x8000,
            
            
// 48 bits for "node"
            
wfWAFUtils::random_int(00xffff), wfWAFUtils::random_int(00xffff), wfWAFUtils::random_int(00xffff)
        );
    }
    
    public static function 
base32_encode($rawString$rightPadFinalBits false$padFinalGroup false$padCharacter '='//Adapted from https://github.com/ademarre/binary-to-text-php
    
{
        
// Unpack string into an array of bytes
        
$bytes unpack('C*'$rawString);
        
$byteCount count($bytes);
        
        
$encodedString '';
        
$byte array_shift($bytes);
        
$bitsRead 0;
        
$oldBits 0;
        
        
$chars             'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
        
$bitsPerCharacter  5;
        
        
$charsPerByte $bitsPerCharacter;
        
$encodedLength $byteCount $charsPerByte;
        
        
// Generate encoded output; each loop produces one encoded character
        
for ($c 0$c $encodedLength$c++) {
            
            
// Get the bits needed for this encoded character
            
if ($bitsRead $bitsPerCharacter 8) {
                
// Not enough bits remain in this byte for the current character
                // Save the remaining bits before getting the next byte
                
$oldBitCount $bitsRead;
                
$oldBits $byte ^ ($byte >> $oldBitCount << $oldBitCount);
                
$newBitCount $bitsPerCharacter $oldBitCount;
                
                if (!
$bytes) {
                    
// Last bits; match final character and exit loop
                    
if ($rightPadFinalBits$oldBits <<= $newBitCount;
                    
$encodedString .= $chars[$oldBits];
                    
                    if (
$padFinalGroup) {
                        
// Array of the lowest common multiples of $bitsPerCharacter and 8, divided by 8
                        
$lcmMap = array(=> 1=> 1=> 3=> 1=> 5=> 3=> 7=> 1);
                        
$bytesPerGroup $lcmMap[$bitsPerCharacter];
                        
$pads $bytesPerGroup $charsPerByte ceil((strlen($rawString) % $bytesPerGroup) * $charsPerByte);
                        
$encodedString .= str_repeat($padCharacter$pads);
                    }
                    
                    break;
                }
                
                
// Get next byte
                
$byte array_shift($bytes);
                
$bitsRead 0;
                
            } else {
                
$oldBitCount 0;
                
$newBitCount $bitsPerCharacter;
            }
            
            
// Read only the needed bits from this byte
            
$bits $byte >> - ($bitsRead + ($newBitCount));
            
$bits ^= $bits >> $newBitCount << $newBitCount;
            
$bitsRead += $newBitCount;
            
            if (
$oldBitCount) {
                
// Bits come from seperate bytes, add $oldBits to $bits
                
$bits = ($oldBits << $newBitCount) | $bits;
            }
            
            
$encodedString .= $chars[$bits];
        }
        
        return 
$encodedString;
    }
    
    private static function 
_home_url_nofilter($path ''$scheme null) { //A version of the native get_home_url and get_option without the filter calls
        
global $pagenow$wpdb$blog_id;
        
        static 
$cached_url null;
        if (
$cached_url !== null) {
            return 
$cached_url;
        }
        
        if (
defined('WP_HOME') && WORDFENCE_PREFER_WP_HOME_FOR_WPML) {
            
$cached_url WP_HOME;
            return 
$cached_url;
        }
        
        if ( empty( 
$blog_id ) || !is_multisite() ) {
            
$url $wpdb->get_var("SELECT option_value FROM {$wpdb->options} WHERE option_name = 'home' LIMIT 1");
            if (empty(
$url)) { //get_option uses siteurl instead if home is empty
                
$url $wpdb->get_var("SELECT option_value FROM {$wpdb->options} WHERE option_name = 'siteurl' LIMIT 1");
            }
        }
        else if (
is_multisite()) {
            
$current_network get_network();
            if ( 
'relative' == $scheme )
                
$url rtrim($current_network->path'/');
            else
                
$url 'http://' rtrim($current_network->domain'/') . '/' trim($current_network->path'/');
        }
        
        if ( ! 
in_array$scheme, array( 'http''https''relative' ) ) ) {
            if ( 
is_ssl() && ! is_admin() && 'wp-login.php' !== $pagenow )
                
$scheme 'https';
            else
                
$scheme parse_url$urlPHP_URL_SCHEME );
        }
        
        
$url set_url_scheme$url$scheme );
        
        if ( 
$path && is_string$path ) )
            
$url .= '/' ltrim$path'/' );
        
        
$cached_url $url;
        return 
$url;
    }
    
    public static function 
refreshCachedHomeURL() {
        
$pullDirectly class_exists('WPML_URL_Filters');
        
$homeurl '';
        if (
$pullDirectly) {
            
//A version of the native get_home_url without the filter call
            
$homeurl self::_home_url_nofilter();
        }
        
        if (
function_exists('get_bloginfo') && empty($homeurl)) {
            if (
is_multisite()) {
                
$homeurl network_home_url();
            }
            else {
                
$homeurl home_url();
            }
            
            
$homeurl rtrim($homeurl'/'); //Because previously we used get_bloginfo and it returns http://example.com without a '/' char.
        
}
        
        if (
wfConfig::get('wp_home_url') !== $homeurl) {
            
wfConfig::set('wp_home_url'$homeurl);
        }
    }
    
    public static function 
wpHomeURL($path ''$scheme null) {
        
$homeurl wfConfig::get('wp_home_url''');
        if (
function_exists('get_bloginfo') && empty($homeurl)) {
            if (
is_multisite()) {
                
$homeurl network_home_url($path$scheme);
            }
            else {
                
$homeurl home_url($path$scheme);
            }
            
            
$homeurl rtrim($homeurl'/'); //Because previously we used get_bloginfo and it returns http://example.com without a '/' char.
        
}
        else {
            
$homeurl set_url_scheme($homeurl$scheme);
            if (
$path && is_string($path)) {
                
$homeurl .= '/' ltrim($path'/');
            }
        }
        return 
$homeurl;
    }
    
    private static function 
_site_url_nofilter($path ''$scheme null) { //A version of the native get_site_url and get_option without the filter calls
        
global $pagenow$wpdb$blog_id;
        
        static 
$cached_url null;
        if (
$cached_url !== null) {
            return 
$cached_url;
        }
        
        if (
defined('WP_SITEURL') && WORDFENCE_PREFER_WP_HOME_FOR_WPML) {
            
$cached_url WP_SITEURL;
            return 
$cached_url;
        }
        
        if ( empty( 
$blog_id ) || !is_multisite() ) {
            
$url $wpdb->get_var("SELECT option_value FROM {$wpdb->options} WHERE option_name = 'siteurl' LIMIT 1");
        }
        else if (
is_multisite()) {
            
$current_network get_network();
            if ( 
'relative' == $scheme )
                
$url rtrim($current_network->path'/');
            else
                
$url 'http://' rtrim($current_network->domain'/') . '/' trim($current_network->path'/');
        }
        
        if ( ! 
in_array$scheme, array( 'http''https''relative' ) ) ) {
            if ( 
is_ssl() && ! is_admin() && 'wp-login.php' !== $pagenow )
                
$scheme 'https';
            else
                
$scheme parse_url$urlPHP_URL_SCHEME );
        }
        
        
$url set_url_scheme$url$scheme );
        
        if ( 
$path && is_string$path ) )
            
$url .= '/' ltrim$path'/' );
        
        
$cached_url $url;
        return 
$url;
    }
    
    public static function 
refreshCachedSiteURL() {
        
$pullDirectly class_exists('WPML_URL_Filters');
        
$siteurl '';
        if (
$pullDirectly) {
            
//A version of the native get_home_url without the filter call
            
$siteurl self::_site_url_nofilter();
        }
        
        if (
function_exists('get_bloginfo') && empty($siteurl)) {
            if (
is_multisite()) {
                
$siteurl network_site_url();
            }
            else {
                
$siteurl site_url();
            }
            
            
$siteurl rtrim($siteurl'/'); //Because previously we used get_bloginfo and it returns http://example.com without a '/' char.
        
}
        
        if (
wfConfig::get('wp_site_url') !== $siteurl) {
            
wfConfig::set('wp_site_url'$siteurl);
        }
    }
    
    
/**
     * Equivalent to network_site_url but uses the cached value for the URL if we have it
     * to avoid breaking on sites that define it based on the requesting hostname.
     * 
     * @param string $path
     * @param null|string $scheme
     * @return string
     */
    
public static function wpSiteURL($path ''$scheme null) {
        
$siteurl wfConfig::get('wp_site_url''');
        if (
function_exists('get_bloginfo') && empty($siteurl)) {
            if (
is_multisite()) {
                
$siteurl network_site_url($path$scheme);
            }
            else {
                
$siteurl site_url($path$scheme);
            }
            
            
$siteurl rtrim($siteurl'/'); //Because previously we used get_bloginfo and it returns http://example.com without a '/' char.
        
}
        else {
            
$siteurl set_url_scheme($siteurl$scheme);
            if (
$path && is_string($path)) {
                
$siteurl .= '/' ltrim($path'/');
            }
        }
        return 
$siteurl;
    }
    
    
/**
     * Equivalent to network_admin_url but uses the cached value for the URL if we have it
     * to avoid breaking on sites that define it based on the requesting hostname.
     *
     * @param string $path
     * @param null|string $scheme
     * @return string
     */
    
public static function wpAdminURL($path ''$scheme null) {
        if (!
is_multisite()) {
            
$adminURL self::wpSiteURL('wp-admin/'$scheme);
        }
        else {
            
$adminURL self::wpSiteURL('wp-admin/network/'$scheme);
        }
        
        if (
$path && is_string($path)) {
            
$adminURL .= ltrim($path'/');
        }
        
        if (!
is_multisite()) {
            return 
apply_filters('admin_url'$adminURL$pathnull);
        }
        
        return 
apply_filters('network_admin_url'$adminURL$path);
    }
    
    public static function 
wafInstallationType() {
        
$storage 'file';
        if (
defined('WFWAF_STORAGE_ENGINE')) { $storage WFWAF_STORAGE_ENGINE; }
        
        try {
            
$status = (defined('WFWAF_ENABLED') && !WFWAF_ENABLED) ? 'disabled' wfWaf::getInstance()->getStorageEngine()->getConfig('wafStatus');
            if (
defined('WFWAF_ENABLED') && !WFWAF_ENABLED) {
                return 
"{$status}|const|{$storage}";
            }
            else if (
defined('WFWAF_SUBDIRECTORY_INSTALL') && WFWAF_SUBDIRECTORY_INSTALL) {
                return 
"{$status}|subdir|{$storage}";
            }
            else if (
defined('WFWAF_AUTO_PREPEND') && WFWAF_AUTO_PREPEND) {
                return 
"{$status}|extended|{$storage}";
            }
            
            return 
"{$status}|basic|{$storage}";
        }
        catch (
Exception $e) {
            
//Do nothing
        
}
        
        return 
'unknown';
    }
    
    public static function 
hex2bin($string) { //Polyfill for PHP < 5.4
        
if (!is_string($string)) { return false; }
        if (
strlen($string) % == 1) { return false; }
        return 
pack('H*'$string);
    }
    
    
/**
     * Returns whether or not the site should be treated as if it's full-time SSL.
     * 
     * @return bool
     */
    
public static function isFullSSL() {
        return 
is_ssl() && parse_url(self::wpHomeURL(), PHP_URL_SCHEME) === 'https'//It's possible for only wp-admin to be SSL so we check the home URL too
    
}

    
/**
     * Identical to the same functions in wfWAFUtils.
     * 
     * Set the mbstring internal encoding to a binary safe encoding when func_overload
     * is enabled.
     *
     * When mbstring.func_overload is in use for multi-byte encodings, the results from
     * strlen() and similar functions respect the utf8 characters, causing binary data
     * to return incorrect lengths.
     *
     * This function overrides the mbstring encoding to a binary-safe encoding, and
     * resets it to the users expected encoding afterwards through the
     * `reset_mbstring_encoding` function.
     *
     * It is safe to recursively call this function, however each
     * `mbstring_binary_safe_encoding()` call must be followed up with an equal number
     * of `reset_mbstring_encoding()` calls.
     *
     * @see wfWAFUtils::reset_mbstring_encoding
     *
     * @staticvar array $encodings
     * @staticvar bool  $overloaded
     *
     * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
     *                    Default false.
     */
    
public static function mbstring_binary_safe_encoding($reset false) {
        static 
$encodings = array();
        static 
$overloaded null;
        
        if (
is_null($overloaded)) {
            
// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated
            
$overloaded function_exists('mb_internal_encoding') && (ini_get('mbstring.func_overload') & 2);
        }
        
        if (
false === $overloaded) { return; }
        
        if (!
$reset) {
            
$encoding mb_internal_encoding();
            
array_push($encodings$encoding);
            
mb_internal_encoding('ISO-8859-1');
        }
        
        if (
$reset && $encodings) {
            
$encoding array_pop($encodings);
            
mb_internal_encoding($encoding);
        }
    }
    
    
/**
     * Reset the mbstring internal encoding to a users previously set encoding.
     *
     * @see wfWAFUtils::mbstring_binary_safe_encoding
     */
    
public static function reset_mbstring_encoding() {
        
self::mbstring_binary_safe_encoding(true);
    }
    
    
/**
     * @param callable $function
     * @param array $args
     * @return mixed
     */
    
protected static function callMBSafeStrFunction($function$args) {
        
self::mbstring_binary_safe_encoding();
        
$return call_user_func_array($function$args);
        
self::reset_mbstring_encoding();
        return 
$return;
    }
    
    
/**
     * Multibyte safe strlen.
     *
     * @param $binary
     * @return int
     */
    
public static function strlen($binary) {
        
$args func_get_args();
        return 
self::callMBSafeStrFunction('strlen'$args);
    }
    
    
/**
     * @param $haystack
     * @param $needle
     * @param int $offset
     * @return int
     */
    
public static function stripos($haystack$needle$offset 0) {
        
$args func_get_args();
        return 
self::callMBSafeStrFunction('stripos'$args);
    }
    
    
/**
     * @param $string
     * @return mixed
     */
    
public static function strtolower($string) {
        
$args func_get_args();
        return 
self::callMBSafeStrFunction('strtolower'$args);
    }
    
    
/**
     * @param $string
     * @param $start
     * @param $length
     * @return mixed
     */
    
public static function substr($string$start$length null) {
        if (
$length === null) { $length self::strlen($string); }
        return 
self::callMBSafeStrFunction('substr', array(
            
$string$start$length
        
));
    }
    
    
/**
     * @param $haystack
     * @param $needle
     * @param int $offset
     * @return mixed
     */
    
public static function strpos($haystack$needle$offset 0) {
        
$args func_get_args();
        return 
self::callMBSafeStrFunction('strpos'$args);
    }
    
    
/**
     * @param string $haystack
     * @param string $needle
     * @param int $offset
     * @param int $length
     * @return mixed
     */
    
public static function substr_count($haystack$needle$offset 0$length null) {
        if (
$length === null) { $length self::strlen($haystack); }
        return 
self::callMBSafeStrFunction('substr_count', array(
            
$haystack$needle$offset$length
        
));
    }
    
    
/**
     * @param $string
     * @return mixed
     */
    
public static function strtoupper($string) {
        
$args func_get_args();
        return 
self::callMBSafeStrFunction('strtoupper'$args);
    }
    
    
/**
     * @param string $haystack
     * @param string $needle
     * @param int $offset
     * @return mixed
     */
    
public static function strrpos($haystack$needle$offset 0) {
        
$args func_get_args();
        return 
self::callMBSafeStrFunction('strrpos'$args);
    }
    
    public static function 
sets_equal($a1$a2) {
        if (!
is_array($a1) || !is_array($a2)) {
            return 
false;
        }
        
        if (
count($a1) != count($a2)) {
            return 
false;
        }
        
        
sort($a1SORT_NUMERIC);
        
sort($a2SORT_NUMERIC);
        return 
$a1 == $a2;
    }
    
    public static function 
array_first($array) {
        if (empty(
$array)) {
            return 
null;
        }
        
        
$values array_values($array);
        return 
$values[0];
    }
    
    public static function 
array_last($array) {
        if (empty(
$array)) {
            return 
null;
        }
        
        
$values array_values($array);
        return 
$values[count($values) - 1];
    }
    
    public static function 
array_strtolower($array) {
        
$result = array();
        foreach (
$array as $a) {
            
$result[] = strtolower($a);
        }
        return 
$result;
    }
    
    public static function 
array_column($input null$columnKey null$indexKey null) { //Polyfill from https://github.com/ramsey/array_column/blob/master/src/array_column.php
        
$argc func_num_args();
        
$params func_get_args();
        if (
$argc 2) {
            
trigger_error("array_column() expects at least 2 parameters, {$argc} given"E_USER_WARNING);
            return 
null;
        }
        
        if (!
is_array($params[0])) {
            
trigger_error(
                
'array_column() expects parameter 1 to be array, ' gettype($params[0]) . ' given',
                
E_USER_WARNING
            
);
            return 
null;
        }
        
        if (!
is_int($params[1]) && !is_float($params[1]) && !is_string($params[1]) && $params[1] !== null && !(is_object($params[1]) && method_exists($params[1], '__toString'))) {
            
trigger_error('array_column(): The column key should be either a string or an integer'E_USER_WARNING);
            return 
false;
        }
        
        if (isset(
$params[2]) && !is_int($params[2]) && !is_float($params[2]) && !is_string($params[2]) && !(is_object($params[2]) && method_exists($params[2], '__toString'))) {
            
trigger_error('array_column(): The index key should be either a string or an integer'E_USER_WARNING);
            return 
false;
        }
        
        
$paramsInput $params[0];
        
$paramsColumnKey = ($params[1] !== null) ? (string) $params[1] : null;
        
$paramsIndexKey null;
        if (isset(
$params[2])) {
            if (
is_float($params[2]) || is_int($params[2])) {
                
$paramsIndexKey = (int) $params[2];
            }
            else {
                
$paramsIndexKey = (string) $params[2];
            }
        }
        
        
$resultArray = array();
        foreach (
$paramsInput as $row) {
            
$key $value null;
            
$keySet $valueSet false;
            if (
$paramsIndexKey !== null && array_key_exists($paramsIndexKey$row)) {
                
$keySet true;
                
$key = (string) $row[$paramsIndexKey];
            }
            
            if (
$paramsColumnKey === null) {
                
$valueSet true;
                
$value $row;
            }
            elseif (
is_array($row) && array_key_exists($paramsColumnKey$row)) {
                
$valueSet true;
                
$value $row[$paramsColumnKey];
            }
            
            if (
$valueSet) {
                if (
$keySet) {
                    
$resultArray[$key] = $value;
                }
                else {
                    
$resultArray[] = $value;
                }
            }
        }
        
        return 
$resultArray;
    }
    
    
/**
     * Returns $string if it isn't empty, $ifEmpty if it is.
     * 
     * @param string $string
     * @param string $ifEmpty
     * @return string
     */
    
public static function string_empty($string$ifEmpty) {
        if (empty(
$string)) {
            return 
$ifEmpty;
        }
        return 
$string;
    }
    
    
/**
     * Returns the current timestamp, adjusted as needed to get close to what we consider a true timestamp. We use this
     * because a significant number of servers are using a drastically incorrect time.
     *
     * @return int
     */
    
public static function normalizedTime($base false) {
        if (
$base === false) {
            
$base time();
        }
        
        
$offset = (int) wfConfig::get('timeoffset_wf'0);
        return 
$base $offset;
    }
    
    
/**
     * Returns what we consider a true timestamp, adjusted as needed to match the local server's drift. We use this
     * because a significant number of servers are using a drastically incorrect time.
     *
     * @return int
     */
    
public static function denormalizedTime($base) {
        
$offset = (int) wfConfig::get('timeoffset_wf'0);
        return 
$base $offset;
    }
    
    
/**
     * Returns the number of minutes for the time zone offset from UTC. If $timestamp and using a named time zone, 
     * it will be adjusted automatically to match whether or not the server's time zone is in Daylight Savings Time.
     * 
     * @param bool|int $timestamp Assumed to be in UTC. If false, defaults to the current timestamp.
     * @return int
     */
    
public static function timeZoneMinutes($timestamp false) {
        if (
$timestamp === false) {
            
$timestamp time();
        }
        
        
$tz get_option('timezone_string');
        if (!empty(
$tz)) {
            
$timezone = new DateTimeZone($tz);
            
$dtStr gmdate("c", (int) $timestamp); //Have to do it this way because of PHP 5.2
            
$dt = new DateTime($dtStr$timezone);
            return (int) (
$timezone->getOffset($dt) / 60);
        }
        else {
            
$gmt get_option('gmt_offset');
            if (!empty(
$gmt)) {
                return (int) (
$gmt 60);
            }
        }
        
        return 
0;
    }
    
    
/**
     * Formats and returns the given timestamp using the time zone set for the WordPress installation.
     * 
     * @param string $format See the PHP docs on DateTime for the format options. 
     * @param int|bool $timestamp Assumed to be in UTC. If false, defaults to the current timestamp.
     * @return string
     */
    
public static function formatLocalTime($format$timestamp false) {
        if (
$timestamp === false) {
            
$timestamp time();
        }
        
        
$utc = new DateTimeZone('UTC');
        
$dtStr gmdate("c", (int) $timestamp); //Have to do it this way because of PHP 5.2
        
$dt = new DateTime($dtStr$utc);
        
$tz get_option('timezone_string');
        if (!empty(
$tz)) {
            
$dt->setTimezone(new DateTimeZone($tz));
        }
        else {
            
$gmt get_option('gmt_offset');
            if (!empty(
$gmt)) {
                if (
PHP_VERSION_ID 50510) {
                    
$dtStr gmdate("c", (int) ($timestamp $gmt 3600)); //Have to do it this way because of < PHP 5.5.10
                    
$dt = new DateTime($dtStr$utc);
                }
                else {
                    
$direction = ($gmt '+' '-');
                    
$gmt abs($gmt);
                    
$h = (int) $gmt;
                    
$m = ($gmt $h) * 60;
                    
$dt->setTimezone(new DateTimeZone($direction str_pad($h2'0'STR_PAD_LEFT) . str_pad($m2'0'STR_PAD_LEFT)));
                }
            }
        }
        return 
$dt->format($format);
    }
    
    
/**
     * Parses the given time string and returns its DateTime with the server's configured time zone.
     * 
     * @param string $timestring
     * @return DateTime
     */
    
public static function parseLocalTime($timestring) {
        
$utc = new DateTimeZone('UTC');
        
$tz get_option('timezone_string');
        if (!empty(
$tz)) {
            
$tz = new DateTimeZone($tz);
            return new 
DateTime($timestring$tz);
        }
        else {
            
$gmt get_option('gmt_offset');
            if (!empty(
$gmt)) {
                if (
PHP_VERSION_ID 50510) {
                    
$timestamp strtotime($timestring);
                    
$dtStr gmdate("c", (int) ($timestamp $gmt 3600)); //Have to do it this way because of < PHP 5.5.10
                    
return new DateTime($dtStr$utc);
                }
                else {
                    
$direction = ($gmt '+' '-');
                    
$gmt abs($gmt);
                    
$h = (int) $gmt;
                    
$m = ($gmt $h) * 60;
                    
$tz = new DateTimeZone($direction str_pad($h2'0'STR_PAD_LEFT) . str_pad($m2'0'STR_PAD_LEFT));
                    return new 
DateTime($timestring$tz);
                }
            }
        }
        return new 
DateTime($timestring);
    }
    
    
/**
     * Base64URL-encodes the given payload. This is identical to base64_encode except it substitutes characters
     * not safe for use in URLs.
     * 
     * @param string $payload
     * @return string
     */
    
public static function base64url_encode($payload) {
        
$intermediate base64_encode($payload);
        
$intermediate rtrim($intermediate'=');
        
$intermediate str_replace('+''-'$intermediate);
        
$intermediate str_replace('/''_'$intermediate);
        return 
$intermediate;
    }
    
    
/**
     * Base64URL-decodes the given payload. This is identical to base64_encode except it allows for the characters
     * substituted by base64url_encode.
     * 
     * @param string $payload
     * @return string
     */
    
public static function base64url_decode($payload) {
        
$intermediate str_replace('_''/'$payload);
        
$intermediate str_replace('-''+'$intermediate);
        
$intermediate base64_decode($intermediate);
        return 
$intermediate;
    }
    
    
/**
     * Returns a signed JWT for the given payload. Payload is expected to be an array suitable for JSON-encoding.
     * 
     * @param array $payload
     * @param int $maxAge How long the JWT will be considered valid.
     * @return string
     */
    
public static function generateJWT($payload$maxAge 604800 /* 7 days */) {
        
$payload['_exp'] = time() + $maxAge;
        
$key wfConfig::get('longEncKey');
        
$header '{"alg":"HS256","typ":"JWT"}';
        
$body self::base64url_encode($header) . '.' self::base64url_encode(json_encode($payload));
        
$signature hash_hmac('sha256'$body$keytrue);
        return 
$body '.' self::base64url_encode($signature);
    }
    
    
/**
     * Decodes and returns the payload of a JWT. This also validates the signature.
     * 
     * @param string $token
     * @return array|bool The decoded payload or false if the token is invalid or fails validation.
     */
    
public static function decodeJWT($token) {
        
$components explode('.'$token);
        if (
count($components) != 3) {
            return 
false;
        }
        
        
$key wfConfig::get('longEncKey');
        
$body $components[0] . '.' $components[1];
        
$signature hash_hmac('sha256'$body$keytrue);
        
$testSignature self::base64url_decode($components[2]);
        if (!
hash_equals($signature$testSignature)) {
            return 
false;
        }
        
        
$json self::base64url_decode($components[1]);
        
$payload = @json_decode($jsontrue);
        if (!
is_array($payload) || (isset($payload['_exp']) && $payload['_exp'] < time())) {
            return 
false;
        }
        return 
$payload;
    }

    
/**
     * Split a path into its components
     * @param string $path
     */
    
public static function splitPath($path) {
        return 
preg_split('/[\\/\\\\]/'$path, -1PREG_SPLIT_NO_EMPTY);
    }

    
/**
     * Convert an absolute path to a path relative to $to
     * @param string $absolute the absolute path to convert
     * @param string $to the absolute path from which to derive the relative path
     * @param bool $leadingSlash if true, prepend the resultant URL with a slash
     */
    
public static function relativePath($absolute$to$leadingSlash false) {
        
$trailingSlash in_array(substr($absolute, -1), array('/''\\'));
        
$absoluteComponents self::splitPath($absolute);
        
$toComponents self::splitPath($to);
        
$relativeComponents = array();
        do {
            
$currentAbsolute array_shift($absoluteComponents);
            
$currentTo array_shift($toComponents);
        } while(
$currentAbsolute === $currentTo && $currentAbsolute !== null);
        while (
$currentTo !== null) {
            
array_push($relativeComponents'..');
            
$currentTo array_shift($toComponents);
        }
        while (
$currentAbsolute !== null) {
            
array_push($relativeComponents$currentAbsolute);
            
$currentAbsolute array_shift($absoluteComponents);
        }
        return 
implode(array(
            
$leadingSlash '/' '',
            
implode('/'$relativeComponents),
            (
$trailingSlash && (count($relativeComponents) > || !$leadingSlash)) ? '/' ''
        
));
    }

    
/**
     * Determine the effective port given the output of parse_url
     * @param array $urlComponents
     * @return int the resolved port number
     */
    
private static function resolvePort($urlComponents) {
        if (
array_key_exists('port'$urlComponents) && !empty($urlComponents['port'])) {
            return 
$urlComponents['port'];
        }
        if (
array_key_exists('scheme'$urlComponents) && $urlComponents['scheme'] === 'https') {
            return 
443;
        }
        return 
80;
    }

    
/**
     * Check if two site URLs identify the same site
     * @param string $a first url
     * @param string $b second url
     * @param array $ignoredSubdomains An array of subdomains to ignore when matching (e.g., www)
     * @return bool true if the URLs match, false otherwise
     */
    
public static function compareSiteUrls($a$b$ignoredSubdomains = array()) {
        
$patterns array_map(function($p) { return '/^' preg_quote($p'/') . '\\./i'; }, $ignoredSubdomains);
        
        
$componentsA parse_url($a);
        if (isset(
$componentsA['host'])) { $componentsA['host'] = preg_replace($patterns''$componentsA['host']); }
        
$componentsB parse_url($b);
        if (isset(
$componentsB['host'])) { $componentsB['host'] = preg_replace($patterns''$componentsB['host']); }
        foreach (array(
'host''port''path') as $component) {
            
$valueA array_key_exists($component$componentsA) ? $componentsA[$component] : null;
            
$valueB array_key_exists($component$componentsB) ? $componentsB[$component] : null;
            if (
$valueA !== $valueB) {
                if (
$component === 'port') {
                    
$portA self::resolvePort($componentsA);
                    
$portB self::resolvePort($componentsB);
                    if (
$portA !== $portB)
                        return 
false;
                }
                else {
                    return 
false;
                }
            }
        }
        return 
true;
    }

    public static function 
getHomePath() {
        if (!
function_exists('get_home_path')) {
            include_once(
ABSPATH 'wp-admin/includes/file.php');
        }
        if (
WF_IS_FLYWHEEL)
            return 
trailingslashit($_SERVER['DOCUMENT_ROOT']);
        return 
get_home_path();
    }

    public static function 
includeOnceIfPresent($path) {
        if (
file_exists($path) && is_readable($path)) {
            @include_once(
$path);
            return @include_once(
$path); //Calling `include_once` for an already included file will return true
        
}
        return 
false;
    }

    public static function 
isCurlSupported() {
        if (!
function_exists('curl_init') || !function_exists('curl_exec')) {
            return 
false;
        }
        
        
$is_ssl = isset($args['ssl']) && $args['ssl'];
        
        if (
$is_ssl) {
            
$curl_version curl_version();
            
// Check whether this cURL version support SSL requests.
            
if (!(CURL_VERSION_SSL $curl_version['features'])) {
                return 
false;
            }
        }
        
        return 
true;
    }

    private static function 
isValidJsonValue($value) {
        return 
json_encode($value) !== false;
    }

    private static function 
filterInvalidJsonValues($data, &$modified, &$valid null) {
        if (
is_array($data)) {
            
$modified = array();
            
$filtered = array();
            
$valid true;
            foreach (
$data as $key => $value) {
                
$value self::filterInvalidJsonValues($value$itemModified$itemValid);
                if ((
$itemValid || $itemModified) && self::isValidJsonValue(array($key => $value))) {
                    
$filtered[$key] = $value;
                    if (
$itemModified)
                        
$modified[$key] = $itemModified;
                }
                else {
                    
$valid false;
                }
            }
            return 
$filtered;
        }
        else {
            
$modified false;
            
$valid self::isValidJsonValue($data);
            if (
$valid) {
                return 
$data;
            }
            else if (
is_string($data)) {
                
$modified true;
                return 
base64_encode($data);
            }
            else {
                return 
null;
            }
        }
    }

    public static function 
jsonEncodeSafely($data) {
        
$encoded json_encode($data);
        if (
$encoded === false) {
            
$data self::filterInvalidJsonValues($data$modified);
            if (
$modified)
                
$data['__modified__'] = $modified;
            
$encoded json_encode($data);
        }
        return 
$encoded;
    }
    
    
/**
     * Convenience function to extract a matched pattern from a string. If $pattern has no matching groups, the entire
     * matched portion is returned. If it has at least one matching group, the first one is returned (others are 
     * ignored). If there is no match, false is returned.
     * 
     * @param string $pattern
     * @param string $subject
     * @param bool $expandToLine Whether or not to expand the captured value to include the entire line's contents
     * @return false|string
     */
    
public static function pregExtract($pattern$subject$expandToLine false) {
        if (
preg_match($pattern$subject$matchesPREG_OFFSET_CAPTURE)) {
            if (
count($matches) > 1) {
                
$start $matches[1][1];
                
$text $matches[1][0];
                
$end $start strlen($text);
            }
            else {
                
$start $matches[0][1];
                
$text $matches[0][0];
                
$end $start strlen($text);
            }
            
            if (
$expandToLine) {
                if (
preg_match_all('/[\r\n]/'substr($subject0$start), $matchesPREG_OFFSET_CAPTURE)) {
                    
$start $matches[0][count($matches[0]) - 1][1] + 1;
                }
                else {
                    
$start 0;
                }
                
                if (
preg_match('/[\r\n]/'$subject$matchesPREG_OFFSET_CAPTURE$end)) {
                    
$end $matches[0][1];
                }
                else {
                    
$end strlen($subject) - 0;
                }
                
                
$text substr($subject$start$end $start);
            }
            
            return 
$text;
        }
        return 
false;
    }
    
    
/**
     * Returns whether or not MySQLi should be used directly when needed. Returns true if there's a valid DB handle,
     * our database test succeeded, our constant is not set to prevent it, and then either $wpdb indicates it's using
     * mysqli (older WordPress versions) or we're on PHP 7+ (only mysqli is ever used).
     * 
     * @return bool
     */
    
public static function useMySQLi() {
        global 
$wpdb;
        
$dbh $wpdb->dbh;
        
$useMySQLi = (is_object($dbh) && (PHP_MAJOR_VERSION >= || $wpdb->use_mysqli) && wfConfig::get('allowMySQLi'true) && WORDFENCE_ALLOW_DIRECT_MYSQLI);
        return 
$useMySQLi;
    }
}

// GeoIP lib uses these as well
if (!function_exists('inet_ntop')) {
    function 
inet_ntop($ip) {
        return 
wfUtils::_inet_ntop($ip);
    }
}
if (!
function_exists('inet_pton')) {
    function 
inet_pton($ip) {
        return 
wfUtils::_inet_pton($ip);
    }
}


class 
wfWebServerInfo {

    const 
APACHE 1;
    const 
NGINX 2;
    const 
LITESPEED 4;
    const 
IIS 8;

    private 
$handler;
    private 
$software;
    private 
$softwareName;

    
/**
     *
     */
    
public static function createFromEnvironment() {
        
$serverInfo = new self;
        
$sapi php_sapi_name();
        if (
WF_IS_FLYWHEEL) {
            
$serverInfo->setSoftware(self::NGINX);
            
$serverInfo->setSoftwareName('Flywheel');
        }
        else if (
strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'ExpressionDevServer') !== false) {
            
$serverInfo->setSoftware(self::IIS);
            
$serverInfo->setSoftwareName('iis');
        }
        else if (
strpos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
            
$serverInfo->setSoftware(self::NGINX);
            
$serverInfo->setSoftwareName('nginx');
        }
        else if (
stripos($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false || $sapi == 'litespeed') {
            
$serverInfo->setSoftware(self::LITESPEED);
            
$serverInfo->setSoftwareName('litespeed');
        }
        else if (
stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) {
            
$serverInfo->setSoftware(self::APACHE);
            
$serverInfo->setSoftwareName('apache');
        }
        else if (
stripos($_SERVER['SERVER_SOFTWARE'], 'unit') !== false) {
            
$serverInfo->setSoftware(self::NGINX);
            
$serverInfo->setSoftwareName('unit');
        }

        
$serverInfo->setHandler($sapi);

        return 
$serverInfo;
    }

    
/**
     * @return bool
     */
    
public function isApache() {
        return 
$this->getSoftware() === self::APACHE;
    }

    
/**
     * @return bool
     */
    
public function isNginx() {
        return 
$this->getSoftware() === self::NGINX;
    }

    
/**
     * @return bool
     */
    
public function isLiteSpeed() {
        return 
$this->getSoftware() === self::LITESPEED;
    }

    
/**
     * @return bool
     */
    
public function isIIS() {
        return 
$this->getSoftware() === self::IIS;
    }

    
/**
     * @return bool
     */
    
public function isApacheModPHP() {
        return 
$this->isApache() && function_exists('apache_get_modules');
    }

    
/**
     * Not sure if this can be implemented at the PHP level.
     * @return bool
     */
    
public function isApacheSuPHP() {
        return 
$this->isApache() && $this->isCGI() &&
            
function_exists('posix_getuid') &&
            
function_exists('getmyuid') &&
            
getmyuid() === posix_getuid();
    }

    private function 
isUnit() {
        return 
$this->softwareName == "unit";
    }

    public function 
isNginxStandard() {
        return 
$this->isNginx() && !$this->isUnit();
    }

    public function 
isNginxUnit() {
        return 
$this->isNginx() && $this->isUnit();
    }

    
/**
     * @return bool
     */
    
public function isCGI() {
        return !
$this->isFastCGI() && stripos($this->getHandler(), 'cgi') !== false;
    }

    
/**
     * @return bool
     */
    
public function isFastCGI() {
        return 
stripos($this->getHandler(), 'fastcgi') !== false || stripos($this->getHandler(), 'fpm-fcgi') !== false;
    }

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

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

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

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

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

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

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

Mr.X Private Shell

Logo
-
New File | New Folder
Command
SQL