web-dev-qa-db-fra.com

Récupération de l'en-tête uniquement en php via curl

En fait, j'ai deux questions.

(1) Y a-t-il une réduction de puissance de traitement ou bande passante utilisée sur le serveur distant si je récupère uniquement les en-têtes par opposition à la récupération de la pleine page en utilisant php et curl?

(2) Puisque je pense, et je peux me tromper, que la réponse aux premières questions est OUI , j'essaie d'obtenir la dernière date de modification ou If-Modified -Depuis l'en-tête du fichier distant uniquement afin de le comparer avec la date et l'heure des données stockées localement, je peux donc, en cas de modification, le stocker localement. Cependant, mon script semble incapable de récupérer cette information, j'obtiens NULL, lorsque j'exécute ceci:

class last_change {

 public last_change;

 function set_last_change() {
  $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, "http://url/file.xml");
    curl_setopt($curl, CURLOPT_HEADER, true);
    curl_setopt($curl, CURLOPT_FILETIME, true);
    curl_setopt($curl, CURLOPT_NOBODY, true);
  // $header = curl_exec($curl);
  $this -> last_change = curl_getinfo($header);
  curl_close($curl);
 }

 function get_last_change() {
  return $this -> last_change['datetime']; // I have tested with Last-Modified & If-Modified-Since to no avail
 }

}

Dans le cas où $header = curl_exec($curl) n'est pas compliquée, les données d'en-tête sont affichées, même si je ne les ai pas demandées et sont les suivantes:

HTTP/1.1 200 OK
Date: Fri, 04 Sep 2009 12:15:51 GMT
Server: Apache/2.2.8 (Linux/SUSE)
Last-Modified: Thu, 03 Sep 2009 12:46:54 GMT
ETag: "198054-118c-472abc735ab80"
Accept-Ranges: bytes
Content-Length: 4492
Content-Type: text/xml

Sur cette base, 'Last-Modified' est retourné.

Alors, qu'est-ce que je fais mal?

59
Krule

Vous passez $ header à curl_getinfo(). Il doit s'agir de $curl (La poignée de bouclage). Vous pouvez obtenir juste le filetime en passant CURLINFO_FILETIME Comme deuxième paramètre à curl_getinfo(). (Souvent, le filetime n'est pas disponible, auquel cas il sera signalé comme -1).

Votre classe semble être un gaspillage, cependant, jetant beaucoup d'informations qui pourraient être utiles. Voici une autre façon de procéder:

class URIInfo 
{
    public $info;
    public $header;
    private $url;

    public function __construct($url)
    {
        $this->url = $url;
        $this->setData();
    }

    public function setData() 
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $this->url);
        curl_setopt($curl, CURLOPT_FILETIME, true);
        curl_setopt($curl, CURLOPT_NOBODY, true);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, true);
        $this->header = curl_exec($curl);
        $this->info = curl_getinfo($curl);
        curl_close($curl);
    }

    public function getFiletime() 
    {
        return $this->info['filetime'];
    }

    // Other functions can be added to retrieve other information.
}

$uri_info = new URIInfo('http://www.codinghorror.com/blog/');
$filetime = $uri_info->getFiletime();
if ($filetime != -1) {
    echo date('Y-m-d H:i:s', $filetime);
} else {
    echo 'filetime not available';
}

Oui, la charge sera plus légère sur le serveur, car elle ne renvoie que l'en-tête HTTP (répondant, après tout, à une requête HEAD). La quantité de briquet variera considérablement.

50
GZipp

Pourquoi utiliser CURL pour cela? Il existe une fonction PHP pour cela:

$headers=get_headers("http://www.amazingjokes.com/img/2014/530c9613d29bd_CountvonCount.jpg");
print_r($headers);

renvoie ce qui suit:

Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Tue, 11 Mar 2014 22:44:38 GMT
    [2] => Server: Apache
    [3] => Last-Modified: Tue, 25 Feb 2014 14:08:40 GMT
    [4] => ETag: "54e35e8-8873-4f33ba00673f4"
    [5] => Accept-Ranges: bytes
    [6] => Content-Length: 34931
    [7] => Connection: close
    [8] => Content-Type: image/jpeg
)

Cela devrait être facile d'obtenir le type de contenu après cela.

Vous pouvez également ajouter le format = 1 à get_headers:

$headers=get_headers("http://www.amazingjokes.com/img/2014/530c9613d29bd_CountvonCount.jpg",1);
    print_r($headers);

Cela renverra les éléments suivants:

Array
(
    [0] => HTTP/1.1 200 OK
    [Date] => Tue, 11 Mar 2014 22:44:38 GMT
    [Server] => Apache
    [Last-Modified] => Tue, 25 Feb 2014 14:08:40 GMT
    [ETag] => "54e35e8-8873-4f33ba00673f4"
    [Accept-Ranges] => bytes
    [Content-Length] => 34931
    [Connection] => close
    [Content-Type] => image/jpeg
)

Plus de lecture ici (PHP.NET)

37
patrick

(1) Oui. Une demande HEAD (comme vous émettez dans ce cas) est beaucoup plus légère sur le serveur car elle ne renvoie que les en-têtes HTTP, par opposition aux en-têtes et au contenu comme une demande GET standard.

(2) Vous devez définir l'option CURLOPT_RETURNTRANSFER sur true avant d'appeler curl_exec() pour que le contenu soit renvoyé, par opposition à imprimé:

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

Cela devrait également permettre à votre classe de fonctionner correctement.

15
Ian Kemp

Vous pouvez définir le contexte de flux par défaut:

stream_context_set_default(
    array(
        'http' => array(
            'method' => 'HEAD'
        )
    )
);

Utilisez ensuite:

$headers = get_headers($url,1);

get_headers semble être plus efficace que cURL une fois que get_headers ignore les étapes telles que les routines d'authentification de déclenchement telles que les invites de connexion ou les cookies.

4
lipinf

Voici mon implémentation en utilisant CURLOPT_HEADER, puis en analysant la chaîne de sortie dans une carte:

function http_headers($url){
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_NOBODY, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);

    $headers = curl_exec($ch);

    curl_close($ch);

    $data = [];
    $headers = explode(PHP_EOL, $headers);
    foreach ($headers as $row) {
        $parts = explode(':', $row);
        if (count($parts) === 2) {
            $data[trim($parts[0])] = trim($parts[1]);
        }
    }

    return $data;
};

Exemple d'utilisation:

$headers = http_headers('https://i.ytimg.com/vi_webp/g-dKXOlsf98/hqdefault.webp');
print_r($headers);

Array
(
    ['Content-Type'] => 'image/webp'
    ['ETag'] => '1453807629'
    ['X-Content-Type-Options'] => 'nosniff'
    ['Server'] => 'sffe'
    ['Content-Length'] => 32958
    ['X-XSS-Protection'] => '1; mode=block'
    ['Age'] => 11
    ['Cache-Control'] => 'public, max-age=7200'
)
4
rodrigo-silveira

Vous devez ajouter

curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

pour retourner l'en-tête au lieu de l'imprimer.

Que le renvoi des en-têtes uniquement soit plus léger sur le serveur dépend du script en cours d'exécution, mais il le sera généralement.

Je pense que vous voulez aussi "filetime" au lieu de "datetime".

4
Greg