: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Returns whether or not the scanner should use its low resource mode.
public function useLowResourceScanning() {
$options = $this->scanOptions();
return $options['lowResourceScansEnabled'];
* Returns the array of user-defined malware signatures for use by the scanner.
public function userScanSignatures() {
$options = $this->scanOptions();
$value = $options['scan_include_extra'];
$regexs = explode("\n", $value);
foreach ($regexs as $r) {
if (preg_match('/' . $r . '/i', "") !== false) {
$signatures[] = array($id++, time(), $r, __('User defined scan pattern', 'wordfence'));
* Returns whether or not the scanner should check files outside of the WordPress installation.
public function scanOutsideWordPress() {
$options = $this->scanOptions();
return $options['other_scanOutside'];
* Returns the cleaned up array of user-excluded scan paths and patterns.
public function userExclusions() {
$options = $this->scanOptions();
$value = $options['scan_exclude'];
return explode("\n", wfUtils::cleanupOneEntryPerLine($value));
* Fetches the scan summary items into the internal cache.
private function _fetchSummaryItems() {
if ($this->_summary !== false) {
$this->_summary = wfConfig::get_ser('wf_summaryItems', array());
* Writes the scan summary cache to permanent storage.
private function _saveSummaryItems() {
if ($this->_summary !== false && $this->_dirty) {
$this->_summary['lastUpdate'] = time();
wfConfig::set_ser('wf_summaryItems', $this->_summary);
* Saves the scan summary cache if it has been more than two seconds since the last update.
* @return bool Whether or not it saved.
private function _maybeSaveSummaryItems() {
if ($this->_summary !== false && $this->_summary['lastUpdate'] < (time() - 2)) {
$this->_saveSummaryItems();
* Populates the scan summary with the default counters.
public function resetSummaryItems() {
$this->_summary = array();
$this->_summary[self::SUMMARY_SCANNED_POSTS] = 0;
$this->_summary[self::SUMMARY_SCANNED_COMMENTS] = 0;
$this->_summary[self::SUMMARY_SCANNED_FILES] = 0;
$this->_summary[self::SUMMARY_SCANNED_PLUGINS] = 0;
$this->_summary[self::SUMMARY_SCANNED_THEMES] = 0;
$this->_summary[self::SUMMARY_SCANNED_USERS] = 0;
$this->_summary[self::SUMMARY_SCANNED_URLS] = 0;
$this->_saveSummaryItems();
* Forces a save of the scan summary cache.
public function flushSummaryItems() {
$this->_saveSummaryItems();
* Returns the corresponding summary value for $key or $default if not found.
* @param mixed $default The value returned if there is no value for $key.
public function getSummaryItem($key, $default = false) {
$this->_fetchSummaryItems();
if (isset($this->_summary[$key])) {
return $this->_summary[$key];
* Sets the summary item $key as $value.
public function setSummaryItem($key, $value) {
$this->_fetchSummaryItems();
$this->_summary[$key] = $value;
if (!$this->_maybeSaveSummaryItems() && !$this->_destructRegistered) {
register_shutdown_function(array($this, 'flushSummaryItems'));
$this->_destructRegistered = true;
* Atomically increments the summary item under $key by $value.
public function incrementSummaryItem($key, $value = 1) {
if ($value == 0) { return; }
$this->_fetchSummaryItems();
if (isset($this->_summary[$key])) {
$this->_summary[$key] += $value;
if (!$this->_maybeSaveSummaryItems() && !$this->_destructRegistered) {
register_shutdown_function(array($this, 'flushSummaryItems'));
$this->_destructRegistered = true;
* Schedules a single scan for the given time. If $originalTime is provided, it will be associated with the cron.
* @param bool|int $originalTime
public function scheduleSingleScan($futureTime, $originalTime = false) {
if (is_main_site()) { // Removed ability to activate on network site in v5.3.12
if ($originalTime === false) {
$originalTime = $futureTime;
wp_schedule_single_event($futureTime, 'wordfence_start_scheduled_scan', array((int) $originalTime));
//Saving our own copy of the schedule because the wp-cron functions all require the args list to act
$allScansScheduled = wfConfig::get_ser('allScansScheduled', array());
$allScansScheduled[] = array('timestamp' => $futureTime, 'args' => array((int) $originalTime));
wfConfig::set_ser('allScansScheduled', $allScansScheduled);
* Clears all scheduled scan cron jobs and re-creates them.
public function scheduleScans() {
$this->unscheduleAllScans();
if (!$this->isEnabled()) {
if ($this->schedulingMode() == wfScanner::SCAN_SCHEDULING_MODE_MANUAL) {
//Generate a two-week schedule
$manualType = $this->manualSchedulingType();
$preferredHour = $this->manualSchedulingStartHour();
case self::MANUAL_SCHEDULING_ONCE_DAILY:
$schedule = array_fill(0, 14, array_fill(0, 24, 0));
foreach ($schedule as $dayNumber => &$day) {
$day[$preferredHour] = 1;
case self::MANUAL_SCHEDULING_TWICE_DAILY:
$schedule = array_fill(0, 14, array_fill(0, 24, 0));
foreach ($schedule as $dayNumber => &$day) {
$day[$preferredHour] = 1;
$day[($preferredHour + 12) % 24] = 1;
case self::MANUAL_SCHEDULING_EVERY_OTHER_DAY:
$baseDay = floor(time() / 86400);
$schedule = array_fill(0, 14, array_fill(0, 24, 0));
foreach ($schedule as $dayNumber => &$day) {
if (($baseDay + $dayNumber) % 2) {
$day[$preferredHour] = 1;
case self::MANUAL_SCHEDULING_WEEKDAYS:
$schedule = array_fill(0, 14, array_fill(0, 24, 0));
foreach ($schedule as $dayNumber => &$day) {
if ($dayNumber > 0 && $dayNumber < 6) {
$day[$preferredHour] = 1;
case self::MANUAL_SCHEDULING_WEEKENDS:
$schedule = array_fill(0, 14, array_fill(0, 24, 0));
foreach ($schedule as $dayNumber => &$day) {
if ($dayNumber == 0 || $dayNumber == 6) {
$day[$preferredHour] = 1;
case self::MANUAL_SCHEDULING_ODD_DAYS_WEEKENDS:
$schedule = array_fill(0, 14, array_fill(0, 24, 0));
foreach ($schedule as $dayNumber => &$day) {
if ($dayNumber == 0 || $dayNumber == 6 || ($dayNumber % 2)) {
$day[$preferredHour] = 1;
case self::MANUAL_SCHEDULING_CUSTOM:
$oneWeekSchedule = $this->customSchedule();
foreach ($oneWeekSchedule as $day) { $schedule[] = $day; }
foreach ($oneWeekSchedule as $day) { $schedule[] = $day; }
$tzOffset = wfUtils::formatLocalTime('Z', $now);
//Apply the time zone shift so the start times align to the server's time zone
$shiftedSchedule = array_fill(0, 14, array());
foreach ($schedule as $dayNumber => $day) {
foreach ($day as $hourNumber => $enabled) {
$effectiveHour = round(($hourNumber * 3600 - $tzOffset) / 3600, 2); //round() rather than floor() to account for fractional time zones
$wrappedHour = ($effectiveHour + 24) % 24;
if ($effectiveHour < 0) {
$shiftedSchedule[$dayNumber - 1][$wrappedHour] = 1;
else if ($effectiveHour > 23) {
if ($dayNumber < count($schedule) - 1) {
$shiftedSchedule[$dayNumber + 1][$wrappedHour] = 1;
$shiftedSchedule[$dayNumber][$effectiveHour] = 1;
$schedule = $shiftedSchedule;
//Trim out all but an 8-day period
$currentDayOfWeekUTC = date('w', $now);
$currentHourUTC = date('G', $now);
$periodStart = floor($now / 86400) * 86400 - $currentDayOfWeekUTC * 86400;
$schedule = array_slice($schedule, $currentDayOfWeekUTC, null, true);
$schedule = array_slice($schedule, 0, 8, true);
foreach ($schedule as $dayNumber => $day) {
foreach ($day as $hourNumber => $enabled) {
if ($dayNumber == $currentDayOfWeekUTC && $currentHourUTC > $hourNumber) { //It's today and we've already passed its hour, skip it
else if ($dayNumber > 6 && ($dayNumber % 7) == $currentDayOfWeekUTC && $currentHourUTC <= $hourNumber) { //It's one week from today but beyond the current hour, skip it this cycle
$scanTime = $periodStart + $dayNumber * 86400 + $hourNumber * 3600 + wfWAFUtils::random_int(0, 3600);
wordfence::status(4, 'info', sprintf(
/* translators: 1. Day of week. 2. Hour of day. 3. Localized date. */
__("Scheduled time for day %s hour %s is: %s", 'wordfence'),
wfUtils::formatLocalTime('l jS \of F Y h:i:s A P', $scanTime)
$this->scheduleSingleScan($scanTime);
$noc1ScanSchedule = wfConfig::get_ser('noc1ScanSchedule', array());
foreach ($noc1ScanSchedule as $timestamp) {
$timestamp = wfUtils::denormalizedTime($timestamp);
if ($timestamp > time()) {
$this->scheduleSingleScan($timestamp);
public function unscheduleAllScans() {
$allScansScheduled = wfConfig::get_ser('allScansScheduled', array());
foreach ($allScansScheduled as $entry) {
wp_unschedule_event($entry['timestamp'], 'wordfence_start_scheduled_scan', $entry['args']);
wp_clear_scheduled_hook('wordfence_start_scheduled_scan');
wfConfig::set_ser('allScansScheduled', array());
public function nextScheduledScanTime() {
$cron = _get_cron_array();
foreach($cron as $key => $val){
if(isset($val['wordfence_start_scheduled_scan'])){
public function lastScanTime() {
return wfConfig::get('scanTime');
public function recordLastScanTime() {
wfConfig::set('scanTime', microtime(true));
public function lastQuickScanTime() {
return wfConfig::get('lastQuickScan', 0);
public function recordLastQuickScanTime() {
wfConfig::set('lastQuickScan', microtime(true));