使用withCredentials / CORS进行PHP CURL调用

时间:2016-05-18 15:42:09

标签: php curl cookies cors

我有一个设置cookie的PHP脚本(脚本A)。它是由来自不同域的AJAX JS调用调用的(所以它使用带有withCredentials标志的预检CORS)。我现在想要这个PHP脚本来CURL另一个域的PHP脚本(脚本B),以便它也设置一个cookie。但是,我在设置这些cookie时遇到了麻烦。

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

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

<?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失败。

感谢您提供任何帮助!

1 个答案:

答案 0 :(得分:0)

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

PS:您可以使用if(!isset($_SESSION['cookiejar'])) $_SESSION['cookiejar'] = tempnam(); $url = "http://www.domainB.com/scriptB.php"; $resp = request($url, null, null, $_SESSION['cookiejar']); 创建您的cookiejar文件。

以下是使用以下功能的示例:

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

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

HashMap<String,List<Integer> results = new HashMap<String,List<Integer>();
// Does Key already exist?
List<Integer> temp = results.get(curve.getTenor());

       if(temp != null){

               //if it does add to object
               temp.add(curve.getMaturitydate());
               temp.add(curve.getParrate());


       }else{
           // if not make object and put in has map
       List<Integer> nn = new ArrayList<Integer>();

       nn.add(curve.getMaturitydate());
       nn.add(curve.getParrate());
       userList.put(curve.getTenor(), nn);

           }