has_scan_data()){ $scanned_data = $this->do_file_change_scan(); //Scan the filesystem and get details $last_scan_data = $this->get_last_scan_data(); $scan_result = $this->compare_scan_data($last_scan_data,$scanned_data); $scan_result['initial_scan'] = ''; $this->save_scan_data_to_db($scanned_data, 'update', $scan_result); if (!empty($scan_result['files_added']) || !empty($scan_result['files_removed']) || !empty($scan_result['files_changed'])){ //This means there was a change detected $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', TRUE); $aio_wp_security->configs->save_config(); $aio_wp_security->debug_logger->log_debug("File Change Detection Feature: change to filesystem detected!"); $this->aiowps_send_file_change_alert_email($scan_result); //Send file change scan results via email if applicable } else { //Reset the change flag $aio_wp_security->configs->set_value('aiowps_fcds_change_detected', FALSE); $aio_wp_security->configs->save_config(); } return $scan_result; } else{ $scanned_data = $this->do_file_change_scan(); $this->save_scan_data_to_db($scanned_data); $scan_result['initial_scan'] = '1'; return $scan_result; } } /** * Send email with notification about file changes detected by last scan. * @global AIO_WP_Security $aio_wp_security * @param array $scan_result Array with scan result returned by compare_scan_data() method. */ function aiowps_send_file_change_alert_email($scan_result) { global $aio_wp_security; if ( $aio_wp_security->configs->get_value('aiowps_send_fcd_scan_email') == '1' ) { $site_title = get_bloginfo( 'name' ); $from_name = empty($site_title)?'WordPress':$site_title; $headers = 'From: ' . $from_name . ' <' . get_option('admin_email') . '>' . PHP_EOL; $subject = __( 'All In One WP Security - File change detected!', 'all-in-one-wp-security-and-firewall' ) . ' ' . date( 'l, F jS, Y \a\\t g:i a', current_time( 'timestamp' ) ); //$attachment = array(); $message = __( 'A file change was detected on your system for site URL', 'all-in-one-wp-security-and-firewall' ) . ' ' . get_option( 'siteurl' ) . __( '. Scan was generated on', 'all-in-one-wp-security-and-firewall' ) . ' ' . date( 'l, F jS, Y \a\\t g:i a', current_time( 'timestamp' ) ); $message .= "\r\n\r\n".__( 'A summary of the scan results is shown below:', 'all-in-one-wp-security-and-firewall' ); $message .= "\r\n\r\n"; $message .= self::get_file_change_summary($scan_result); $message .= "\r\n".__( 'Login to your site to view the scan details.', 'all-in-one-wp-security-and-firewall' ); // Get the email address(es). $addresses = $aio_wp_security->configs->get_value('aiowps_fcd_scan_email_address'); // If no explicit email address(es) are given, send email to site admin. $to = empty( $addresses ) ? array( get_site_option('admin_email') ) : explode(PHP_EOL, $addresses); if ( !wp_mail( $to, $subject, $message, $headers ) ) { $aio_wp_security->debug_logger->log_debug("File change notification email failed to send.",4); } } } function aiowps_scheduled_fcd_scan_handler() { global $aio_wp_security; if($aio_wp_security->configs->get_value('aiowps_enable_automated_fcd_scan')=='1') { $aio_wp_security->debug_logger->log_debug_cron("Filescan - Scheduled fcd_scan is enabled. Checking now to see if scan needs to be done..."); $time_now = date_i18n( 'Y-m-d H:i:s' ); $current_time = strtotime($time_now); $fcd_scan_frequency = $aio_wp_security->configs->get_value('aiowps_fcd_scan_frequency'); //Number of hours or days or months interval $interval_setting = $aio_wp_security->configs->get_value('aiowps_fcd_scan_interval'); //Hours/Days/Months switch($interval_setting) { case '0': $interval = 'hours'; break; case '1': $interval = 'days'; break; case '2': $interval = 'weeks'; break; } $last_fcd_scan_time = $aio_wp_security->configs->get_value('aiowps_last_fcd_scan_time'); if ($last_fcd_scan_time != NULL) { $last_fcd_scan_time = strtotime($aio_wp_security->configs->get_value('aiowps_last_fcd_scan_time')); $next_fcd_scan_time = strtotime("+".abs($fcd_scan_frequency).$interval, $last_fcd_scan_time); if ($next_fcd_scan_time <= $current_time) { //It's time to do a filescan $result = $this->execute_file_change_detection_scan(ABSPATH); // if ($result) // { $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $time_now); $aio_wp_security->configs->save_config(); $aio_wp_security->debug_logger->log_debug_cron("Filescan - Scheduled filescan was successfully completed."); // } // else // { // $aio_wp_security->debug_logger->log_debug_cron("Filescan - Scheduled filescan operation failed!",4); // } } } else { //Set the last scan time to now so it can trigger for the next scheduled period $aio_wp_security->configs->set_value('aiowps_last_fcd_scan_time', $time_now); $aio_wp_security->configs->save_config(); } } } /* Returns true if there is at least one previous scaned data in the DB. False otherwise */ function has_scan_data() { global $wpdb; //For scanned data the meta_key1 column valu is 'file_change_detection', meta_value1 column value is 'file_scan_data'. Then the data is stored in meta_value4 column. $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA; $sql = $wpdb->prepare("SELECT * FROM $aiowps_global_meta_tbl_name WHERE meta_key1=%s AND meta_value1=%s", 'file_change_detection', 'file_scan_data'); $resultset = $wpdb->get_row($sql, OBJECT); if($resultset){ $scan_data = maybe_unserialize($resultset->meta_value4); if(!empty($scan_data)){ return true; } } return false; } function get_last_scan_data() { global $wpdb; //For scanned data the meta_key1 column valu is 'file_change_detection', meta_value1 column value is 'file_scan_data'. Then the data is stored in meta_value4 column. $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA; $sql = $wpdb->prepare("SELECT * FROM $aiowps_global_meta_tbl_name WHERE meta_key1=%s AND meta_value1=%s", 'file_change_detection', 'file_scan_data'); $resultset = $wpdb->get_row($sql, OBJECT); if($resultset){ $scan_data = maybe_unserialize($resultset->meta_value4); return $scan_data; } return array(); //return empty array if no old scan data } function save_scan_data_to_db($scanned_data, $save_type = 'insert', $scan_result = array()) { global $wpdb, $aio_wp_security; $result = ''; //For scanned data the meta_key1 column value is 'file_change_detection', meta_value1 column value is 'file_scan_data'. Then the data is stored in meta_value4 column. $aiowps_global_meta_tbl_name = AIOWPSEC_TBL_GLOBAL_META_DATA; $payload = maybe_serialize($scanned_data); $scan_result = maybe_serialize($scan_result); $date_time = date_i18n( 'Y-m-d H:i:s' ); $data = array('date_time' => $date_time, 'meta_key1' => 'file_change_detection', 'meta_value1' => 'file_scan_data', 'meta_value4' => $payload, 'meta_key5' => 'last_scan_result', 'meta_value5' => $scan_result); if($save_type == 'insert'){ $result = $wpdb->insert($aiowps_global_meta_tbl_name, $data); } else{ $where = array('meta_key1' => 'file_change_detection', 'meta_value1' => 'file_scan_data'); $result = $wpdb->update($aiowps_global_meta_tbl_name, $data, $where); } if ($result === false){ $aio_wp_security->debug_logger->log_debug("save_scan_data_to_db() - Error inserting data to DB!",4); return false; }else{ return true; } } /** * Recursively scan the entire $start_dir directory and return file size * and last modified date of every regular file. Ignore files and file * types specified in file scanner settings. * @global AIO_WP_Security $aio_wp_security * @param string $start_dir * @return array */ function do_file_change_scan($start_dir=ABSPATH) { global $aio_wp_security; $filescan_data = array(); // Iterator key is absolute file path, iterator value is SplFileInfo object, // iteration skips '..' and '.' records, because we're not interested in directories. $dit = new RecursiveDirectoryIterator( $start_dir, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS ); $rit = new RecursiveIteratorIterator( $dit, RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD ); // Grab files/directories to skip $files_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty($aio_wp_security->configs->get_value('aiowps_fcd_exclude_files')); // Grab (lowercased) file types to skip $file_types_to_skip = AIOWPSecurity_Utility::explode_trim_filter_empty(strtolower($aio_wp_security->configs->get_value('aiowps_fcd_exclude_filetypes'))); $start_dir_length = strlen($start_dir); foreach ($rit as $filename => $fileinfo) { if ( !file_exists($filename) || is_dir($filename) ) { continue; // if file doesn't exist or is a directory move on to next iteration } if ( $fileinfo->getFilename() == 'wp-security-log-cron-job.txt' || $fileinfo->getFilename() == 'wp-security-log.txt' ) { continue; // skip aiowps log files } // Let's omit any file types from the scan which were specified in the settings if necessary if ( !empty($file_types_to_skip) ) { //$current_file_ext = strtolower($fileinfo->getExtension()); //getExtension() only available on PHP 5.3.6 or higher $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if (in_array($ext, $file_types_to_skip) ) { continue; } } // Let's omit specific files or directories from the scan which were specified in the settings if ( !empty($files_to_skip) ) { $skip_this = false; foreach ($files_to_skip as $f_or_dir) { // Expect files/dirs to be specified relatively to $start_dir, // so start searching at $start_dir_length offset. if (strpos($filename, $f_or_dir, $start_dir_length) !== false) { $skip_this = true; break; // ! } } if ($skip_this) { continue; } } $filescan_data[$filename] = array( 'last_modified' => $fileinfo->getMTime(), 'filesize' => $fileinfo->getSize(), ); } return $filescan_data; } function compare_scan_data($last_scan_data, $new_scanned_data) { // Identify new files added: get all files which are in the new scan but not present in the old scan $files_added = @array_diff_key( $new_scanned_data, $last_scan_data ); // Identify files deleted: get all files which are in the old scan but not present in the new scan $files_removed = @array_diff_key( $last_scan_data, $new_scanned_data ); // Identify existing files: get all files which are in new scan, but were not added $files_kept = @array_diff_key( $new_scanned_data, $files_added ); $files_changed = array(); // Loop through existing files and determine, if they have been changed foreach ( $files_kept as $filename => $new_scan_meta ) { $last_scan_meta = $last_scan_data[$filename]; // Check filesize and last_modified values if ( ($new_scan_meta['last_modified'] !== $last_scan_meta['last_modified']) || ($new_scan_meta['filesize'] !== $last_scan_meta['filesize']) ) { $files_changed[$filename] = $new_scan_meta; } } // Create single array of all changes return array( 'files_added' => $files_added, 'files_removed' => $files_removed, 'files_changed' => $files_changed, ); } function execute_db_scan() { global $aio_wp_security; global $wpdb; //$aio_wp_security->admin_init->filescan_menu->start_buffer(); ob_start(); $info_msg_string = '
'.__('Starting DB scan.....please wait while the plugin scans your database.......', 'all-in-one-wp-security-and-firewall').'
'; echo $info_msg_string; //Options table echo ''.__('Scanning options table.........', 'all-in-one-wp-security-and-firewall').'
'; $options_table = $wpdb->prefix . 'options'; $sql= "SELECT option_id,option_value,option_name FROM $options_table WHERE INSTR(LCASE(option_name), 'class_generic_support') + INSTR(LCASE(option_name), 'widget_generic_support') + INSTR(LCASE(option_name), 'fwp') + INSTR(LCASE(option_name), 'wp_check_hash') + INSTR(LCASE(option_name), 'ftp_credentials') + INSTR(LCASE(option_name), 'page_option') + INSTR(LCASE(option_value), '