155 lines
5.3 KiB
PHP
155 lines
5.3 KiB
PHP
<?php
|
||
/**
|
||
* HLS Proxy — sunucu taraflı CORS bypass
|
||
* Kullanım: /hls-proxy.php?url=https://u.aniziumserver.sbs/.../master.m3u8&ref=https://anizium.co/
|
||
*/
|
||
|
||
$ALLOWED_DOMAINS = [
|
||
'aniziumserver.sbs',
|
||
'aniziumserver.site',
|
||
'aniziumserver.com',
|
||
'misakina.asia',
|
||
'misakina.cfd',
|
||
'irtau1.online',
|
||
'tsuriko-1.asia', 'tsuriko-2.asia', 'tsuriko-3.asia',
|
||
'rhyzoku-2.asia', 'rhyzoku-4.asia',
|
||
'kamadotanjiro.asia',
|
||
'uryuishida.asia',
|
||
'tohru.icu', 'tohru.cyou',
|
||
'zappy-net.store',
|
||
'pixel-quirk.shop',
|
||
'tau-video.xyz',
|
||
];
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||
header('Access-Control-Allow-Origin: *');
|
||
header('Access-Control-Allow-Methods: GET, OPTIONS');
|
||
header('Access-Control-Allow-Headers: Range, Origin');
|
||
header('Access-Control-Max-Age: 86400');
|
||
exit;
|
||
}
|
||
|
||
$url = trim($_GET['url'] ?? '');
|
||
if (!$url || !str_starts_with($url, 'http')) { http_response_code(400); die('url parametresi eksik'); }
|
||
|
||
$parsed = parse_url($url);
|
||
$host = strtolower($parsed['host'] ?? '');
|
||
|
||
$allowed = false;
|
||
foreach ($ALLOWED_DOMAINS as $d) {
|
||
if ($host === $d || str_ends_with($host, '.' . $d)) { $allowed = true; break; }
|
||
}
|
||
if (!$allowed) { http_response_code(403); die('Bu domain proxy edilmiyor: ' . htmlspecialchars($host)); }
|
||
|
||
$referer = trim($_GET['ref'] ?? 'https://anizium.co/');
|
||
if (!str_ends_with($referer, '/')) $referer .= '/';
|
||
$origin = rtrim($referer, '/'); // Origin header referer'dan türet (hotlink koruması Origin de kontrol edebilir)
|
||
|
||
// Tek istek yürüten yardımcı — 403'te farklı header setiyle tekrar denemek için
|
||
$doFetch = function (string $url, array $headers) {
|
||
$ch = curl_init($url);
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_HEADER => true,
|
||
CURLOPT_FOLLOWLOCATION => true,
|
||
CURLOPT_MAXREDIRS => 5,
|
||
CURLOPT_HTTPHEADER => $headers,
|
||
CURLOPT_SSL_VERIFYPEER => false,
|
||
CURLOPT_TIMEOUT => 30,
|
||
CURLOPT_CONNECTTIMEOUT => 10,
|
||
CURLOPT_ENCODING => '', // gzip/br otomatik çöz
|
||
]);
|
||
$raw = curl_exec($ch);
|
||
$info = [
|
||
'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
|
||
'hsize' => curl_getinfo($ch, CURLINFO_HEADER_SIZE),
|
||
'ctype' => curl_getinfo($ch, CURLINFO_CONTENT_TYPE) ?? '',
|
||
'final' => curl_getinfo($ch, CURLINFO_EFFECTIVE_URL),
|
||
'err' => curl_error($ch),
|
||
];
|
||
curl_close($ch);
|
||
return [$raw, $info];
|
||
};
|
||
|
||
$UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';
|
||
|
||
$baseHeaders = [
|
||
'User-Agent: ' . $UA,
|
||
'Accept: */*',
|
||
'Accept-Language: tr-TR,tr;q=0.9,en;q=0.8',
|
||
'Accept-Encoding: identity',
|
||
'Referer: ' . $referer,
|
||
'Origin: ' . $origin,
|
||
'Sec-Fetch-Dest: empty',
|
||
'Sec-Fetch-Mode: cors',
|
||
'Sec-Fetch-Site: cross-site',
|
||
];
|
||
if (!empty($_SERVER['HTTP_RANGE'])) {
|
||
$baseHeaders[] = 'Range: ' . $_SERVER['HTTP_RANGE'];
|
||
}
|
||
|
||
[$raw, $info] = $doFetch($url, $baseHeaders);
|
||
|
||
// 403/401 → hotlink koruması olabilir; Origin'siz ve sadece Referer ile bir kez daha dene
|
||
if (in_array($info['code'], [401, 403], true)) {
|
||
$retryHeaders = array_values(array_filter($baseHeaders, function ($h) {
|
||
return !preg_match('/^(Origin|Sec-Fetch-):/i', $h);
|
||
}));
|
||
[$raw2, $info2] = $doFetch($url, $retryHeaders);
|
||
if (!in_array($info2['code'], [401, 403], true) && $raw2 !== false) {
|
||
$raw = $raw2; $info = $info2;
|
||
}
|
||
}
|
||
|
||
$httpCode = $info['code'];
|
||
$hdrSize = $info['hsize'];
|
||
$ctype = $info['ctype'];
|
||
$finalUrl = $info['final'];
|
||
$curlErr = $info['err'];
|
||
|
||
if ($raw === false || $curlErr) { http_response_code(502); die('Upstream hatası: ' . $curlErr); }
|
||
|
||
$body = substr($raw, $hdrSize);
|
||
|
||
header('Access-Control-Allow-Origin: *');
|
||
header('Access-Control-Allow-Methods: GET, OPTIONS');
|
||
header('Access-Control-Allow-Headers: Range');
|
||
header('Access-Control-Expose-Headers: Content-Length, Content-Range, Content-Type');
|
||
http_response_code($httpCode);
|
||
|
||
$isM3u8 = str_contains($ctype, 'mpegurl')
|
||
|| preg_match('/\.m3u8(\?|$)/i', strtok($url, '#'));
|
||
|
||
if ($isM3u8 && str_starts_with(ltrim($body), '#EXTM3U')) {
|
||
header('Content-Type: application/vnd.apple.mpegurl');
|
||
header('Cache-Control: no-cache');
|
||
|
||
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||
$proxyBase = $scheme . '://' . $_SERVER['HTTP_HOST'] . '/hls-proxy.php?ref=' . urlencode($referer) . '&url=';
|
||
$baseDir = dirname($finalUrl) . '/';
|
||
|
||
$output = [];
|
||
foreach (explode("\n", $body) as $line) {
|
||
$line = rtrim($line, "\r");
|
||
if ($line === '') { $output[] = ''; continue; }
|
||
|
||
if (str_starts_with($line, '#')) {
|
||
$line = preg_replace_callback('/URI="([^"]+)"/', function ($m) use ($baseDir, $proxyBase) {
|
||
$uri = $m[1];
|
||
if (!str_starts_with($uri, 'http')) $uri = $baseDir . $uri;
|
||
return 'URI="' . $proxyBase . urlencode($uri) . '"';
|
||
}, $line);
|
||
$output[] = $line;
|
||
} else {
|
||
if (!str_starts_with($line, 'http')) $line = $baseDir . $line;
|
||
$output[] = $proxyBase . urlencode($line);
|
||
}
|
||
}
|
||
echo implode("\n", $output);
|
||
} else {
|
||
if ($ctype) header('Content-Type: ' . $ctype);
|
||
$len = strlen($body);
|
||
if ($len) header('Content-Length: ' . $len);
|
||
echo $body;
|
||
}
|