Php 当Curl跟随位置时,是否有任何方法进行urlencode/转义?

Php 当Curl跟随位置时,是否有任何方法进行urlencode/转义?,php,php-curl,Php,Php Curl,我正在做SEB open banking的Api集成,而它并不像普通浏览器那样编码url $url = 'https://api-sandbox.sebgroup.com/mga/sps/oauth/oauth20/authorize?' . 'client_id=XXXXXXXXXXXX&response_type=code&scope=psd2_accounts%20psd2_payments&redirect_uri=https://testcall

我正在做SEB open banking的Api集成,而它并不像普通浏览器那样编码url

        $url = 'https://api-sandbox.sebgroup.com/mga/sps/oauth/oauth20/authorize?' . 'client_id=XXXXXXXXXXXX&response_type=code&scope=psd2_accounts%20psd2_payments&redirect_uri=https://testcallback.com/test';
        curl_setopt_array($curl, array(
            CURLOPT_HEADER => true,
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 30,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_CUSTOMREQUEST => "GET",
            CURLOPT_VERBOSE => true,
            CURLOPT_HTTPHEADER => array(
                "accept: text/html",
            ),
        ));

        $response = curl_exec($curl);
        $err = curl_error($curl);
下面是日志中的curl verbose

< HTTP/1.1 302 Found
< content-language: en-US
< date: Thu, 25 Jul 2019 21:15:49 GMT
< location: https://api-sandbox.sebgroup.com/mga/sps/authsvc?PolicyId=urn:ibm:security:authentication:asf:username_login&client_id=XXXXXXXXXXXX&response_type=code&scope=psd2_accounts psd2_payments&redirect_uri=https://testcallback.com/test&state=undefined
< p3p: CP="NON CUR OTPi OUR NOR UNI"
< x-frame-options: SAMEORIGIN
< Strict-Transport-Security: max-age=15552000; includeSubDomains
< Transfer-Encoding: chunked
< 
* Ignoring the response-body
* Connection #0 to host api-sandbox.sebgroup.com left intact
* Issue another request to this URL: 'https://api-sandbox.sebgroup.com/mga/sps/authsvc?PolicyId=urn:ibm:security:authentication:asf:username_login&client_id=XXXXXXXXXXXX&response_type=code&scope=psd2_accounts psd2_payments&redirect_uri=https://testcallback.com/test&state=undefined'
* Expire in 30000 ms for 8 (transfer 0x5572d97d6ad0)
* Found bundle for host api-sandbox.sebgroup.com: 0x5572d97744f0 [can pipeline]
* Could pipeline, but not asked to!
* Re-using existing connection! (#0) with host api-sandbox.sebgroup.com
* Connected to api-sandbox.sebgroup.com (129.178.54.70) port 443 (#0)
* Expire in 0 ms for 6 (transfer 0x5572d97d6ad0)
> GET /mga/sps/authsvc?PolicyId=urn:ibm:security:authentication:asf:username_login&client_id=XXXXXXXXXXXX&response_type=code&scope=**psd2_accounts psd2_payments**&redirect_uri=https://testcallback.com/test&state=undefined HTTP/1.1
Host: api-sandbox.sebgroup.com
Cookie: AMWEBJCT!%2Fmga!JSESSIONID=00009xuAYPuCp9GW43jcmC-CafK:f218d509-b31a-4e85-82f3-4026c87d2a41; TS01edf909=0107224bed281ed0132bcd33d1abd742777866cf59ada955adfb4e11b262eec4177bcfece6d5008e34b56a7ab37f409ab22798b97dd781fcdbe67b1d85c3acb10a1c21f2ca; TS01ef558a=0107224bed32bbf99c1c620e086bb40f0577a7d1fcada955adfb4e11b262eec4177bcfece69dd83308b2725dc487ace1c823d15bd6e2e5d0d2968f3683570ed32b96ea5da2; C0WNET=03758b02-5d3a-4321-a19f-1c022988e2f4
accept: text/html

< HTTP/1.1 400 Bad Request
< Cache-Control: no-cache
< Connection: close
< Content-Type: text/html; charset=utf-8
< Pragma: no-cache
< Content-Length: 246
< 
* Closing connection 0
如何对以下位置参数进行编码,使上述url自动成为

/mga/sps/authsvc?PolicyId=urn:ibm:security:authentication:asf:username_login&client_id=XXXXXXXXXXXX&response_type=code&scope=**psd2_accounts%20psd2_payments**&redirect_uri=https://testcallback.com/test&state=undefined

URL已按定义进行URL编码。否则它不是一个URL。根据定义,HTTP重定向应该重定向到URL,并且它们必须已经是URL编码的。不这样做违反了HTTP规范()。api-sandbox.sebgroup.com网站在重定向中未返回真实URL。也许你应该考虑联系他们并通知他们这个问题,因为CURL是一个非常常见的访问API的方法。 如果他们不能及时解决这个问题,我不建议只对
位置
标题进行url编码,因为他们可能会在将来解决这个问题,然后您将对url进行双重编码,这显然也是错误的。只有当它无效时,才需要对其进行URL编码

因此,我建议删除
CURLOPT\u FOLLOWLOCATION
选项,以确保它不遵循重定向,并添加
CURLOPT\u HEADERFUNCTION
,curl将为接收到的每个头调用该函数,urlcode对
位置
头进行编码,仅当存在且无效时,然后在循环中执行curl,直到没有
位置
头。由于URL中的空格违反了规范,PHP的
filter\u var()
函数正确地认为它是无效的

$url = 'https://example.com';

$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// this function is called by curl for each header received
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
    function($curl, $header) use (&$headers) {
        $len = strlen($header);
        $header = explode(':', $header, 2);
        if (count($header) < 2) {
            // ignore invalid headers
            return $len;
        }

        $name = strtolower(trim($header[0]));

        if ($name == 'location' && !filter_var(trim($header[1]), FILTER_VALIDATE_URL)) {
            $header[1] = urlencode(trim($header[1]));
        }

        $headers[$name][] = trim($header[1]);

        return $len;
    }
);

// Maximum number of redirects
$max_iterations = 10;
$iterations = 0;

do {
    $url = $headers['location'][0] ?? $url;
    $headers = [];
    curl_setopt($ch, CURLOPT_URL, $url);
    $data = curl_exec($ch);
    print_r($headers);

} while (isset($headers['location']) && ++$iterations < $max_iterations);
$url='1!'https://example.com';
$ch=curl_init();
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
//curl为接收到的每个标头调用此函数
卷曲设置($ch,卷曲设置头功能,
函数($curl,$header)使用(&$headers){
$len=strlen($header);
$header=分解(“:”,$header,2);
如果(计数($header)<2){
//忽略无效的标题
返回$len;
}
$name=strtolower(修剪($header[0]);
如果($name=='location'&&!filter\u var(trim($header[1]),filter\u VALIDATE\u URL)){
$header[1]=urlencode(trim($header[1]);
}
$headers[$name][]=trim($header[1]);
返回$len;
}
);
//最大重定向数
$max_迭代次数=10;
$iterations=0;
做{
$url=$headers['location'][0]??$url;
$headers=[];
curl_setopt($ch,CURLOPT_URL,$URL);
$data=curl\u exec($ch);
打印(页眉);
}而(isset($headers['location'])&&+$iterations<$max\u iterations);

its在名称中
urlencode()
$url = 'https://example.com';

$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// this function is called by curl for each header received
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
    function($curl, $header) use (&$headers) {
        $len = strlen($header);
        $header = explode(':', $header, 2);
        if (count($header) < 2) {
            // ignore invalid headers
            return $len;
        }

        $name = strtolower(trim($header[0]));

        if ($name == 'location' && !filter_var(trim($header[1]), FILTER_VALIDATE_URL)) {
            $header[1] = urlencode(trim($header[1]));
        }

        $headers[$name][] = trim($header[1]);

        return $len;
    }
);

// Maximum number of redirects
$max_iterations = 10;
$iterations = 0;

do {
    $url = $headers['location'][0] ?? $url;
    $headers = [];
    curl_setopt($ch, CURLOPT_URL, $url);
    $data = curl_exec($ch);
    print_r($headers);

} while (isset($headers['location']) && ++$iterations < $max_iterations);