<?php
error_reporting(0);
while (ob_get_level() > 0) { ob_end_clean(); }
ob_implicit_flush(true);
@ini_set('zlib.output_compression', 'Off');
@ini_set('output_buffering', 'off');
@ini_set('implicit_flush', 1);
set_time_limit(0);
ignore_user_abort(true);

function resolve_ips_cached($host) {
    if (filter_var($host, FILTER_VALIDATE_IP)) return [$host];
    $cacheKey = 'dlproxy_ip_' . md5($host);
    if (function_exists('apcu_fetch')) {
        $cached = apcu_fetch($cacheKey, $ok);
        if ($ok && $cached) return $cached;
    }
    $ips = [];
    $records = @dns_get_record($host, DNS_A + DNS_AAAA);
    if ($records) {
        foreach ($records as $r) {
            if (!empty($r['ip'])) $ips[] = $r['ip'];
            if (!empty($r['ipv6'])) $ips[] = $r['ipv6'];
        }
    }
    if (!$ips) {
        $ip = @gethostbyname($host);
        if ($ip && $ip !== $host) $ips[] = $ip;
    }
    if ($ips && function_exists('apcu_store')) {
        apcu_store($cacheKey, $ips, 300);
    }
    return $ips;
}

function is_safe_ip($ip) {
    return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false;
}

function validate_target($url) {
    $p = @parse_url($url);
    if (!$p || empty($p['host']) || !in_array(strtolower($p['scheme'] ?? ''), ['http', 'https'], true)) {
        return false;
    }
    $ips = resolve_ips_cached($p['host']);
    if (!$ips) return false;
    foreach ($ips as $ip) {
        if (!is_safe_ip($ip)) return false;
    }
    $port = $p['port'] ?? (strtolower($p['scheme']) === 'https' ? 443 : 80);
    $resolve = [];
    foreach ($ips as $ip) $resolve[] = "{$p['host']}:{$port}:{$ip}";
    return $resolve;
}

// استخراج نام فایل از هدر Content-Disposition که سرور بالادستی فرستاده
function parse_upstream_filename($cdValue) {
    // filename*=UTF-8''xxx (اولویت با این، چون استاندارد و انکود شده است)
    if (preg_match("/filename\*\s*=\s*UTF-8''([^;]+)/i", $cdValue, $m)) {
        $decoded = rawurldecode(trim($m[1]));
        if ($decoded !== '') return $decoded;
    }
    // filename="xxx" یا filename=xxx
    if (preg_match('/filename\s*=\s*"([^"]+)"/i', $cdValue, $m)) {
        return trim($m[1]);
    }
    if (preg_match('/filename\s*=\s*([^;]+)/i', $cdValue, $m)) {
        return trim($m[1], " \t\"'");
    }
    return null;
}

$url = $_GET['url'] ?? '';
if (!$url || !filter_var($url, FILTER_VALIDATE_URL)) {
    http_response_code(400);
    exit('Invalid URL');
}

$isHead = $_SERVER['REQUEST_METHOD'] === 'HEAD';

// نام فایل حدسی اولیه (فال‌بک) از روی خود URL درخواستی
$origPath = parse_url($url, PHP_URL_PATH);
$fallbackFilename = basename(urldecode((string)$origPath));
if (!$fallbackFilename || $fallbackFilename === '' ) $fallbackFilename = 'download.bin';

header('X-Accel-Buffering: no');
header('X-LiteSpeed-Cache-Control: no-cache');

$reqHeaders = ['User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36'];
if (isset($_SERVER['HTTP_RANGE'])) {
    $reqHeaders[] = 'Range: ' . $_SERVER['HTTP_RANGE'];
}

$currentUrl = $url;
$maxRedirects = 5;
$dispositionSent = false;
$upstreamFilename = null;

