没有不值得去解决的问题,也没有不值得去学习的技术!

在 PHP 中基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取远程文件的大小),使用文件系统函数 fopen — 打开文件或者 URL

最终代码实现如下

1、在实现渠道发布的过程中,存在待上传至渠道的文件过大的情况,进而导致上传失败。比如说抖音,暂时限制为 128 MB。如图1

在实现渠道发布的过程中,存在待上传至渠道的文件过大的情况,进而导致上传失败。比如说抖音,暂时限制为 128 MB
图1

2、但是现阶段的实现逻辑是,先基于文件的 HTTP (absolute_url:来源的资源文件的绝对URL) 下载文件后,得到文件的 relative_path:渠道发布的资源文件的相对路径,然后才能够获取到文件的大小。而这个实现阶段是异步的。如图2

但是现阶段的实现逻辑是,先基于文件的 HTTP (absolute_url:来源的资源文件的绝对URL) 下载文件后,得到文件的 relative_path:渠道发布的资源文件的相对路径,然后才能够获取到文件的大小。而这个实现阶段是异步的。
图2

3、现在希望优化用户的体验,能够在调用接口时,基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取文件的大小)。

4、参考 文件系统函数 filesize — 取得文件大小:https://www.php.net/manual/zh/function.filesize.php 。The simplest and most efficient implemention for getting remote filesize。获取远程文件大小的最简单和最有效的实现。如图3

参考 文件系统函数 filesize — 取得文件大小:https://www.php.net/manual/zh/function.filesize.php 。The simplest and most efficient implemention for getting remote filesize。获取远程文件大小的最简单和最有效的实现
图3

5、执行 fopen() 时可以使用变量 $http_response_header。 其中包含响应标头的数组。打印变量 $http_response_header。如图4

执行 fopen() 时可以使用变量 $http_response_header。 其中包含响应标头的数组。打印变量 $http_response_header
图4
<?php
function remote_filesize($url) {
    static $regex = '/^Content-Length: *+\K\d++$/im';
    // 将 $url 指定的名字资源绑定到一个流上,只读方式打开,将文件指针指向文件头
    if (!$fp = @fopen($url, 'rb')) {
        return false;
    }
    // 执行 fopen() 时可以使用变量 $http_response_header。 其中包含响应标头的数组。
    if (
        isset($http_response_header) &&
        preg_match($regex, implode("\n", $http_response_header), $matches)
    ) {
        print_r($http_response_header);
        return (int)$matches[0];
    }
    echo 1;
    return strlen(stream_get_contents($fp));
}
 
$startTime = time();
$url = 'https://media.shuijingwanwq.com/2021/07/秦时明月第一集荧惑守心.mp4';
echo remote_filesize($url) . "\n";
$endTime = time();
echo '耗费时间:' . ($endTime - $startTime) . '秒';
?>


Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Server: nginx
    [2] => Date: Mon, 09 Aug 2021 05:46:41 GMT
    [3] => Content-Type: video/mp4
    [4] => Content-Length: 143162935
    [5] => Last-Modified: Tue, 30 Oct 2018 09:52:18 GMT
    [6] => Connection: close
    [7] => ETag: "5bd829d2-8887e37"
    [8] => Expires: Wed, 08 Sep 2021 05:46:41 GMT
    [9] => Cache-Control: max-age=2592000
    [10] => Strict-Transport-Security: max-age=15768000
    [11] => Accept-Ranges: bytes
)
143162935
耗费时间:0秒


6、如果变量 $http_response_header 不存在,则 使用函数 stream_get_contents — 读取资源流到一个字符串。文件大小:1.27 MB,测试一下耗费时间:2秒,发现无法接受。决定当变量 $http_response_header 不存在时,返回 false。如图5

如果变量 $http_response_header 不存在,则 使用函数 stream_get_contents — 读取资源流到一个字符串。文件大小:1.27 MB,测试一下耗费时间:2秒,发现无法接受。决定当变量 $http_response_header 不存在时,返回 false
图5
<?php
function remote_filesize($url) {
    static $regex = '/^Content-Length: *+\K\d++$/im';
    // 将 $url 指定的名字资源绑定到一个流上,只读方式打开,将文件指针指向文件头
    if (!$fp = @fopen($url, 'rb')) {
        return false;
    }
    // 执行 fopen() 时可以使用变量 $http_response_header。 其中包含响应标头的数组。
    /*
    if (
        isset($http_response_header) &&
        preg_match($regex, implode("\n", $http_response_header), $matches)
    ) {
        print_r($http_response_header);
        return (int)$matches[0];
    }
    */
    echo 1;
    return strlen(stream_get_contents($fp));
}
 
$startTime = time();
$url = 'https://media.shuijingwanwq.com/2021/07/兔子、牛、还有一只什么哟?认不出来了.mp4';
echo remote_filesize($url) . "\n";
$endTime = time();
echo '耗费时间:' . ($endTime - $startTime) . '秒';
?>


1334721
耗费时间:2秒


7、最终代码实现如下。如图6

最终代码实现如下
图6
<?php
function remote_filesize($url) {
    static $regex = '/^Content-Length: *+\K\d++$/im';
    // 将 $url 指定的名字资源绑定到一个流上,只读方式打开,将文件指针指向文件头
    if (!$fp = @fopen($url, 'rb')) {
        return 0;
    }
    // 执行 fopen() 时可以使用变量 $http_response_header。其中包含响应标头的数组。
    if (
        isset($http_response_header) &&
        preg_match($regex, implode("\n", $http_response_header), $matches)
    ) {
        print_r($http_response_header);
        return (int)$matches[0];
    }
    return 0;
}
 
$startTime = time();
$url = 'https://media.shuijingwanwq.com/2021/07/ChinaJoy 2015 上海 梦幻西游.mp4';
echo remote_filesize($url) . "\n";
$endTime = time();
echo '耗费时间:' . ($endTime - $startTime) . '秒';
?>
 

8、在调用接口时,基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取文件的大小),最终实现预期目标。如图7

在调用接口时,基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取文件的大小),最终实现预期目标
图7

需要长期技术维护或远程问题排查?

我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。

如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:

  • ✅ PHP / Laravel / Yii2 老项目无人维护
  • ✅ Go / Gin 后端接口需要排查或优化
  • ✅ WordPress 网站访问慢、报错或插件冲突
  • ✅ Nginx / MySQL / Redis / Linux 服务器异常
  • ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
  • ✅ 需要长期远程技术支持或兼职维护

更多介绍请查看:关于我 & 合作

微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

评论

一条对“在 PHP 中基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取远程文件的大小),使用文件系统函数 fopen — 打开文件或者 URL”的回复

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理