2010-04-08 67 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");