Czy istnieje sposób uzyskania rozmiaru zdalnego pliku http: //my_url/my_file.txt bez pobierania pliku?
84
Czy istnieje sposób uzyskania rozmiaru zdalnego pliku http: //my_url/my_file.txt bez pobierania pliku?
Znalazłem coś na ten temat tutaj :
Oto najlepszy sposób (jaki znalazłem), aby uzyskać rozmiar pliku zdalnego. Zwróć uwagę, że żądania HEAD nie otrzymują rzeczywistej treści żądania, po prostu pobierają nagłówki. Zatem wysłanie żądania HEAD do zasobu o wielkości 100 MB zajmie tyle samo czasu, co żądanie HEAD do zasobu o wielkości 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;
}
?>
Stosowanie:
$file_size = curl_get_file_size( "http://stackoverflow.com/questions/2602612/php-remote-file-size-without-downloading-file" );
curl_getinfo
, jak sugeruje @macki?get_user_agent_string()
nie zostało zdefiniowane. Usunięcie całej linii sprawiło, że całość działała.http://www.dailymotion.com/rss/user/dialhainaut/
patrz SO: stackoverflow.com/questions/36761377/…Wypróbuj ten kod
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; }
źródło
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
.CURLOPT_FOLLOWLOCATION
na prawdę.Jak wspomniano kilka razy, do zrobienia jest, aby pobrać informacje z nagłówka odpowiedzi na
Content-Length
polu .Jednak powinieneś to zauważyć
fopen
lub podobnych, a nawet wywoływać bibliotekę curl, gdy PHP maget_headers()
(pamiętaj: KISS )Użycie jest
get_headers()
zgodne z zasadą KISS i działa nawet jeśli sondowany serwer nie obsługuje żądania HEAD.Oto moja wersja (sztuczka: zwraca sformatowany rozmiar czytelny dla człowieka ;-)):
Streszczenie: https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d (wersja curl i get_headers)
get_headers () - Wersja:
<?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 }
Stosowanie:
$url = 'http://download.tuxfamily.org/notepadplus/6.6.9/npp.6.6.9.Installer.exe'; echo getRemoteFilesize($url); // echoes "7.51 MiB"
Dodatkowa uwaga: nagłówek Content-Length jest opcjonalny. Dlatego jako rozwiązanie ogólne nie jest to kuloodporne !
źródło
Content-Length
jest opcjonalne, ale jest to jedyny sposób na uzyskanie rozmiaru pliku bez jego pobierania - iget_headers
jest to najlepszy sposób na uzyskaniecontent-length
.stream_context_create
do tworzenia oddzielnego kontekstu do użycia dla wywołaniaget_headers
(7.1+).Pewnie. Stwórz żądanie tylko nagłówków i poszukaj
Content-Length
nagłówka.źródło
Funkcja php
get_headers()
działa dla mnie, aby sprawdzić długość zawartości jako$headers = get_headers('http://example.com/image.jpg', 1); $filesize = $headers['Content-Length'];
Więcej szczegółów: Funkcja PHP get_headers ()
źródło
Nie jestem pewien, ale czy nie mógłbyś użyć do tego funkcji 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;
źródło
najlepsze rozwiązanie w jednej linii:
echo array_change_key_case(get_headers("http://.../file.txt",1))['content-length'];
php jest zbyt delikatny
function urlsize($url):int{ return array_change_key_case(get_headers($url,1))['content-length']; } echo urlsize("http://.../file.txt");
źródło
Najprostsza i najbardziej wydajna realizacja:
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)); }
źródło
Content-Length
nagłówek. A wyraźne$fp
zamknięcie NIE JEST KONIECZNE; jest automatycznie zwalniany po wygaśnięciu. php.net/manual/en/language.types.resource.phpnc -l localhost 8080
*close
funkcji nie jest potrzebna we współczesnym PHP. Wynikają one z dwóch historycznych powodów: ograniczenia implementacji i naśladowania języka C.Ponieważ to pytanie jest już oznaczone jako „php” i „curl”, zakładam, że wiesz, jak używać Curl w PHP.
Jeśli ustawisz,
curl_setopt(CURLOPT_NOBODY, TRUE)
wykonasz żądanie HEAD i prawdopodobnie będziesz mógł sprawdzić nagłówek „Content-Length” odpowiedzi, który będzie tylko nagłówkami.źródło
Wypróbuj poniższą funkcję, aby uzyskać rozmiar pliku zdalnego
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; }
źródło
Oto inne podejście, które będzie działać z serwerami, które nie obsługują
HEAD
żądań.Używa cURL do żądania treści z nagłówkiem zakresu HTTP z pytaniem o pierwszy bajt pliku.
Jeśli serwer obsługuje żądania dotyczące zakresu (większość serwerów multimediów), otrzyma odpowiedź z informacją o rozmiarze zasobu.
Jeśli serwer nie odpowie podając zakres bajtów, będzie szukał nagłówka content-length, aby określić długość.
Jeśli rozmiar zostanie znaleziony w nagłówku zakresu lub długości zawartości, przesyłanie jest przerywane. Jeśli rozmiar nie zostanie znaleziony, a funkcja zacznie odczytywać treść odpowiedzi, przesyłanie zostanie przerwane.
Może to być podejście uzupełniające, jeśli
HEAD
żądanie skutkuje405
odpowiedzią na nieobsługiwaną metodę./** * 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; }
Stosowanie:
$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."; }
źródło
Content-Length
nie jest dostępny.Większość odpowiedzi używa CURL lub opiera się na czytaniu nagłówków. Ale w niektórych sytuacjach możesz użyć o wiele prostszego rozwiązania. Zwróć uwagę na
filesize()
dokumentację na PHP.net . Znajdziesz tam wskazówkę mówiącą: " Od PHP 5.0.0, ta funkcja może być również używana z niektórymi opakowaniami URL. Zobacz Obsługiwane protokoły i opakowania, aby określić, które opakowania obsługują rodzinę funkcji stat () ".Tak więc, jeśli twój serwer i parser PHP są odpowiednio skonfigurowane, możesz po prostu użyć
filesize()
funkcji, podać mu pełny adres URL, wskazując zdalny plik, którego rozmiar chcesz uzyskać, i pozwolić PHP zrobić całą magię.źródło
Spróbuj tego: używam go i uzyskałem dobry wynik.
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; }
Teraz przetestuj w ten sposób:
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;
Wyniki:
24,82 KiB
912 KiB
101,85 KiB
źródło
Aby pokryć żądanie HTTP / 2, funkcja podana tutaj https://stackoverflow.com/a/2602624/2380767 musi zostać nieco zmieniona:
<?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; } ?>
źródło