Daily Plugin and Theme File Change Monitor
Fingerprints every PHP file in your plugins and themes once a day and emails the administrator a list of files that were added, changed or removed outside of normal updates.
Opens WPIDE on
Code
// Folders to watch and the maximum number of files to fingerprint.
$wpide_watch_dirs = array( WP_PLUGIN_DIR, get_theme_root() );
$wpide_watch_limit = 30000;
$wpide_fingerprint = function () use ( $wpide_watch_dirs, $wpide_watch_limit ) {
$map = array();
foreach ( $wpide_watch_dirs as $dir ) {
if ( ! is_dir( $dir ) ) {
continue;
}
$files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) );
foreach ( $files as $file ) {
if ( count( $map ) >= $wpide_watch_limit ) {
break 2;
}
if ( $file->isFile() && preg_match( '/\.(php|phtml|phar)$/i', $file->getFilename() ) && false === strpos( $file->getPathname(), '/node_modules/' ) ) {
$map[ str_replace( WP_CONTENT_DIR, '', $file->getPathname() ) ] = substr( md5_file( $file->getPathname() ), 0, 12 );
}
}
}
return $map;
};
$wpide_save_baseline = function ( $map ) {
update_option( 'wpide_file_baseline', base64_encode( gzcompress( wp_json_encode( $map ), 6 ) ), false );
};
add_action( 'init', function () {
if ( ! wp_next_scheduled( 'wpide_file_change_scan' ) ) {
wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'wpide_file_change_scan' );
}
} );
add_action( 'upgrader_process_complete', function () use ( $wpide_fingerprint, $wpide_save_baseline ) {
$wpide_save_baseline( $wpide_fingerprint() );
}, 99 );
add_action( 'wpide_file_change_scan', function () use ( $wpide_fingerprint, $wpide_save_baseline ) {
$stored = get_option( 'wpide_file_baseline' );
$now = $wpide_fingerprint();
$wpide_save_baseline( $now );
if ( ! $stored ) {
return;
}
$old = json_decode( (string) gzuncompress( base64_decode( $stored ) ), true );
if ( ! is_array( $old ) ) {
return;
}
$added = array_keys( array_diff_key( $now, $old ) );
$removed = array_keys( array_diff_key( $old, $now ) );
$changed = array_keys( array_diff_assoc( array_intersect_key( $now, $old ), $old ) );
if ( ! $added && ! $removed && ! $changed ) {
return;
}
$lines = array();
foreach ( array( 'Added' => $added, 'Changed' => $changed, 'Removed' => $removed ) as $label => $list ) {
if ( $list ) {
$lines[] = $label . ' (' . count( $list ) . "):\n " . implode( "\n ", array_slice( $list, 0, 50 ) );
}
}
wp_mail(
get_option( 'admin_email' ),
sprintf( '[%s] Plugin or theme files changed', wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ) ),
"These PHP files changed since yesterday without a dashboard update:\n\n" . implode( "\n\n", $lines ) . "\n\nIf you did not make these changes, check the files for malware."
);
} );
Notes
The baseline is refreshed automatically after updates done from the dashboard; changes made over FTP or by malware are reported.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.