我有一个使用cURL与Paypal API集成的SSL网站.
这是我的PHP包括文件类:
class paypalApi { public $username; public $password; public $signature; function post($method, $params, $mode) { // Method: Required // Parameters: An array containing the requested parameters // The request URL $url = "https://api-3t".$mode.".paypal.com/nvp"; // Version of the API $version = '116.0'; // Construct the query params // Set the API method, version, and API credentials. $credentials = array('METHOD' => $method, 'VERSION' => $version, 'USER' => $this->username, 'PWD' => $this->password, 'SIGNATURE' => $this->signature); $params = array_merge($credentials, $params); // Set the curl parameters. if(function_exists('curl_exec')) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_VERBOSE, 1); // Turn off the server and peer verification (TrustManager Concept). curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params)); $response = curl_exec($ch); } if(empty($response)) { $opts = array('http' => array( 'protocol_version' => '1.1', 'method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => http_build_query($params) ) ); $context = stream_context_create($opts); $response = file_get_contents($url, false, $context); } // Parse the response parse_str($response, $responseArr); // If the request fails if(empty($responseArr) || !array_key_exists('ACK', $responseArr)) { global $LNG; // Mimic a fake response return array('L_SHORTMESSAGE0' => $LNG['error'], 'L_LONGMESSAGE0' => $LNG['payment_error_0'], 'ACK' => 'REQUEST_FAILED'); } return $responseArr; } }
由于某种原因,它不起作用,点击付费按钮将用户带到Paypal,但在完成该过程后,它将用户带回网站,该网址似乎是正确的(例如https://example.com/pro&type=successful?token=EC-8BB04791XJ708490K&PayerID=QL54Q696KZCLA
),但没有付款.
我也尝试了沙盒,但我在Apache日志文件中看不到任何错误,所以我需要调试$response
,因此我尝试echo var_dump($response);
在解析响应之前添加.
但我没有太多调试经验,在Chrome上我不知道在哪里检查响应.(在JS控制台上我看不到它)
我如何调试此API响应以检查为什么paypal不允许我的网站付款?(该网站已经过验证)
UPDATE
作为身份验证我正在使用带有SetExpressCheckout
方法的API签名NVP格式.
这是我的回复代码:
// Execute SetExpressCheckOut method to create the payment token and PayerID $paypalResponse = $paypal->post('SetExpressCheckout', $params, $PayPalMode); //Respond according to message we receive from Paypal if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") { // Generat the PayPal payment url with the response Token $paypalurl = 'https://www'.$PayPalMode.'.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='.$paypalResponse["TOKEN"].''; // Redirect to PayPal payment page header('Location: '.$paypalurl); // Execute DoExpressCheckoutPayment to receive the payment from the user $paypalResponse = $paypal->post('DoExpressCheckoutPayment', $params, $PayPalMode); // Check if the payment was successful if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") { // Verify if the payment is Completed if($paypalResponse["PAYMENTINFO_0_PAYMENTSTATUS"] == 'Completed') { // Execute GetExpressCheckoutDetails to retrieve the transaction details $params = array('TOKEN' => $token); $paypalResponse = $paypal->post('GetExpressCheckoutDetails', $params, $PayPalMode); // If the GetExpressCheckoutDetails was successful if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") { $date = date("Y-m-d H:m:s", strtotime(($_SESSION['SelectedPlan'] == 1 ? "+1 year" : "+1 month"))); $stmt = $db->prepare(sprintf("INSERT INTO `payments` (`by`, `payer_id`, `payer_first_name`, `payer_last_name`, `payer_email`, `payer_country`, `txn_id`, `amount`, `currency`, `type`, `status`, `valid`, `time`) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s','%s', '%s', '%s', '%s')", $db->real_escape_string($feed->id), $db->real_escape_string($paypalResponse['PAYERID']), $db->real_escape_string($paypalResponse['FIRSTNAME']), $db->real_escape_string($paypalResponse['LASTNAME']), $db->real_escape_string($paypalResponse['EMAIL']), $db->real_escape_string($paypalResponse['SHIPTOCOUNTRYNAME']), $db->real_escape_string($paypalResponse['PAYMENTREQUEST_0_TRANSACTIONID']), $db->real_escape_string($paypalResponse['AMT']), $settings['currency'], $_SESSION['SelectedPlan'], 1, $date, date("Y-m-d H:m:s"))); // Execute the statement $stmt->execute(); // Check the affected rows $affected = $stmt->affected_rows; // Close the statement $stmt->close(); // If the pro status has been added if($affected) { // Set the pro account to valid $proAccount = 2; } } else { $TMPL['error'] = notificationBox('error', ''.urldecode($paypalResponse['L_SHORTMESSAGE0'].': '.$paypalResponse['L_LONGMESSAGE0'])); } } else { $TMPL['error'] = notificationBox('error', ''.urldecode($paypalResponse['L_SHORTMESSAGE0'].': '.$paypalResponse['L_LONGMESSAGE0'])); } } else { $TMPL['error'] = notificationBox('error', ''.urldecode($paypalResponse['L_SHORTMESSAGE0'].': '.$paypalResponse['L_LONGMESSAGE0'])); } }
编辑
这是我的error.log文件:
* Hostname was NOT found in DNS cache * Trying 173.0.82.83... * Connected to api-3t.sandbox.paypal.com (173.0.82.83) port 443 (#0) * successfully set certificate verify locations: * CAfile: none CApath: /etc/ssl/certs * SSL connection using *********************** * Server certificate: * subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api-3t.sandbox.paypal.com * start date: 2015-09-16 00:00:00 GMT * expire date: 2016-10-31 23:59:59 GMT * issuer: C=US; O=VeriSign, Inc.; OU=VeriSign Trust Network; OU=Terms of use at https://www.verisign.com/rpa (c)10; CN=VeriSign Class 3 Secure Server CA - G3 * SSL certificate verify ok. > POST /nvp HTTP/1.1 Host: api-3t.sandbox.paypal.com Accept: */* Content-Length: 862 Content-Type: application/x-www-form-urlencoded * upload completely sent off: 862 out of 862 bytes < HTTP/1.1 200 OK < Date: Wed, 30 Dec 2015 09:49:59 GMT * Server Apache is not blacklisted < Server: Apache < X-PAYPAL-OPERATION-NAME: SetExpressCheckout < X-PAYPAL-API-RC: < Connection: close < Content-Length: 138 < Paypal-Debug-Id: 7d9949c818525 < Set-Cookie: X-PP-SILOVER=name%3DSANDBOX3.API.1%26silo_version%3D880%26app%3Dappdispatcher_apit%26TIME%3D3349709654; domain=.paypal.com; path=/; Secure; HttpOnly < Set-Cookie: X-PP-SILOVER=; Expires=Thu, 01 Jan 1970 00:00:01 GMT < Content-Type: text/plain; charset=utf-8 * Closing connection 0
第二次编辑
最后我能够调试响应(存在重定向问题)
TOKEN=EC-9F8624569H0752611 BILLINGAGREEMENTACCEPTEDSTATUS=0 CHECKOUTSTATUS=PaymentActionCompleted TIMESTAMP=2015-12-30T15:41:54Z CORRELATIONID=19204729b140 ACK=Success VERSION=116.0 BUILD=18308778 EMAIL=info-buyer@example.org PAYERID=QL54Q696KZCLA PAYERSTATUS=verified FIRSTNAME=test LASTNAME=buyer COUNTRYCODE=IT SHIPTONAME=test buyer SHIPTOSTREET=Via Unit? d\'Italia, 5783296 SHIPTOCITY=Napoli SHIPTOSTATE=NAPOLI SHIPTOZIP=80127 SHIPTOCOUNTRYCODE=IT SHIPTOCOUNTRYNAME=Italy ADDRESSSTATUS=Unconfirmed CURRENCYCODE=EUR AMT=4.00 ITEMAMT=4.00 SHIPPINGAMT=0.00 HANDLINGAMT=0.00 TAXAMT=0.00 INSURANCEAMT=0.00 SHIPDISCAMT=0.00 L_NAME0=Monthly Pro Plan - example subdirectory L_NUMBER0=cfcd208495d565ef66e7dff9f98764da L_QTY0=1 L_TAXAMT0=0.00 L_AMT0=4.00 L_DESC0=Monthly Pro Plan - example subdirectory L_ITEMWEIGHTVALUE0= 0.00000 L_ITEMLENGTHVALUE0= 0.00000 L_ITEMWIDTHVALUE0= 0.00000 L_ITEMHEIGHTVALUE0= 0.00000 PAYMENTREQUEST_0_CURRENCYCODE=EUR PAYMENTREQUEST_0_AMT=4.00 PAYMENTREQUEST_0_ITEMAMT=4.00 PAYMENTREQUEST_0_SHIPPINGAMT=0.00 PAYMENTREQUEST_0_HANDLINGAMT=0.00 PAYMENTREQUEST_0_TAXAMT=0.00 PAYMENTREQUEST_0_INSURANCEAMT=0.00 PAYMENTREQUEST_0_SHIPDISCAMT=0.00 PAYMENTREQUEST_0_TRANSACTIONID=61M42051UB346361T PAYMENTREQUEST_0_INSURANCEOPTIONOFFERED=false PAYMENTREQUEST_0_SHIPTONAME=test buyer PAYMENTREQUEST_0_SHIPTOSTREET=Via Unit? d\'Italia, 5783296 PAYMENTREQUEST_0_SHIPTOCITY=Napoli PAYMENTREQUEST_0_SHIPTOSTATE=NAPOLI PAYMENTREQUEST_0_SHIPTOZIP=80127 PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE=IT PAYMENTREQUEST_0_SHIPTOCOUNTRYNAME=Italy PAYMENTREQUEST_0_ADDRESSSTATUS=Unconfirmed PAYMENTREQUEST_0_ADDRESSNORMALIZATIONSTATUS=None L_PAYMENTREQUEST_0_NAME0=Monthly Pro Plan - example subdirectory L_PAYMENTREQUEST_0_NUMBER0=cfcd208495d565ef66e7dff9f98764da L_PAYMENTREQUEST_0_QTY0=1 L_PAYMENTREQUEST_0_TAXAMT0=0.00 L_PAYMENTREQUEST_0_AMT0=4.00 L_PAYMENTREQUEST_0_DESC0=Monthly Pro Plan - example subdirectory L_PAYMENTREQUEST_0_ITEMWEIGHTVALUE0= 0.00000 L_PAYMENTREQUEST_0_ITEMLENGTHVALUE0= 0.00000 L_PAYMENTREQUEST_0_ITEMWIDTHVALUE0= 0.00000 L_PAYMENTREQUEST_0_ITEMHEIGHTVALUE0= 0.00000 PAYMENTREQUESTINFO_0_TRANSACTIONID=61M42051UB346361T PAYMENTREQUESTINFO_0_ERRORCODE=0
所以,从我这边一切都工作正常,但我看到没有关于沙盒Paypal的交易.怎么了?
你的过程似乎非常复杂.让我们打破这个
// Execute SetExpressCheckOut method to create the payment token and PayerID $paypalResponse = $paypal->post('SetExpressCheckout', $params, $PayPalMode); //Respond according to message we receive from Paypal if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") { // Generat the PayPal payment url with the response Token $paypalurl = 'https://www'.$PayPalMode.'.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='.$paypalResponse["TOKEN"].''; // Redirect to PayPal payment page header('Location: '.$paypalurl);
到现在为止还挺好.您进行SEC呼叫,获取令牌并将用户传递给PayPal.但接下来的部分令人困惑
// Execute DoExpressCheckoutPayment to receive the payment from the user $paypalResponse = $paypal->post('DoExpressCheckoutPayment', $params, $PayPalMode); // Check if the payment was successful if(strtoupper($paypalResponse["ACK"]) == "SUCCESS") {
这没有任何意义.您刚刚将用户退回到PayPal,header
我们称之为与我们传递给SEC电话的数据相同.DoExpressCheckoutPayment
要求您传回令牌,用户刚离开网站进行授权.我希望看到你的代码寻找$_GET['TOKEN']
(意味着用户从PayPal返回),然后为此构建一个新的请求.现在,在编写代码时,它只是在一个巨链中链接所有3个调用.
这是过程应该是什么样子
SetExpressCheckout
- 将用户退回到PayPal.停止处理
GetExpressCheckoutDetails
- 用户已从PayPal返回,因为我们在查询字符串中有一个TOKEN.现在运行此调用可以确保TOKEN有效
DoExpressCheckoutPayment
- 如果TOKEN有效,我们完成销售.
最后但并非最不重要的是,你不能只寻找成功.阅读关于ACK的文档.您还可以获得SuccessWithWarning.将您的成功条件更改为
if(stripos($paypalResponse["ACK"], "SUCCESS") !== false) {