Ainsi, un type d'une autre société a pensé qu'il serait génial de ne pas utiliser savon ou XML-rpc ou rest ou tout autre protocole de communication raisonnable, mais simplement d'intégrer toute sa réponse sous forme de cookies dans l'en-tête.
Je dois retirer ces cookies comme un tableau de cette réponse curl. Si je dois gaspiller une partie de ma vie à écrire un analyseur pour cela, je serai très malheureux.
Est-ce que quelqu'un sait comment cela peut être fait simplement, de préférence sans rien écrire dans un fichier?
Je serai très reconnaissant si quelqu'un peut m'aider avec cela.
$ch = curl_init('http://www.google.com/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// get headers too with this line
curl_setopt($ch, CURLOPT_HEADER, 1);
$result = curl_exec($ch);
// get cookie
// multi-cookie variant contributed by @Combuster in comments
preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $result, $matches);
$cookies = array();
foreach($matches[1] as $item) {
parse_str($item, $cookie);
$cookies = array_merge($cookies, $cookie);
}
var_dump($cookies);
Bien que cette question soit assez ancienne et que la réponse acceptée soit valide, je la trouve un peu inconfortable car le contenu de la réponse HTTP (HTML, XML, JSON, binaire ou autre) est mélangé aux en-têtes.
J'ai trouvé une alternative différente. CURL fournit une option (CURLOPT_HEADERFUNCTION
) pour définir un rappel qui sera appelé pour chaque ligne d'en-tête de réponse. La fonction recevra l'objet curl et une chaîne avec la ligne d'en-tête.
Vous pouvez utiliser un code comme celui-ci (adapté de la réponse TML):
$cookies = Array();
$ch = curl_init('http://www.google.com/');
// Ask for the callback.
curl_setopt($ch, CURLOPT_HEADERFUNCTION, "curlResponseHeaderCallback");
$result = curl_exec($ch);
var_dump($cookies);
function curlResponseHeaderCallback($ch, $headerLine) {
global $cookies;
if (preg_match('/^Set-Cookie:\s*([^;]*)/mi', $headerLine, $cookie) == 1)
$cookies[] = $cookie;
return strlen($headerLine); // Needed by curl
}
Cette solution présente l’inconvénient d’utiliser une variable globale, mais j’imagine que ce n’est pas un problème pour les scripts courts. Et vous pouvez toujours utiliser des méthodes et attributs statiques si curl est encapsulé dans une classe.
Ceci le fait sans expressions rationnelles, mais nécessite le extension HTTP PECL .
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$result = curl_exec($ch);
curl_close($ch);
$headers = http_parse_headers($result);
$cookobjs = Array();
foreach($headers AS $k => $v){
if (strtolower($k)=="set-cookie"){
foreach($v AS $k2 => $v2){
$cookobjs[] = http_parse_cookie($v2);
}
}
}
$cookies = Array();
foreach($cookobjs AS $row){
$cookies[] = $row->cookies;
}
$tmp = Array();
// sort k=>v format
foreach($cookies AS $v){
foreach ($v AS $k1 => $v1){
$tmp[$k1]=$v1;
}
}
$cookies = $tmp;
print_r($cookies);
Si vous utilisez CURLOPT_COOKIE_FILE et CURLOPT_COOKIE_JAR, curl lira/écrira les cookies de/dans un fichier. Vous pouvez, après avoir terminé, lisez et/ou modifiez-le comme vous le souhaitez.
libcurl fournit également CURLOPT_COOKIELIST qui extrait tous les cookies connus. Tout ce dont vous avez besoin est de vous assurer que la liaison PHP/CURL peut l'utiliser.
La réponse acceptée semble permettre de parcourir l'intégralité du message de réponse. Cela pourrait vous donner de fausses correspondances pour les en-têtes de cookie si le mot "Set-Cookie" est au début d'une ligne. Bien que cela devrait aller dans la plupart des cas. Le moyen le plus sûr consiste peut-être à lire le message du début à la première ligne vide indiquant la fin des en-têtes du message. Ceci est juste une solution alternative qui devrait rechercher la première ligne vierge puis utiliser preg_grep sur ces lignes uniquement pour trouver "Set-Cookie".
curl_setopt($ch, CURLOPT_HEADER, 1);
//Return everything
$res = curl_exec($ch);
//Split into lines
$lines = explode("\n", $res);
$headers = array();
$body = "";
foreach($lines as $num => $line){
$l = str_replace("\r", "", $line);
//Empty line indicates the start of the message body and end of headers
if(trim($l) == ""){
$headers = array_slice($lines, 0, $num);
$body = $lines[$num + 1];
//Pull only cookies out of the headers
$cookies = preg_grep('/^Set-Cookie:/', $headers);
break;
}
}
quelqu'un ici peut trouver cela utile. hhb_curl_exec2 fonctionne à peu près comme curl_exec, mais arg3 est un tableau qui sera rempli avec les en-têtes http renvoyés (index numérique) et arg4 est un tableau qui sera rempli avec les cookies retournés ($ cookies ["expires"] => " Vendredi, 06-mai-2016 05:58:51 GMT "), et arg5 sera peuplé avec ... des informations sur la demande brute faite par curl.
l'inconvénient, c'est que CURLOPT_RETURNTRANSFER doit être activé, sinon l'erreur est supprimée, et cela écrasera CURLOPT_STDERR et CURLOPT_VERBOSE, si vous les utilisiez déjà pour autre chose.
exemple d'utilisation:
<?php
header("content-type: text/plain;charset=utf8");
$ch=curl_init();
$headers=array();
$cookies=array();
$debuginfo="";
$body="";
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$body=hhb_curl_exec2($ch,'https://www.youtube.com/',$headers,$cookies,$debuginfo);
var_dump('$cookies:',$cookies,'$headers:',$headers,'$debuginfo:',$debuginfo,'$body:',$body);
et la fonction elle-même ..
function hhb_curl_exec2($ch, $url, &$returnHeaders = array(), &$returnCookies = array(), &$verboseDebugInfo = "")
{
$returnHeaders = array();
$returnCookies = array();
$verboseDebugInfo = "";
if (!is_resource($ch) || get_resource_type($ch) !== 'curl') {
throw new InvalidArgumentException('$ch must be a curl handle!');
}
if (!is_string($url)) {
throw new InvalidArgumentException('$url must be a string!');
}
$verbosefileh = tmpfile();
$verbosefile = stream_get_meta_data($verbosefileh);
$verbosefile = $verbosefile['uri'];
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_STDERR, $verbosefileh);
curl_setopt($ch, CURLOPT_HEADER, 1);
$html = hhb_curl_exec($ch, $url);
$verboseDebugInfo = file_get_contents($verbosefile);
curl_setopt($ch, CURLOPT_STDERR, NULL);
fclose($verbosefileh);
unset($verbosefile, $verbosefileh);
$headers = array();
$crlf = "\x0d\x0a";
$thepos = strpos($html, $crlf . $crlf, 0);
$headersString = substr($html, 0, $thepos);
$headerArr = explode($crlf, $headersString);
$returnHeaders = $headerArr;
unset($headersString, $headerArr);
$htmlBody = substr($html, $thepos + 4); //should work on utf8/ascii headers... utf32? not so sure..
unset($html);
//I REALLY HOPE THERE EXIST A BETTER WAY TO GET COOKIES.. good grief this looks ugly..
//at least it's tested and seems to work perfectly...
$grabCookieName = function($str)
{
$ret = "";
$i = 0;
for ($i = 0; $i < strlen($str); ++$i) {
if ($str[$i] === ' ') {
continue;
}
if ($str[$i] === '=') {
break;
}
$ret .= $str[$i];
}
return urldecode($ret);
};
foreach ($returnHeaders as $header) {
//Set-Cookie: crlfcoookielol=crlf+is%0D%0A+and+newline+is+%0D%0A+and+semicolon+is%3B+and+not+sure+what+else
/*Set-Cookie:ci_spill=a%3A4%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%22305d3d67b8016ca9661c3b032d4319df%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A14%3A%2285.164.158.128%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A109%3A%22Mozilla%2F5.0+%28Windows+NT+6.1%3B+WOW64%29+AppleWebKit%2F537.36+%28KHTML%2C+like+Gecko%29+Chrome%2F43.0.2357.132+Safari%2F537.36%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1436874639%3B%7Dcab1dd09f4eca466660e8a767856d013; expires=Tue, 14-Jul-2015 13:50:39 GMT; path=/
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT;
//Cookie names cannot contain any of the following '=,; \t\r\n\013\014'
//
*/
if (stripos($header, "Set-Cookie:") !== 0) {
continue;
/**/
}
$header = trim(substr($header, strlen("Set-Cookie:")));
while (strlen($header) > 0) {
$cookiename = $grabCookieName($header);
$returnCookies[$cookiename] = '';
$header = substr($header, strlen($cookiename) + 1); //also remove the =
if (strlen($header) < 1) {
break;
}
;
$thepos = strpos($header, ';');
if ($thepos === false) { //last cookie in this Set-Cookie.
$returnCookies[$cookiename] = urldecode($header);
break;
}
$returnCookies[$cookiename] = urldecode(substr($header, 0, $thepos));
$header = trim(substr($header, $thepos + 1)); //also remove the ;
}
}
unset($header, $cookiename, $thepos);
return $htmlBody;
}
function hhb_curl_exec($ch, $url)
{
static $hhb_curl_domainCache = "";
//$hhb_curl_domainCache=&$this->hhb_curl_domainCache;
//$ch=&$this->curlh;
if (!is_resource($ch) || get_resource_type($ch) !== 'curl') {
throw new InvalidArgumentException('$ch must be a curl handle!');
}
if (!is_string($url)) {
throw new InvalidArgumentException('$url must be a string!');
}
$tmpvar = "";
if (parse_url($url, PHP_URL_Host) === null) {
if (substr($url, 0, 1) !== '/') {
$url = $hhb_curl_domainCache . '/' . $url;
} else {
$url = $hhb_curl_domainCache . $url;
}
}
;
curl_setopt($ch, CURLOPT_URL, $url);
$html = curl_exec($ch);
if (curl_errno($ch)) {
throw new Exception('Curl error (curl_errno=' . curl_errno($ch) . ') on url ' . var_export($url, true) . ': ' . curl_error($ch));
// echo 'Curl error: ' . curl_error($ch);
}
if ($html === '' && 203 != ($tmpvar = curl_getinfo($ch, CURLINFO_HTTP_CODE)) /*203 is "success, but no output"..*/ ) {
throw new Exception('Curl returned nothing for ' . var_export($url, true) . ' but HTTP_RESPONSE_CODE was ' . var_export($tmpvar, true));
}
;
//remember that curl (usually) auto-follows the "Location: " http redirects..
$hhb_curl_domainCache = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL), PHP_URL_Host);
return $html;
}
D'après ce que je comprends, les cookies de curl
doivent être écrits dans un fichier (curl -c cookie_file
). Si vous utilisez curl
via les fonctions exec
ou system
de PHP (ou quelque chose de cette famille), vous devriez pouvoir enregistrer les cookies dans un fichier, puis ouvrir le fichier et les lire.