2009-09-25 2 views
1

이 작업이 가능합니까? 나는 현재 cURL 라이브러리를 사용하여 PHP로 코딩하고 있지만 이것은 전체적으로 HTTP에 적용됩니다.HTTP를 통해 데이터를 다운로드하기 전에 파일 크기를 결정하십시오.

HEAD 요청을 데이터 URL에 던지고 Content-Length 헤더를 읽는 것과 같이 가장 분명한 방법은 아파치 2.0을 포함한 일부 서버가 HEAD 요청에 대해 Content-Length를 보내지 않으며 그 이후의 필수 사항이 아니기 때문입니다. 거기서 모든 서버가 GET 요청에서도 그러한 정보로 회신한다는 보장은 없습니다.

사용자 입력에 의해 지정된 서버 다운로드 웹 페이지를 만들고 서버에 저장하지만, 모든 요청을 다운로드하도록 허용하지 않습니다. 모든 요청을 다운로드하기 만하면 너무 많은 파일을 다운로드 한 후 삭제할 수 없습니다. 악의적 인 요청으로 인한 대역폭을 막습니다. 그래서 실제로 데이터가 전송되고 안정적으로 전달되기 전에 콘텐츠의 크기를 알고 싶습니다.

악의적 인 웹 서버가 잘못된 Content-Length를 보내는 경우와 그 이상한 경우는 저의 일반적인 경우의 모든 경우에 적용됩니다.

지금까지 내 생각에 최악의 아이디어는 실제로 GET 요청으로 콘텐츠를 다운로드하고 전송 중에 지정된 크기 제한을 초과하는 경우 연결을 끊는 것입니다. 그러나 이것은 일반적인 경우에 매우 추악한 솔루션처럼 들릴 수 있습니다 HTTP로 프로토콜.

더 좋은 아이디어가 있습니까?

답변

3

아니요, 서버는 지식을 보유하고 있지 않기 때문에 서비스를 제공 할 자원의 크기를 알려줄 필요가 없습니다. 따라서 일반적인 방법은 없지만 제공 될 때마다 Content-length 헤더를 찾아 볼 수 있습니다.

+0

신뢰할 수있는 방법은 아닙니다. 주어진 크기를 초과하면 연결을 끊는 것만이 유일한 방법입니다. –

+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; 
} 
관련 문제