<?php
/**
 * Advanced IP Detection Script
 * 
 * This script provides comprehensive IP address detection that handles:
 * - Cloudflare (CF-Connecting-IP)
 * - Proxy servers (X-Forwarded-For)
 * - Load balancers
 * - IPv4 and IPv6 addresses
 * - Localhost variations
 * 
 * Usage:
 *   Simple: $ip = detect_ip();
 *   Detailed: $info = IPDetector::getDetailedInfo();
 */

class IPDetector {
    
    /**
     * Get the real client IP address
     * Handles Cloudflare, proxies, and various headers
     * 
     * @return string The detected IP address
     */
    public static function detect() {
        $ip = null;
        
        // Priority 1: Cloudflare (most reliable when using Cloudflare)
        if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
            $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
        }
        // Priority 2: True-Client-IP (used by some CDNs)
        else if (!empty($_SERVER['HTTP_TRUE_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_TRUE_CLIENT_IP'];
        }
        // Priority 3: X-Real-IP (nginx and other proxies)
        else if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
            $ip = $_SERVER['HTTP_X_REAL_IP'];
        }
        // Priority 4: X-Forwarded-For (handle comma-separated list)
        else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $forwarded = $_SERVER['HTTP_X_FORWARDED_FOR'];
            $ipList = explode(',', $forwarded);
            $ip = trim($ipList[0]); // Get first IP in chain
        }
        // Priority 5: X-Forwarded
        else if (!empty($_SERVER['HTTP_X_FORWARDED'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED'];
        }
        // Priority 6: Forwarded-For
        else if (!empty($_SERVER['HTTP_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_FORWARDED_FOR'];
        }
        // Priority 7: Forwarded
        else if (!empty($_SERVER['HTTP_FORWARDED'])) {
            $ip = $_SERVER['HTTP_FORWARDED'];
        }
        // Priority 8: Client-IP
        else if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        }
        // Priority 9: Remote Address (fallback, least reliable with proxies)
        else if (!empty($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        
        // Validate and clean the IP
        $ip = self::validateIP($ip);
        
        // Handle localhost variations
        if ($ip === '::1' || $ip === '0:0:0:0:0:0:0:1') {
            $ip = '127.0.0.1';
        }
        
        return $ip ?: 'UNKNOWN';
    }
    
    /**
     * Validate IP address (IPv4 or IPv6)
     * 
     * @param string $ip IP address to validate
     * @return string|false Valid IP address or false
     */
    private static function validateIP($ip) {
        if (empty($ip)) {
            return false;
        }
        
        // Clean the IP (remove whitespace, port numbers if present)
        $ip = trim($ip);
        
        // Handle IPv6 with brackets (e.g., [::1])
        if (preg_match('/^\[(.+)\]$/', $ip, $matches)) {
            $ip = $matches[1];
        }
        
        // Remove port if present (e.g., 192.168.1.1:8080)
        if (strpos($ip, ':') !== false && !self::isIPv6($ip)) {
            $parts = explode(':', $ip);
            $ip = $parts[0];
        }
        
        // Validate IPv4
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return $ip;
        }
        
        // Validate IPv6
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            return $ip;
        }
        
        return false;
    }
    
    /**
     * Check if IP is IPv6 format
     * 
     * @param string $ip IP address
     * @return bool
     */
    private static function isIPv6($ip) {
        return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
    }
    
    /**
     * Get detailed IP information
     * 
     * @return array Detailed IP information
     */
    public static function getDetailedInfo() {
        $ip = self::detect();
        $publicIP = self::getPublicIP();
        
        $info = [
            'ip' => $ip,
            'public_ip' => $publicIP ?: null,
            'ip_version' => self::getIPVersion($ip),
            'is_localhost' => self::isLocalhost($ip),
            'is_private' => self::isPrivateIP($ip),
            'detection_method' => self::getDetectionMethod(),
            'all_headers' => self::getAllIPHeaders(),
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown',
            'timestamp' => date('Y-m-d H:i:s'),
        ];
        
        return $info;
    }
    
    /**
     * Get IP version (IPv4 or IPv6)
     * 
     * @param string $ip IP address
     * @return string IPv4, IPv6, or Unknown
     */
    private static function getIPVersion($ip) {
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            return 'IPv4';
        }
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            return 'IPv6';
        }
        return 'Unknown';
    }
    
    /**
     * Check if IP is localhost
     * 
     * @param string $ip IP address
     * @return bool
     */
    private static function isLocalhost($ip) {
        return in_array($ip, ['127.0.0.1', '::1', '0:0:0:0:0:0:0:1', 'localhost']);
    }
    
    /**
     * Check if IP is private/internal
     * 
     * @param string $ip IP address
     * @return bool
     */
    private static function isPrivateIP($ip) {
        if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            return true;
        }
        return false;
    }
    
    /**
     * Determine which method was used to detect the IP
     * 
     * @return string Detection method name
     */
    private static function getDetectionMethod() {
        if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
            return 'Cloudflare (CF-Connecting-IP)';
        }
        if (!empty($_SERVER['HTTP_TRUE_CLIENT_IP'])) {
            return 'True-Client-IP';
        }
        if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
            return 'X-Real-IP';
        }
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            return 'X-Forwarded-For';
        }
        if (!empty($_SERVER['HTTP_X_FORWARDED'])) {
            return 'X-Forwarded';
        }
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            return 'Client-IP';
        }
        if (!empty($_SERVER['REMOTE_ADDR'])) {
            return 'REMOTE_ADDR';
        }
        return 'Unknown';
    }
    
    /**
     * Get all IP-related headers
     * 
     * @return array All IP headers
     */
    private static function getAllIPHeaders() {
        $headers = [];
        $headerKeys = [
            'HTTP_CF_CONNECTING_IP',
            'HTTP_TRUE_CLIENT_IP',
            'HTTP_X_REAL_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'HTTP_CLIENT_IP',
            'REMOTE_ADDR'
        ];
        
        foreach ($headerKeys as $key) {
            if (!empty($_SERVER[$key])) {
                $headers[$key] = $_SERVER[$key];
            }
        }
        
        return $headers;
    }
    
    /**
     * Check if request is behind Cloudflare
     * 
     * @return bool
     */
    public static function isCloudflare() {
        return !empty($_SERVER['HTTP_CF_CONNECTING_IP']) || 
               !empty($_SERVER['HTTP_CF_RAY']) ||
               !empty($_SERVER['HTTP_CF_IPCOUNTRY']);
    }
    
    /**
     * Get Cloudflare country code (if available)
     * 
     * @return string|null Country code
     */
    public static function getCloudflareCountry() {
        return $_SERVER['HTTP_CF_IPCOUNTRY'] ?? null;
    }
    
    /**
     * Get public IP address via external service
     * Useful when testing on localhost to see your real public IP
     * 
     * @return string|false Public IP address or false on failure
     */
    public static function getPublicIP() {
        // List of IP detection services (try multiple for reliability)
        $services = [
            'https://api.ipify.org?format=text',
            'https://checkip.amazonaws.com',
            'https://icanhazip.com',
            'https://ifconfig.me/ip',
            'https://ipecho.net/plain'
        ];
        
        foreach ($services as $service) {
            $context = stream_context_create([
                'http' => [
                    'timeout' => 3,
                    'method' => 'GET',
                    'header' => "User-Agent: Mozilla/5.0\r\n"
                ]
            ]);
            
            $publicIP = @file_get_contents($service, false, $context);
            $publicIP = trim($publicIP);
            
            if ($publicIP && filter_var($publicIP, FILTER_VALIDATE_IP)) {
                return $publicIP;
            }
        }
        
        return false;
    }
}

/**
 * Simple function to detect IP address
 * Usage: $ip = detect_ip();
 * 
 * @return string The detected IP address
 */
function detect_ip() {
    return IPDetector::detect();
}

/**
 * Get client IP (alias for detect_ip)
 * 
 * @return string The detected IP address
 */
function get_client_ip() {
    return IPDetector::detect();
}

/**
 * Get public IP address (via external service)
 * 
 * @return string|false Public IP address or false on failure
 */
function get_public_ip() {
    return IPDetector::getPublicIP();
}

// If accessed directly, just print the client IP
echo detect_ip();
?>
