: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
'error' => __('No license was provided to install.', 'wordfence'),
public static function ajax_recordTOUPP_callback() {
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
$result = $api->call('record_toupp', array(), array());
wfConfig::set('touppBypassNextCheck', 1); //In case this call kicks off the cron that checks, this avoids the race condition of that setting the prompt as being needed at the same time we've just recorded it as accepted
wfConfig::set('touppPromptNeeded', 0);
public static function ajax_mailingSignup_callback() {
if (isset($_POST['emails'])) {
$emails = @json_decode(stripslashes($_POST['emails']), true);
if (is_array($emails) && count($emails)) {
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
$result = $api->call('mailing_signup', array(), array('signup' => json_encode(array('emails' => $emails)), 'ip' => wfUtils::getIP()));
public static function ajax_enableAllOptionsPage_callback() {
wfConfig::set('displayTopLevelOptions', 1);
$n = wfNotification::getNotificationForCategory('wfplugin_devalloptions');
$response = array('success' => true);
if (function_exists('network_admin_url') && is_multisite()) {
$response['redirect'] = network_admin_url('admin.php?page=WordfenceOptions');
$response['redirect'] = admin_url('admin.php?page=WordfenceOptions');
public static function ajax_restoreDefaults_callback() {
if (!empty($_POST['section'])) {
if (wfConfig::restoreDefaults($_POST['section'])) {
'error' => __('An unknown configuration section was provided.', 'wordfence'),
'error' => __('No configuration section was provided.', 'wordfence'),
public static function ajax_saveOptions_callback() {
if (!empty($_POST['changes']) && ($changes = json_decode(stripslashes($_POST['changes']), true)) !== false) {
$errors = wfConfig::validate($changes);
if (count($errors) == 1) {
'error' => sprintf(/* translators: Error message. */ __('An error occurred while saving the configuration: %s', 'wordfence'), $errors[0]['error']),
else if (count($errors) > 1) {
$compoundMessage = array();
foreach ($errors as $e) {
$compoundMessage[] = $e['error'];
'error' => sprintf(/* translators: Error message. */ __('Errors occurred while saving the configuration: %s', 'wordfence'), implode(', ', $compoundMessage)),
'error' => __('Errors occurred while saving the configuration.', 'wordfence'),
wfConfig::save(wfConfig::clean($changes));
$response = array('success' => true);
if (!empty($_POST['page']) && preg_match('/^Wordfence/i', $_POST['page'])) {
if ($_POST['page'] == 'WordfenceOptions' && isset($changes['displayTopLevelOptions']) && !wfUtils::truthyToBoolean($changes['displayTopLevelOptions'])) {
if (function_exists('network_admin_url') && is_multisite()) {
$response['redirect'] = network_admin_url('admin.php?page=Wordfence');
$response['redirect'] = admin_url('admin.php?page=Wordfence');
catch (wfWAFStorageFileException $e) {
'error' => __('An error occurred while saving the configuration.', 'wordfence'),
catch (wfWAFStorageEngineMySQLiException $e) {
'error' => __('An error occurred while saving the configuration.', 'wordfence'),
'error' => $e->getMessage(),
'error' => __('No configuration changes were provided to save.', 'wordfence'),
public static function ajax_setDeactivationOption_callback() {
$key = array_key_exists('option', $_POST) ? $_POST['option'] : null;
$option = wfDeactivationOption::forKey($key);
'error' => __('Invalid option specified', 'wordfence')
wfConfig::set('deleteTablesOnDeact', $option->deletesMain());
\WordfenceLS\Controller_Settings::shared()->set('delete-deactivation', $option->deletesLoginSecurity());
public static function ajax_updateIPPreview_callback() {
$howGet = $_POST['howGetIPs'];
$testIPs = preg_split('/[\r\n,]+/', $_POST['howGetIPs_trusted_proxies']);
foreach ($testIPs as $val) {
if (wfUtils::isValidIP($val) || wfUtils::isValidCIDRRange($val)) {
$trustedProxies = $validIPs;
$preset = $_POST['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;
$ipAll = wfUtils::getIPPreview($howGet, $trustedProxies);
$ip = wfUtils::getIPForField($howGet, $trustedProxies);
return array('ok' => 1, 'ip' => $ip, 'ipAll' => $ipAll, 'resolvedProxies' => $trustedProxies);
public static function ajax_hideFileHtaccess_callback(){
$issues = new wfIssues();
$issue = $issues->getIssueByID((int) $_POST['issueID']);
return array('errorMsg' => __("We could not find that issue in our database.", 'wordfence'));
if (!function_exists('get_home_path')) {
include_once(ABSPATH . 'wp-admin/includes/file.php');
$homeURL = get_home_url();
$components = parse_url($homeURL);
if ($components === false) {
return array('errorMsg' => __("An error occurred while trying to hide the file.", 'wordfence'));
if (isset($components['path'])) {
$sitePath = trim($components['path'], '/');
$homePath = wfUtils::getHomePath();
$file = $issue['data']['file'];
$localFile = ABSPATH . '/' . $file; //The scanner uses ABSPATH as its base rather than get_home_path()
$localFile = realpath($localFile);
if (strpos($localFile, $homePath) !== 0) {
return array('errorMsg' => __("An invalid file was requested for hiding.", 'wordfence'));
$localFile = substr($localFile, strlen($homePath));
$absoluteURIPath = trim($sitePath . '/' . $localFile, '/');
$regexLocalFile = preg_replace('#/#', '/+', preg_quote($absoluteURIPath));
$filename = basename($localFile);
$htaccessContent = <<<HTACCESS
RewriteCond %{REQUEST_URI} ^/?{$regexLocalFile}$
RewriteRule .* - [F,L,NC]
<IfModule !mod_rewrite.c>
<IfModule mod_authz_core.c>
<IfModule !mod_authz_core.c>
if (!wfUtils::htaccessPrepend($htaccessContent)) {
return array('errorMsg' => __("You don't have permission to repair .htaccess. You need to either fix the file manually using FTP or change the file permissions and ownership so that your web server has write access to repair the file.", 'wordfence'));
$issues->updateIssue((int) $_POST['issueID'], 'delete');
wfScanEngine::refreshScanNotification($issues);
$counts = $issues->getIssueCounts();
'issueCounts' => $counts,
public static function ajax_unlockOutIP_callback(){
wfBlock::unlockOutIP($IP);
self::clearLockoutCounters($IP);
public static function ajax_unblockIP_callback(){
self::clearLockoutCounters($IP);
public static function ajax_permBlockIP_callback(){
wfBlock::createIP(__('Manual permanent block by admin', 'wordfence'), $IP, wfBlock::DURATION_FOREVER, time(), false, 0, wfBlock::TYPE_IP_MANUAL);
public static function ajax_unblockRange_callback(){
$id = trim($_POST['id']);
wfBlock::removeBlockIDs(array($id));
public static function ajax_whois_callback(){
$val = trim($_POST['val']);
$val = preg_replace('/[^a-zA-Z0-9\.\-:]+/', '', $val);
$api = new wfAPI(wfConfig::get('apiKey'), wfUtils::getWPVersion());
$result = $api->call('whois', array(), array(
return array('ok' => 1, 'result' => $result['result']);
catch (wfAPICallErrorResponseException $e) {
public static function ajax_recentTraffic_callback(){
$ip = trim($_POST['ip']);
$response = self::IPTraf($ip);
$reverseLookup = $response['reverseLookup'];
$results = $response['results'];
require(dirname(__FILE__) . '/IPTrafList.php');
$content = ob_get_clean();
return array('ok' => 1, 'result' => $content);
} catch (InvalidArgumentException $e) {
return array('errorMsg' => $e->getMessage());
public static function ajax_blockIP_callback() {
$IP = trim($_POST['IP']);
$perm = (isset($_POST['perm']) && $_POST['perm'] == '1') ? wfBlock::DURATION_FOREVER : wfConfig::getInt('blockedTime');
if (!wfUtils::isValidIP($IP)) {
return array('err' => 1, 'errorMsg' => __("Please enter a valid IP address to block.", 'wordfence'));
if ($IP == wfUtils::getIP()) {
return array('err' => 1, 'errorMsg' => __("You can't block your own IP address.", 'wordfence'));
$forcedWhitelistEntry = false;
if (wfBlock::isWhitelisted($IP, $forcedWhitelistEntry)) {
$message = sprintf(/* translators: IP address. */ __("The IP address %s is allowlisted and can't be blocked. You can remove this IP from the allowlist on the Wordfence options page.", 'wordfence'), wp_kses($IP, array()));
if ($forcedWhitelistEntry) {
$message = sprintf(/* translators: IP address. */ __("The IP address %s is in a range of IP addresses that Wordfence does not block. The IP range may be internal or belong to a service safe to allow access for.", 'wordfence'), wp_kses($IP, array()));
return array('err' => 1, 'errorMsg' => $message);
if (wfConfig::get('neverBlockBG') != 'treatAsOtherCrawlers') { //Either neverBlockVerified or neverBlockUA is selected which means the user doesn't want to block google
if (wfCrawl::isVerifiedGoogleCrawler($IP)) {
return array('err' => 1, 'errorMsg' => __("The IP address you're trying to block belongs to Google. Your options are currently set to not block these crawlers. Change this in Wordfence options if you want to manually block Google.", 'wordfence'));
wfBlock::createIP($_POST['reason'], $IP, $perm);
wfActivityReport::logBlockedIP($IP, null, 'manual');
public static function ajax_avatarLookup_callback() {
$ids = explode(',', $_POST['ids']);
$avatar = get_avatar($id, 16);
return array('ok' => 1, 'avatars' => $res);
public static function ajax_reverseLookup_callback(){
$ips = explode(',', $_POST['ips']);
$res[$ip] = wfUtils::reverseLookup($ip);
return array('ok' => 1, 'ips' => $res);
public static function ajax_deleteIssue_callback(){
$wfIssues = new wfIssues();
$wfIssues->deleteIssue($issueID);
wfScanEngine::refreshScanNotification($wfIssues);
public static function ajax_updateAllIssues_callback(){
if($op == 'deleteIgnored'){
} else if($op == 'deleteNew'){
} else if($op == 'ignoreAllNew'){
return array('errorMsg' => __("An invalid operation was called.", 'wordfence'));
wfScanEngine::refreshScanNotification($i);
public static function ajax_updateIssueStatus_callback(){
$wfIssues = new wfIssues();
$status = $_POST['status'];
if(! preg_match('/^(?:new|delete|ignoreP|ignoreC)$/', $status)){
return array('errorMsg' => __("An invalid status was specified when trying to update that issue.", 'wordfence'));
$wfIssues->updateIssue($issueID, $status);
wfScanEngine::refreshScanNotification($wfIssues);
$counts = $wfIssues->getIssueCounts();
'issueCounts' => $counts,
public static function ajax_killScan_callback(){
wordfence::status(1, 'info', __("Scan stop request received.", 'wordfence'));
wordfence::status(10, 'info', 'SUM_KILLED:' . __("A request was received to stop the previous scan.", 'wordfence'));
wfUtils::clearScanLock(); //Clear the lock now because there may not be a scan running to pick up the kill request and clear the lock
wfScanEngine::requestKill();
wfConfig::remove('scanStartAttempt');
wfConfig::set('lastScanFailureType', false);
public static function ajax_loadIssues_callback(){
$offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
$limit = isset($_POST['limit']) ? intval($_POST['limit']) : WORDFENCE_SCAN_ISSUES_PER_PAGE;
$ignoredOffset = isset($_POST['ignoredOffset']) ? intval($_POST['ignoredOffset']) : 0;
$ignoredLimit = isset($_POST['ignoredLimit']) ? intval($_POST['ignoredLimit']) : WORDFENCE_SCAN_ISSUES_PER_PAGE;
$issues = wfIssues::shared()->getIssues($offset, $limit, $ignoredOffset, $ignoredLimit);
$issueCounts = array_merge(array('new' => 0, 'ignoreP' => 0, 'ignoreC' => 0), wfIssues::shared()->getIssueCounts());
'issueCounts' => $issueCounts,
public static function ajax_ticker_callback() {
$table_wfStatus = wfDB::networkTable('wfStatus');
$serverTime = $wfdb->querySingle("select unix_timestamp()");
'serverTime' => $serverTime,
'serverMicrotime' => microtime(true),
'msg' => wp_kses_data((string) $wfdb->querySingle("SELECT msg FROM {$table_wfStatus} WHERE level < 3 AND ctime > (UNIX_TIMESTAMP() - 3600) ORDER BY ctime DESC LIMIT 1")),
if (get_site_option('wordfence_syncAttackDataAttempts') > 10) {
self::syncAttackData(false);
$results = self::ajax_loadLiveTraffic_callback();
$events = $results['data'];
if (isset($results['sql'])) {
$jsonData['sql'] = $results['sql'];
$jsonData['events'] = $events;
public static function ajax_activityLogUpdate_callback() {
$statusTable = wfDB::networkTable('wfStatus');
$row = $wpdb->get_row("SELECT ctime, msg FROM {$statusTable} WHERE level < 3 AND ctime > (UNIX_TIMESTAMP() - 3600) ORDER BY ctime DESC LIMIT 1", ARRAY_A);
$lastMessage = __('Idle', 'wordfence');
$lastScanCompleted = wfConfig::get('lastScanCompleted');
$lastMessage = '[' . strtoupper(wfUtils::formatLocalTime('M d H:i:s', $row['ctime'])) . '] ' . wp_kses_data($row['msg']);
else if ($lastScanCompleted == 'ok') {
$scanLastCompletion = (int) wfScanner::shared()->lastScanTime();
if ($scanLastCompletion) {
$lastMessage = sprintf(/* translators: Localized date. */ __('Scan completed on %s', 'wordfence'), wfUtils::formatLocalTime(get_option('date_format') . ' ' . get_option('time_format'), $scanLastCompletion));
else if ($lastScanCompleted === false || empty($lastScanCompleted)) {
$lastMessage = __('Last scan failed', 'wordfence');
$issues = wfIssues::shared();
$scanFailed = $issues->hasScanFailed();
$scanner = wfScanner::shared();
$stages = $scanner->stageStatus();
foreach ($stages as $key => &$value) {
case wfScanner::STATUS_PENDING:
case wfScanner::STATUS_RUNNING:
case wfScanner::STATUS_RUNNING_WARNING:
$value = 'wf-scan-step wf-scan-step-running';
case wfScanner::STATUS_COMPLETE_SUCCESS:
$value = 'wf-scan-step wf-scan-step-complete-success';
case wfScanner::STATUS_COMPLETE_WARNING:
$value = 'wf-scan-step wf-scan-step-complete-warning';
case wfScanner::STATUS_PREMIUM:
$value = 'wf-scan-step wf-scan-step-premium';
case wfScanner::STATUS_DISABLED:
$value = 'wf-scan-step wf-scan-step-disabled';
'wf-scan-results-stats-postscommentsfiles' => $scanner->getSummaryItem(wfScanner::SUMMARY_SCANNED_POSTS, 0) + $scanner->getSummaryItem(wfScanner::SUMMARY_SCANNED_COMMENTS, 0) + $scanner->getSummaryItem(wfScanner::SUMMARY_SCANNED_FILES, 0),
'wf-scan-results-stats-themesplugins' => $scanner->getSummaryItem(wfScanner::SUMMARY_SCANNED_PLUGINS, 0) + $scanner->getSummaryItem(wfScanner::SUMMARY_SCANNED_THEMES, 0),
'wf-scan-results-stats-users' => $scanner->getSummaryItem(wfScanner::SUMMARY_SCANNED_USERS, 0),
'wf-scan-results-stats-urls' => $scanner->getSummaryItem(wfScanner::SUMMARY_SCANNED_URLS, 0),
'wf-scan-results-stats-issues' => $issues->getIssueCount(),
$lastIssueUpdateTimestamp = wfIssues::shared()->getLastIssueUpdateTimestamp();
$issueCounts = array_merge(array('new' => 0, 'ignoreP' => 0, 'ignoreC' => 0), wfIssues::shared()->getIssueCounts());
if ($lastIssueUpdateTimestamp > $_POST['lastissuetime']) {
$issues = wfIssues::shared()->getIssues(0, WORDFENCE_SCAN_ISSUES_PER_PAGE, 0, WORDFENCE_SCAN_ISSUES_PER_PAGE);
$timeLimit = intval(wfConfig::get('scan_maxDuration'));
$timeLimit = WORDFENCE_DEFAULT_MAX_SCAN_TIME;