PHP:远程文件大小,无需下载文件
有没有办法得到一个远程文件的大小http://my_url/my_file.txt没有下载文件?
在这里find一些关于这个:
这是我find的最好的方法来获取远程文件的大小。 请注意,HEAD请求不会获得请求的实际正文,它们只是检索标题。 因此,对100MB的资源进行HEAD请求将花费与1KB的资源的HEAD请求相同的时间量。
<?php /** * Returns the size of a file without downloading it, or -1 if the file * size could not be determined. * * @param $url - The location of the remote file to download. Cannot * be null or empty. * * @return The size of the file referenced by $url, or -1 if the size * could not be determined. */ function curl_get_file_size( $url ) { // Assume failure. $result = -1; $curl = curl_init( $url ); // Issue a HEAD request and follow any redirects. curl_setopt( $curl, CURLOPT_NOBODY, true ); curl_setopt( $curl, CURLOPT_HEADER, true ); curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true ); curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true ); curl_setopt( $curl, CURLOPT_USERAGENT, get_user_agent_string() ); $data = curl_exec( $curl ); curl_close( $curl ); if( $data ) { $content_length = "unknown"; $status = "unknown"; if( preg_match( "/^HTTP\/1\.[01] (\d\d\d)/", $data, $matches ) ) { $status = (int)$matches[1]; } if( preg_match( "/Content-Length: (\d+)/", $data, $matches ) ) { $content_length = (int)$matches[1]; } // http://en.wikipedia.org/wiki/List_of_HTTP_status_codes if( $status == 200 || ($status > 300 && $status <= 308) ) { $result = $content_length; } } return $result; } ?>
用法:
$file_size = curl_get_file_size( "http://stackoverflow.com/questions/2602612/php-remote-file-size-without-downloading-file" );
试试这个代码
function retrieve_remote_file_size($url){ $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_HEADER, TRUE); curl_setopt($ch, CURLOPT_NOBODY, TRUE); $data = curl_exec($ch); $size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); curl_close($ch); return $size; }
正如前面提到的那样,要走的路是从响应头的Content-Length
字段中检索信息。
但是,你应该注意到
- 您正在探测的服务器不一定实现HEAD方法(!)
- 当PHP有
get_headers()
(记住: KISS )的时候,绝对不需要使用fopen
或者类似的方式来手动创buildHEAD请求(甚至可能不支持这个请求),甚至不需要调用curl库。
使用get_headers()
遵循KISS原则 ,即使您正在探测的服务器不支持HEAD请求,也能正常工作。
所以,这是我的版本(噱头:返回人类可读格式的大小;-)):
要点: https ://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d(curl和get_headers版本)
get_headers() – 版本:
<?php /** * Get the file size of any remote resource (using get_headers()), * either in bytes or - default - as human-readable formatted string. * * @author Stephan Schmitz <eyecatchup@gmail.com> * @license MIT <http://eyecatchup.mit-license.org/> * @url <https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d> * * @param string $url Takes the remote object's URL. * @param boolean $formatSize Whether to return size in bytes or formatted. * @param boolean $useHead Whether to use HEAD requests. If false, uses GET. * @return string Returns human-readable formatted size * or size in bytes (default: formatted). */ function getRemoteFilesize($url, $formatSize = true, $useHead = true) { if (false !== $useHead) { stream_context_set_default(array('http' => array('method' => 'HEAD'))); } $head = array_change_key_case(get_headers($url, 1)); // content-length of download (in bytes), read from Content-Length: field $clen = isset($head['content-length']) ? $head['content-length'] : 0; // cannot retrieve file size, return "-1" if (!$clen) { return -1; } if (!$formatSize) { return $clen; // return size in bytes } $size = $clen; switch ($clen) { case $clen < 1024: $size = $clen .' B'; break; case $clen < 1048576: $size = round($clen / 1024, 2) .' KiB'; break; case $clen < 1073741824: $size = round($clen / 1048576, 2) . ' MiB'; break; case $clen < 1099511627776: $size = round($clen / 1073741824, 2) . ' GiB'; break; } return $size; // return formatted size }
用法:
$url = 'http://download.tuxfamily.org/notepadplus/6.6.9/npp.6.6.9.Installer.exe'; echo getRemoteFilesize($url); // echoes "7.51 MiB"
附加说明: Content-Length标头是可选的。 因此,作为一个通用的解决scheme, 这不是防弹的 !
当然。 创build一个仅包含头的请求并查找Content-Length
头。
由于这个问题已经被标记为“php”和“curl”,我假设你知道如何在PHP中使用Curl。
如果你设置了curl_setopt(CURLOPT_NOBODY, TRUE)
那么你将会发出一个HEAD请求,并且可能会检查响应的“Content-Length”标题,这将只是标题。
尝试下面的函数来获得远程文件大小
function remote_file_size($url){ $head = ""; $url_p = parse_url($url); $host = $url_p["host"]; if(!preg_match("/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/",$host)){ $ip=gethostbyname($host); if(!preg_match("/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/",$ip)){ return -1; } } if(isset($url_p["port"])) $port = intval($url_p["port"]); else $port = 80; if(!$port) $port=80; $path = $url_p["path"]; $fp = fsockopen($host, $port, $errno, $errstr, 20); if(!$fp) { return false; } else { fputs($fp, "HEAD " . $url . " HTTP/1.1\r\n"); fputs($fp, "HOST: " . $host . "\r\n"); fputs($fp, "User-Agent: http://www.example.com/my_application\r\n"); fputs($fp, "Connection: close\r\n\r\n"); $headers = ""; while (!feof($fp)) { $headers .= fgets ($fp, 128); } } fclose ($fp); $return = -2; $arr_headers = explode("\n", $headers); foreach($arr_headers as $header) { $s1 = "HTTP/1.1"; $s2 = "Content-Length: "; $s3 = "Location: "; if(substr(strtolower ($header), 0, strlen($s1)) == strtolower($s1)) $status = substr($header, strlen($s1)); if(substr(strtolower ($header), 0, strlen($s2)) == strtolower($s2)) $size = substr($header, strlen($s2)); if(substr(strtolower ($header), 0, strlen($s3)) == strtolower($s3)) $newurl = substr($header, strlen($s3)); } if(intval($size) > 0) { $return=intval($size); } else { $return=$status; } if (intval($status)==302 && strlen($newurl) > 0) { $return = remote_file_size($newurl); } return $return; }
最简单和最有效的实施:
function remote_filesize($url) { static $regex = '/^Content-Length: *+\K\d++$/im'; if (!$fp = @fopen($url, 'rb')) { return false; } if ( isset($http_response_header) && preg_match($regex, implode("\n", $http_response_header), $matches) ) { return (int)$matches[0]; } return strlen(stream_get_contents($fp)); }
我不确定,但是你不能使用get_headers函数吗?
$url = 'http://example.com/dir/file.txt'; $headers = get_headers($url, true); if ( isset($headers['Content-Length']) ) { $size = 'file size:' . $headers['Content-Length']; } else { $size = 'file size: unknown'; } echo $size;
这里的大多数答案都使用CURL或基于阅读标题。 但在某些情况下,您可以使用一种更简单的解决scheme。 请考虑关于PHP.net上filesize()
的文档的注释。 你会发现有一个提示:“ 从PHP 5.0.0开始,这个函数也可以用于一些URL包装器。参考支持的协议和包装器来确定哪些包装器支持stat()系列的function 。
所以,如果你的服务器和PHPparsing器configuration正确,你可以简单地使用filesize()
函数,用完整的URL提供它,指向一个你想要的大小的远程文件,然后让PHP完成所有的魔术。
这是另一种方法,将与不支持HEAD
请求的服务器一起使用。
它使用cURL通过HTTP范围头部请求文件的第一个字节。
如果服务器支持范围请求(大多数媒体服务器将会),那么它将接收到具有资源大小的响应。
如果服务器没有响应一个字节范围,它将查找一个内容长度头来确定长度。
如果在范围或内容长度标题中find大小,传输将被中止。 如果未find大小,并且函数开始读取响应主体,则传输将中止。
如果HEAD
请求导致405
方法不支持响应,这可能是一种补充方法。
/** * Try to determine the size of a remote file by making an HTTP request for * a byte range, or look for the content-length header in the response. * The function aborts the transfer as soon as the size is found, or if no * length headers are returned, it aborts the transfer. * * @return int|null null if size could not be determined, or length of content */ function getRemoteFileSize($url) { $ch = curl_init($url); $headers = array( 'Range: bytes=0-1', 'Connection: close', ); $in_headers = true; $size = null; curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2450.0 Iron/46.0.2450.0'); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($ch, CURLOPT_VERBOSE, 0); // set to 1 to debug curl_setopt($ch, CURLOPT_STDERR, fopen('php://output', 'r')); curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $line) use (&$in_headers, &$size) { $length = strlen($line); if (trim($line) == '') { $in_headers = false; } list($header, $content) = explode(':', $line, 2); $header = strtolower(trim($header)); if ($header == 'content-range') { // found a content-range header list($rng, $s) = explode('/', $content, 2); $size = (int)$s; return 0; // aborts transfer } else if ($header == 'content-length' && 206 != curl_getinfo($curl, CURLINFO_HTTP_CODE)) { // found content-length header and this is not a 206 Partial Content response (range response) $size = (int)$content; return 0; } else { // continue return $length; } }); curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) use ($in_headers) { if (!$in_headers) { // shouldn't be here unless we couldn't determine file size // abort transfer return 0; } // write function is also called when reading headers return strlen($data); }); $result = curl_exec($ch); $info = curl_getinfo($ch); return $size; }
用法:
$size = getRemoteFileSize('http://example.com/video.mp4'); if ($size === null) { echo "Could not determine file size from headers."; } else { echo "File size is {$size} bytes."; }
PHP函数get_headers()
对我来说,检查内容的长度为
$headers = get_headers('http://example.com/image.jpg', TRUE); $filesize = $headers['content-length'];
更多细节: PHP函数get_headers()