﻿<?php

declare(strict_types=1);

/**
 * RCE Detection Test Runner v1.0
 * Specialized testing module for Remote Code Execution detection patterns
 */

final class RCETestRunner {
    private string $testKey;
    private array $testResults = [];
    private float $startTime;
    private array $rceVectors = [];

    public function __construct() {
        $this->startTime = microtime(true);
        $this->initializeTestEnvironment();
        $this->loadRCEVectors();
    }

    private function initializeTestEnvironment(): void {
        $testKeyFile = __DIR__ . '/.test_key';
        
        if (!file_exists($testKeyFile)) {
            $this->testKey = bin2hex(random_bytes(32));
            file_put_contents($testKeyFile, $this->testKey, LOCK_EX);
            chmod($testKeyFile, 0600);
        } else {
            $this->testKey = trim(file_get_contents($testKeyFile));
        }

        $_SERVER['HTTP_X_SECURITY_TEST'] = $this->testKey;
    }

    private function loadRCEVectors(): void {
        $this->rceVectors = [
            'command_injection' => [
                ['input' => "system('id')", 'expected_score' => 99],
                ['input' => "exec(\$_GET['cmd'])", 'expected_score' => 99],
                ['input' => "shell_exec('whoami')", 'expected_score' => 99],
                ['input' => "passthru('ls')", 'expected_score' => 99],
                ['input' => "`id`", 'expected_score' => 89],
            ],
            'code_injection' => [
                ['input' => "eval('phpinfo();')", 'expected_score' => 97],
                ['input' => "assert(\$_POST['code'])", 'expected_score' => 97],
                ['input' => "create_function('', 'system(\"id\");')", 'expected_score' => 97],
            ],
            'file_inclusion' => [
                ['input' => "include('/etc/passwd')", 'expected_score' => 94],
                ['input' => "require(\$_GET['file'])", 'expected_score' => 94],
                ['input' => "include_once('config.php')", 'expected_score' => 94],
            ],
            'deserialization' => [
                ['input' => "unserialize(\$_POST['data'])", 'expected_score' => 98],
                ['input' => "json_decode(\$_GET['json'], true)", 'expected_score' => 98],
            ],
            'webshells' => [
                ['input' => "c99.php", 'expected_score' => 99],
                ['input' => "r57.php", 'expected_score' => 99],
                ['input' => "b374k.php", 'expected_score' => 99],
                ['input' => "wso.php", 'expected_score' => 99],
            ],
            'obfuscated_attacks' => [
                ['input' => "s y s t e m ( ' i d ' )", 'expected_score' => 88],
                ['input' => "\x73\x79\x73\x74\x65\x6d('id')", 'expected_score' => 85],
                ['input' => "base64_decode('c3lzdGVtKCdpZCcp')", 'expected_score' => 84],
            ]
        ];
    }

    /**
     * Run comprehensive RCE test suite
     */
    public function runAllTests(): array {
        echo "Starting RCE Detection Test Suite...\n";
        echo "Test Key: " . substr($this->testKey, 0, 16) . "...\n\n";

        $this->testCommandInjection();
        $this->testCodeInjection();
        $this->testFileInclusion();
        $this->testDeserialization();
        $this->testWebshellDetection();
        $this->testObfuscatedAttacks();
        $this->testFalsePositives();
        $this->testPerformance();

        return $this->generateTestReport();
    }

