<?php
// don't call the file directly
defined( 'ABSPATH' ) or die();

require_once __DIR__ . '/vp-scanner.php';

if ( !function_exists( 'apply_filters_ref_array' ) ) :

function apply_filters_ref_array($tag, $args) {
	global $wp_filter, $merged_filters, $wp_current_filter;

	// Do 'all' actions first
	if ( isset($wp_filter['all']) ) {
		$all_args = func_get_args();
		$wp_current_filter[] = $tag;
		_wp_call_all_hook($all_args);
	}

	if ( !isset($wp_filter[$tag]) ) {
		if ( isset($wp_filter['all']) )
			array_pop($wp_current_filter);
			return $args[0];
	}

	if ( !isset($wp_filter['all']) )
		$wp_current_filter[] = $tag;

	// Sort
	if ( !isset( $merged_filters[ $tag ] ) ) {
		ksort($wp_filter[$tag]);
		$merged_filters[ $tag ] = true;
	}

	reset( $wp_filter[ $tag ] );

	do {
		foreach( (array) current($wp_filter[$tag]) as $the_ )
			if ( !is_null($the_['function']) )
				$args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));

	} while ( next($wp_filter[$tag]) !== false );

	array_pop( $wp_current_filter );

	return $args[0];
}

endif;

class VP_Site_Scanner {
	function __construct() {
		// Only scan once in multisites.
		if( function_exists( 'is_main_site' ) && !is_main_site() )
			return;
		add_action( 'vp_scan_site'      , array( $this, '_scan_site') );
		add_filter( 'cron_schedules'    , array( $this, '_custom_cron' ) );
		add_action( 'vp_scan_next_batch', array( $this, '_scan_batch' ) );

		$signatures = get_option( '_vp_signatures' );
		if ( $signatures && ! wp_next_scheduled( 'vp_scan_site' ) )
			wp_schedule_event( time(), 'daily', 'vp_scan_site' );
		if ( $signatures && ! wp_next_scheduled( 'vp_scan_next_batch' ) )
			wp_schedule_event( time(), 'five_minutes_interval', 'vp_scan_next_batch' );
	}

	function _custom_cron( $schedules ) {
		$schedules['five_minutes_interval'] = array(
			'interval' => 300,
			'display'  => __( 'Once every five minutes' , 'vaultpress'),
		);
		return $schedules;
	}

	function _scan_site() {
		if ( !get_option( '_vp_current_scan' ) ) {
			$ignore_symlinks = get_option( '_vp_ignore_symlinks', false );
			$paths = array( 'root' => new VP_FileScan( ABSPATH, $ignore_symlinks ) );

			// Is WP_CONTENT_DIR inside ABSPATH?
			if ( is_dir( WP_CONTENT_DIR ) && strpos( realpath( WP_CONTENT_DIR ), realpath( ABSPATH ) . DIRECTORY_SEPARATOR ) !== 0 )
				$paths['content'] = new VP_FileScan( WP_CONTENT_DIR, $ignore_symlinks );

			// Is WP_PLUGIN_DIR inside ABSPATH or WP_CONTENT_DIR?
			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 )
				$paths['plugins'] = new VP_FileScan( WP_PLUGIN_DIR, $ignore_symlinks );

			// Is WPMU_PLUGIN_DIR inside ABSPATH or WP_CONTENT_DIR?
			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 )
				$paths['mu-plugins'] = new VP_FileScan( WPMU_PLUGIN_DIR, $ignore_symlinks );

			update_option( '_vp_current_scan', $paths );
		}
	}

	function _scan_clean_up( &$paths, $type = null ) {
		if( is_array( $paths ) )
			unset( $paths[$type] );
		if ( empty( $paths ) || !is_array( $paths ) ) {
			delete_option( '_vp_current_scan' );
			return true;
		}
		return false;
	}

	function _scan_batch() {
		$paths = get_option( '_vp_current_scan' );
		if ( empty( $paths ) || $this->_scan_clean_up( $paths ) )
			return false;

		if ( ! is_array( $paths ) ) {
			return false;
		}

		reset( $paths );

		$type    = null;
		$current = false;
		foreach ( $paths as $type => $current ) {
			break;
		}

		if ( !is_object( $current ) || empty( $current->last_dir ) )
			return $this->_scan_clean_up( $paths, $type );

		$default_batch_limit = 400;
		if ( ! function_exists( 'set_time_limit' ) || ! @set_time_limit( 0 ) ) {
			$default_batch_limit = 100; // avoid timeouts
		}

		$GLOBALS['vp_signatures'] = get_option( '_vp_signatures' );
		if ( empty( $GLOBALS['vp_signatures'] ) )
			return false;

		$limit = get_option( '_vp_batch_file_size', $default_batch_limit );
		$files = $current->get_files( $limit );

		// No more files to scan.
		if ( !$current->last_dir || count( $files ) < $limit )
			unset( $paths[$type] );

		update_option( '_vp_current_scan', $paths );
		$results = array();
		foreach ( $files as $file ) {
			$verdict = vp_scan_file( $file );
			if ( !empty( $verdict ) )
				$results[$file] = array( 'hash' => @md5_file( $file ), 'verdict' => $verdict );
		}

		if ( !empty( $results ) ) {
			$vaultpress = VaultPress::init();
			$vaultpress->add_ping( 'security', array( 'suspicious_v2' => $results ) );
		}
	}

	static function &init() {
		static $instance = false;
		if ( !$instance )
			$instance = new VP_Site_Scanner();
		return $instance;
	}
}
VP_Site_Scanner::init();
