2010-04-08 7 views

ответ

83

Найдено что-то об этом here:

Вот лучший способ (что я нашел), чтобы получить размер удаленного файла . Обратите внимание, что запросы HEAD не получают фактического тела запроса, они просто извлекают заголовки. Таким образом, запрос HEAD к ресурсу , который составляет 100 МБ, будет занимать тот же промежуток времени, что и запрос HEAD для ресурса , который составляет 1 КБ.

<?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

+0

хорошо, если запрос возвращает файл, размер запроса * * размер файла – Gareth

+3

Но имейте в виду, что там _can_ будут ответы без Content-length. – VolkerK

14

Несомненно. Сделайте запрос только для заголовков и найдите заголовок Content-Length.

2

Поскольку этот вопрос уже помечено "PHP" и "свернуться", я предполагаю, что вы знаете, как использовать Curl в 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

+0

-1 для меня тоже ... – mozgras

+4

отлично работает для меня – Eva

2

Попробуйте ниже функции, чтобы получить Remote размер файла

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

Это единственный, который работал для меня на сервере Apache Ubuntu Linux. Мне нужно было инициализировать $ size и $ status в начале функции, иначе работал как есть. –

1

Большинство ответов здесь используется либо CURL или основывают на чтение заголовков. Но в некоторых определенных ситуациях вы можете использовать более легкое решение. Рассмотрим примечание к filesize()'s docs on PHP.net. Вы найдете там подсказку: «Начиная с PHP 5.0.0, эта функция также может использоваться с некоторыми оболочками URL-адресов. Обратитесь к Supported Protocols and Wrappers, чтобы определить, какие оболочки поддерживают семейство функций stat()».

Итак, если ваш сервер и парсер PHP правильно настроены, вы можете просто использовать функцию filesize(), загрузить ее с полным URL-адресом, указывая на удаленный файл, какой размер вы хотите получить, и пусть PHP сделает все волшебство.

4

Самый простой и наиболее эффективный РЕАЛИЗАЦИЯ:

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

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 одновременно. –

22

Как уже упоминалось несколько раз, путь, чтобы получить информацию от Content-Length поля заголовка ответа в.

Однако, следует отметить, что

  • сервера вы зондирование не обязательно реализует метод HEAD (!)
  • нет абсолютно никакой необходимости вручную обработать запрос HEAD (который, опять же, может даже не поддерживаться) с помощью fopen или так или даже вызвать локон библиотеку, когда PHP имеет get_headers() (помните: K.I.S.S.)

Использование get_headers() следует за K.I.S.S. principleи работает, даже если сервер, который вы изучаете, не поддерживает запрос HEAD.

Итак, вот моя версия (трюк: возвращает читаемый человек форматированного ;-)):

Gist: 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'. –

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

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"); 
Смежные вопросы