    private function testCommandInjection(): void {
        echo "1. Testing Command Injection Vectors...\n";

        $this->testResults['command_injection'] = [
            'total_tests' => 0,
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($this->rceVectors['command_injection'] as $test) {
            $this->setupTestEnvironment([
                'get' => ['input' => $test['input']],
                'server' => [
                    'REQUEST_URI' => '/test?input=' . urlencode($test['input']),
                    'HTTP_USER_AGENT' => 'RCE-Tester/1.0'
                ]
            ]);

            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['confidence_score'] >= $test['expected_score'];

            $testResult = [
                'input' => $test['input'],
                'expected_score' => $test['expected_score'],
                'actual_score' => $result['confidence_score'],
                'passed' => $passed,
                'detected_vectors' => $result['detected_vectors'],
                'is_hack' => $result['is_hack']
            ];

            $this->testResults['command_injection']['test_results'][] = $testResult;
            $this->testResults['command_injection']['total_tests']++;

            if ($passed) {
                $this->testResults['command_injection']['passed_tests']++;
            } else {
                $this->testResults['command_injection']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . $this->testResults['command_injection']['total_tests'] . " command injection vectors\n";
    }

    private function testCodeInjection(): void {
        echo "2. Testing Code Injection Vectors...\n";

        $this->testResults['code_injection'] = [
            'total_tests' => 0,
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($this->rceVectors['code_injection'] as $test) {
            $this->setupTestEnvironment([
                'get' => ['input' => $test['input']],
                'server' => [
                    'REQUEST_URI' => '/eval?input=' . urlencode($test['input']),
                    'HTTP_USER_AGENT' => 'RCE-Tester/1.0'
                ]
            ]);

            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['confidence_score'] >= $test['expected_score'];

            $testResult = [
                'input' => $test['input'],
                'expected_score' => $test['expected_score'],
                'actual_score' => $result['confidence_score'],
                'passed' => $passed,
                'detected_vectors' => $result['detected_vectors']
            ];

            $this->testResults['code_injection']['test_results'][] = $testResult;
            $this->testResults['code_injection']['total_tests']++;

            if ($passed) {
                $this->testResults['code_injection']['passed_tests']++;
            } else {
                $this->testResults['code_injection']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . $this->testResults['code_injection']['total_tests'] . " code injection vectors\n";
    }

    private function testFileInclusion(): void {
        echo "3. Testing File Inclusion Vectors...\n";

        $this->testResults['file_inclusion'] = [
            'total_tests' => 0,
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($this->rceVectors['file_inclusion'] as $test) {
            $this->setupTestEnvironment([
                'get' => ['input' => $test['input']],
                'server' => [
                    'REQUEST_URI' => '/include?input=' . urlencode($test['input']),
                    'HTTP_USER_AGENT' => 'RCE-Tester/1.0'
                ]
            ]);

            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['confidence_score'] >= $test['expected_score'];

            $testResult = [
                'input' => $test['input'],
                'expected_score' => $test['expected_score'],
                'actual_score' => $result['confidence_score'],
                'passed' => $passed,
                'detected_vectors' => $result['detected_vectors']
            ];

            $this->testResults['file_inclusion']['test_results'][] = $testResult;
            $this->testResults['file_inclusion']['total_tests']++;

            if ($passed) {
                $this->testResults['file_inclusion']['passed_tests']++;
            } else {
                $this->testResults['file_inclusion']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . $this->testResults['file_inclusion']['total_tests'] . " file inclusion vectors\n";
    }

    private function testDeserialization(): void {
        echo "4. Testing Deserialization Attacks...\n";

        $this->testResults['deserialization'] = [
            'total_tests' => 0,
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($this->rceVectors['deserialization'] as $test) {
            $this->setupTestEnvironment([
                'post' => ['data' => $test['input']],
                'server' => [
                    'REQUEST_URI' => '/unserialize',
                    'HTTP_USER_AGENT' => 'RCE-Tester/1.0',
                    'REQUEST_METHOD' => 'POST'
                ]
            ]);

            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['confidence_score'] >= $test['expected_score'];

            $testResult = [
                'input' => $test['input'],
                'expected_score' => $test['expected_score'],
                'actual_score' => $result['confidence_score'],
                'passed' => $passed,
                'detected_vectors' => $result['detected_vectors']
            ];

            $this->testResults['deserialization']['test_results'][] = $testResult;
            $this->testResults['deserialization']['total_tests']++;

            if ($passed) {
                $this->testResults['deserialization']['passed_tests']++;
            } else {
                $this->testResults['deserialization']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . $this->testResults['deserialization']['total_tests'] . " deserialization vectors\n";
    }

    private function testWebshellDetection(): void {
        echo "5. Testing Webshell Detection...\n";

        $this->testResults['webshell_detection'] = [
            'total_tests' => 0,
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($this->rceVectors['webshells'] as $test) {
            $this->setupTestEnvironment([
                'get' => ['file' => $test['input']],
                'server' => [
                    'REQUEST_URI' => '/files?file=' . urlencode($test['input']),
                    'HTTP_USER_AGENT' => 'RCE-Tester/1.0'
                ]
            ]);

            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['confidence_score'] >= $test['expected_score'];

            $testResult = [
                'input' => $test['input'],
                'expected_score' => $test['expected_score'],
                'actual_score' => $result['confidence_score'],
                'passed' => $passed,
                'detected_vectors' => $result['detected_vectors']
            ];

            $this->testResults['webshell_detection']['test_results'][] = $testResult;
            $this->testResults['webshell_detection']['total_tests']++;

            if ($passed) {
                $this->testResults['webshell_detection']['passed_tests']++;
            } else {
                $this->testResults['webshell_detection']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . $this->testResults['webshell_detection']['total_tests'] . " webshell patterns\n";
    }

    private function testObfuscatedAttacks(): void {
        echo "6. Testing Obfuscated Attacks...\n";

        $this->testResults['obfuscated_attacks'] = [
            'total_tests' => 0,
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($this->rceVectors['obfuscated_attacks'] as $test) {
            $this->setupTestEnvironment([
                'get' => ['input' => $test['input']],
                'server' => [
                    'REQUEST_URI' => '/obfuscated?input=' . urlencode($test['input']),
                    'HTTP_USER_AGENT' => 'RCE-Tester/1.0'
                ]
            ]);

            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['confidence_score'] >= $test['expected_score'];

            $testResult = [
                'input' => $test['input'],
                'expected_score' => $test['expected_score'],
                'actual_score' => $result['confidence_score'],
                'passed' => $passed,
                'detected_vectors' => $result['detected_vectors']
            ];

            $this->testResults['obfuscated_attacks']['test_results'][] = $testResult;
            $this->testResults['obfuscated_attacks']['total_tests']++;

            if ($passed) {
                $this->testResults['obfuscated_attacks']['passed_tests']++;
            } else {
                $this->testResults['obfuscated_attacks']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . $this->testResults['obfuscated_attacks']['total_tests'] . " obfuscated attack vectors\n";
    }

    private function testFalsePositives(): void {
        echo "7. Testing False Positives...\n";

        $legitimateRequests = [
            [
                'input' => ['get' => ['action' => 'view', 'page' => 'home']],
                'description' => 'Normal page request'
            ],
            [
                'input' => ['get' => ['search' => 'normal search term']],
                'description' => 'Search query'
            ],
            [
                'input' => ['post' => ['username' => 'user', 'password' => 'pass']],
                'description' => 'Login attempt'
            ],
            [
                'input' => ['get' => ['id' => '12345']],
                'description' => 'Numeric parameter'
            ]
        ];

        $this->testResults['false_positives'] = [
            'total_tests' => 0,
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($legitimateRequests as $test) {
            $this->setupTestEnvironment($test['input']);

            $result = HackDetectionService::detectHackAttempt();
            $passed = !$result['is_hack'] && $result['confidence_score'] < 50;

            $testResult = [
                'description' => $test['description'],
                'is_hack' => $result['is_hack'],
                'confidence_score' => $result['confidence_score'],
                'passed' => $passed
            ];

            $this->testResults['false_positives']['test_results'][] = $testResult;
            $this->testResults['false_positives']['total_tests']++;

            if ($passed) {
                $this->testResults['false_positives']['passed_tests']++;
            } else {
                $this->testResults['false_positives']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . $this->testResults['false_positives']['total_tests'] . " legitimate requests\n";
    }

    private function testPerformance(): void {
        echo "8. Testing Performance...\n";

        $performanceTests = [];
        $totalTime = 0;
        $testCount = 20;

        for ($i = 0; $i < $testCount; $i++) {
            $this->setupTestEnvironment([
                'get' => ['test' => 'performance_' . $i],
                'server' => [
                    'REQUEST_URI' => '/test/performance_' . $i,
                    'HTTP_USER_AGENT' => 'RCE-Performance-Tester/1.0'
                ]
            ]);

            $startTime = microtime(true);
            $result = HackDetectionService::detectHackAttempt();
            $endTime = microtime(true);

            $executionTime = $endTime - $startTime;
            $totalTime += $executionTime;

            $performanceTests[] = [
                'iteration' => $i + 1,
                'execution_time' => $executionTime,
                'memory_usage' => memory_get_peak_usage(true),
                'vectors_detected' => count($result['detected_vectors'])
            ];
        }

        $this->testResults['performance'] = [
            'iterations' => $testCount,
            'average_time' => $totalTime / $testCount,
            'total_time' => $totalTime,
            'max_time' => max(array_column($performanceTests, 'execution_time')),
            'min_time' => min(array_column($performanceTests, 'execution_time')),
            'tests' => $performanceTests
        ];

        echo "   ✓ Completed " . $testCount . " performance iterations\n";
    }

    private function setupTestEnvironment(array $input): void {
        $_GET = $input['get'] ?? [];
        $_POST = $input['post'] ?? [];
        $_COOKIE = $input['cookie'] ?? [];
        $_SERVER = array_merge($_SERVER, $input['server'] ?? []);
        $_FILES = $input['files'] ?? [];
        $_SERVER['HTTP_X_SECURITY_TEST'] = $this->testKey;
    }

    private function generateTestReport(): array {
        $endTime = microtime(true);
        $totalTime = $endTime - $this->startTime;

        $report = [
            'test_summary' => [
                'total_execution_time' => $totalTime,
                'memory_peak_usage' => memory_get_peak_usage(true),
                'test_timestamp' => date('Y-m-d H:i:s'),
                'php_version' => PHP_VERSION
            ],
            'detailed_results' => $this->testResults
        ];

        // Calculate overall statistics
        $totalTests = 0;
        $passedTests = 0;

        foreach ($this->testResults as $category => $results) {
            if (isset($results['total_tests']) && isset($results['passed_tests'])) {
                $totalTests += $results['total_tests'];
                $passedTests += $results['passed_tests'];
            }
        }

        $report['test_summary']['total_tests'] = $totalTests;
        $report['test_summary']['passed_tests'] = $passedTests;
        $report['test_summary']['failed_tests'] = $totalTests - $passedTests;
        $report['test_summary']['success_rate'] = $totalTests > 0 ? ($passedTests / $totalTests) * 100 : 0;

        $this->printReport($report);

        return $report;
    }

    private function printReport(array $report): void {
        echo "\n" . str_repeat("=", 70) . "\n";
        echo "RCE DETECTION TEST REPORT\n";
        echo str_repeat("=", 70) . "\n";

        $summary = $report['test_summary'];
        
        printf("Total Execution Time: %.3f seconds\n", $summary['total_execution_time']);
        printf("Memory Peak Usage: %.2f MB\n", $summary['memory_peak_usage'] / 1024 / 1024);
        printf("PHP Version: %s\n", $summary['php_version']);
        printf("Total Tests: %d\n", $summary['total_tests']);
        printf("Passed Tests: %d\n", $summary['passed_tests']);
        printf("Failed Tests: %d\n", $summary['failed_tests']);
        printf("Success Rate: %.1f%%\n", $summary['success_rate']);

        echo "\nDETAILED RESULTS:\n";
        echo str_repeat("-", 50) . "\n";

        foreach ($report['detailed_results'] as $category => $results) {
            if (isset($results['total_tests']) && isset($results['passed_tests'])) {
                $categoryName = str_replace('_', ' ', ucfirst($category));
                printf("%-30s: %d/%d passed (%.1f%%)\n", 
                    $categoryName, 
                    $results['passed_tests'], 
                    $results['total_tests'],
                    ($results['passed_tests'] / $results['total_tests']) * 100
                );
            }
        }

        // Performance summary
        if (isset($report['detailed_results']['performance'])) {
            $perf = $report['detailed_results']['performance'];
            printf("\n%-30s: %.3f sec average (%.3f min, %.3f max)\n",
                'Performance',
                $perf['average_time'],
                $perf['min_time'],
                $perf['max_time']
            );
        }

        echo str_repeat("=", 70) . "\n";

        // Recommendations
        if ($summary['success_rate'] >= 95) {
            echo "✓ EXCELLENT: RCE detection is highly effective!\n";
        } elseif ($summary['success_rate'] >= 85) {
            echo "✓ GOOD: RCE detection is working well.\n";
        } elseif ($summary['success_rate'] >= 75) {
            echo "⚠ FAIR: Some RCE vectors may not be detected effectively.\n";
        } else {
            echo "✗ POOR: Significant improvements needed in RCE detection.\n";
        }
    }

    /**
     * Run specific RCE test category
     */
    public function runSpecificTest(string $testCategory): array {
        switch ($testCategory) {
            case 'command':
                $this->testCommandInjection();
                break;
            case 'code':
                $this->testCodeInjection();
                break;
            case 'file':
                $this->testFileInclusion();
                break;
            case 'deserialize':
                $this->testDeserialization();
                break;
            case 'webshell':
                $this->testWebshellDetection();
                break;
            case 'obfuscated':
                $this->testObfuscatedAttacks();
                break;
            case 'falsepositives':
                $this->testFalsePositives();
                break;
            case 'performance':
                $this->testPerformance();
                break;
            default:
                throw new InvalidArgumentException("Unknown RCE test category: $testCategory");
        }

        return $this->testResults[$testCategory] ?? [];
    }

    public function cleanup(): void {
        $_GET = $_POST = $_COOKIE = $_FILES = [];
        $_SERVER = array_filter($_SERVER, fn($key) => !str_starts_with($key, 'HTTP_X_SECURITY'), ARRAY_FILTER_USE_KEY);
        $this->testResults = [];
    }
}

// Command line interface
if (php_sapi_name() === 'cli' && basename(__FILE__) === basename($_SERVER['argv'][0] ?? '')) {
    $tester = new RCETestRunner();
    
    $options = getopt('', ['category:', 'help']);
    
    if (isset($options['help'])) {
        echo "RCE Detection Test Runner\n";
        echo "Usage: php RCETestRunner.php [--category=name]\n";
        echo "Categories: command, code, file, deserialize, webshell, obfuscated, falsepositives, performance\n";
        exit(0);
    }
    
    if (isset($options['category'])) {
        $result = $tester->runSpecificTest($options['category']);
    } else {
        $result = $tester->runAllTests();
    }
    
    $tester->cleanup();
    exit($result['test_summary']['success_rate'] >= 85 ? 0 : 1);
}