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

如何使用PHP批量修改m3u8文件中的URL(兼容PHP 5版本)

如何使用PHP批量修改m3u8文件中的URL(兼容PHP 5版本)

我理解你的需求:要批量处理m3u8文件,给非HTTP(S)开头的媒体路径拼接基础URL,URL编码后套上proxy.php?前缀,同时要兼容PHP 5.x版本,还要覆盖EXTINF行和媒体路径同行/异行的两种常见m3u8格式。下面给你分场景提供解决方案:


核心思路分析

m3u8的媒体文件路径有两种常见写法:

  1. 和#EXTINF同行:#EXTINF:4.004, radio002live-15084.ts
  2. 单独占一行:
    #EXTINF:4.004,
    radio002live-15084.ts
    

我们需要用正则或逐行遍历的方式匹配到所有媒体路径,判断是否为HTTP(S)绝对URL:

  • 若不是:拼接基础URL生成完整绝对URL
  • 若是:直接使用原URL
    然后对完整URL做rawurlencode编码(比urlencode更适合URL整体编码),最后拼接proxy.php?前缀替换原路径。

方案1:正则批量替换(PHP 5.3+ 推荐)

PHP 5.3及以上支持preg_replace_callback,这个方法更安全且代码可读性高,适合大多数场景:

<?php
// 1. 读取m3u8文件内容
$m3u8Content = file_get_contents('input.m3u8');
if ($m3u8Content === false) {
    die('无法读取m3u8文件');
}

// 2. 配置参数
$baseUrl = 'http://someurl.tld/path/'; // 你的基础URL
$proxyPrefix = 'proxy.php?'; // 你的代理前缀

// 3. 定义处理媒体路径的回调函数
$processCallback = function($matches) use ($baseUrl, $proxyPrefix) {
    $extinfPart = $matches[1];
    $mediaPath = trim($matches[2]);
    
    // 空路径直接返回原内容
    if (empty($mediaPath)) {
        return $matches[0];
    }

    // 判断是否已经是HTTP(S)绝对URL
    if (stripos($mediaPath, 'http://') === 0 || stripos($mediaPath, 'https://') === 0) {
        $fullUrl = $mediaPath;
    } else {
        // 拼接基础URL,自动处理首尾斜杠避免重复
        $fullUrl = rtrim($baseUrl, '/') . '/' . ltrim($mediaPath, '/');
    }

    // URL编码(用rawurlencode符合RFC3986标准,适配所有URL字符)
    $encodedUrl = rawurlencode($fullUrl);
    // 拼接代理前缀并返回
    return rtrim($extinfPart) . ' ' . $proxyPrefix . $encodedUrl;
};

// 4. 正则匹配并替换
// 正则说明:匹配EXTINF行+同行/下一行的媒体路径,兼容行尾空白、下一行是标签的情况
$pattern = '/(#EXTINF:\d+(?:\.\d+)?,)(?:\s*)(.*?)(?:\s*$|\s*#)/ms';
$newM3u8Content = preg_replace_callback($pattern, $processCallback, $m3u8Content);

// 5. 保存处理后的内容
if (file_put_contents('output.m3u8', $newM3u8Content) === false) {
    die('无法写入处理后的m3u8文件');
}

echo 'm3u8文件处理完成!';
?>

