ThinkPHP 5接入PayPal 支付,PayPal的流程是服务器请求Paypal的接口下单(需要传订单id/支付成功的重定向地址/支付失败的重定向地址),接会返回一个支付地址,项目服务器把地址返给用户,用户打开链接登录Paypal完成付款,然后Paypal给重定向到指定地址。
在paypal官网开通商户号,设置通知地址。
开通沙箱模式用于测试,后台会给沙箱模式生成商户账号和用户账号,请注意区分。
申请和开通网上有教程不在赘述。
具体实现步骤如下
1.安装包
composer require paypal/rest-api-sdk-php:*
2.具体实现代码
<?php
namespace app\api\controller;
use app\common\controller\Api;
use app\common\model\ShopOrder;
use PayPal\Api\Amount;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\Transaction;
use PayPal\Api\PaymentExecution;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Rest\ApiContext;
use PayPal\Api\RedirectUrls;
use think\Log;
class Paypal extends Api
{
protected $noNeedLogin = ['*'];
protected $noNeedRight = ['*'];
private $apiContext;
public function __construct()
{
parent::__construct();
// 初始化PayPal API上下文
$this->apiContext = new ApiContext(
new OAuthTokenCredential(
'AV8d**************************N-jbpRvV-K0_dLuEA5d8uodUowab6jdWtM', // 客户端ID
'EByrRAncAi*****************************RSqIRA' // 客户端密钥
)
);
$this->apiContext->setConfig([
'mode' => 'sandbox', // 或者 'live'
// 其他配置...
]);
}
/**
* 下单接口
* @return \think\response\Json|void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function createPaypalPaymentUrl()
{
// 获取前端传递的order_Id
$orderId = input('post.order_id');
// 查询订单信息(这里你需要根据自己的数据库结构进行查询)
// 假设我们得到了一个包含订单详情的数组$orderInfo
$orderInfo = ShopOrder::where('id', $orderId)->where('status', '1')->find();
if (empty($orderInfo)) {
$this->error('订单不存在或不是待支付状态');
}
// 设置Payer信息,表明付款人是通过PayPal付款
$payer = new Payer();
$payer->setPaymentMethod("paypal");
// 设置交易金额
$amount = new Amount();
$amount->setCurrency("AUD")
->setTotal(number_format($orderInfo['actual_money'], 2, '.', ''));
// 创建Transaction对象,并使用订单ID作为发票号
$transaction = new Transaction();
$transaction->setAmount($amount)
->setDescription("Slem order pay") // 描述可选
->setInvoiceNumber($orderInfo->order_num); // 使用订单order_num作为发票号
// 创建RedirectUrls对象
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl("https://*******.cn/api/paypal/paymentSuccess") // 支付成功后的回调地址
->setCancelUrl("https://********/api/paypal/paymentCancel"); // 用户取消支付后的回调地址
// 创建Payment对象
$payment = new Payment();
$payment->setIntent("sale")
->setPayer($payer)
->setRedirectUrls($redirectUrls)
->setTransactions([$transaction]);
try {
// 创建支付请求
$payment->create($this->apiContext);
// 获取approval_url,这是用户需要访问来完成支付的URL
foreach ($payment->getLinks() as $link) {
if ($link->getRel() == 'approval_url') {
// 返回支付链接给客户端
return json(['code' => 1, 'data' => $link->getHref()]);
// $data = ['status' => 'success', 'approval_url' => $link->getHref()];
// $this->success(__('SUccess'),$data);
}
}
} catch (\Exception $ex) {
// 输出详细的错误信息
return json([
'status' => 'error',
'message' => 'Error creating PayPal payment: ' . $ex->getMessage(),
'details' => $ex->getTraceAsString(),
'response' => $payment->toArray()
]);
}
}
/**
* 支付成功跳转的页面
* 建议前端出个html后台做渲染,本方法只为展示流程
* @return \think\response\Json
*/
public function paymentSuccess()
{
// 获取PayPal传递过来的参数
$paymentId = input('get.paymentId');
$payerId = input('get.PayerID');
if (empty($paymentId) || empty($payerId)) {
return json(['status' => 'error', 'message' => 'Missing payment ID or payer ID']);
}
try {
// 获取支付信息
$payment = Payment::get($paymentId, $this->apiContext);
// 创建PaymentExecution对象并设置payer_id
$execution = new PaymentExecution();
$execution->setPayerId($payerId);
// 执行支付请求
$result = $payment->execute($execution, $this->apiContext);
// 检查支付状态
if ($result->getState() === 'approved') {
// 使用发票号(即订单ID)来查找订单
$invoiceNumber = $payment->getTransactions()[0]->getInvoiceNumber();
$order = ShopOrder::where('order_num', $invoiceNumber)->find();
if (!empty($order)) {
// 更新订单状态为已支付
$order->payment = 'paypal';
$order->status = '2';
$order->save();
// 你可以在这里添加更多的业务逻辑,比如发送确认邮件等
// 返回成功信息给前端
return json(['status' => 'success', 'message' => 'Payment successful']);
} else {
return json(['status' => 'error', 'message' => 'Order not found']);
}
} else {
return json(['status' => 'error', 'message' => 'Payment not approved']);
}
} catch (\Exception $ex) {
// 错误处理
Log::error('PayPal Error: ' . $ex->getMessage());
return json([
'status' => 'error',
'message' => 'Error executing payment: ' . $ex->getMessage(),
'details' => $ex->getTraceAsString()
]);
}
}
/**
* 支付取消跳转的页面
* @return \think\response\Json
*/
public function paymentCancel()
{
// 获取订单ID或其他相关信息(如果需要)
$orderId = input('get.order_id'); // 如果PayPal回调包含order_id
if (!empty($orderId)) {
try {
// 根据订单ID查找订单信息
$order = ShopOrder::where('id', $orderId)->find();
if (!empty($order)) {
// 你可以在这里添加更多的业务逻辑,比如记录取消原因、发送通知等
// 更新订单状态为已取消或保持不变,视业务需求而定
// 这里假设我们不改变订单状态,仅记录取消事件
Log::info("Payment cancelled for order ID: " . $orderId);
// 返回取消信息给前端
return json(['status' => 'info', 'message' => 'Payment cancelled.']);
} else {
return json(['status' => 'error', 'message' => 'Order not found.']);
}
} catch (\Exception $ex) {
// 错误处理
Log::error('Error handling payment cancellation: ' . $ex->getMessage());
return json([
'status' => 'error',
'message' => 'An error occurred while processing your request.',
'details' => $ex->getTraceAsString()
]);
}
} else {
// 如果没有提供订单ID,则简单地告知用户支付已被取消
return json(['status' => 'info', 'message' => 'Payment cancelled.']);
}
}
}