for ($i = 0; $i <= $maxRedirects; $i++) {
    $resolveOpts = validate_target($currentUrl);
    if (!$resolveOpts) {
        http_response_code(403);
        exit('Blocked or invalid target');
    }

    $statusCode = 0;
    $httpCodeSet = false;
    $redirectLocation = null;

    $ch = curl_init($currentUrl);
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER => $reqHeaders,
        CURLOPT_RESOLVE => $resolveOpts,
        CURLOPT_RETURNTRANSFER => false,
        CURLOPT_HEADER => false,
        CURLOPT_NOBODY => $isHead,
        CURLOPT_FOLLOWLOCATION => false,
        CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
        CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2TLS,
        CURLOPT_TCP_NODELAY => true,
        CURLOPT_TIMEOUT => 0,
        CURLOPT_CONNECTTIMEOUT => 8,
        CURLOPT_DNS_CACHE_TIMEOUT => 300,
        CURLOPT_BUFFERSIZE => 131072,
        CURLOPT_TCP_KEEPALIVE => 1,
        CURLOPT_LOW_SPEED_LIMIT => 512,
        CURLOPT_LOW_SPEED_TIME => 60,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_NOPROGRESS => false,
        CURLOPT_PROGRESSFUNCTION => function ($res, $dlSize, $dl, $ulSize, $ul) {
            return connection_aborted() ? 1 : 0;
        },
        CURLOPT_HEADERFUNCTION => function ($curl, $header) use (&$httpCodeSet, &$statusCode, &$redirectLocation, &$dispositionSent, &$upstreamFilename, $fallbackFilename) {
            $len = strlen($header);
            if (!$httpCodeSet && preg_match('#^HTTP/\S+\s(\d+)#', $header, $m)) {
                $statusCode = (int)$m[1];
                $httpCodeSet = true;
                http_response_code($statusCode);
                return $len;
            }
            $p = explode(':', $header, 2);
            if (count($p) < 2) return $len;
            $name = strtolower(trim($p[0]));
            $value = trim($p[1]);
            if ($statusCode >= 300 && $statusCode < 400) {
                if ($name === 'location') $redirectLocation = $value;
                return $len;
            }
            if ($name === 'content-length' || $name === 'accept-ranges' || $name === 'content-range') {
                header("$name: $value");
            } elseif ($name === 'content-type') {
                header("content-type: $value");
            } elseif ($name === 'content-disposition') {
                // نام واقعی رو از بالادستی می‌گیریم (اولویت اول)
                $fname = parse_upstream_filename($value);
                if ($fname) $upstreamFilename = $fname;
            }
            // درست قبل از شروع بدنه (که بعد از تموم شدن هدرها میاد) دیسپوزیشن نهایی رو می‌فرستیم
            return $len;
        },
        CURLOPT_WRITEFUNCTION => function ($curl, $data) use (&$statusCode, $isHead, &$dispositionSent, &$upstreamFilename, $fallbackFilename) {
            if (!$dispositionSent && !($statusCode >= 300 && $statusCode < 400)) {
                $finalName = $upstreamFilename ?: $fallbackFilename;
                $encoded = rawurlencode($finalName);
                header("Content-Disposition: attachment; filename=\"$finalName\"; filename*=UTF-8''$encoded");
                $dispositionSent = true;
            }
            if ($isHead) return strlen($data);
            if ($statusCode >= 300 && $statusCode < 400) return strlen($data);
            if (connection_aborted()) return 0;
            echo $data;
            return strlen($data);
        },
    ]);

    curl_exec($ch);
    $hadError = curl_errno($ch) !== 0;
    curl_close($ch);

    if ($redirectLocation && $statusCode >= 300 && $statusCode < 400) {
        if (!filter_var($redirectLocation, FILTER_VALIDATE_URL)) {
            $base = parse_url($currentUrl);
            $redirectLocation = $base['scheme'] . '://' . $base['host'] . (isset($base['port']) ? ':' . $base['port'] : '') . '/' . ltrim($redirectLocation, '/');
        }
        $currentUrl = $redirectLocation;
        continue;
    }

    if ($hadError && !$httpCodeSet && !connection_aborted()) {
        http_response_code(502);
    }

    // اگه با HEAD یا بدون بدنه تموم شد و دیسپوزیشن هنوز نرفته، الان بفرست
    if (!$dispositionSent) {
        $finalName = $upstreamFilename ?: $fallbackFilename;
        $encoded = rawurlencode($finalName);
        header("Content-Disposition: attachment; filename=\"$finalName\"; filename*=UTF-8''$encoded");
        $dispositionSent = true;
    }

    break;
}