代码解释

  • 正则/(#EXTINF:\d+(?:\.\d+)?,)(?:\s*)(.*?)(?:\s*$|\s*#)/ms:
    • #EXTINF:\d+(?:\.\d+)?,:匹配带整数/小数时长的EXTINF前缀
    • (?:\s*):匹配逗号后的空白字符(兼容有无空格的情况)
    • (.*?):非贪婪匹配媒体路径(兼容同行/异行)
    • (?:\s*$|\s*#):匹配路径的结束位置(行尾或下一个m3u8标签)
  • rawurlencode:严格按照URL编码标准处理,比如把://编码为%3A%2F%2F,完全符合你需要的格式
  • use ($baseUrl, $proxyPrefix):在回调函数中引入外部变量(PHP 5.3闭包特性)

方案2:PHP 5.2 兼容方案

如果你的环境是PHP 5.2(不支持闭包和preg_replace_callback),可以用preg_replace的/e修饰符实现(注意:/e在PHP5.5+被废弃,仅适合PHP5.2场景):

<?php
// 1. 定义处理函数(必须全局或在当前作用域可访问)
function processMediaPath($mediaPath, $baseUrl, $proxyPrefix) {
    $mediaPath = trim($mediaPath);
    if (empty($mediaPath)) {
        return '';
    }

    if (stripos($mediaPath, 'http://') === 0 || stripos($mediaPath, 'https://') === 0) {
        $fullUrl = $mediaPath;
    } else {
        $fullUrl = rtrim($baseUrl, '/') . '/' . ltrim($mediaPath, '/');
    }

    $encodedUrl = rawurlencode($fullUrl);
    return $proxyPrefix . $encodedUrl;
}

// 2. 读取文件
$m3u8Content = file_get_contents('input.m3u8');
if ($m3u8Content === false) {
    die('无法读取m3u8文件');
}

// 3. 配置参数
$baseUrl = 'http://someurl.tld/path/';
$proxyPrefix = 'proxy.php?';

// 4. 转义参数避免引号冲突
$escapedBaseUrl = addslashes($baseUrl);
$escapedProxyPrefix = addslashes($proxyPrefix);

// 5. 正则替换(使用/e修饰符执行代码)
$pattern = '/(#EXTINF:\d+(?:\.\d+)?,)(?:\s*)(.*?)(?:\s*$|\s*#)/ms';
$newM3u8Content = preg_replace($pattern, "\"$1 \" . processMediaPath(\"$2\", \"$escapedBaseUrl\", \"$escapedProxyPrefix\")", $m3u8Content);

// 6. 保存文件
if (file_put_contents('output.m3u8', $newM3u8Content) === false) {
    die('无法写入处理后的m3u8文件');
}

echo 'm3u8文件处理完成!';
?>

方案3:大文件逐行处理(PHP 5.x 全兼容)

如果你的m3u8文件特别大(比如几百MB),一次性读取到内存会导致性能问题,可以用逐行遍历的方式处理,内存占用更低:

<?php
function processMediaPath($mediaPath, $baseUrl, $proxyPrefix) {
    $mediaPath = trim($mediaPath);
    if (empty($mediaPath)) {
        return '';
    }

    if (stripos($mediaPath, 'http://') === 0 || stripos($mediaPath, 'https://') === 0) {
        $fullUrl = $mediaPath;
    } else {
        $fullUrl = rtrim($baseUrl, '/') . '/' . ltrim($mediaPath, '/');
    }

    return $proxyPrefix . rawurlencode($fullUrl);
}

// 1. 打开文件句柄
$inputHandle = fopen('input.m3u8', 'r');
$outputHandle = fopen('output.m3u8', 'w');
if (!$inputHandle || !$outputHandle) {
    die('无法打开文件');
}

// 2. 配置参数
$baseUrl = 'http://someurl.tld/path/';
$proxyPrefix = 'proxy.php?';
$isExtinfLine = false; // 标记上一行是否是EXTINF行

// 3. 逐行读取处理
while (($line = fgets($inputHandle)) !== false) {
    $trimmedLine = trim($line);
    
    // 匹配EXTINF行
    if (strpos($trimmedLine, '#EXTINF:') === 0) {
        $isExtinfLine = true;
        $commaPos = strrpos($trimmedLine, ',');
        
        if ($commaPos !== false) {
            $extinfPart = substr($line, 0, $commaPos + 1);
            $mediaPath = trim(substr($line, $commaPos + 1));
            
            if (!empty($mediaPath)) {
                // 同行有路径,直接处理替换
                $processedPath = processMediaPath($mediaPath, $baseUrl, $proxyPrefix);
                fwrite($outputHandle, rtrim($extinfPart) . ' ' . $processedPath . "\n");
                $isExtinfLine = false;
            } else {
                // 只有EXTINF前缀,下一行是路径
                fwrite($outputHandle, $line);
            }
        } else {
            // 异常格式,直接写入
            fwrite($outputHandle, $line);
            $isExtinfLine = false;
        }
    } elseif ($isExtinfLine && !empty($trimmedLine)) {
        // 上一行是EXTINF行,当前行是媒体路径
        $processedPath = processMediaPath($trimmedLine, $baseUrl, $proxyPrefix);
        fwrite($outputHandle, $processedPath . "\n");
        $isExtinfLine = false;
    } else {
        // 其他行直接写入
        fwrite($outputHandle, $line);
        $isExtinfLine = false;
    }
}

// 4. 关闭文件句柄
fclose($inputHandle);
fclose($outputHandle);

echo 'm3u8文件处理完成!';
?>

注意事项

  1. 权限问题:确保PHP有读取原m3u8文件和写入新文件的权限
  2. 格式兼容性:测试不同格式的m3u8文件,比如带注释、不同时长格式的EXTINF行
  3. URL编码:必须用rawurlencode而不是urlencode,前者会严格编码所有特殊字符,符合URL规范
  4. 基础URL拼接:用rtrim($baseUrl, '/') . '/' . ltrim($mediaPath, '/')避免出现//的情况

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 09:28:03