Есть ли способ получить размер удаленного файла http: //my_url/my_file.txt без загрузки файла?
84
Есть ли способ получить размер удаленного файла http: //my_url/my_file.txt без загрузки файла?
Нашел кое-что об этом здесь :
Вот лучший способ (который я нашел) получить размер удаленного файла. Обратите внимание, что запросы HEAD не получают фактического тела запроса, они просто получают заголовки. Таким образом, выполнение запроса HEAD к ресурсу размером 100 МБ займет столько же времени, что и запрос HEAD к ресурсу размером 1 КБ.
<?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;
}
?>
Применение:
$file_size = curl_get_file_size( "http://stackoverflow.com/questions/2602612/php-remote-file-size-without-downloading-file" );
curl_getinfo
, как предлагает @macki?get_user_agent_string()
не было определено. Удаление всей линии заставило все работать.Попробуйте этот код
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; }
источник
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
.CURLOPT_FOLLOWLOCATION
установил истинное значение.Как упоминалось несколько раз, нужно получить информацию из
Content-Length
поля заголовка ответа .Однако следует отметить, что
fopen
или аналогичным образом, или даже вызывать библиотеку curl, когда PHP имеетget_headers()
(помните: KISS )Использование
get_headers()
следует принципу KISS и работает, даже если исследуемый сервер не поддерживает запрос HEAD.Итак, вот моя версия (трюк: возвращает размер в удобочитаемом формате ;-)):
Суть: https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d (версия curl и get_headers)
get_headers () - Версия:
<?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 }
Применение:
$url = 'http://download.tuxfamily.org/notepadplus/6.6.9/npp.6.6.9.Installer.exe'; echo getRemoteFilesize($url); // echoes "7.51 MiB"
Дополнительное примечание: заголовок Content-Length необязателен. Таким образом, в качестве общего решения это не пуленепробиваемое !
источник
Content-Length
это необязательно, но это единственный способ получить размер файла, не загружая его, иget_headers
это лучший способ получитьcontent-length
.stream_context_create
для создания отдельного контекста, который будет использоваться для вызоваget_headers
(7.1+).Конечно. Сделайте запрос только с заголовками и найдите
Content-Length
заголовок.источник
Функция PHP
get_headers()
работает для меня, чтобы проверить длину содержимого как$headers = get_headers('http://example.com/image.jpg', 1); $filesize = $headers['Content-Length'];
Для получения дополнительной информации: функция PHP get_headers ()
источник
Я не уверен, но нельзя ли использовать для этого функцию 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;
источник
однострочное лучшее решение:
echo array_change_key_case(get_headers("http://.../file.txt",1))['content-length'];
php слишком деликатен
function urlsize($url):int{ return array_change_key_case(get_headers($url,1))['content-length']; } echo urlsize("http://.../file.txt");
источник
Самая простая и эффективная реализация:
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)); }
источник
Content-Length
заголовок. И явное$fp
закрытие НЕ НУЖНО; он автоматически выпускается по истечении срока действия. php.net/manual/en/language.types.resource.phpnc -l localhost 8080
*close
функций в современном PHP не нужны. Они происходят по двум историческим причинам: ограничения реализации и имитация языка C.Поскольку этот вопрос уже помечен как «php» и «curl», я предполагаю, что вы знаете, как использовать Curl в PHP.
Если вы установите,
curl_setopt(CURLOPT_NOBODY, TRUE)
то вы сделаете запрос HEAD и, вероятно, сможете проверить заголовок «Content-Length» ответа, который будет только заголовками.источник
Попробуйте функцию ниже, чтобы получить размер удаленного файла
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; }
источник
Вот еще один подход, который будет работать с серверами, которые не поддерживают
HEAD
запросы.Он использует cURL для запроса содержимого с заголовком диапазона HTTP, запрашивающим первый байт файла.
Если сервер поддерживает запросы диапазона (большинство медиа-серверов будут), то он получит ответ с размером ресурса.
Если сервер не отвечает с диапазоном байтов, он будет искать заголовок длины содержимого, чтобы определить длину.
Если размер находится в заголовке диапазона или длины содержимого, передача прерывается. Если размер не найден и функция начинает чтение тела ответа, передача прерывается.
Это может быть дополнительным подходом, если в
HEAD
результате запроса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; }
Применение:
$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."; }
источник
Content-Length
нет в наличии.Большинство ответов здесь используют либо CURL, либо основаны на чтении заголовков. Но в некоторых ситуациях вы можете использовать более простое решение. Обратите внимание на
filesize()
документацию на PHP.net . Вы найдете там подсказку: « Начиная с PHP 5.0.0, эту функцию также можно использовать с некоторыми оболочками URL. Обратитесь к разделу Поддерживаемые протоколы и оболочки, чтобы определить, какие оболочки поддерживают семейство функций stat () ».Итак, если ваш сервер и PHP-парсер правильно настроены, вы можете просто использовать
filesize()
функцию, передать ей полный URL-адрес, указывая на удаленный файл, размер которого вы хотите получить, и позволить PHP делать всю магию.источник
Попробуйте так: пользуюсь, результат хороший.
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; }
А теперь протестируйте вот так:
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;
Полученные результаты:
24,82 КБ
912 КБ
101,85 КБ
источник
Чтобы охватить запрос HTTP / 2, функцию, представленную здесь https://stackoverflow.com/a/2602624/2380767, необходимо немного изменить:
<?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; } ?>
источник