【问题标题】:PHP CURL call with withCredentials/CORSPHP CURL 调用 withCredentials/CORS
【发布时间】:2016-09-15 05:15:21
【问题描述】:

我有一个设置 cookie 的 PHP 脚本(脚本 A)。它由来自不同域的 AJAX JS 调用调用(因此它使用预检 CORS 并设置了 withCredentials 标志)。我现在希望这个 PHP 脚本卷曲另一个域的 PHP 脚本(脚本 B),以便它也设置一个 cookie。但是,我无法设置这些 cookie。

CURL 成功返回,scriptB.php 中的 setcookie() 返回 true,但加载 domainB.com 页面时浏览器上不存在 cookie。

脚本 B 使用与脚本 A 相同的预检 CORS 概念(请忽略此代码中的安全风险,这是在概念验证阶段):

<?php

$allowedDomains = array('http://www.domainA.com', 'http://www.domainB.com', 'http://www.domainC.com');

// Make sure the request is from an accepted domain
if(!in_array($_SERVER['HTTP_ORIGIN'], $allowedDomains))
{
    header("HTTP/1.1 403 Access Forbidden");
    header("Content-Type: text/plain");
    echo "Access denied";
    exit;
}

// "Preflight' request required by CORS
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS')
{
    // Preflight response
    header('Access-Control-Allow-Origin: '.$_SERVER['REQUEST_METHOD']);
    header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
    header('Access-Control-Allow-Credentials: true');       
    header('Access-Control-Max-Age: 1728000');
    header("Content-Length: 0");
    header("Content-Type: text/plain");
    exit;
}

// Handles the actual requests
if($_SERVER['REQUEST_METHOD'] == "POST")
{

    // Get the POST data
    $json = file_get_contents('php://input');
    $obj = json_decode($json);


    if(!isset($obj->cv) || !isset($obj->e))
    {
        header("HTTP/1.1 403 Access Forbidden");
        header("Content-Type: text/plain");
        echo "Access denied.";
        exit;   
    }

    $cookieValue = $_POST['cv'];
    $expires = $_POST['e'];
    if(!is_numeric($expires))
    {
        $expires = strtotime($expires);
    }

    $r = setcookie('cpn_auth',$cookieValue,$expires,'/','domainB.com',false,false);

    $response = array('result' => 1);

    sendResponse($response);

}


/**
* Sets the reply headers and outputs the reply message
*
* @param    array       $response The data to send back to the requesting script
* @return   void
*/
function sendResponse($response)
{

    header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
    header('Access-Control-Allow-Credentials: true');
    header('Cache-Control: no-cache');
    header('Pragma: no-cache');
    header('Content-Type: text/plain');
    echo json_encode($response);
    exit;

}

调用此脚本的 CURL:

$post = json_encode(array('cv'=>$cv, 'e'=>$e));

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://www.domainB.com/scriptB.php');
curl_setopt($curl, CURLOPT_USERPWD, "user123:pass123"); 
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_TIMEOUT, 5);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
    'Content-Type: text/plain',
    'Origin: http://www.domainA.com',
    'Referer: http://www.domainA.com',
    'Content-Length: ' . strlen($post)
));
$result = curl_exec($curl);
$return = json_decode($result, true);
curl_close($curl);

有人知道我在这里做错了什么吗?或者如果有更简单的方法?我已经看到了一些类似问题的答案,这些问题建议设置诸如 CURLOPT_COOKIE、CURLOPT_COOKIESESSION、CURLOPT_COOKIEFILE、CURLOPT_COOKIEJAR 和 CURLOPT_HEADER 之类的东西,我已经以不同的方式尝试了它们。要么没有任何变化,要么 CURL 失败。

感谢您提供的任何帮助!

