: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
return self::hasIPv6Support() ? @inet_ntop($ip) : self::_inet_ntop($ip);
* Return the packed binary string of an IPv4 or IPv6 address.
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);
* Added compatibility for hosts that do not have inet_pton.
public static function _inet_pton($ip) {
if (preg_match('/^(?:\d{1,3}(?:\.|$)){4}/', $ip)) {
$octets = explode('.', $ip);
$bin = chr($octets[0]) . chr($octets[1]) . chr($octets[2]) . chr($octets[3]);
if (preg_match('/^((?:[\da-f]{1,4}(?::|)){0,8})(::)?((?:[\da-f]{1,4}(?::|)){0,8})$/i', $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 === 0 || $dbl_colon_pos === strlen($ip) - 2) ? 9 : 8) - $colon_count) . ':', $ip);
$ip_groups = explode(':', $ip);
foreach ($ip_groups as $ip_group) {
$ipv6_bin .= pack('H*', str_pad($ip_group, 4, '0', STR_PAD_LEFT));
return strlen($ipv6_bin) === 16 ? $ipv6_bin : false;
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]);
* Added compatibility for hosts that do not have inet_ntop.
public static function _inet_ntop($ip) {
return ord($ip[0]) . '.' . ord($ip[1]) . '.' . ord($ip[2]) . '.' . ord($ip[3]);
if (strlen($ip) === 16) {
if (substr($ip, 0, 12) == "\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]);
$groups = str_split($hex, 4);
foreach ($groups as $index => $group) {
if ($group == '0000' && !$done_collapse) {
$groups[$index] = ltrim($groups[$index], '0');
if (strlen($groups[$index]) === 0) {
$ip = join(':', array_filter($groups, 'strlen'));
$ip = str_replace(':::', '::', $ip);
return $ip == ':' ? '::' : $ip;
* 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.
public static function hasIPv6Support() {
return defined('AF_INET6');
public static function hasLoginCookie(){
foreach($_COOKIE as $key => $val){
if(strpos($key, 'wordpress_logged_in') === 0){
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/');
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:
* - numeric (0 => false, otherwise true)
* - 'false', 'f', 'no', 'n', or 'off' => false
* - 'true', 't', 'yes', 'y', or 'on' => true
* - empty value => false, otherwise true
public static function truthyToBoolean($value) {
if ($value === true || $value === false) {
if (is_numeric($value)) {
if (preg_match('/^(?:f(?:alse)?|no?|off)$/i', $value)) {
else if (preg_match('/^(?:t(?:rue)?|y(?:es)?|on)$/i', $value)) {
* Converts a truthy value to 1 or 0.
* @see wfUtils::truthyToBoolean
public static function truthyToInt($value) {
return self::truthyToBoolean($value) ? 1 : 0;
* Returns the whitelist presets, which first grabs the bundled list and then merges the dynamic list into it.
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);
$_cachedPresets = $wfIPWhitelist;
* Returns an array containing all whitelisted service IPs/ranges. The returned array is grouped by service
* tag: array('service1' => array('range1', 'range2', range3', ...), ...)
public static function whitelistedServiceIPs() {
$whitelistPresets = self::whitelistPresets();
$whitelistedServices = wfConfig::getJSON('whitelistedServices', array());
foreach ($whitelistPresets as $tag => $preset) {
if (!isset($preset['n'])) { //Just an array of IPs/ranges
if ((isset($preset['h']) && $preset['h']) || (isset($preset['f']) && $preset['f'])) { //Forced
$result[$tag] = $preset['r'];
if ((!isset($whitelistedServices[$tag]) && isset($preset['d']) && $preset['d']) || (isset($whitelistedServices[$tag]) && $whitelistedServices[$tag])) {
$result[$tag] = $preset['r'];
* Get the list of whitelisted IPs and networks, which is a combination of preset IPs/ranges and user-entered
* @param string $filter Group name to filter whitelist by
public static function getIPWhitelist($filter = null) {
if (!isset($wfIPWhitelist)) {
$wfIPWhitelist = self::whitelistedServiceIPs();
$wfIPWhitelist['user'] = array();
foreach (array_filter(explode(',', wfConfig::get('whitelisted'))) as $ip) {
$wfIPWhitelist['user'][] = new wfUserIPRange($ip);
foreach ($wfIPWhitelist as $group => $values) {
if ($filter === null || $group === $filter) {
$whitelist = array_merge($whitelist, $values);
* @param string $addr Should be in dot or colon notation (127.0.0.1 or ::1)
public static function isPrivateAddress($addr) {
// Run this through the preset list for IPv4 addresses.
if (filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
foreach (self::getIPWhitelist('private') as $a) {
if (self::subnetContainsIP($a, $addr)) {
return filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6) !== false
&& filter_var($addr, FILTER_VALIDATE_IP, FILTER_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.
private static function getCleanIP($arr){
$privates = array(); //Store private addrs until end as last resort.
for($i = 0; $i < count($arr); $i++){
// 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)) {
continue; //This was an array so we can skip to the next item
foreach(array(',', ' ', "\t") as $char){
if(strpos($item, $char) !== false){
$sp = explode($char, $item);
$sp = array_reverse($sp);
if (!self::isValidIP($j)) {
$j = preg_replace('/:\d+$/', '', $j); //Strip off port
if(self::isPrivateAddress($j)){
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)){
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.
* 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.
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];
// 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);
continue; //This was an array so we can skip to the next item
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){
if (!self::isValidIP($j)) {
$j = preg_replace('/:\d+$/', '', $j); //Strip off port
if (self::isIPv6MappedIPv4($j)) {
$j = self::inet_ntop(self::inet_pton($j));
foreach ($trustedProxies as $proxy) {
if (self::subnetContainsIP($proxy, $j) && $index < count($sp) - 1) {
if(self::isPrivateAddress($j)){
$privates[] = array($j, $var);
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);
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.
* Returns an array of all trusted proxies, combining both the user-entered ones and those from the selected preset.
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 (wfUtils::isValidIP($val) || wfUtils::isValidCIDRRange($val)) {
$trustedProxies[] = $val;
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]);
* Returns the known server IPs, ordered by those as the best match for outgoing requests.
* @param bool $refreshCache
public static function serverIPs($refreshCache = false) {