为何PayPal Sandbox数据通过GET可转发,cURL却失效?
PayPal cURL跳转失败问题排查
我尝试绕过PayPal官方推荐的经典表单,用cURL传递交易数据,但遇到了问题:
正常工作的GET方法代码
$fields = [ 'business' => 'xxxxxxxxxxxxxxxxx@business.example.com', 'cmd' => '_xclick', 'return' => 'https://www.examplemysite.com/thank_you.php', 'cancel_return' => 'https://www.examplemysite.com/cart.php', 'notify_url' => 'https://www.examplemysite.com/ipn.php', 'rm' => '2', 'currency_code' => 'EUR', 'lc' => 'IT', 'cbt' => 'Continua', 'shipping' => $_POST['shipping'], 'cs' => '1', 'item_name' => $_POST['item_name'], 'amount' => $_POST['amount'], 'custom' => $_POST['custom'], 'first_name' => $_POST['first_name'], 'last_name' => $_POST['last_name'], 'address1' => $_POST['address1'], 'city' => $_POST['city'], 'state' => $_POST['state'], 'zip' => $_POST['zip'], 'note' => $_POST['note'], 'email' => $_POST['email'] ]; $fields_string = http_build_query($fields); header('Location: https://ipnpb.sandbox.paypal.com/cgi-bin/webscr?' . $fields_string); exit;
无法正常跳转的cURL代码
$fields = [ 'business' => 'xxxxxxxxxxxxxxxxx@business.example.com', 'cmd' => '_xclick', 'return' => 'https://www.examplemysite.com/thank_you.php', 'cancel_return' => 'https://www.examplemysite.com/cart.php', 'notify_url' => 'https://www.examplemysite.com/ipn.php', 'rm' => '2', 'currency_code' => 'EUR', 'lc' => 'IT', 'cbt' => 'Continua', 'shipping' => $_POST['shipping'], 'cs' => '1', 'item_name' => $_POST['item_name'], 'amount' => $_POST['amount'], 'custom' => $_POST['custom'], 'first_name' => $_POST['first_name'], 'last_name' => $_POST['last_name'], 'address1' => $_POST['address1'], 'city' => $_POST['city'], 'state' => $_POST['state'], 'zip' => $_POST['zip'], 'note' => $_POST['note'], 'email' => $_POST['email'] ]; $fields_string = http_build_query($fields); $ch = curl_init(); //set the url, number of POST vars, POST data curl_setopt($ch, CURLOPT_URL, 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr'); curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string); curl_setopt($ch, CURLOPT_SSLVERSION, 6); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_FORBID_REUSE, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); //execute post $result = curl_exec($ch); echo $result;
问题现象
执行cURL代码后,地址栏仍显示我的网站地址(本应跳转到PayPal),显示的地址示例:www.examplemysite.com/signin?intent=checkout&ctxId=xo_ctx_XXXXXXXXXXXX&returnUri=%2Fwebapps%2Fhermes&state=%3Fflow%3D1-P%26ulReturn%3Dtrue%26token%3D4EY4066234167522P%26useraction%3Dcommit%26rm%3D2%26mfid%3D1668497487713_32d532f25ea2c%26rcache%3D2%26cookieBannerVariant%3D1%26targetService4174%3Dxorouternodeweb&locale.x=it_IT&country.x=IT&flowId=4EY4066234167522P
问题原因
- 请求逻辑完全错误:GET方式是让用户浏览器直接发起请求到PayPal,地址栏自然切换;而cURL是服务器端向PayPal发起请求,再把返回内容输出到当前页面,用户相当于一直在你的网站页面查看PayPal的返回内容,地址栏不会改变。
- PayPal设计限制:
_xclick这类快捷支付命令是给用户浏览器直接访问用的,服务器端请求时,PayPal因无法获取用户端的会话Cookie,会返回登录页的HTML内容,你把这个内容echo出来,就会在你的网站域名下显示PayPal登录界面。 - 会话隔离问题:服务器端cURL的会话与用户浏览器的会话完全独立,PayPal无法识别用户状态,因此会要求登录,而非直接进入支付流程。
解决方法
- 最简方案:继续使用
header("Location")的GET跳转方式,这是PayPal预期的前端跳转流程,完全符合需求。 - 官方推荐方案:用前端表单POST提交到PayPal,浏览器直接发起请求到PayPal,地址栏会切换,同时满足POST提交数据的需求。
- 服务器端处理方案:改用PayPal REST API创建支付订单,拿到支付链接后引导用户跳转,这种方式需先调用API获取授权链接再做跳转。
内容的提问来源于stack exchange,提问作者Roberto Rocco
相关产品推荐
相关产品推荐

