2010-04-08 68 views

回答

83

找到东西这个here

这里得到一个远程 文件大小的最佳方式(我发现)。请注意,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"); 
+0

我读的是较早的,不知道,如果内容长度指长度或文件大小 – dassouki 2010-04-08 18:59:45

+0

好,如果该请求返回一个文件,请求大小*是*文件大小 – Gareth 2010-04-08 19:01:07

+3

但请记住,在没有内容长度的情况下,_can_可能是响应。 – VolkerK 2010-04-08 19:26:25

14

当然。制作仅限标题的请求并查找Content-Length标题。

2

因为这个问题已经被标记 “PHP” 和 “卷曲”,我假设你知道如何在PHP中使用卷曲。

如果你设置了curl_setopt(CURLOPT_NOBODY, TRUE)那么你将发出一个HEAD请求,并且可能会检查响应的“Content-Length”标题,这将只是标题。

55

试试这个代码

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; 
} 
+3

它总是返回-1为我尝试过的URL。 – Abenil 2012-07-18 10:38:04

+0

-1对我来说也是如此... – mozgras 2012-09-09 08:58:36

+4

对我来说工作正常 – Eva 2012-11-01 16:41:53

2

试试下面的函数获取远程文件大小

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; 
} 
+0

这是唯一一个在Ubuntu Linux apache服务器上为我工作的人。我在函数开始时不得不初始化$ size和$ status,否则按原样工作。 – 2013-11-12 12:50:25

1

大多数答案在这里使用任何卷曲或正在基础上读头。但在某些情况下,您可以使用更简单的解决方案。考虑关于filesize()'s docs on PHP.net的说明。你会发现有一个提示:“从PHP 5.0.0开始,这个函数也可以用于一些URL包装器,参考Supported Protocols and Wrappers来确定哪些包装器支持stat()系列的功能”。因此,如果您的服务器和PHP解析器配置正确,那么您可以简单地使用filesize()函数,用完整的URL填充它,指向一个远程文件,您希望获得的大小,然后让PHP完成所有的魔术。

4

最简单和最有效的FPGA实现:

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)); 
} 
+0

像魔术一样工作。谢谢。 – rottenoats 2016-02-26 14:23:57

3

我不知道,但不能使用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; 
+0

在这个例子中,$ url的目标服务器可能利用get_headers来保持连接处于打开状态,直到PHP进程超时(通过非常缓慢地返回头部,而不足以让连接失效)。由于整个PHP进程可能受FPM限制,因此当多个“用户”同时访问您的get_headers脚本时,这可能允许一种缓慢的洛里斯攻击。 – 2016-10-12 16:14:00

22

如前所述几次,要走的路是检索与响应报头的Content-Length场信息

但是,你要注意,

  • 你探测服务器不一定实现了HEAD方法(!)
  • 但绝对不需要手工手艺使用fopen或相似,甚至调用curl库HEAD请求(再次,甚至可能不支持),PHP有get_headers()时(记住:K.I.S.S.

使用get_headers()跟在K.I.S.S. principle之后即使您正在探测的服务器不支持HEAD请求也能正常工作。

所以,这里是我的版本(噱头:返回人类可读格式的大小;-)):

要点:https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d(卷曲和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 <[email protected]> 
* @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标头是可选的。因此,作为一般解决方案它不是防弹


+2

这应该是被接受的答案。诚然,Content-Length是可选的,但它是获得文件大小而不下载它的唯一方法 - 而'get_headers'是获得'content-length'的最好方法。 – 2017-08-31 22:17:59

1

这是另一种方法,它可以与不支持HEAD请求的服务器一起使用。

它使用cURL使用HTTP范围标头请求文件的第一个字节。

如果服务器支持范围请求(大多数媒体服务器将会),那么它将接收到具有资源大小的响应。

如果服务器没有响应一个字节范围,它会查找一个内容长度标头来确定长度。

如果在范围或内容长度标题中找到大小,传输将中止。如果未找到大小并且函数开始读取响应主体,则传输将中止。

如果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."; 
} 
2

PHP函数get_headers()作品为我检查内容长度作为

$headers = get_headers('http://example.com/image.jpg', TRUE); 
$filesize = $headers['content-length']; 

更多细节:PHP Function get_headers()

+0

对我来说(使用nginx)标题是Content-Length – Pangamma 2017-09-19 18:11:58

0

一行最佳解决方案:

echo array_change_key_case(get_headers("http://.../file.txt",1))['content-length']; 

PHP是太delicius

function urlsize($url):int{ 
    return array_change_key_case(get_headers($url,1))['content-length']; 
} 

echo urlsize("http://.../file.txt");