: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
catch (wfViewNotFoundException $e) {
//Ignore -- should never happen since we validate the type
if (!empty($viewContent)) {
$content .= $viewContent . "\n\n";
$content .= __('No Ignored Issues', 'wordfence') . "\n\n";
$content .= str_repeat('-', 80);
if (wfUtils::funcEnabled('phpinfo')) { phpinfo(); } else { echo "\n\n" . __('Unable to output phpinfo content because it is disabled', 'wordfence') . "\n\n"; }
$phpinfo = ob_get_contents();
$rawEmails = explode(",", $_POST['email']);
foreach ($rawEmails as $e) {
if (wfUtils::isValidEmail($e)) {
wp_mail(implode(', ', $emails), __('Wordfence Activity Log', 'wordfence'), $content);
public static function ajax_downgradeLicense_callback(){
$api = new wfAPI('', wfUtils::getWPVersion());
$keyData = $api->call('get_anon_api_key', array(), array('previousLicense' => wfConfig::get('apiKey')));
if($keyData['ok'] && $keyData['apiKey']){
wfLicense::current()->downgradeToFree($keyData['apiKey'])->save();
//When downgrading we must disable all two factor authentication because it can lock an admin out if we don't.
wfConfig::set_ser('twoFactorUsers', array());
wfConfig::remove('premiumAutoRenew');
wfConfig::remove('premiumNextRenew');
wfConfig::remove('premiumPaymentExpiring');
wfConfig::remove('premiumPaymentExpired');
wfConfig::remove('premiumPaymentMissing');
wfConfig::remove('premiumPaymentHold');
self::licenseStatusChanged();
if (method_exists(wfWAF::getInstance()->getStorageEngine(), 'purgeIPBlocks')) {
wfWAF::getInstance()->getStorageEngine()->purgeIPBlocks(wfWAFStorageInterface::IP_BLOCKS_BLACKLIST);
throw new Exception(__("Could not understand the response we received from the Wordfence servers when applying for a free license key.", 'wordfence'));
return array('errorMsg' => sprintf(/* translators: Error message. */ __("Could not fetch free license key from Wordfence: %s", 'wordfence'), wp_kses($e->getMessage(), array())));
public static function ajax_tourClosed_callback() {
if (isset($_POST['page'])) {
$keys = array(wfOnboardingController::TOUR_DASHBOARD, wfOnboardingController::TOUR_FIREWALL, wfOnboardingController::TOUR_SCAN, wfOnboardingController::TOUR_BLOCKING, wfOnboardingController::TOUR_LIVE_TRAFFIC, wfOnboardingController::TOUR_LOGIN_SECURITY);
if (in_array($page, $keys)) {
if (wfOnboardingController::shouldShowNewTour($page)) {
wfConfig::set('needsNewTour_' . $page, 0);
else if (wfOnboardingController::shouldShowUpgradeTour($page)) {
wfConfig::set('needsUpgradeTour_' . $page, 0);
public static function ajax_autoUpdateChoice_callback(){
$choice = $_POST['choice'];
wfConfig::set('autoUpdateChoice', '1');
wfConfig::set('autoUpdate', '1');
wfConfig::set('autoUpdate', '0');
public static function ajax_misconfiguredHowGetIPsChoice_callback() {
$choice = $_POST['choice'];
wfConfig::set('howGetIPs', wfConfig::get('detectProxyRecommendation', ''));
if (isset($_POST['issueID'])) {
$issueID = intval($_POST['issueID']);
$wfIssues = new wfIssues();
$wfIssues->updateIssue($issueID, 'delete');
wfScanEngine::refreshScanNotification($wfIssues);
wfConfig::set('misconfiguredHowGetIPsChoice' . WORDFENCE_VERSION, '1');
public static function ajax_switchLiveTrafficSecurityOnlyChoice_callback() {
$choice = $_POST['choice'];
wfConfig::set('liveTrafficEnabled', false);
wfConfig::set('switchLiveTrafficSecurityOnlyChoice', '1');
public static function ajax_wordfenceSatisfactionChoice_callback() {
wfConfig::set('satisfactionPromptDismissed', time());
$choice = $_POST['choice'];
if ($choice == 'feedback' && isset($_POST['feedback']) && !empty($_POST['feedback'])) {
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
$result = $api->call('plugin_feedback', array(), array('feedback' => $_POST['feedback']));
//else -- no additional action for yes/no
public static function ajax_dismissAdminNotice_callback() {
if (isset($_POST['id'])) {
wfAdminNoticeQueue::removeAdminNotice($_POST['id']);
public static function ajax_hideNoticeForUser_callback() {
if (isset($_POST['id'])) {
self::hideNoticeForUser($_POST['id']);
public static function ajax_updateConfig_callback(){
wfConfig::set($key, $val);
if ($key == 'howGetIPs') {
wfConfig::set('detectProxyNextCheck', false, wfConfig::DONT_AUTOLOAD);
$ipAll = wfUtils::getIPPreview();
$ip = wfUtils::getIP(true);
return array('ok' => 1, 'ip' => $ip, 'ipAll' => $ipAll);
public static function ajax_checkHtaccess_callback(){
return array('nginx' => 1);
$file = wfCache::getHtaccessPath();
return array('err' => __("We could not find your .htaccess file to modify it.", 'wordfence'));
$fh = @fopen($file, 'r+');
return array('err' => sprintf(/* translators: Error message. */ __("We found your .htaccess file but could not open it for writing: %s", 'wordfence'), $err['message']));
public static function ajax_downloadHtaccess_callback(){
$url = preg_replace('/^https?:\/\//i', '', $url);
$url = preg_replace('/[^a-zA-Z0-9\.]+/', '_', $url);
$url = preg_replace('/^_+/', '', $url);
$url = preg_replace('/_+$/', '', $url);
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="htaccess_Backup_for_' . $url . '.txt"');
$file = wfCache::getHtaccessPath();
public static function ajax_downloadLogFile_callback() {
if (!isset($_GET['logfile'])) {
wfErrorLogHandler::outputErrorLog(stripslashes($_GET['logfile'])); //exits
public static function _blocksAJAXReponse(&$hasCountryBlock = false, $offset = 0, $sortColumn = 'type', $sortDirection = 'ascending', $filter = '') {
$includeAutomatic = wfConfig::get('displayAutomaticBlocks');
$types = array(); //Empty array is all
if (!$includeAutomatic) {
$types = array(wfBlock::TYPE_IP_MANUAL, wfBlock::TYPE_IP_AUTOMATIC_PERMANENT, wfBlock::TYPE_COUNTRY, wfBlock::TYPE_PATTERN);
$blocks = wfBlock::allBlocks(true, $types, $offset, WORDFENCE_BLOCKED_IPS_PER_PAGE, $sortColumn, $sortDirection);
$blocks = wfBlock::filteredBlocks(true, $types, $offset, WORDFENCE_BLOCKED_IPS_PER_PAGE, $sortColumn, $sortDirection, $filter);
$dateFormat = get_option('date_format') . ' ' . get_option('time_format');
$hasCountryBlock = wfUtils::array_first(wfBlock::countryBlocks(true));
if ($hasCountryBlock !== null) {
$hasCountryBlock = json_encode($hasCountryBlock->editValues());
foreach ($blocks as $b) {
$entry['typeSort'] = $b->type;
$entry['typeDisplay'] = esc_html(wfBlock::nameForType($b->type));
case wfBlock::TYPE_IP_MANUAL:
$entry['editType'] = 'ip-address';
case wfBlock::TYPE_IP_AUTOMATIC_PERMANENT:
$entry['detailSort'] = base64_encode(wfUtils::inet_pton($b->ip));
$entry['detailDisplay'] = esc_html($b->ip);
case wfBlock::TYPE_IP_AUTOMATIC_TEMPORARY:
case wfBlock::TYPE_WFSN_TEMPORARY:
case wfBlock::TYPE_RATE_BLOCK:
case wfBlock::TYPE_RATE_THROTTLE:
case wfBlock::TYPE_LOCKOUT:
if (!$includeAutomatic) { $skip = true; }
$entry['detailSort'] = base64_encode(wfUtils::inet_pton($b->ip));
$entry['detailDisplay'] = esc_html($b->ip);
case wfBlock::TYPE_COUNTRY:
require(WORDFENCE_PATH . 'lib/wfBulkCountries.php'); /** @var array $wfBulkCountries */
$countries = $b->countries;
$entry['editType'] = 'country';
$entry['editValues'] = json_encode($b->editValues());
$entry['detailSort'] = $b->blockLogin . '|' . $b->blockSite . '|' . implode('|', $countries);
$entry['detailDisplay'] = '';
if ($countries == array_keys($wfBulkCountries)) {
$entry['detailDisplay'] = __('All Countries', 'wordfence');
else if (count($countries) == 1) {
$entry['detailDisplay'] = __('1 Country', 'wordfence');
$entry['detailDisplay'] = sprintf(/* translators: Number of countries. */ __('%d Countries', 'wordfence'), count($countries));
if ($b->blockLogin && $b->blockSite) {
$entry['detailDisplay'] .= ' (' . __('Entire Site', 'wordfence') . ')';
else if ($b->blockLogin) {
$entry['detailDisplay'] .= ' (' . __('Login Only', 'wordfence') . ')';
else if ($b->blockSite) {
$entry['detailDisplay'] .= ' (' . __('Site Except Login', 'wordfence') . ')';
case wfBlock::TYPE_PATTERN:
$entry['editType'] = 'custom-pattern';
$entry['detailSort'] = base64_encode($b->ipRange . '|' . $b->userAgent . '|' . $b->referrer . '|' . $b->hostname);
if (!empty($b->ipRange)) { $components[] = __('IP Range', 'wordfence') . ' - ' . $b->ipRange; }
if (!empty($b->userAgent)) { $components[] = __('User Agent', 'wordfence') . ' - ' . $b->userAgent; }
if (!empty($b->referrer)) { $components[] = __('Referrer', 'wordfence') . ' - ' . $b->referrer; }
if (!empty($b->hostname)) { $components[] = __('Hostname', 'wordfence') . ' - ' . $b->hostname; }
$entry['detailDisplay'] = esc_html(implode(', ', $components));
$entry['ruleAdded'] = $b->blockedTime;
$entry['ruleAddedSort'] = $b->blockedTime;
$entry['ruleAddedDisplay'] = esc_html(wfUtils::formatLocalTime($dateFormat, $b->blockedTime));
$entry['reasonSort'] = esc_attr($b->reason);
$entry['reasonDisplay'] = esc_html($b->reason);
$entry['expiration'] = $b->expiration;
$entry['expirationSort'] = $b->expiration;
$entry['expirationDisplay'] = ($b->expiration == wfBlock::DURATION_FOREVER ? __('Permanent', 'wordfence') : esc_html(wfUtils::formatLocalTime($dateFormat, $b->expiration)));
$entry['blockCountSort'] = $b->blockedHits;
$entry['blockCountDisplay'] = $b->blockedHits;
$entry['lastAttemptSort'] = $b->lastAttempt;
$entry['lastAttemptDisplay'] = ($b->lastAttempt == 0 ? __('Never', 'wordfence') : esc_html(wfUtils::formatLocalTime($dateFormat, $b->lastAttempt)));
public static function ajax_getBlocks_callback() {
if (isset($_POST['offset'])) {
$offset = (int) $_POST['offset'];
if (isset($_POST['sortColumn']) && in_array($_POST['sortColumn'], array('type', 'detail', 'ruleAdded', 'reason', 'expiration', 'blockCount', 'lastAttempt'))) {
$sortColumn = $_POST['sortColumn'];
$sortDirection = 'ascending';
if (isset($_POST['sortDirection']) && in_array($_POST['sortDirection'], array('ascending', 'descending'))) {
$sortDirection = $_POST['sortDirection'];
if (isset($_POST['blocksFilter'])) {
$filter = $_POST['blocksFilter'];
$hasCountryBlock = false;
$blocks = self::_blocksAJAXReponse($hasCountryBlock, $offset, $sortColumn, $sortDirection, $filter);
return array('blocks' => $blocks, 'hasCountryBlock' => $hasCountryBlock);
public static function ajax_createBlock_callback() {
if (isset($_POST['offset'])) {
$offset = (int) $_POST['offset'];
if (isset($_POST['sortColumn']) && in_array($_POST['sortColumn'], array('type', 'detail', 'ruleAdded', 'reason', 'expiration', 'blockCount', 'lastAttempt'))) {
$sortColumn = $_POST['sortColumn'];
$sortDirection = 'ascending';
if (isset($_POST['sortDirection']) && in_array($_POST['sortDirection'], array('ascending', 'descending'))) {
$sortDirection = $_POST['sortDirection'];
if (isset($_POST['blocksFilter'])) {
$filter = $_POST['blocksFilter'];
if (!empty($_POST['payload']) && ($payload = json_decode(stripslashes($_POST['payload']), true)) !== false) {
$error = wfBlock::validate($payload);
wfBlock::create($payload);
$hasCountryBlock = false;
$blocks = self::_blocksAJAXReponse($hasCountryBlock, $offset, $sortColumn, $sortDirection, $filter);
return array('success' => true, 'blocks' => $blocks, 'hasCountryBlock' => $hasCountryBlock);
'error' => __('An error occurred while creating the block.', 'wordfence'),
'error' => __('No block parameters were provided.', 'wordfence'),
public static function ajax_deleteBlocks_callback() {
if (isset($_POST['offset'])) {
$offset = (int) $_POST['offset'];
if (isset($_POST['sortColumn']) && in_array($_POST['sortColumn'], array('type', 'detail', 'ruleAdded', 'reason', 'expiration', 'blockCount', 'lastAttempt'))) {
$sortColumn = $_POST['sortColumn'];
$sortDirection = 'ascending';
if (isset($_POST['sortDirection']) && in_array($_POST['sortDirection'], array('ascending', 'descending'))) {
$sortDirection = $_POST['sortDirection'];
if (isset($_POST['blocksFilter'])) {
$filter = $_POST['blocksFilter'];
if (!empty($_POST['blocks']) && ($blocks = json_decode(stripslashes($_POST['blocks']), true)) !== false && is_array($blocks)) {
$removed = wfBlock::removeBlockIDs($blocks, true); //wfBlock::removeBlockIDs sanitizes the array
foreach($removed as $block) {
self::clearLockoutCounters(wfUtils::inet_ntop($block->IP));
$hasCountryBlock = false;
$blocks = self::_blocksAJAXReponse($hasCountryBlock, $offset, $sortColumn, $sortDirection, $filter);
return array('success' => true, 'blocks' => $blocks, 'hasCountryBlock' => $hasCountryBlock);
'error' => __('No blocks were provided.', 'wordfence'),
public static function ajax_makePermanentBlocks_callback() {
if (isset($_POST['offset'])) {
$offset = (int) $_POST['offset'];
if (isset($_POST['sortColumn']) && in_array($_POST['sortColumn'], array('type', 'detail', 'ruleAdded', 'reason', 'expiration', 'blockCount', 'lastAttempt'))) {
$sortColumn = $_POST['sortColumn'];
$sortDirection = 'ascending';
if (isset($_POST['sortDirection']) && in_array($_POST['sortDirection'], array('ascending', 'descending'))) {
$sortDirection = $_POST['sortDirection'];
if (isset($_POST['blocksFilter'])) {
$filter = $_POST['blocksFilter'];
if (!empty($_POST['updates']) && ($updates = json_decode(stripslashes($_POST['updates']), true)) !== false && is_array($updates)) {
wfBlock::makePermanentBlockIDs($updates); //wfBlock::makePermanentBlockIDs sanitizes the array
$hasCountryBlock = false;
$blocks = self::_blocksAJAXReponse($hasCountryBlock, $offset, $sortColumn, $sortDirection, $filter);
return array('success' => true, 'blocks' => $blocks, 'hasCountryBlock' => $hasCountryBlock);
'error' => __('No blocks were provided.', 'wordfence'),
public static function ajax_installLicense_callback() {
if (!empty($_POST['license'])) {
$statusChange = array_key_exists('status_change', $_POST) ? filter_var($_POST['status_change'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) : null;
$license = strtolower(trim($_POST['license']));
if (!preg_match('/^[a-fA-F0-9]+$/', $license)) {
'error' => __('The license key entered is not in a valid format. It must contain only numbers and the letters A-F.', 'wordfence'),
$existingLicense = strtolower(wfConfig::get('apiKey', ''));
if ($existingLicense != $license) { //Key changed, try activating
$api = new wfAPI($license, wfUtils::getWPVersion());
if (!empty($existingLicense))
$parameters['previousLicense'] = $existingLicense;
$res = $api->call('check_api_key', array(), $parameters);
if ($res['ok'] && isset($res['isPaid'])) {
$isPaid = wfUtils::truthyToBoolean($res['isPaid']);
wfConfig::set('apiKey', $license);
wfConfig::set('isPaid', $isPaid); //res['isPaid'] is boolean coming back as JSON and turned back into PHP struct. Assuming JSON to PHP handles bools.
if ($statusChange !== false) {
self::licenseStatusChanged();
wfConfig::set('keyType', wfLicense::KEY_TYPE_FREE);
'isPaid' => wfConfig::get('isPaid') ? 1 : 0,
'type' => wfLicense::current()->getType()
else if (isset($res['_hasKeyConflict']) && $res['_hasKeyConflict']) {
'error' => __('The license provided is already in use on another site.', 'wordfence'),
'error' => __('The Wordfence activation server returned an unexpected response. Please try again.', 'wordfence'),
'error' => __('We received an error while trying to activate the license with the Wordfence servers: ', 'wordfence') . wp_kses($e->getMessage(), array())
if ($statusChange === true) {
self::licenseStatusChanged();
'isPaid' => wfConfig::get('isPaid') ? 1 : 0,
'type' => wfLicense::current()->getType()