วิธีรับคุกกี้จาก php curl เป็นตัวแปร


126

ดังนั้นผู้ชายบางคนใน บริษัท อื่นบางคนคิดว่ามันจะดีมากถ้าแทนที่จะใช้สบู่หรือ xml-rpc หรือพักผ่อนหรือโปรโตคอลการสื่อสารที่สมเหตุสมผลอื่น ๆ เขาเพียงแค่ฝังการตอบสนองทั้งหมดของเขาเป็นคุกกี้ในส่วนหัว

ฉันจำเป็นต้องดึงคุกกี้เหล่านี้ออกมาเพื่อหวังว่าจะได้อาร์เรย์จากการตอบสนองแบบโค้งนี้ ถ้าฉันต้องเสียชีวิตมากมายในการเขียนโปรแกรมแยกวิเคราะห์สำหรับสิ่งนี้ฉันจะไม่มีความสุขมาก

มีใครรู้บ้างว่าสิ่งนี้สามารถทำได้โดยไม่ต้องเขียนอะไรลงในไฟล์?

ฉันจะขอบคุณมากถ้าใครสามารถช่วยฉันในเรื่องนี้

คำตอบ:


174
$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
น่าเสียดายที่ฉันมีความรู้สึกว่านี่คือคำตอบที่ถูกต้อง ฉันคิดว่ามันไร้สาระที่ curl ไม่สามารถส่งอาร์เรย์ที่แมปให้ฉันได้
หิวน้ำ 93

3
ฉันจะให้ แต่ preg_match ผิด ฉันไม่ได้ต้องการแค่เซสชันฉันเข้าใจว่าทำไมคุณถึงคิดอย่างนั้น แต่อัจฉริยะที่สร้างระบบของพวกเขากำลังโหลดคุกกี้พร้อมแผนที่ตอบกลับทั้งหมดเช่นรับหรือโพสต์ อึแบบนี้: Set-Cookie: price = 1 Set-Cookie: status = accept I needed a preg_match_all with '/ ^ Set-Cookie: (. *?) = (. *?) $ / sm'
หิวน้ำ 93

7
@ Thirsty93 Curl ไม่สามารถมอบอาร์เรย์ที่แมปให้คุณได้ แต่แสดงให้คุณเห็นวิธีการบันทึกcurl_setopt($ch, CURLOPT_HEADERFUNCTION, 'callback_SaveHeaders');
Shiplu Mokaddim

2
ขึ้นอยู่กับโครงสร้างคุกกี้ที่ส่งคืนบรรทัดสุดท้ายอาจต้องแก้ไขเป็นบางอย่างเช่นparse_str($m[1], $cookies)ซึ่งจะบรรจุคุกกี้ลงในอาร์เรย์ที่เชื่อมโยงใน$cookiesตัวแปร ....
random_user_name

7
สำหรับการแก้ไขแบบรวมที่จับคุกกี้มากกว่าหนึ่งตัว: 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

แม้ว่าคำถามนี้จะค่อนข้างเก่าและคำตอบที่ได้รับการยอมรับนั้นถูกต้อง แต่ฉันคิดว่ามันไม่สะดวกสบายเล็กน้อยเนื่องจากเนื้อหาของการตอบกลับ HTTP (HTML, XML, JSON, ไบนารีหรืออะไรก็ตาม) ผสมกับส่วนหัว

ฉันพบทางเลือกอื่นแล้ว CURL มีตัวเลือก (CURLOPT_HEADERFUNCTION ) เพื่อตั้งค่าการเรียกกลับที่จะถูกเรียกสำหรับบรรทัดส่วนหัวการตอบกลับแต่ละบรรทัด ฟังก์ชันจะรับวัตถุ curl และสตริงที่มีบรรทัดส่วนหัว

คุณสามารถใช้รหัสเช่นนี้ (ดัดแปลงจากการตอบสนอง 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
}

โซลูชันนี้มีข้อเสียของการใช้ตัวแปรส่วนกลาง แต่ฉันเดาว่านี่ไม่ใช่ปัญหาสำหรับสคริปต์สั้น ๆ และคุณสามารถใช้วิธีการแบบคงที่และแอตทริบิวต์ได้ตลอดเวลาหาก curl ถูกรวมเข้ากับคลาส


