2010-04-08 35 views

Respuesta

83

encontrado algo sobre este here:

Ésta es la mejor manera (que he encontrado) para obtener el tamaño de un archivo remoto . Tenga en cuenta que las solicitudes HEAD no obtienen el cuerpo real de la solicitud, , solo recuperan los encabezados. Entonces hacer una solicitud HEAD a un recurso que es 100MB tomará la misma cantidad de tiempo que una solicitud HEAD a un recurso que es 1KB.

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

Uso:

$file_size = curl_get_file_size("http://stackoverflow.com/questions/2602612/php-remote-file-size-without-downloading-file"); 
+0

i estaba leyendo que antes, no estaba seguro de si el contenido de longitud significaba que el tamaño de la longitud o archivo – dassouki

+0

bien si la solicitud devuelve un archivo, el tamaño de la solicitud * es * el tamaño del archivo – Gareth

+3

Pero tenga en cuenta que _can_ pueden haber respuestas sin Longitud del contenido. – VolkerK

14

Sure. Realice una solicitud de solo encabezados y busque el encabezado Content-Length.

2

Dado que esta cuestión ya está etiquetada "php" y "rizar", estoy asumiendo que usted sabe cómo utilizar Curl en PHP.

Si configura curl_setopt(CURLOPT_NOBODY, TRUE), entonces hará una solicitud HEAD y probablemente verifique el encabezado "Content-Length" de la respuesta, que será solo encabezados.

55

probar este código

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

siempre devuelve -1 para las URL que probé. – Abenil

+0

-1 para mí también ... – mozgras

+4

funciona bien para mí – Eva

2

Pruebe la función de abajo para obtener el tamaño del archivo remoto

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

Este es el único que funcionó para mí en Ubuntu Linux Apache Server. Tuve que iniciar $ size y $ status al comienzo de la función, de lo contrario funcionaba como está. –

1

mayoría de las respuestas aquí utiliza ya sea CURL o están basando en las cabeceras de lectura. Pero en algunas situaciones determinadas puede usar una solución mucho más fácil. Considere la nota en filesize()'s docs on PHP.net. Encontrarás un consejo que dice: "A partir de PHP 5.0.0, esta función también se puede utilizar con algunos contenedores de URL. Consulta Supported Protocols and Wrappers para determinar qué envoltorios admiten la familia de funcionalidades de stat()".

Por lo tanto, si su servidor y analizador PHP están configurados correctamente, puede simplemente usar la función filesize(), alimentarla con URL completa, señalar un archivo remoto, qué tamaño desea obtener y dejar que PHP haga toda la magia.

4

El IMPLEMENTACIÓN más simple y más eficiente:

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

Funcionó como magia. Gracias. – rottenoats

3

No estoy seguro, pero no podía utilizar la función get_headers para esto?

$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

Con este ejemplo, es posible que el servidor de destino en $ url explote get_headers para mantener la conexión abierta hasta que el proceso de PHP agote el tiempo (devolviendo los encabezados muy lentamente, aunque no lo suficientemente lento como para dejar la conexión obsoleta). Como los procesos totales de PHP pueden estar limitados por FPM, esto puede permitir un tipo de ataque de loris lento cuando múltiples "usuarios" acceden a su secuencia de comandos get_headers simultáneamente. –

22

Como se ha mencionado un par de veces, el camino a seguir es para recuperar la información de Content-Length campo de la cabecera de respuesta.

Sin embargo, debe tener en cuenta que

  • el servidor que está sondeando no necesariamente pone en práctica el método HEAD (!)
  • no hay absolutamente ninguna necesidad de elaborar manualmente una petición HEAD (que, de nuevo, no podría incluso ser compatible) usando fopen o similar o incluso para invocar la librería curl, cuando PHP tiene get_headers() (recuerda: K.I.S.S.)

El uso de get_headers() sigue el K.I.S.S. principley funciona incluso si el servidor que está sondeando no admite la solicitud HEAD.

tanto, aquí está mi versión (truco: devuelve el tamaño legible con formato ;-)):

Síntesis: https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d (rizo y get_headers versión)
get_headers() - Versión:

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

Uso:

$url = 'http://download.tuxfamily.org/notepadplus/6.6.9/npp.6.6.9.Installer.exe'; 
echo getRemoteFilesize($url); // echoes "7.51 MiB" 

Nota adicional: El encabezado Content-Length es opcional. Por lo tanto, como una solución general no es a prueba de balas!


+2

Esta debería ser la respuesta aceptada. Es cierto que 'Content-Length' es opcional, pero es la única forma de obtener el tamaño del archivo sin descargarlo, y' get_headers' es la mejor forma de obtener 'content-length'. –

1

Aquí hay otro enfoque que trabajará con los servidores que no soportan HEAD solicitudes.

Utiliza cURL para realizar una solicitud del contenido con un encabezado de rango HTTP que solicita el primer byte del archivo.

Si el servidor admite solicitudes de rango (la mayoría de los servidores de medios lo harán), recibirá la respuesta con el tamaño del recurso.

Si el servidor no responde con un rango de bytes, buscará un encabezado de longitud de contenido para determinar la longitud.

Si el tamaño se encuentra en un rango o un encabezado de longitud de contenido, la transferencia se cancela. Si no se encuentra el tamaño y la función comienza a leer el cuerpo de la respuesta, la transferencia se cancela.

Esto podría ser un enfoque suplementario si una solicitud HEAD da como resultado una respuesta no compatible con el método 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; 
} 

Uso:

$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

función de PHP get_headers() obras para que compruebe la de longitud de contenido como

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

Para más detalle: PHP Function get_headers()

+0

Para mí (con nginx) el encabezado era Content-Length – Pangamma

0

una línea mejor solución:

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

php es demasiado delicius

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

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