在 PHP 中基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取远程文件的大小),使用文件系统函数 fopen — 打开文件或者 URL
1、在实现渠道发布的过程中,存在待上传至渠道的文件过大的情况,进而导致上传失败。比如说抖音,暂时限制为 128 MB。如图1
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
5、执行 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://www.shuijingwanwq.com/wp-content/uploads/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
<?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://www.shuijingwanwq.com/wp-content/uploads/2021/07/兔子、牛、还有一只什么哟?认不出来了.mp4'; echo remote_filesize($url) . "\n"; $endTime = time(); echo '耗费时间:' . ($endTime - $startTime) . '秒'; ?>
1334721 耗费时间:2秒
7、最终代码实现如下。如图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://www.shuijingwanwq.com/wp-content/uploads/2021/07/ChinaJoy 2015 上海 梦幻西游.mp4'; echo remote_filesize($url) . "\n"; $endTime = time(); echo '耗费时间:' . ($endTime - $startTime) . '秒'; ?>
8、在调用接口时,基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取文件的大小),最终实现预期目标。如图7
1 条回复
[…] […]