You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP获取YouTube直链时的signature问题求助

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:

  1. Fetch the YouTube player JS file that contains the signature-decoding algorithm
  2. Extract core decoding steps (like reverse, slice, swap) from that JS
  3. Replicate those steps in PHP to decrypt the s parameter
  4. 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 curl with a proper User-Agent header avoids being blocked by YouTube's anti-bot measures. Never use file_get_contents without 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:22:40