如何让Curl使用与PHP浏览器相同的cookie

时间:2009-07-13 18:37:28

标签: php curl cookies

我有一个PHP脚本代表浏览器执行HTTP请求,并输出对浏览器的响应。问题是当我点击此页面上浏览器中的链接时,它会抱怨cookie变量。我假设它需要网站的浏览器cookie。

如何拦截并将其转发到远程站点?

6 个答案:

答案 0 :(得分:10)

这是我将所有浏览器cookie转发为curl并将curl请求的所有cookie返回给浏览器的方式。为此我需要解决一些问题,比如从curl获取cookie,解析http头,发送多个cookie和会话锁定:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// get http header for cookies
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);

// forward current cookies to curl
$cookies = array();
foreach ($_COOKIE as $key => $value)
{
    if ($key != 'Array')
    {
        $cookies[] = $key . '=' . $value;
    }
}
curl_setopt( $ch, CURLOPT_COOKIE, implode(';', $cookies) );

// Stop session so curl can use the same session without conflicts
session_write_close();

$response = curl_exec($ch);
curl_close($ch);

// Session restart
session_start();

// Seperate header and body
list($header, $body) = explode("\r\n\r\n", $response, 2);

// extract cookies form curl and forward them to browser
preg_match_all('/^(Set-Cookie:\s*[^\n]*)$/mi', $header, $cookies);
foreach($cookies[0] AS $cookie)
{
     header($cookie, false);
}

echo $body;

答案 1 :(得分:5)

事实上,这是可能的。您只需要获取浏览器的cookie并将其作为参数传递给curl以模仿浏览器。 这就像一次会议...... ...

以下是示例代码:

// Init curl connection
$curl = curl_init('http://otherserver.com/');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// You can add your GET or POST param

// Retrieving session ID 
$strCookie = 'PHPSESSID=' . $_COOKIE['PHPSESSID'] . '; path=/';    

// We pass the sessionid of the browser within the curl request
curl_setopt( $curl, CURLOPT_COOKIE, $strCookie ); 

// We receive the answer as if we were the browser
$curl_response = curl_exec($curl);

如果您的目的是调用另一个网站,它的效果非常好,但是如果您调用Web服务器(与启动curl命令相同),则会失败。这是因为您的会话文件仍然被此脚本打开/锁定,因此您调用的URL无法访问它。

如果要绕过该限制(在同一服务器上调用页面),则必须在执行curl之前使用此代码关闭会话文件:

$curl = curl_init('http://sameserver.com/');
//...
session_write_close();
$curl_response = curl_exec($curl);

希望这会有所帮助:)

答案 2 :(得分:3)

来自curl_setopt

  

默认情况下,libcurl始终存储并加载所有cookie,如果它们是会话cookie,则独立。

但是,您可能需要直接设置cookie,这可以使用以下方式完成:

curl_setopt($ch, CURLOPT_COOKIE, 'foo=bar');

与Set-Cookie HTTP标头相同。检查你没有使用curl_setopt($ch, CURLOPT_COOKIESESSION, true),因为这会使libcurl忽略一些cookie。

答案 3 :(得分:1)

你不能。

如果您卷曲请求,则需要解析输出,并替换所有链接,以便它们通过您的服务器。

  www.yourdomain.com/f?=www.someotherdomain.com/realpage

唯一可行的方法是在curl请求中使用持久性cookie。 CURL可以自己保留cookie。将会话ID分配给cookie文件(在curl中),以便后续请求获得相同的cookie。当用户点击链接时,您需要再次卷曲请求。

允许site1为site2设置cookie是一个安全问题。想象一下,如果您可以在浏览器中为paypal设置cookie,并诱使用户认为他们已经记录了int或其他恶意行为。

答案 4 :(得分:0)

Cookie通常与HTTP请求标头一起发送,如

Host stackoverflow.com
User-Agent ...
Accept-Language en-us,en;q=0.5
Referer http://stackoverflow.com/unanswered
Cookie bla=blabla;blubb=blu

所以我想只需要修改标题中的cookie部分。

答案 5 :(得分:0)

PiTheNumber的答案很棒,但是我遇到了一些问题导致它仍然将标题打印到页面上。所以我调整它以使用更可靠的curl_getinfo函数。此版本也遵循重定向。

public function get_page_content( $url ) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
    curl_setopt($ch, CURLOPT_HEADER, 1);

    // Forward current cookies to curl
    $cookies = array();
    foreach ($_COOKIE as $key => $value) {
        if ($key != 'Array') {
            $cookies[] = $key . '=' . $value;
        }
    }
    curl_setopt( $ch, CURLOPT_COOKIE, implode(';', $cookies) );

    $destination = $url;

    while ($destination) {
        session_write_close();
        curl_setopt($ch, CURLOPT_URL, $destination);
        $response = curl_exec($ch);
        $curl_info = curl_getinfo($ch);
        $destination = $curl_info["redirect_url"];
        session_start();
    }
    curl_close($ch);

    $headers = substr($response, 0, $curl_info["header_size"]);
    $body = substr($response, $curl_info["header_size"]);

    // Extract cookies from curl and forward them to browser
    preg_match_all('/^(Set-Cookie:\s*[^\n]*)$/mi', $headers, $cookies);
    foreach($cookies[0] AS $cookie) {
        header($cookie, false);
    }

    return $body;
}