2009-09-25 9 views
1

Можно ли это сделать? В настоящее время я кодирую PHP с использованием библиотеки cURL, но это скорее относится к HTTP в целом.Определить размер файла перед загрузкой данных через HTTP

Самый очевидный способ звучал как запрос запроса HEAD на URL-адрес данных и чтение заголовка Content-Length, но проблема в том, что некоторые серверы, включая apache 2.0, не отправляют Content-Length в отношении запросов HEAD и, поскольку это не является обязательным , нет никакой гарантии, что все серверы там будут отвечать такой информацией даже по запросу GET.

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

Случаи, связанные с вредоносными веб-серверами, отправляющими неверные данные Content-Length и те незначительные странные события, не касаются меня, если они работают для всех остальных случаев.

Худшая идея, на мой взгляд, заключается в том, чтобы фактически загрузить контент с помощью запроса GET и просто удалить соединение, если оно превышает ограничение по размеру, указанное во время передачи, но это звучит как очень уродливое решение для такого общего протокол как HTTP.

Есть ли у кого-нибудь лучшие идеи?

ответ

3

Нет, серверы не должны сообщать вам размер ресурса, который они будут служить вам, потому что у них могут не быть самих знаний. Нет, нет универсального способа, но да, вы можете попробовать посмотреть заголовок Content-length всякий раз, когда он предоставляется.

+0

Это ненадежный способ. Кажется, что разрезание соединения, когда оно превышает заданный размер, является единственным способом. – 2009-09-26 11:48:45

+0

Да, это не так, поэтому * всякий раз, когда предоставляется * часть. На самом деле, да, даже когда он предоставляется, он может быть полезен только для оценки, так как ничто не мешает серверу рекламировать 10-байтовый контент и кормить клиента всем содержимым '/ dev/urandom'. –

0

Я наткнулся на ваш вопрос, ища тот же ответ. Поскольку ответа пока нет, я сам взломал реализацию. Конечно, все упомянутые предостережения все еще применяются, и да, он использует ваш «уродливый» вариант, но это единственный способ получить данные, если информация существует.

/** 
* Returns the size reported by the server, for the given URL, in bytes. 
* 
* Note this information may not be accurate, or may even be plain wrong. 
* 
* Also note, the return value is explicitly NOT converted to an integer, as 
* the remote file might be bigger than 2^31, which may mess up the number if 
* you are on a 32bit machine. 
* 
* @throws  InvalidArgumentException on unknown URL scheme 
* @throws  Exception when unable to connect 
* @param   string $url 
* @returns  int 
*/ 
function getURLDownloadSize($url) { 
    $parts = parse_url($url); 

    if(isset($parts['port'])) { 
     $port = $parts['port']; 
    } 
    else { 
     $port = 80; 
    } 
    if($parts['scheme'] != 'http') { 
     throw new \InvalidArgumentException('Scheme not supported'); 
    } 

    $sock = fsockopen($parts['host'], $port, $errno, $errstr, 3); 
    if(!$sock) { 
     throw new \Exception(
      sprintf(
       'Unable to connect to host: %s', 
       $errstr 
      ) 
     ); 
    } 
    stream_set_timeout($sock, 5); 

    fwrite($sock, sprintf("GET %s HTTP/1.1\r\n", $parts['path'])); 
    fwrite($sock, sprintf("Host: %s\r\n",  $parts['host'])); 
    fwrite($sock,   "Connection: close\r\n"    ); 
    fwrite($sock,   "\r\n"        ); 

    $data = fread($sock, 1024*20); 
    fclose($sock); 

    $matchresult = array(); 
    if (preg_match('/Content-Length:\s+(\d+)/', $data, $matchresult)) { 
     return $matchresult[1]; 
    } 
    return 0; 
} 
Смежные вопросы