Làm thế nào để có được các cookie từ một php curl thành một biến


126

Vì vậy, một số người ở một số công ty khác nghĩ rằng sẽ thật tuyệt vời nếu thay vì sử dụng xà phòng hoặc xml-rpc hoặc nghỉ ngơi hoặc bất kỳ giao thức giao tiếp hợp lý nào khác, anh ta chỉ nhúng tất cả phản hồi của mình dưới dạng cookie vào tiêu đề.

Tôi cần phải rút các cookie này ra vì hy vọng một mảng từ phản hồi cuộn tròn này. Nếu tôi phải lãng phí một loạt cuộc đời mình để viết một trình phân tích cú pháp cho việc này, tôi sẽ rất không vui.

Có ai biết làm thế nào đơn giản có thể được thực hiện, tốt nhất là không cần viết bất cứ điều gì vào một tập tin?

Tôi sẽ rất biết ơn nếu bất cứ ai có thể giúp tôi với điều này.

Câu trả lời:


173
$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);

31
Thật không may, tôi có cảm giác rằng đây là câu trả lời đúng. Tôi nghĩ thật nực cười khi curl không thể đưa cho tôi một mảng được ánh xạ.
khát93

3
Tôi sẽ đưa nó cho bạn nhưng preg_match đã sai. Tôi không chỉ muốn phiên, tôi hiểu lý do tại sao bạn sẽ nghĩ như vậy. Nhưng thiên tài đã tạo ra hệ thống của họ đang tải cookie với toàn bộ bản đồ phản hồi như với nhận hoặc đăng. Chết tiệt như thế này: Set-Cookie: price = 1 Set-Cookie: status = accept Tôi cần một preg_match_all với '/ ^ Set-Cookie: (. *?) = (. *?) $ /
Sm

7
@ thirsty93 Curl không thể đưa cho bạn một mảng được ánh xạ. Nhưng chỉ cho bạn một cách để cứu nócurl_setopt($ch, CURLOPT_HEADERFUNCTION, 'callback_SaveHeaders');
Shiplu Mokaddim

2
Tùy thuộc vào cấu trúc cookie được trả về, dòng cuối cùng có thể cần được sửa đổi thành một cái gì đó giống như parse_str($m[1], $cookies), nó sẽ nhồi cookie vào một mảng kết hợp trong $cookiesbiến ....
Random_user_name

7
Đối với các bản sửa lỗi kết hợp lấy nhiều hơn một cookie: 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); }
Combuster

39

Mặc dù câu hỏi này khá cũ và phản hồi được chấp nhận là hợp lệ, tôi thấy nó hơi đáng tiếc vì nội dung của phản hồi HTTP (HTML, XML, JSON, nhị phân hoặc bất cứ điều gì) trở nên lẫn lộn với các tiêu đề.

Tôi đã tìm thấy một sự thay thế khác. CURL cung cấp một tùy chọn ( CURLOPT_HEADERFUNCTION) để đặt một cuộc gọi lại sẽ được gọi cho mỗi dòng tiêu đề phản hồi. Hàm sẽ nhận được đối tượng curl và một chuỗi với dòng tiêu đề.

Bạn có thể sử dụng mã như thế này (được điều chỉnh từ phản hồi 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
}

Giải pháp này có nhược điểm là sử dụng biến toàn cục, nhưng tôi đoán đây không phải là vấn đề đối với các tập lệnh ngắn. Và bạn luôn có thể sử dụng các phương thức và thuộc tính tĩnh nếu curl đang được gói vào một lớp.


