php - 无法在 SSL 网站上使用 Paypal API

标签 php ssl curl paypal paypal-sandbox

我有一个使用 cURL 与 Paypal API 集成的 SSL 网站。

这是我的 PHP 类(class)包含文件:

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,但在完成该过程后,它将用户带回网站,url 似乎是正确的(例如 https://example.com/pro&type=successful?token=EC-8BB04791XJ708490K&PayerID=QL54Q696KZCLA) 但没有付款。

我也尝试了沙箱,但我在 Apache 日志文件中看不到任何错误,所以我需要调试 $response,因此我尝试添加 echo var_dump($response ); 在解析响应之前。

但是我没有太多的调试经验,在 Chrome 上我不知道去哪里查看响应。(在 JS 控制台上我看不到)

我如何调试此 API 响应以检查为什么 paypal 不允许为我的网站付款? (该网站已经过验证)

更新

作为身份验证,我使用 API 签名 NVP 格式和 SetExpressCheckout 方法。

这是我的回复代码:

        // 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', '<strong>'.urldecode($paypalResponse['L_SHORTMESSAGE0'].'</strong>: '.$paypalResponse['L_LONGMESSAGE0']));
                    }
                } else {
                    $TMPL['error'] = notificationBox('error', '<strong>'.urldecode($paypalResponse['L_SHORTMESSAGE0'].'</strong>: '.$paypalResponse['L_LONGMESSAGE0']));
                }
            } else {
                $TMPL['error'] = notificationBox('error', '<strong>'.urldecode($paypalResponse['L_SHORTMESSAGE0'].'</strong>: '.$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 电话,获取您的 token 并将用户传递给 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") {

这没有任何意义。您刚刚使用 header 将用户退回到 PayPal,我们调用它时使用的数据似乎与我们传递给 SEC 调用的数据相同。 DoExpressCheckoutPayment 要求您传回 token 并且用户刚刚离开站点以对其进行授权。我希望看到您的代码查找 $_GET['TOKEN'](表示用户从 PayPal 返回),然后为此构建一个请求。现在,当您编写代码时,它只是将所有 3 个调用链接到一个巨大的链中。

流程应该是这样的

  • SetExpressCheckout - 将用户跳转到 PayPal。停止处理
  • GetExpressCheckoutDetails - 用户已从 PayPal 返回,因为我们在查询字符串中有一个 token 。现在运行此调用让我们确保 token 有效
  • DoExpressCheckoutPayment - 如果 token 有效,让我们完成销售。

最后但同样重要的是,您不能只寻找成功Read the docs on ACK .您还可以获得SuccessWithWarning。将您的成功条件更改为

 if(stripos($paypalResponse["ACK"], "SUCCESS") !== false) {

关于php - 无法在 SSL 网站上使用 Paypal API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34452327/

相关文章:

java - SSL 连接被 NEED_WRAP 拒绝

php - 将 "data-binary"从 cURL 翻译成 PHP

javascript - php ajax 实时数据库搜索或一个查询,获取所有要搜索的结果

php - 尝试在 Mac OS lion 上的 MAMP 中使用 PECL 安装 OAUTH 时出现问题

azure - 用于 SSL 卸载的 Azure 应用程序网关的 SSL 证书

ruby-on-rails - Letsencrypt Solr SSL JVM

php - 如何通过 curl/wget/file_get_contents 使用不同的 IP?

通过 XMPP 与 talk.google.com curl

php - 如何在 codeigniter 中插入具有多个单选名称的单选按钮值?

php - 如何在laravel php中使用ajax根据日期范围从mysql数据库检索数据?