我一直试图通过this interactive tutorial page上的示例找出PHP SDK。我稍微修改了代码以适应我自己的应用程序的目的,并包括我自己的clientId和clientSecret,但不足以构成一个重大违规。您将在下面的注释代码中看到我所做的更改。
我的问题是payment-> create()方法不接受我的凭据。它正在抛出400代码异常,并显示消息“Invalid Credentials”。我做错了什么?
代码:(输出如下)
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
//I wrote the PayPalAutoloader and stored it in the PayPal folder.
//the autoloader uses the namespace data to parse the folder structure
//and loads the corresponding object or throws an Exception if the file
//is not found.
require_once 'PayPal-PHP-SDK/PayPalAutoloader.php';
//added my own INI file, where I can store API related values.
$ini = \parse_ini_file('libsec.ini', true);
$clientId = $ini['PayPal']['clientId'];
$clientSecret = $ini['PayPal']['clientSecret'];
//Step 1 of 5 from website
$sdkConfig = [ "mode" => "sandbox"];
$oauthCredential = new \PayPal\Auth\OAuthTokenCredential($clientId, $clientSecret, $sdkConfig);
$apiContext = new \PayPal\Rest\ApiContext($oauthCredential);
//end Step 1 of 5
//observation, apiContext is never actually used in Step 1 and is redefined in Step 2
//I found that to send the request I had to call getAccessToken (not mentioned in interactive tutorial)
$accessToken = $oauthCredential->getAccessToken($sdkConfig);
//peaking at the accessToken value
var_dump( $accessToken );
//Begin Step 2 of 5 from website
//reuse sdkConfig from Step 1, it is unchanged
$credentials = "Bearer {$accessToken}";
$apiContext = new \PayPal\Rest\ApiContext($credentials, 'Request' . time() );
$apiContext->setConfig($sdkConfig);
$payer = new \PayPal\Api\Payer();
$payer->setPaymentMethod("paypal");
$amount = new \PayPal\Api\Amount();
$amount->setCurrency("USD");
$amount->setTotal("483.00");
$transaction = new \PayPal\Api\Transaction();
$transaction->setDescription("Annual Dues");
$transaction->setAmount($amount);
//removed as $baseURL is not actually used by any of the code that follows.
//the results of the code are the same after commenting out the baseURL variable.
//$baseUrl = getBaseUrl();
$rootURL = $ini['General']['rootURL'];
$successfulTransactionURL = $rootURL . $ini['PayPal']['success_bill_pay'];
$cancelledTransactionURL = $rootURL . $ini['PayPal']['cancel_bill_pay'];
$redirectUrls = new \PayPal\Api\RedirectUrls();
$redirectUrls->setReturnUrl($successfulTransactionURL);
$redirectUrls->setCancelUrl($cancelledTransactionURL);
$payment = new \PayPal\Api\Payment();
$payment->setIntent("sale");
$payment->setPayer($payer);
$payment->setRedirectUrls($redirectUrls);
$payment->setTransactions($transaction);
//a var_dump is added in the create method to look at the payment formatted as JSON prior to the
//REST API call.
$result = $payment->create($apiContext);
//peaking at result
var_dump( $result );
?>
</body>
</html>
以上输出是来自同一程序运行的3个独立输出实例。第一个字符串是$ accessToken的var_dump(),用于验证是否正在检索令牌。每次运行都会成功检索此令牌,并且值会更改。
第二个输出是在Payment :: create()方法中形成的$ json对象的var_dump。这个json对象被传递给API系统,用于通过POST方法对硬编码地址“/ v1 / payments / payment”进行REST调用。
输出的第三部分是Exception,它已传播到屏幕并阻止完成Payment :: create()方法。
答案 0 :(得分:1)
在进一步调查中,问题出现在指定行的RestHandler中。代码如下:
if ($credential == null || !($credential instanceof OAuthTokenCredential)) {
throw new PayPalInvalidCredentialException("Invalid credentials passed");
}
但是,当我转储$ credential变量时,我有:
string 'Bearer A015kCDeXpDfAvtTj7dbRg7ldRk-OdKboQhPaY4EmYu-bRA' (length=54)
必须在编写教程时更新SDK。不幸的是,仍然存在从PayPal的API文档到这个过时的交互式教程的链接。
事实证明,当我在OAuthTokenCredential对象上调用“getAccessToken”时,它会准备将来再次使用。我不需要存储结果并创建“承载”。 $ token字符串。我只是再次使用相同的OAuthTokenCredential,一切正常。
在找到解决方案的过程中,我删除了我的代码并从网站上复制了代码,演示修复的工作代码如下:
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
//I wrote the PayPalAutoloader and stored it in the PayPal folder.
//the autoloader uses the namespace data to parse the folder structure
//and loads the corresponding object or throws an Exception if the file
//is not found.
require_once 'PayPal-PHP-SDK/PayPalAutoloader.php';
echo "<h2>Success</h2>";
//added my own INI file, where I can store API related values.
$sdkConfig = array(
"mode" => "sandbox"
);
$cred = new \PayPal\Auth\OAuthTokenCredential("AQkquBDf1zctJOWGKWUEtKXm6qVhueUEMvXO_-MCI4DQQ4-LWvkDLIN2fGsd", "EL1tVxAjhT7cJimnz5-Nsx9k2reTKSVfErNQF-CmrwJgxRtylkGTKlU4RvrX", $sdkConfig);
//storing the result is not needed, because the result automatically updates the same credential object.
//we will use the variable $cred as is and forget about the accessToken. We also will not set a "Bearer" string for the header"
$accessToken = $cred->getAccessToken($sdkConfig);
//peaking at the credential object to verify that the accessToken is listed.
var_dump( $cred );
//peaking at the accessToken value
var_dump($accessToken);
//Begin Step 2 of 5 from website
$sdkConfig = array(
"mode" => "sandbox"
);
//we comment out the redefinition of cred in Step2.... We will use the OAuthtokenCredential from Step 1,
//which is also stored in $cred at this point.
//$cred = "Bearer {$accessToken}";
$apiContext = new \PayPal\Rest\ApiContext($cred, 'Request' . time());
$apiContext->setConfig($sdkConfig);
$payer = new \PayPal\Api\Payer();
$payer->setPaymentMethod("paypal");
$amount = new \PayPal\Api\Amount();
$amount->setCurrency("USD");
$amount->setTotal("12");
$transaction = new \PayPal\Api\Transaction();
$transaction->setDescription("creating a payment");
$transaction->setAmount($amount);
$redirectUrls = new \PayPal\Api\RedirectUrls();
$redirectUrls->setReturnUrl("https://devtools-paypal.com/guide/pay_paypal/php?success=true");
$redirectUrls->setCancelUrl("https://devtools-paypal.com/guide/pay_paypal/php?cancel=true");
$payment = new \PayPal\Api\Payment();
$payment->setIntent("sale");
$payment->setPayer($payer);
$payment->setRedirectUrls($redirectUrls);
$payment->setTransactions(array($transaction));
var_dump( $payment->create($apiContext) );
//the payment object is successfully updated with the payment id.
?>
</body>
</html>