<?php
// load_env.php — Hardened .env loader with enhanced security features

// =============================================================================
// SECURITY CONFIGURATION
// =============================================================================
define('ENV_MAX_FILE_SIZE', 10240); // 10KB max for .env file
define('ENV_ALLOWED_PATTERNS', '/^[A-Z][A-Z0-9_]*$/'); // Valid pattern for env names

// =============================================================================
// POLYFILLS FOR PHP < 8
// =============================================================================
if (!function_exists('str_starts_with')) {
    function str_starts_with($haystack, $needle) {
        return substr($haystack, 0, strlen($needle)) === $needle;
    }
}

if (!function_exists('str_ends_with')) {
    function str_ends_with($haystack, $needle) {
        return substr($haystack, -strlen($needle)) === $needle;
    }
}

// =============================================================================
// ENVIRONMENT LOADER FUNCTION
// =============================================================================
function load_env(string $path): void
{
    // Security check: Validate file path
    if (!is_readable($path)) {
        error_log("Security: .env file not readable or doesn't exist at $path");
        throw new RuntimeException('Environment configuration unavailable');
    }

    // Security check: Prevent path traversal
    if (strpos($path, '..') !== false) {
        error_log("Security: Potential path traversal attack detected: $path");
        throw new RuntimeException('Invalid environment file path');
    }

    // Security check: File size limitation
    if (filesize($path) > ENV_MAX_FILE_SIZE) {
        error_log("Security: .env file too large: $path");
        throw new RuntimeException('Environment file exceeds size limit');
    }

    $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    
    if ($lines === false) {
        error_log("Failed to read .env file: $path");
        return;
    }

    foreach ($lines as $line) {
        $line = trim($line);

        // Skip empty lines and comments
        if ($line === '' || str_starts_with($line, '#')) {
            continue;
        }

        // Skip lines without equals sign
        if (strpos($line, '=') === false) {
            error_log("Invalid line in .env file: $line");
            continue;
        }

        list($name, $value) = explode('=', $line, 2);
        $name = trim($name);
        $value = trim($value);

        // Security: Validate environment variable name
        if (!preg_match(ENV_ALLOWED_PATTERNS, $name)) {
            error_log("Security: Invalid environment variable name: $name");
            continue;
        }

        // Remove surrounding quotes while preserving quoted content
        if (
            (str_starts_with($value, '"') && str_ends_with($value, '"')) ||
            (str_starts_with($value, "'") && str_ends_with($value, "'"))
        ) {
            $value = substr($value, 1, -1);
        }

        // Security: Basic sanitization of values
        $value = sanitize_env_value($value);

        // Set environment variables
        $_ENV[$name] = $value;
        $_SERVER[$name] = $value;
        putenv("$name=$value");
    }
}

// =============================================================================
// SECURITY HELPER FUNCTIONS
// =============================================================================
function sanitize_env_value(string $value): string
{
    // Remove null bytes and other potentially dangerous characters
    $value = str_replace("\0", '', $value);
    
    // Trim whitespace
    $value = trim($value);
    
    return $value;
}

function validate_env_file_location(string $path): bool
{
    $webRoot = $_SERVER['DOCUMENT_ROOT'] ?? '';
    
    // Check if .env is outside web root (more secure)
    if (strpos(realpath($path), realpath($webRoot)) === 0) {
        error_log("SECURITY WARNING: .env file is inside web root: $path");
        return false;
    }
    
    return true;
}

function get_env_value(string $key, $default = null)
{
    // Check in order of priority: getenv(), $_ENV, $_SERVER
    $value = getenv($key);
    
    if ($value === false) {
        $value = $_ENV[$key] ?? $_SERVER[$key] ?? $default;
    }
    
    return $value;
}

// =============================================================================
// AUTO-LOAD ENVIRONMENT
// =============================================================================
try {
    $envPaths = [
        __DIR__ . '/.env',                // Same directory as load_env.php
        dirname(__DIR__) . '/.env',       // Parent directory (backup)
        __DIR__ . '/../.env',             // Parent directory (alternative)
    ];
    
    $envLoaded = false;
    foreach ($envPaths as $envPath) {
        if (file_exists($envPath)) {
            // Validate file location
            validate_env_file_location($envPath);
            
            // Load environment variables
            load_env($envPath);
            $envLoaded = true;
            break;
        }
    }
    
    if (!$envLoaded) {
        error_log('Warning: No .env file found in expected locations');
    }
    
} catch (Exception $e) {
    // Log error but don't expose details to users
    error_log('Environment loading failed: ' . $e->getMessage());
    
    // Optional: Set default values for critical variables
    if (!getenv('DB_HOST')) putenv('DB_HOST=localhost');
    if (!getenv('DB_NAME')) putenv('DB_NAME=affinter');
}

// =============================================================================
// VALIDATE REQUIRED ENVIRONMENT VARIABLES
// =============================================================================
function validate_required_env_vars(array $requiredVars): void
{
    $missing = [];
    
    foreach ($requiredVars as $var) {
        if (empty(get_env_value($var))) {
            $missing[] = $var;
        }
    }
    
    if (!empty($missing)) {
        error_log('Missing required environment variables: ' . implode(', ', $missing));
        throw new RuntimeException('Application configuration incomplete');
    }
}

// Validate critical environment variables
try {
    validate_required_env_vars(['DB_HOST', 'DB_USER', 'DB_NAME']);
} catch (RuntimeException $e) {
    // Log the error but allow the application to continue
    error_log('Configuration validation failed: ' . $e->getMessage());
}

?>