<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class ASA_Malware_Scan {

	const MAX_RESULTS = 50;

	public function run() {
		$results   = array();
		$scan_dirs = array( WP_CONTENT_DIR . '/plugins', WP_CONTENT_DIR . '/themes', WP_CONTENT_DIR . '/uploads' );

		foreach ( $scan_dirs as $dir ) {
			if ( ! is_dir( $dir ) ) {
				continue;
			}

			$iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) );
			foreach ( $iterator as $file ) {
				if ( ! $file->isFile() ) {
					continue;
				}

				$path = wp_normalize_path( $file->getPathname() );
				if ( $this->should_skip_path( $path ) ) {
					continue;
				}

				$ext = strtolower( pathinfo( $file->getFilename(), PATHINFO_EXTENSION ) );
				if ( ! in_array( $ext, array( 'php', 'phtml' ), true ) ) {
					continue;
				}

				if ( $file->getSize() > 1024 * 1024 ) {
					continue;
				}

				$contents = @file_get_contents( $path );
				if ( false === $contents || '' === $contents ) {
					continue;
				}

				$finding = $this->evaluate_file( $path, $contents );
				if ( ! empty( $finding ) ) {
					$results[] = $finding;
					if ( count( $results ) >= self::MAX_RESULTS ) {
						break 2;
					}
				}
			}
		}

		if ( empty( $results ) ) {
			$results[] = array( 'severity' => 'passed', 'category' => 'malware-heuristic', 'title' => 'No high-confidence suspicious patterns found', 'details' => 'No high-confidence malware-style pattern combinations were found in scanned files.' );
		}

		return $results;
	}

	private function should_skip_path( $path ) {
		foreach ( array( '/vendor/', '/node_modules/', '/tests/', '/test/', '/.git/' ) as $segment ) {
			if ( false !== strpos( $path, $segment ) ) {
				return true;
			}
		}

		return false;
	}

	private function evaluate_file( $path, $contents ) {
		$normalized_path = wp_normalize_path( $path );
		$is_uploads_php  = false !== strpos( $normalized_path, wp_normalize_path( WP_CONTENT_DIR . '/uploads/' ) );

		$dangerous_patterns = array(
			'eval'       => '/\beval\s*\(/i',
			'assert'     => '/\bassert\s*\(/i',
			'shell_exec' => '/\bshell_exec\s*\(/i',
			'exec'       => '/\bexec\s*\(/i',
			'passthru'   => '/\bpassthru\s*\(/i',
			'system'     => '/\bsystem\s*\(/i',
		);
		$decode_patterns = array(
			'base64_decode' => '/\bbase64_decode\s*\(/i',
			'gzinflate'     => '/\bgzinflate\s*\(/i',
			'gzuncompress'  => '/\bgzuncompress\s*\(/i',
			'str_rot13'     => '/\bstr_rot13\s*\(/i',
			'hex2bin'       => '/\bhex2bin\s*\(/i',
			'rawurldecode'  => '/\brawurldecode\s*\(/i',
		);

		$matches = array();
		foreach ( $dangerous_patterns as $label => $pattern ) {
			if ( preg_match( $pattern, $contents ) ) {
				$matches[] = $label;
			}
		}
		$dangerous_count = count( $matches );

		$decode_matches = array();
		foreach ( $decode_patterns as $label => $pattern ) {
			if ( preg_match( $pattern, $contents ) ) {
				$decode_matches[] = $label;
			}
		}
		$decode_count = count( $decode_matches );

		$has_eval_decode_chain = (bool) preg_match( '/\b(?:eval|assert)\s*\(\s*(?:base64_decode|gzinflate|gzuncompress|str_rot13|hex2bin|rawurldecode)\s*\(/i', $contents );
		$has_long_encoded_blob = (bool) preg_match( '/["\'][A-Za-z0-9+\/=]{200,}["\']/', $contents );
		$has_variable_function = (bool) preg_match( '/\$[A-Za-z_][A-Za-z0-9_]*\s*\(/', $contents );

		$confidence = 0;
		if ( $is_uploads_php ) {
			$confidence += 3;
		}
		if ( $has_eval_decode_chain ) {
			$confidence += 4;
		}
		if ( $has_long_encoded_blob && $decode_count > 0 ) {
			$confidence += 2;
		}
		if ( $dangerous_count > 0 && $decode_count > 0 ) {
			$confidence += 2;
		}
		if ( $dangerous_count >= 2 ) {
			$confidence += 1;
		}
		if ( $decode_count >= 2 ) {
			$confidence += 1;
		}
		if ( $has_variable_function && ( $dangerous_count > 0 || $decode_count > 0 ) ) {
			$confidence += 1;
		}

		if ( $confidence < 4 ) {
			return array();
		}

		$indicators = array_merge( $matches, $decode_matches );
		if ( $has_eval_decode_chain ) {
			$indicators[] = 'eval/decode-chain';
		}
		if ( $has_long_encoded_blob ) {
			$indicators[] = 'long-encoded-blob';
		}
		if ( $is_uploads_php ) {
			$indicators[] = 'php-in-uploads';
		}
		$indicators = array_values( array_unique( $indicators ) );

		return array(
			'severity' => $confidence >= 6 ? 'high' : 'medium',
			'category' => 'malware-heuristic',
			'title'    => 'High-confidence suspicious code pattern detected',
			'details'  => sprintf( 'Indicators [%1$s] found in %2$s', implode( ', ', $indicators ), $path ),
		);
	}
}