10
$cookiesแทนที่จะเป็นโลกที่คุณสามารถใช้การปิดการถือครองการอ้างอิงถึง $curlResponseHeaderCallback = function ($ch, $headerLine) use (&$cookies) {แล้วcurl_setopt($ch, CURLOPT_HEADERFUNCTION, $curlResponseHeaderCallback);.
ก.ย.

จะเกิดอะไรขึ้นถ้าคุณมีทั้งหมดนี้ในชั้นเรียน? คุณอ้างอิงฟังก์ชันคลาส$class->curlResponseHeaderCallback()อย่างไร หรือคุณมีแค่curlResponseHeaderCallbackนอกชั้นเรียน?
Sevenearths

13

นี้ไม่ได้โดยไม่ต้อง regexps แต่ต้องขยาย 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
ขอบคุณสำหรับสิ่งนี้. โซลูชันที่ชัดเจนและมีความหมายคุ้มค่ากับปัญหาในการติดตั้งส่วนขยาย
Ben Jacobs

2
นี่จะเป็นทางออกที่ดีที่สุดหากpecl installใช้งานได้จริงเท่านั้น ฮึ่ม
Robin Winslow

11

หากคุณใช้ CURLOPT_COOKIE_FILE และ CURLOPT_COOKIE_JAR curl จะอ่าน / เขียนคุกกี้จาก / ไปยังไฟล์ คุณสามารถอ่านและ / หรือแก้ไขได้ตามที่คุณต้องการ


12
ฉันคิดว่าเป้าหมายคือไม่ใช้ไฟล์นี้
Nicolas Thery

3

libcurl ยังมี CURLOPT_COOKIELIST ซึ่งแยกคุกกี้ที่รู้จักทั้งหมด สิ่งที่คุณต้องมีคือตรวจสอบให้แน่ใจว่าการเชื่อม PHP / CURL สามารถใช้งานได้


12
ไม่สามารถใช้งานผ่าน PHP API
Emre Yazici

1

ใครบางคนที่นี่อาจพบว่ามีประโยชน์ hhb_curl_exec2 ทำงานได้ดีเหมือน curl_exec แต่ arg3 เป็นอาร์เรย์ที่จะถูกเติมด้วยส่วนหัว http ที่ส่งคืน (ดัชนีตัวเลข) และ arg4 คืออาร์เรย์ซึ่งจะถูกเติมด้วยคุกกี้ที่ส่งคืน ($ cookies ["expires"] => " ศ. 06- พ.ค. -2559 เวลา 05:58:51 GMT ") และ arg5 จะถูกเติมด้วย ... ข้อมูลเกี่ยวกับคำขอดิบที่ทำโดย curl

ข้อเสียคือต้องเปิด CURLOPT_RETURNTRANSFER มิฉะนั้นจะเกิดข้อผิดพลาดและจะเขียนทับ CURLOPT_STDERR และ CURLOPT_VERBOSE หากคุณเคยใช้งานอย่างอื่นอยู่แล้ว .. (ฉันอาจแก้ไขได้ในภายหลัง)

ตัวอย่างวิธีการใช้งาน:

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

และฟังก์ชั่นเอง ..

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

คำตอบที่ยอมรับดูเหมือนว่าจะค้นหาผ่านข้อความตอบกลับทั้งหมด ซึ่งอาจทำให้คุณจับคู่ส่วนหัวคุกกี้ผิดพลาดได้หากคำว่า "Set-Cookie" อยู่ที่จุดเริ่มต้นของบรรทัด ในขณะที่ควรจะดีในกรณีส่วนใหญ่ วิธีที่ปลอดภัยกว่าคืออ่านข้อความตั้งแต่เริ่มต้นจนถึงบรรทัดแรกที่ว่างซึ่งระบุจุดสิ้นสุดของส่วนหัวของข้อความ นี่เป็นเพียงวิธีอื่นที่ควรมองหาบรรทัดว่างบรรทัดแรกจากนั้นใช้ preg_grep ในบรรทัดเหล่านั้นเพื่อค้นหา "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
คำตอบที่ยอมรับดูเหมือนว่าจะค้นหาผ่านข้อความตอบกลับทั้งหมด ซึ่งอาจทำให้คุณจับคู่ส่วนหัวคุกกี้ผิดพลาดได้หากคำว่า "Set-Cookie" อยู่ที่จุดเริ่มต้นของบรรทัด ในขณะที่ควรจะดีในกรณีส่วนใหญ่ วิธีที่ปลอดภัยกว่าคืออ่านข้อความตั้งแต่เริ่มต้นจนถึงบรรทัดแรกที่ว่างซึ่งระบุจุดสิ้นสุดของส่วนหัวของข้อความ นี่เป็นเพียงทางเลือกอื่นที่ควรมองหาบรรทัดว่างบรรทัดแรกจากนั้นใช้ preg_grep ในบรรทัดเหล่านั้นเท่านั้นเพื่อค้นหา "Set-Cookie"
Rich Wandell

0

ความเข้าใจของฉันคือcurlต้องเขียนคุกกี้จากไปยังไฟล์ ( curl -c cookie_file) หากคุณใช้งานcurlผ่าน PHP execหรือsystemฟังก์ชัน (หรืออะไรก็ตามในตระกูลนั้น) คุณควรจะบันทึกคุกกี้ลงในไฟล์ได้จากนั้นเปิดไฟล์และอ่านในไฟล์


4
เขาเกือบจะอ้างถึง php.net/curl :)
TML
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.