web-dev-qa-db-fra.com

Taille du fichier distant sans téléchargement de fichier

Existe-t-il un moyen d’obtenir la taille d’un fichier distant http: //my_url/my_file.txt sans télécharger le fichier?

71
dassouki

J'ai trouvé quelque chose à ce sujet ici :

Voici le meilleur moyen (que j'ai trouvé) d'obtenir la taille d'une télécommande fichier. Notez que les demandes HEAD n'obtiennent pas le corps réel de la demande, ils récupèrent simplement les en-têtes. Donc, faire une demande HEAD à une ressource Autrement dit, 100 Mo prendront autant de temps qu'une demande HEAD à un ressource qui est 1Ko.

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

Usage:

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

Essayez ce 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;
}
59
macki

Comme mentionné à plusieurs reprises, la solution consiste à récupérer les informations du champ Content-Length de l'en-tête de la réponse.

Cependant, vous devriez noter que

  • le serveur que vous testez n'implémente pas nécessairement la méthode HEAD (!)
  • il n'est absolument pas nécessaire de créer manuellement une requête HEAD (qui, encore une fois, risque même de ne pas être prise en charge) en utilisant fopen ou similaire ou même d'appeler la bibliothèque curl, lorsque PHP a get_headers() ( rappelez-vous: KISS )

L'utilisation de get_headers() suit le K.I.S.S. principeet fonctionne même si le serveur que vous testez ne prend pas en charge la demande HEAD.

Alors, voici ma version (gimmick: retourne une taille formatée lisible par l’homme ;-)):

Gist: https://Gist.github.com/eyecatchup/f26300ffd7e50a92bc4d (version de curl et get_headers)
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 <[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
}

Usage:

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

Remarque supplémentaire: L'en-tête Content-Length est facultatif. Ainsi, en tant que solution générale, ce n’est pas à l’abri des balles!


27
eyecatchUp

Sûr. Faites une requête en-têtes uniquement et recherchez l'en-tête Content-Length.

14
ceejayoz

La fonction php get_headers() me permet de vérifier le content-length comme 

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

Pour plus de détails: PHP Function get_headers ()

7
Sanchit Gupta

Je ne suis pas sûr, mais vous ne pouvez pas utiliser la fonction get_headers pour cela?

$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;
5
Jake

La mise en œuvre la plus simple et la plus efficace:

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));
}
3
mpyw

Essayez la fonction ci-dessous pour obtenir la taille du fichier distant

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;
}
2
Rahul Kaushik

Puisque cette question est déjà étiquetée "php" et "curl", je suppose que vous savez utiliser Curl en PHP.

Si vous définissez curl_setopt(CURLOPT_NOBODY, TRUE), vous ferez une demande HEAD et pourrez probablement vérifier l'en-tête "Content-Length" de la réponse, qui ne sera que des en-têtes.

2
dkamins

Voici une autre approche qui fonctionnera avec des serveurs qui ne prennent pas en charge les demandes HEAD.

Il utilise cURL pour demander le contenu avec un en-tête de plage HTTP demandant le premier octet du fichier.

Si le serveur prend en charge les demandes de plage (la plupart des serveurs de médias le feront), il recevra la réponse avec la taille de la ressource.

Si le serveur ne répond pas avec une plage d'octets, il recherchera un en-tête de longueur pour déterminer la longueur.

Si la taille est trouvée dans un en-tête de plage ou de contenu, le transfert est annulé. Si la taille n'est pas trouvée et que la fonction commence à lire le corps de la réponse, le transfert est annulé.

Cela peut constituer une approche supplémentaire si une demande HEAD entraîne une réponse non prise en charge par la méthode 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;
}

Usage:

$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.";
}
1
drew010

une ligne meilleure solution:

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

php est trop délicieuse

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

echo urlsize("http://.../file.txt");
1
Samad

La plupart des réponses ici utilisent CURL ou se basent sur les en-têtes de lecture. Mais dans certaines situations, vous pouvez utiliser une solution plus simple. Considérez la note sur la documentation de filesize() sur PHP.net . Vous y trouverez un conseil indiquant: "À partir de PHP 5.0.0, cette fonction peut également être utilisée avec certains wrappers d'URL. Reportez-vous à Protocoles et wrappes supportés pour déterminer quels wrappers prennent en charge stat () famille de fonctionnalités ".

Donc, si votre serveur et votre analyseur PHP sont correctement configurés, vous pouvez simplement utiliser la fonction filesize(), lui donner l'URL complète, pointer vers un fichier distant, quelle taille vous voulez obtenir, et laisser PHP faire le tout magique.

1
trejder

Essayez ceci: je l'utilise et j'ai un bon résultat.

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

Maintenant, testez comme ceci:

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('https://stackoverflow.com/questions/14679268/downloading-files-as-attachment-filesize-incorrect').PHP_EOL;

Résultats:

24.82 KiB

912 KiB

101,85 Ko

0
josef