$url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_CONNECTTIMEOUT => 3, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 3, CURLOPT_USERAGENT => 'Mozilla/5.0', CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, ]); // 处理 Range 请求 $headers = ['Accept: */*']; if (isset($_SERVER['HTTP_RANGE'])) { $headers[] = 'Range: ' . $_SERVER['HTTP_RANGE']; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $body = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); $contentLength = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); $error = curl_error($ch); curl_close($ch); if ($body === false || $httpCode >= 400) { http_response_code(502); header('Content-Type: text/plain'); echo "Error: HTTP $httpCode"; exit; } // 设置响应头 header('Content-Type: ' . ($contentType ?: 'video/MP2T')); if ($contentLength > 0) { header('Content-Length: ' . $contentLength); } header('Cache-Control: public, max-age=7200'); header('Accept-Ranges: bytes'); echo $body; exit; } // M3U8 文件使用缓冲模式(需要重写内容) $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5, CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', CURLOPT_ENCODING => '', // 支持压缩 CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, ]); $headerContent = ''; curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use (&$headerContent) { $headerContent .= $header; return strlen($header); }); $body = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $effectiveUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); $error = curl_error($ch); curl_close($ch); if ($body === false || $httpCode >= 400) { http_response_code(502); header('Content-Type: text/plain; charset=utf-8'); echo "Proxy Error: HTTP $httpCode\n"; echo "Error: " . ($error ?: 'Request failed') . "\n"; exit; } // ProxyM3U8: 处理 M3U8 文件 if ($_GET['api'] === 'ProxyM3U8') { $parsedUrl = parse_url($effectiveUrl); $baseUrl = ($parsedUrl['scheme'] ?? 'http') . '://' . ($parsedUrl['host'] ?? ''); if (isset($parsedUrl['port'])) { $baseUrl .= ':' . $parsedUrl['port']; } $basePath = isset($parsedUrl['path']) ? dirname($parsedUrl['path']) : '/'; $scriptPath = $_SERVER['SCRIPT_NAME']; // 重写 TS 链接为代理链接 $body = preg_replace_callback( '/^(?!#)(.*?\.ts[^\r\n]*)/im', function($matches) use ($baseUrl, $basePath, $scriptPath) { $tsUrl = trim($matches[1]); // 如果已经是代理链接,不处理 if (strpos($tsUrl, 'api=ProxyTS') !== false) { return $tsUrl; } // 转换为绝对路径 if (!preg_match('/^https?:\/\//i', $tsUrl)) { if ($tsUrl[0] === '/') { $tsUrl = $baseUrl . $tsUrl; } else { $tsUrl = $baseUrl . $basePath . '/' . $tsUrl; } } return $scriptPath . '?api=ProxyTS&url=' . urlencode($tsUrl); }, $body ); header('Content-Type: application/vnd.apple.mpegurl'); header('Cache-Control: no-cache'); echo $body; exit; } // ProxyTS: 处理 TS 分片 if ($_GET['api'] === 'ProxyTS') { // 转发 Content-Type if (preg_match('/Content-Type:\s*(.+?)\r?\n/i', $headerContent, $m)) { header('Content-Type: ' . trim($m[1])); } else { header('Content-Type: video/MP2T'); } // 转发 Content-Length if (preg_match('/Content-Length:\s*(\d+)\r?\n/i', $headerContent, $m)) { header('Content-Length: ' . $m[1]); } // 转发 Range 相关头部 if (preg_match('/Accept-Ranges:\s*(.+?)\r?\n/i', $headerContent, $m)) { header('Accept-Ranges: ' . trim($m[1])); } if (preg_match('/Content-Range:\s*(.+?)\r?\n/i', $headerContent, $m)) { header('Content-Range: ' . trim($m[1])); } header('Cache-Control: public, max-age=3600'); echo $body; exit; } http_response_code(400); die('Invalid API type'); } // ==================== 播放器界面 ==================== $defaultUrl = isset($_GET['url']) ? $_GET['url'] : 'http://tvgslb.hn.chinamobile.com:8089/180000001002/00000001000000000007000000001249/main.m3u8'; ?> M3U8 播放器
准备就绪