24

Is it possible to receive the cookies set by the remote server when doing a file_get_contents request?

I need php to do a http request, store the cookies, and then make a second http request using the stored cookies.

Tim Penner
  • 3,551
  • 21
  • 36
Louis W
  • 3,166
  • 6
  • 46
  • 76

7 Answers7

36

There's a magic variable for this, called $http_response_header; it's an array comprising all headers that were received. To extract the cookies you have to filter out the headers that start with Set-Cookie:.

file_get_contents('http://example.org');

$cookies = array();
foreach ($http_response_header as $hdr) {
    if (preg_match('/^Set-Cookie:\s*([^;]+)/', $hdr, $matches)) {
        parse_str($matches[1], $tmp);
        $cookies += $tmp;
    }
}
print_r($cookies);

An equivalent but less magical approach would be to use stream_get_meta_data():

if (false !== ($f = fopen('http://www.example.org', 'r'))) {
        $meta = stream_get_meta_data($f);
        $headers = $meta['wrapper_data'];

        $contents = stream_get_contents($f);
        fclose($f);
}
// $headers now contains the same array as $http_response_header
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
24

you should use cURL for that purpose, cURL implement a feature called the cookie jar which permit to save cookies in a file and reuse them for subsequent request(s).

Here come a quick code snipet how to do it:

/* STEP 1. let’s create a cookie file */
$ckfile = tempnam ("/tmp", "CURLCOOKIE");
/* STEP 2. visit the homepage to set the cookie properly */
$ch = curl_init ("http://somedomain.com/");
curl_setopt ($ch, CURLOPT_COOKIEJAR, $ckfile); 
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec ($ch);

/* STEP 3. visit cookiepage.php */
$ch = curl_init ("http://somedomain.com/cookiepage.php");
curl_setopt ($ch, CURLOPT_COOKIEFILE, $ckfile); 
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec ($ch);

note: has to be noted you should have the pecl extension (or compiled in PHP) installed or you won't have access to the cURL API.

RageZ
  • 26,800
  • 12
  • 67
  • 76
  • Is it possible to just store the cookies in a variable, I was trying to prevent writing them to disk. I really just need to pull out one cookie value. – Louis W Nov 25 '09 at 15:08
  • 1
    Doesn't look like it. Use http://www.php.net/manual/en/function.tempnam.php to create a temp file and remove it after you're done. – ceejayoz Nov 25 '09 at 15:15
  • 1
    @Louis: not with curl but anyway it's kind of a few bytes file and you can just `unlink` it after you are done. – RageZ Nov 25 '09 at 15:21
  • Reflected in my answer, there are ways to do this (not using CURL) that do not require file storage for cookies. – Tim Lytle Nov 25 '09 at 15:28
  • Just a heads up: I tried this but it didn't write the cookie until I added a curl_close($ch) call – Muc Apr 25 '17 at 12:32
17

I realize this is, late, but there is actually a way to at least receive individual cookies sent by the server.

I'm assuming you know how to do the whole stream_create_context business to get your file_get_contents http request rolling, and you just need assistance actually setting the cookies.

After running file_get_contents on a url, the (unfortunately, non-associative) array $http_response_header is set.

If the server is sending back a cookie, one of them will start with 'Set-Cookie: ', which you can extract with substr.

However, at the moment, it appears to me that one can only access -one- Set-Cookie through this variable, which is a limitation I am currently trying to find a way to work around.

Laereom
  • 601
  • 7
  • 12
  • 1
    Perfect, and the best answer to the original question.Somehow in 12+ years of PHP I'd missed this function. – Darren Cook Aug 17 '11 at 04:29
  • 1
    Multiple `Set-Cookie` lines are captured in `$http_response_header`; see also a related answer: http://stackoverflow.com/a/10958820/1338292 – Ja͢ck Jun 09 '12 at 07:29
  • I would really be grateful if you could just show us a sample code for those who do NOT `"know how to do the whole stream_create_context business to get your file_get_contents http request rolling"` – azerafati Aug 25 '15 at 08:11
9

Following on from Laereom's answer, here is how to get multiple cookies:

$cookies=array();
foreach($http_response_header as $s){
    if(preg_match('|^Set-Cookie:\s*([^=]+)=([^;]+);(.+)$|',$s,$parts))
        $cookies[$parts[1]]=$parts[2];
    }

NOTES:

  1. I'm liberal with the regex; study the RFCs if you want to be more precise (i.e. to reject badly formed cookie data)
  2. You'll find path=, expires=, etc. in $parts[3]. I'd suggest explode(';',$parts[3]) then another loop to process it (because I'm not sure if there is a fixed order for these attributes.
  3. If two cookies have the same name part, only the last survives, which appears to be correct. (I happen to have this situation in my current project; I assume it is a bug in the website I'm screen-scraping.)
Darren Cook
  • 27,837
  • 13
  • 117
  • 217
  • Thanks for the follow up. I later discovered this was true, but never did follow up to correct the original answer. – Laereom Nov 29 '12 at 16:59
2

You can either install and use the PECL extension for HTTP, or make sure your php installation was compiled with the optional curl library.

soulmerge
  • 73,842
  • 19
  • 118
  • 155
1

I believe you co do it pretty easily with the Zend_Http object. Here is the documentation about adding cookies to a request.

To get the cookies from a request (automatically retrieved I believe), just use getCookieJar() on the Zend_Http object.

That should be easy to implement; however, the php manual has a user comment on how to deal with cookies using the http stream.

Tim Lytle
  • 17,549
  • 10
  • 60
  • 91
0

There's a shorter option using preg_grep:

$cookiesArray = preg_grep('/^Set-Cookie/i', $http_response_header);

This is gonna return an array with the Set-Cookie headers, then you'll have to get the cookie from each header, as the cookie header can include the path and some other flags.

Tomás Cot
  • 992
  • 1
  • 8
  • 18