10
Thay vì toàn cầu, bạn có thể sử dụng một bao đóng giữ một tham chiếu đến $cookies. $curlResponseHeaderCallback = function ($ch, $headerLine) use (&$cookies) {sau đó curl_setopt($ch, CURLOPT_HEADERFUNCTION, $curlResponseHeaderCallback);.
Seph

Điều gì xảy ra nếu bạn có tất cả những thứ này trong một lớp học? Làm thế nào để bạn tham khảo chức năng lớp $class->curlResponseHeaderCallback()? Hay bạn chỉ có curlResponseHeaderCallbackbên ngoài lớp học?
Thứ bảy

13

Điều này thực hiện nó mà không cần regexps, nhưng yêu cầu phần mở rộng PECL HTTP .

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

2
Cảm ơn vì điều đó. Một giải pháp rõ ràng, ngữ nghĩa đáng để cài đặt một phần mở rộng.
Ben Jacobs

2
Đây sẽ là giải pháp tốt nhất, nếu chỉ pecl installthực sự hoạt động. Grrr.
Robin Winslow

11

Nếu bạn sử dụng CURLOPT_COOKIE_FILE và CURLOPT_COOKIE_JAR curl sẽ đọc / ghi cookie từ / vào một tệp. Bạn có thể, sau khi cuộn tròn xong, đọc và / hoặc sửa đổi nó theo cách bạn muốn.


12
Tôi nghĩ mục tiêu không phải là sử dụng tập tin này
Nicolas Thery

3

libcurl cũng cung cấp CURLOPT_COOKIELIST để trích xuất tất cả các cookie đã biết. Tất cả những gì bạn cần là đảm bảo ràng buộc PHP / CURL có thể sử dụng nó.


12
Nó không thể sử dụng được thông qua API PHP.
Emre Yazici

1

ai đó ở đây có thể thấy nó hữu ích. hhb_curl_exec2 hoạt động khá giống curl_exec, nhưng arg3 là một mảng sẽ được điền với các tiêu đề http được trả về (chỉ mục số) và arg4 là một mảng sẽ được điền với các cookie được trả về ($ cookies ["hết hạn"] => " Thứ Sáu, ngày 06 tháng 5 năm 2016 05:58:51 GMT ") và arg5 sẽ được điền với ... thông tin về yêu cầu thô được thực hiện bởi curl.

Nhược điểm là nó yêu cầu phải bật CURLOPT_RETURNTRANSFER, nếu không, nó sẽ báo lỗi và nó sẽ ghi đè lên CURLOPT_STDERR CURLOPT_VERBOSE, nếu bạn đã sử dụng chúng cho mục đích khác .. (tôi có thể khắc phục điều này sau)

ví dụ về cách sử dụng nó:

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

và chính chức năng ..

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

1

Câu trả lời được chấp nhận có vẻ như nó sẽ tìm kiếm thông qua toàn bộ thông điệp phản hồi. Điều này có thể cung cấp cho bạn kết quả khớp sai cho các tiêu đề cookie nếu từ "Set-Cookie" ở đầu dòng. Trong khi nó sẽ ổn trong hầu hết các trường hợp. Cách an toàn hơn có thể là đọc qua tin nhắn từ đầu cho đến dòng trống đầu tiên cho biết phần cuối của tiêu đề thư. Đây chỉ là một giải pháp thay thế nên tìm dòng trống đầu tiên và sau đó sử dụng preg_grep trên các dòng đó chỉ để tìm "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;
        }
    }

1
Câu trả lời được chấp nhận có vẻ như nó sẽ tìm kiếm thông qua toàn bộ thông điệp phản hồi. Điều này có thể cung cấp cho bạn kết quả khớp sai cho các tiêu đề cookie nếu từ "Set-Cookie" ở đầu dòng. Trong khi nó sẽ ổn trong hầu hết các trường hợp. Cách an toàn hơn có thể là đọc qua tin nhắn từ đầu cho đến dòng trống đầu tiên cho biết phần cuối của tiêu đề thư. Đây chỉ là một giải pháp thay thế nên tìm dòng trống đầu tiên và sau đó sử dụng preg_grep trên các dòng đó chỉ để tìm "Set-Cookie".
Rich Wandell

0

Hiểu biết của tôi là cookie từ curlphải được viết ra thành một tập tin ( curl -c cookie_file). Nếu bạn đang chạy curlqua PHP exechoặc các systemchức năng (hoặc bất cứ thứ gì trong gia đình đó), bạn sẽ có thể lưu cookie vào một tệp, sau đó mở tệp và đọc chúng.


4
Anh ấy gần như chắc chắn đề cập đến php.net/curl :)
TML
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.