Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 91
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
apply_filters_ref_array
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
72
VP_Site_Scanner
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 6
1560
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
56
 _custom_cron
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 _scan_site
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
110
 _scan_clean_up
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 _scan_batch
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
240
 init
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2// don't call the file directly
3defined( 'ABSPATH' ) || die( 0 );
4
5require_once __DIR__ . '/vp-scanner.php';
6
7if ( !function_exists( 'apply_filters_ref_array' ) ) :
8
9function apply_filters_ref_array($tag, $args) {
10    global $wp_filter, $merged_filters, $wp_current_filter;
11
12    // Do 'all' actions first
13    if ( isset($wp_filter['all']) ) {
14        $all_args = func_get_args();
15        $wp_current_filter[] = $tag;
16        _wp_call_all_hook($all_args);
17    }
18
19    if ( !isset($wp_filter[$tag]) ) {
20        if ( isset($wp_filter['all']) )
21            array_pop($wp_current_filter);
22            return $args[0];
23    }
24
25    if ( !isset($wp_filter['all']) )
26        $wp_current_filter[] = $tag;
27
28    // Sort
29    if ( !isset( $merged_filters[ $tag ] ) ) {
30        ksort($wp_filter[$tag]);
31        $merged_filters[ $tag ] = true;
32    }
33
34    reset( $wp_filter[ $tag ] );
35
36    do {
37        foreach( (array) current($wp_filter[$tag]) as $the_ )
38            if ( !is_null($the_['function']) )
39                $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
40
41    } while ( next($wp_filter[$tag]) !== false );
42
43    array_pop( $wp_current_filter );
44
45    return $args[0];
46}
47
48endif;
49
50class VP_Site_Scanner {
51    function __construct() {
52        // Only scan once in multisites.
53        if( function_exists( 'is_main_site' ) && !is_main_site() )
54            return;
55        add_action( 'vp_scan_site'      , array( $this, '_scan_site') );
56        add_filter( 'cron_schedules'    , array( $this, '_custom_cron' ) );
57        add_action( 'vp_scan_next_batch', array( $this, '_scan_batch' ) );
58
59        $signatures = get_option( '_vp_signatures' );
60        if ( $signatures && ! wp_next_scheduled( 'vp_scan_site' ) )
61            wp_schedule_event( time(), 'daily', 'vp_scan_site' );
62        if ( $signatures && ! wp_next_scheduled( 'vp_scan_next_batch' ) )
63            wp_schedule_event( time(), 'five_minutes_interval', 'vp_scan_next_batch' );
64    }
65
66    function _custom_cron( $schedules ) {
67        $schedules['five_minutes_interval'] = array(
68            'interval' => 300,
69            'display'  => __( 'Once every five minutes' , 'vaultpress'),
70        );
71        return $schedules;
72    }
73
74    function _scan_site() {
75        if ( !get_option( '_vp_current_scan' ) ) {
76            $ignore_symlinks = get_option( '_vp_ignore_symlinks', false );
77            $paths = array( 'root' => new VP_FileScan( ABSPATH, $ignore_symlinks ) );
78
79            // Is WP_CONTENT_DIR inside ABSPATH?
80            if ( is_dir( WP_CONTENT_DIR ) && strpos( realpath( WP_CONTENT_DIR ), realpath( ABSPATH ) . DIRECTORY_SEPARATOR ) !== 0 )
81                $paths['content'] = new VP_FileScan( WP_CONTENT_DIR, $ignore_symlinks );
82
83            // Is WP_PLUGIN_DIR inside ABSPATH or WP_CONTENT_DIR?
84            if ( is_dir( WP_PLUGIN_DIR ) && strpos( realpath( WP_PLUGIN_DIR ), realpath( WP_CONTENT_DIR ) . DIRECTORY_SEPARATOR ) !== 0 && strpos( realpath( WP_PLUGIN_DIR ), realpath( ABSPATH ) . DIRECTORY_SEPARATOR ) !== 0 )
85                $paths['plugins'] = new VP_FileScan( WP_PLUGIN_DIR, $ignore_symlinks );
86
87            // Is WPMU_PLUGIN_DIR inside ABSPATH or WP_CONTENT_DIR?
88            if ( is_dir( WPMU_PLUGIN_DIR ) && strpos( realpath( WPMU_PLUGIN_DIR ), realpath( WP_CONTENT_DIR ) . DIRECTORY_SEPARATOR ) !== 0 && strpos( realpath( WPMU_PLUGIN_DIR ), realpath( ABSPATH ) . DIRECTORY_SEPARATOR ) !== 0 )
89                $paths['mu-plugins'] = new VP_FileScan( WPMU_PLUGIN_DIR, $ignore_symlinks );
90
91            update_option( '_vp_current_scan', $paths );
92        }
93    }
94
95    function _scan_clean_up( &$paths, $type = null ) {
96        if( is_array( $paths ) )
97            unset( $paths[$type] );
98        if ( empty( $paths ) || !is_array( $paths ) ) {
99            delete_option( '_vp_current_scan' );
100            return true;
101        }
102        return false;
103    }
104
105    function _scan_batch() {
106        $paths = get_option( '_vp_current_scan' );
107        if ( empty( $paths ) || $this->_scan_clean_up( $paths ) )
108            return false;
109
110        if ( ! is_array( $paths ) ) {
111            return false;
112        }
113
114        reset( $paths );
115
116        $type    = null;
117        $current = false;
118        foreach ( $paths as $type => $current ) {
119            break;
120        }
121
122        if ( !is_object( $current ) || empty( $current->last_dir ) )
123            return $this->_scan_clean_up( $paths, $type );
124
125        $default_batch_limit = 400;
126        if ( ! function_exists( 'set_time_limit' ) || ! @set_time_limit( 0 ) ) {
127            $default_batch_limit = 100; // avoid timeouts
128        }
129
130        $GLOBALS['vp_signatures'] = get_option( '_vp_signatures' );
131        if ( empty( $GLOBALS['vp_signatures'] ) )
132            return false;
133
134        $limit = get_option( '_vp_batch_file_size', $default_batch_limit );
135        $files = $current->get_files( $limit );
136
137        // No more files to scan.
138        if ( !$current->last_dir || count( $files ) < $limit )
139            unset( $paths[$type] );
140
141        update_option( '_vp_current_scan', $paths );
142        $results = array();
143        foreach ( $files as $file ) {
144            $verdict = vp_scan_file( $file );
145            if ( !empty( $verdict ) )
146                $results[$file] = array( 'hash' => @md5_file( $file ), 'verdict' => $verdict );
147        }
148
149        if ( !empty( $results ) ) {
150            $vaultpress = VaultPress::init();
151            $vaultpress->add_ping( 'security', array( 'suspicious_v2' => $results ) );
152        }
153    }
154
155    static function &init() {
156        static $instance = false;
157        if ( !$instance )
158            $instance = new VP_Site_Scanner();
159        return $instance;
160    }
161}
162VP_Site_Scanner::init();