【问题讨论】:

    标签: php curl cookies cross-domain


    【解决方案1】:

    您需要设置 cookie jar 以便会话持续存在。具体来说,您需要将 cookiejar 和 cookiefile 选项设置为可读/可写文件的名称。

    PS:您可以使用tempnam() 来创建您的cookiejar 文件。

    下面是一个使用下面函数的例子:

    if(!isset($_SESSION['cookiejar'])) $_SESSION['cookiejar'] = tempnam();
    $url = "http://www.domainB.com/scriptB.php";
    $resp = request($url, null, null, $_SESSION['cookiejar']);
    

    这是我用来登录网站和下载内容的 cURL 函数:

    /*
    * Makes an HTTP request via GET or POST, and can download a file
    * @returns - Returns the response of the request
    * @param $url - The URL to request, including any GET parameters
    * @param $params - An array of POST values to send
    * @param $filename - If provided, the response will be saved to the 
    *    specified filename
    */
    private static function request($url, $params = array(), $filename = "", $cookiejar=null) {
        $ch = curl_init();
        $curlOpts = array(
            CURLOPT_URL => $url,
            // Set Useragent
            CURLOPT_USERAGENT => 'Rockwell Helpdesk API',
            // Don't validate SSL 
            // This is to prevent possible errors with self-signed certs
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true
        );
        if(!empty($cookiejar)){
            $curlOpts[CURLOPT_COOKIEFILE] = $cookiejar;
            $curlOpts[CURLOPT_COOKIEJAR] = $cookiejar;
        }
        if(!empty($filename)){
            // If $filename exists, save content to file
            $file2 = fopen($filename,'w+') or die("Error[".__FILE__.":".__LINE__."] Could not open file: $filename");
            $curlOpts[CURLOPT_FILE] = $file2;
        }
        if (!empty($params)) {
            // If POST values are given, send that shit too
            $curlOpts[CURLOPT_POST] = true;
            $curlOpts[CURLOPT_POSTFIELDS] = http_build_query($params);
        }
        curl_setopt_array($ch, $curlOpts);
        $answer = curl_exec($ch);
        // If there was an error, show it
        if (curl_error($ch)) die(curl_error($ch));
        if(!empty($filename)) fclose($file2);
        curl_close($ch);
        self::$lastRequest = $answer;
        return $answer;
    }
    

    【讨论】:

    • 感谢您的回复,Pamblam。遗憾的是它没有效果(curl 和 setcookie() 仍然返回 true,但 cookie 没有在站点加载时显示)。我对这个命令有一个好奇的问题:“$curlOpts[] = $cookiejar;”调用 curl_setopt_array() 时会变成什么?
    • curl_setopt_array() 是一个简单的函数,可用于一次设置多个 curl 选项。这与调用curl_setopt($curl, CURLOPT_COOKIEFILE, $cookiejar); curl_setopt($curl, CURLOPT_COOKIEJAR, $cookiejar); 相同。此外,您的setCookie 函数将在用户的 计算机上设置cookie。当您使用 cURL 时,是服务器发出请求,而不是用户,这就是为什么在用户的计算机上设置 cookie 根本不会做任何事情的原因。相反,您必须在 服务器 上设置 cookie,唯一的方法是设置 cURL 的 CURLOPT_COOKIEFILE
    • ...CURLOPT_COOKIEJAR options.. 有意义吗?
    • 我得到了 curl_setopt_array() 的功能,这就是为什么 "$curlOpts[] = $cookiejar;"让我很困惑。 “$curlOpts[CURLOPT_COOKIEFILE] = $cookiejar;”设置“CURLOPT_COOKIEFILE”选项的值,但是为“$curlOpts[] = $cookiejar;”设置了什么选项?
    • 谢谢!谢天谢地,如果我不能让这个工作(我已经确认工作)我有另一个不太优雅的解决方案:让javascript(最初称为scriptA)创建一个隐藏的iframe(当scriptA成功返回时)加载一个脚本domainB 为 domainB 设置 cookie。本质上是相同的概念,但使用 iframe 客户端而不是 CURL 调用服务器端。干杯!
    猜你喜欢
    • 2013-11-09
    • 2014-11-09
    • 2018-05-20
    • 2018-10-19
    • 2015-03-22
    • 2019-05-07
    • 2018-11-13
    • 2012-08-23
    • 2012-04-25
    相关资源
    最近更新 更多