¿Hay alguna forma de obtener el tamaño de un archivo remoto http: //my_url/my_file.txt sin descargar el archivo?
84
¿Hay alguna forma de obtener el tamaño de un archivo remoto http: //my_url/my_file.txt sin descargar el archivo?
Encontré algo sobre esto aquí :
Esta es la mejor manera (que he encontrado) de 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. Por lo tanto, realizar una solicitud HEAD a un recurso de 100 MB llevará la misma cantidad de tiempo que una solicitud HEAD a un recurso de 1 KB.
<?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" );
curl_getinfo
, como sugiere @macki?get_user_agent_string()
no estaba definido. Eliminar toda la línea hizo que todo funcionara.http://www.dailymotion.com/rss/user/dialhainaut/
ver SO: stackoverflow.com/questions/36761377/…Prueba 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; }
fuente
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
.CURLOPT_FOLLOWLOCATION
fijado en verdad.Como se mencionó un par de veces, el camino a seguir es recuperar la información del
Content-Length
campo del encabezado de respuesta .Sin embargo, debe tener en cuenta que
fopen
o similar o incluso para invocar la biblioteca curl, cuando PHP lo ha hechoget_headers()
(recuerde: KISS )El uso de
get_headers()
sigue el principio KISS y funciona incluso si el servidor que está probando no admite la solicitud HEAD.Entonces, aquí está mi versión (truco: devuelve un tamaño formateado legible por humanos ;-)):
Gist: https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d (versión curl y get_headers)
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 <eyecatchup@gmail.com> * @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 solución general, ¡ no es a prueba de balas !
fuente
Content-Length
es opcional, pero es la única manera de obtener el tamaño del archivo sin descargarlo, yget_headers
es la mejor manera de obtenerlocontent-length
.stream_context_create
para crear un contexto separado para usar para la llamada aget_headers
(7.1+).Por supuesto. Realice una solicitud de solo encabezados y busque el
Content-Length
encabezado.fuente
La función PHP
get_headers()
me funciona para verificar la longitud del contenido como$headers = get_headers('http://example.com/image.jpg', 1); $filesize = $headers['Content-Length'];
Para más detalles: Función PHP get_headers ()
fuente
No estoy seguro, pero ¿no podrías usar 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;
fuente
la mejor solución de una línea:
echo array_change_key_case(get_headers("http://.../file.txt",1))['content-length'];
php es demasiado delicioso
function urlsize($url):int{ return array_change_key_case(get_headers($url,1))['content-length']; } echo urlsize("http://.../file.txt");
fuente
La implementación más simple y eficiente:
function remote_filesize($url, $fallback_to_download = false) { 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]; } if (!$fallback_to_download) { return false; } return strlen(stream_get_contents($fp)); }
fuente
Content-Length
encabezado. Y el$fp
cierre explícito NO ES NECESARIO; se libera automáticamente al expirar. php.net/manual/en/language.types.resource.phpnc -l localhost 8080
*close
funciones no son necesarias en PHP moderno. Son por dos razones históricas: restricción de implementación e imitación del lenguaje C.Dado que esta pregunta ya está etiquetada como "php" y "curl", supongo que sabe cómo usar Curl en PHP.
Si lo configura
curl_setopt(CURLOPT_NOBODY, TRUE)
, hará una solicitud HEAD y probablemente pueda verificar el encabezado "Content-Length" de la respuesta, que serán solo encabezados.fuente
Pruebe la siguiente función 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; }
fuente
Aquí hay otro enfoque que funcionará con servidores que no admiten
HEAD
solicitudes.Utiliza cURL para realizar una solicitud de 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 encabezado de rango o 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.
Este podría ser un enfoque complementario si una
HEAD
solicitud da como resultado un405
método no admitido como respuesta./** * 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."; }
fuente
Content-Length
no está disponible.La mayoría de las respuestas aquí usan CURL o se basan en la lectura de encabezados. Pero en algunas situaciones determinadas, puede utilizar una solución mucho más sencilla. Considere la nota sobre
filesize()
los documentos de PHP.net . Allí encontrará un consejo que dice: " A partir de PHP 5.0.0, esta función también se puede utilizar con algunos envoltorios de URL. Consulte Protocolos y envoltorios admitidos para determinar qué envoltorios admiten la familia de funciones stat () ".Por lo tanto, si su servidor y analizador de PHP están configurados correctamente, simplemente puede usar la
filesize()
función, alimentarla con la URL completa, señalar un archivo remoto, el tamaño que desea obtener, y dejar que PHP haga toda la magia.fuente
Prueba esto: lo uso y obtuve un buen resultado.
function getRemoteFilesize($url) { $file_headers = @get_headers($url, 1); if($size =getSize($file_headers)){ return $size; } elseif($file_headers[0] == "HTTP/1.1 302 Found"){ if (isset($file_headers["Location"])) { $url = $file_headers["Location"][0]; if (strpos($url, "/_as/") !== false) { $url = substr($url, 0, strpos($url, "/_as/")); } $file_headers = @get_headers($url, 1); return getSize($file_headers); } } return false; } function getSize($file_headers){ if (!$file_headers || $file_headers[0] == "HTTP/1.1 404 Not Found" || $file_headers[0] == "HTTP/1.0 404 Not Found") { return false; } elseif ($file_headers[0] == "HTTP/1.0 200 OK" || $file_headers[0] == "HTTP/1.1 200 OK") { $clen=(isset($file_headers['Content-Length']))?$file_headers['Content-Length']:false; $size = $clen; if($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 false; }
Ahora, prueba así:
echo getRemoteFilesize('http://mandasoy.com/wp-content/themes/spacious/images/plain.png').PHP_EOL; echo getRemoteFilesize('http://bookfi.net/dl/201893/e96818').PHP_EOL; echo getRemoteFilesize('/programming/14679268/downloading-files-as-attachment-filesize-incorrect').PHP_EOL;
Resultados:
24,82 KiB
912 KiB
101,85 KiB
fuente
Para cubrir la solicitud HTTP / 2, la función proporcionada aquí https://stackoverflow.com/a/2602624/2380767 debe cambiarse un poco:
<?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]; } elseif( preg_match( "/^HTTP\/2 (\d\d\d)/", $data, $matches ) ) { $status = (int)$matches[1]; } if( preg_match( "/Content-Length: (\d+)/", $data, $matches ) ) { $content_length = (int)$matches[1]; } elseif( 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; } ?>
fuente