PHP获取YouTube直链时的signature问题求助
Fixing YouTube Direct Link Generation for Signature-Protected Videos
Hey there! Let's break down why your PHP script can't handle signature-protected YouTube videos and how to fix it.
What's the Root Issue?
YouTube uses signature encryption to prevent direct hotlinking for some videos. When you pull data from the get_video_info endpoint, the stream URLs in url_encoded_fmt_stream_map include an s parameter (raw, encrypted signature) instead of a valid signature parameter. Your current script doesn't decrypt this raw signature, so those links are useless.
How to Resolve It
We need to add signature decryption logic to your script, following these steps:
- Fetch the YouTube player JS file that contains the signature-decoding algorithm
- Extract core decoding steps (like reverse, slice, swap) from that JS
- Replicate those steps in PHP to decrypt the
sparameter - Append the decrypted signature to the stream URL to make it valid
Updated Working Code
<?php // Helper function to fetch URLs with proper headers (avoids anti-crawler blocks) function fetchUrl($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $content = curl_exec($ch); curl_close($ch); return $content; } if(isset($_GET['url']) && !empty($_GET['url'])){ parse_str(parse_url($_GET['url'], PHP_URL_QUERY), $urlParams); $videoId = $urlParams['v'] ?? ''; if(empty($videoId)){ echo json_encode([ 'error' => true, 'msg' => 'Invalid YouTube URL - could not extract video ID', 'madeBy' => 'El-zahaby', 'instagram' => 'egy.js' ], JSON_PRETTY_PRINT); exit; } // Fetch video info from YouTube's API endpoint $videoInfo = fetchUrl("https://www.youtube.com/get_video_info?video_id=$videoId&el=embedded&ps=default&eurl=&gl=US&hl=en"); if(strpos($videoInfo, 'status=fail') !== false){ parse_str($videoInfo, $errorDetails); echo json_encode([ 'error' => true, 'message' => urldecode($errorDetails['reason'] ?? 'Unknown error'), 'instagram' => 'egy.js', 'apiMadeBy' => 'El-zahaby' ], JSON_PRETTY_PRINT); exit; } parse_str($videoInfo, $videoData); $streamMap = explode(',', urldecode($videoData['url_encoded_fmt_stream_map'])); $playerResponse = json_decode(urldecode($videoData['player_response']), true); // Get the player JS file that contains signature decipher logic $playerJsUrl = 'https://www.youtube.com' . $playerResponse['assets']['js']; $playerJs = fetchUrl($playerJsUrl); // Extract the signature decipher function (basic regex - adjust if YouTube updates their JS structure) preg_match('/function\s+\w+\(a\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\);\s*([\s\S]*?)\s*return\s*a\.join\(\s*""\s*\);\s*}/', $playerJs, $decipherMatch); $decipherSteps = $decipherMatch[1] ?? ''; // Parse core operations from the JS code $needsReverse = strpos($decipherSteps, '.reverse()') !== false; preg_match('/\.slice\((\d+)\)/', $decipherSteps, $sliceMatch); $sliceAmount = $sliceMatch[1] ?? 0; preg_match('/\.swap\((\d+),\s*(\d+)\)/', $decipherSteps, $swapMatch); $swapPositions = !empty($swapMatch) ? [(int)$swapMatch[1], (int)$swapMatch[2]] : []; $validStreams = []; foreach($streamMap as $streamStr){ parse_str($streamStr, $streamDetails); $streamUrl = urldecode($streamDetails['url']); // Decrypt signature if the raw `s` parameter exists if(isset($streamDetails['s'])){ $rawSignature = $streamDetails['s']; // Apply the decipher steps extracted from JS if($sliceAmount > 0){ $rawSignature = substr($rawSignature, $sliceAmount); } if($needsReverse){ $rawSignature = strrev($rawSignature); } if(!empty($swapPositions)){ $sigChars = str_split($rawSignature); [$pos1, $pos2] = $swapPositions; $temp = $sigChars[$pos1]; $sigChars[$pos1] = $sigChars[$pos2]; $sigChars[$pos2] = $temp; $rawSignature = implode('', $sigChars); } // Append the decrypted signature to make the stream URL valid $streamUrl .= '&signature=' . $rawSignature; } $validStreams[] = [ 'url' => $streamUrl, 'quality' => $streamDetails['quality'], 'mime_type' => $streamDetails['type'] ]; } echo json_encode($validStreams, JSON_PRETTY_PRINT); }else{ echo json_encode([ 'error' => true, 'msg' => 'No YouTube URL provided', 'madeBy' => 'El-zahaby', 'instagram' => 'egy.js' ], JSON_PRETTY_PRINT); } ?>
Key Notes to Keep in Mind
- YouTube Algorithm Updates: YouTube regularly changes their signature encryption logic. If links stop working, you'll need to update the regex patterns that extract the decipher steps from the player JS.
- Anti-Crawler Protection: Using
curlwith a proper User-Agent header avoids being blocked by YouTube's anti-bot measures. Never usefile_get_contentswithout headers here. - Complex Decipher Steps: Some videos might use more complex logic (multiple swaps, custom helper functions). You may need to expand the parsing code for full coverage of all video types.
内容的提问来源于stack exchange,提问作者A. El-zahaby
相关产品推荐
相关产品推荐

