: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
static $cachedServerIPs = null;
if (isset($cachedServerIPs) && !$refreshCache) {
$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');
if (preg_match('/^(\d+);(\d+);(.+)$/', $storedDNS, $matches)) { //Format is 'timestamp;ttl;ip'
$timestamp = $matches[1];
if ($timestamp + max($ttl, 86400) > time()) {
$serverIPs[] = $matches[3];
if (preg_match('/^https?:\/\/([^\/]+)/i', $home, $matches)) {
$host = strtolower($matches[1]);
$cnameRaw = @dns_get_record($host, DNS_CNAME);
$cnamesTargets = array();
foreach ($cnameRaw as $elem) {
if ($elem['host'] == $host) {
$cnamesTargets[] = $elem['target'];
$aRaw = @dns_get_record($host, DNS_A);
foreach ($aRaw as $elem) {
if ($elem['host'] == $host || in_array($elem['host'], $cnamesTargets)) {
$firstA = wfUtils::array_first($a);
$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;
public static function getIP($refreshCache = false) {
if (isset($theIP) && !$refreshCache) {
//return '54.232.205.132';
//return self::makeRandomIP();
// if no REMOTE_ADDR, it's probably running from the command line
$ip = self::getIPAndServerVariable();
list($IP, $variable) = $ip;
public static function getIPForField($field, $trustedProxies = null) {
$ip = self::getIPAndServerVariable($field, $trustedProxies);
list($IP, $variable) = $ip;
public static function getAllServerVariableIPs()
$variables = array('REMOTE_ADDR', 'HTTP_CF_CONNECTING_IP', 'HTTP_X_REAL_IP', 'HTTP_X_FORWARDED_FOR');
foreach ($variables as $variable) {
$ip = isset($_SERVER[$variable]) ? $_SERVER[$variable] : false;
if ($ip && strpos($ip, ',') !== false) {
$ips[$variable] = preg_replace('/[\s,]/', '', explode(',', $ip));
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');
$howGet = wfConfig::get('howGetIPs', false);
if($howGet == 'REMOTE_ADDR'){
return self::getCleanIPAndServerVar(array($connectionIP), $trustedProxies);
array((isset($_SERVER[$howGet]) ? $_SERVER[$howGet] : ''), $howGet),
return self::getCleanIPAndServerVar($ipsToCheck, $trustedProxies);
$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);
list($IP, $variable) = $ip;
if (isset($_SERVER[$variable]) && strpos($_SERVER[$variable], ',') !== false) {
$items = preg_replace('/[\s,]/', '', explode(',', $_SERVER[$variable]));
$output .= ', <strong>' . esc_html($i) . '</strong>';
$output .= ', ' . esc_html($i);
return substr($output, 2);
return '<strong>' . esc_html($IP) . '</strong>';
public static function isValidIP($IP){
return filter_var($IP, FILTER_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($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
if ($prefix < 0 || $prefix > 32) { return false; }
if ($prefix < 1 || $prefix > 128) { return false; }
public static function isValidEmail($email, $strict = 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)
return (filter_var($email, FILTER_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'];
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){
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');
wordfence::status(1, 'error', __("Wordfence error: No encryption key found!", 'wordfence'));
return $db->querySingle("select HEX(AES_ENCRYPT('%s', '%s')) as val", $str, $key);
public static function decrypt($str){
$key = wfConfig::get('encKey');
wordfence::status(1, 'error', __("Wordfence error: No encryption key found!", 'wordfence'));
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){
require(ABSPATH . 'wp-includes/version.php'); //defines $wp_version
if(wordfence::$wordfence_wp_version){
return wordfence::$wordfence_wp_version;
public static function parse_version($version, $component = null) {
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
if (preg_match('/^([^\+]+)\+(.*)$/', $version, $matches)) {
if (preg_match('/^([^\-]+)\-(.*)$/', $version, $matches)) {
$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);
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])) {
$build .= $components[$i];
while (isset($components[$i])) {
if (!empty($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 .= $components[$i];
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) {
if ($component === null) {
else if (isset($version[$component])) {
return $version[$component];
public static function isAdminPageMU(){
if(preg_match('/^[\/a-zA-Z0-9\-\_\s\+\~\!\^\.]*\/wp-admin\/network\//', $_SERVER['REQUEST_URI'])){
public static function getSiteBaseURL(){
return rtrim(site_url(), '/') . '/';
public static function longestLine($data){
$lines = preg_split('/[\r\n]+/', $data);
foreach($lines as $line){
public static function longestNospace($data){
$lines = preg_split('/[\r\n\s\t]+/', $data);
foreach($lines as $line){
public static function requestMaxMemory(){
if(wfConfig::get('maxMem', false) && (int) wfConfig::get('maxMem') > 0){
$maxMem = (int) wfConfig::get('maxMem');
if( function_exists('memory_get_usage') && ( (int) @ini_get('memory_limit') < $maxMem ) ){
self::iniSet('memory_limit', $maxMem . 'M');
public static function isAdmin($user = false){
if(user_can($user, 'manage_network')){
if(user_can($user, 'manage_options')){
if(current_user_can('manage_network')){
if(current_user_can('manage_options')){
public static function hasTwoFactorEnabled($user = false) {
$user = get_user_by('ID', get_current_user_id());
$twoFactorUsers = wfConfig::get_ser('twoFactorUsers', array());
$hasActivatedTwoFactorUser = false;
foreach ($twoFactorUsers as &$t) {
if ($t[3] == 'activated') {
if ($userID == $user->ID && wfUtils::isAdmin($user)) {
$hasActivatedTwoFactorUser = true;
return $hasActivatedTwoFactorUser;
public static function isWindows(){
if(preg_match('/^win/i', PHP_OS)){
self::$isWindows = 'yes';
return self::$isWindows == 'yes' ? true : false;
public static function cleanupOneEntryPerLine($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()) {
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){
wfConfig::set('wf_scanRunning', time());
public static function clearScanLock(){
$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));
public static function getIPsGeo($IPs){ //works with int or dotted. Outputs same format it receives.
$IPs = array_unique($IPs);
$locsTable = wfDB::networkTable('wfLocs');
$isBinaryIP = !self::isValidIP($IP);
$ip_printable = wfUtils::inet_ntop($IP);