在 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?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(); echo remote_filesize( $url ) . "\n" ; $endTime = time(); echo '耗费时间:' . ( $endTime - $startTime ) . '秒' ; ?> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?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(); echo remote_filesize( $url ) . "\n" ; $endTime = time(); echo '耗费时间:' . ( $endTime - $startTime ) . '秒' ; ?> |
1 2 | 1334721 耗费时间:2秒 |
7、最终代码实现如下。如图6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?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(); echo remote_filesize( $url ) . "\n" ; $endTime = time(); echo '耗费时间:' . ( $endTime - $startTime ) . '秒' ; ?> |
8、在调用接口时,基于 HTTP 协议检测文件的大小(即不下载文件的情况下,获取文件的大小),最终实现预期目标。如图7
1 条回复
[…] […]