Gibt es eine Möglichkeit, die Größe einer Remote-Datei http: //my_url/my_file.txt zu ermitteln, ohne die Datei herunterzuladen?
Gibt es eine Möglichkeit, die Größe einer Remote-Datei http: //my_url/my_file.txt zu ermitteln, ohne die Datei herunterzuladen?
Antworten:
Hier etwas dazu gefunden :
Hier ist der beste Weg (den ich gefunden habe), um die Größe einer entfernten Datei zu erhalten. Beachten Sie, dass HEAD-Anforderungen nicht den tatsächlichen Hauptteil der Anforderung erhalten, sondern nur die Header abrufen. Das Erstellen einer HEAD-Anforderung an eine Ressource mit 100 MB dauert also genauso lange wie eine HEAD-Anforderung an eine Ressource mit 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;
}
?>
Verwendung:
$file_size = curl_get_file_size( "http://stackoverflow.com/questions/2602612/php-remote-file-size-without-downloading-file" );
curl_getinfo
, wie @macki vorschlägt?
get_user_agent_string()
nicht definiert. Durch das Entfernen der gesamten Linie funktionierte das Ganze.
http://www.dailymotion.com/rss/user/dialhainaut/
siehe SO: stackoverflow.com/questions/36761377/…
Versuchen Sie diesen Code
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
auf wahr gesetzt.
Wie bereits einige Male erwähnt, müssen Sie die Informationen aus dem Content-Length
Feld des Antwortheaders abrufen .
Beachten Sie dies jedoch
fopen
oder ähnlich zu erstellen oder die Curl-Bibliothek aufzurufen, wenn PHP dies getan hat get_headers()
(denken Sie daran: KISS ).Die Verwendung von get_headers()
folgt dem KISS-Prinzip und funktioniert auch dann, wenn der Server, den Sie prüfen, die HEAD-Anforderung nicht unterstützt.
Also, hier ist meine Version (Gimmick: Gibt eine für Menschen lesbare formatierte Größe zurück ;-)):
Inhalt: https://gist.github.com/eyecatchup/f26300ffd7e50a92bc4d (Curl- und get_headers-Version)
get_headers () - Version:
<?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
}
Verwendung:
$url = 'http://download.tuxfamily.org/notepadplus/6.6.9/npp.6.6.9.Installer.exe';
echo getRemoteFilesize($url); // echoes "7.51 MiB"
Zusätzlicher Hinweis: Der Header "Content-Length" ist optional. Daher ist es als allgemeine Lösung nicht kugelsicher !
Content-Length
ist optional, aber es ist der einzige Weg, die Dateigröße zu erhalten, ohne sie herunterzuladen - und get_headers
der beste Weg, um sie zu erhalten content-length
.
stream_context_create
diese Option , um einen separaten Kontext für den Aufruf von get_headers
(7.1+) zu erstellen .
PHP-Funktion get_headers()
funktioniert für mich, um die Länge des Inhalts als zu überprüfen
$headers = get_headers('http://example.com/image.jpg', 1);
$filesize = $headers['Content-Length'];
Für mehr Details: PHP-Funktion get_headers ()
Ich bin mir nicht sicher, aber konnten Sie die Funktion get_headers dafür nicht verwenden?
$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;
einzeilige beste Lösung:
echo array_change_key_case(get_headers("http://.../file.txt",1))['content-length'];
PHP ist zu delicius
function urlsize($url):int{
return array_change_key_case(get_headers($url,1))['content-length'];
}
echo urlsize("http://.../file.txt");
Die einfachste und effizienteste Implementierung:
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
Header enthält . Ein explizites $fp
Schließen ist NICHT NOTWENDIG. Es wird automatisch nach Ablauf freigegeben. php.net/manual/en/language.types.resource.php
nc -l localhost 8080
*close
Funktionen in modernem PHP nicht erforderlich. Sie haben zwei historische Gründe: Implementierungsbeschränkungen und Nachahmung der C-Sprache.
Da diese Frage bereits mit "php" und "curl" gekennzeichnet ist, gehe ich davon aus, dass Sie wissen, wie man Curl in PHP verwendet.
Wenn Sie festlegen, stellen curl_setopt(CURLOPT_NOBODY, TRUE)
Sie eine HEAD-Anfrage und können wahrscheinlich den Header "Content-Length" der Antwort überprüfen, bei dem es sich nur um Header handelt.
Versuchen Sie die folgende Funktion, um die Größe der Remote-Datei zu ermitteln
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;
}
Hier ist ein weiterer Ansatz, der mit Servern funktioniert, die keine HEAD
Anforderungen unterstützen.
Es verwendet cURL, um eine Anforderung für den Inhalt mit einem HTTP-Bereichskopf zu stellen, der nach dem ersten Byte der Datei fragt.
Wenn der Server Bereichsanforderungen unterstützt (die meisten Medienserver werden dies tun), erhält er die Antwort mit der Größe der Ressource.
Wenn der Server nicht mit einem Bytebereich antwortet, sucht er nach einem Header mit Inhaltslänge, um die Länge zu bestimmen.
Wenn die Größe in einem Header für einen Bereich oder eine Inhaltslänge gefunden wird, wird die Übertragung abgebrochen. Wird die Größe nicht gefunden und die Funktion beginnt mit dem Lesen des Antwortkörpers, wird die Übertragung abgebrochen.
Dies kann ein zusätzlicher Ansatz sein, wenn eine HEAD
Anforderung zu einer 405
nicht unterstützten Antwort führt.
/**
* 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;
}
Verwendung:
$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
nicht verfügbar ist.
Die meisten Antworten hier verwenden entweder CURL oder basieren auf dem Lesen von Headern. In bestimmten Situationen können Sie jedoch eine viel einfachere Lösung verwenden. Beachten Sie den Hinweis zu filesize()
den Dokumenten auf PHP.net . Dort finden Sie einen Tipp: " Ab PHP 5.0.0 kann diese Funktion auch mit einigen URL-Wrappern verwendet werden. Informationen zu den Wrappern, die die stat () -Familie von Funktionen unterstützen, finden Sie unter Unterstützte Protokolle und Wrapper ."
Wenn Ihr Server und Ihr PHP-Parser richtig konfiguriert sind, können Sie einfach die filesize()
Funktion verwenden, sie mit der vollständigen URL versorgen, auf eine entfernte Datei zeigen, welche Größe Sie erhalten möchten, und PHP die ganze Magie machen lassen.
Versuchen Sie Folgendes: Ich benutze es und habe ein gutes Ergebnis erzielt.
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;
}
Testen Sie nun wie folgt:
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;
Ergebnisse:
24,82 KiB
912 KiB
101,85 KiB
Um die HTTP / 2-Anforderung abzudecken, muss die hier bereitgestellte Funktion https://stackoverflow.com/a/2602624/2380767 ein wenig geändert werden:
<?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;
}
?>