PayPal sdk v1版本php开发支付过程

袁轶
2023-12-01

首先PayPal官网下载PHP版SDK程序

通过php composer下载sdk:
composer require paypal/rest-api-sdk-php
或github下载:
git clone https://github.com/paypal/PayPal-PHP-SDK.git

PayPal入口程序

bootstrap.php

<?php
require 'autoload.php';
require 'common.php';

use PayPal\Auth\OAuthTokenCredential;
use PayPal\Rest\ApiContext;

// Suppress DateTime warnings, if not set already
//date_default_timezone_set(@date_default_timezone_get());
// Adding Error Reporting for understanding errors properly
error_reporting(0);
ini_set('display_errors', '1');
//引入支付配置文件
require ROOT . 'config/api/pay/pay.php';
// Replace these values by entering your own ClientId and Secret by visiting https://developer.paypal.com/developer/applications/

//配置参数
if ($_REQUEST['uid'] == 664590) {//某个用户测试sandbox
    //sandbox测试配置
    $clientId = TEST_PAYPAL_CLIENT_ID;
    $clientSecret = TEST_PAYPAL_CLIENT_SECRET;
    $mode = 'sandbox';
}
else {
    //live正式配置
    $clientId = PAYPAL_CLIENT_ID;
    $clientSecret = PAYPAL_CLIENT_SECRET;
    $mode = 'live';
}

$apiContext = getApiContext($clientId, $clientSecret, $mode);
return $apiContext;

/**
 * @param $clientId
 * @param $clientSecret
 * @param $mode //模式,sandbox或live
 * @return ApiContext
 */
function getApiContext($clientId, $clientSecret, $mode) {
    $apiContext = new ApiContext(
        new OAuthTokenCredential(
            $clientId,
            $clientSecret
        )
    );
    $apiContext->setConfig(
        array(
            'mode' => $mode,
            'cache.enabled' => true,
        )
    );
    return $apiContext;
}

pay.php

<?php

// # Create Billing Agreement with PayPal as Payment Source
//
// This sample code demonstrate how you can create a billing agreement, as documented here at:
// https://developer.paypal.com/webapps/developer/docs/api/#create-an-agreement
// API used: /v1/payments/billing-agreements

// Retrieving the Plan from the Create Update Sample. This would be used to
// define Plan information to create an agreement. Make sure the plan you are using is in active state.
/** @var Plan $createdPlan */
require 'bootstrap.php';

use PayPal\Api\Amount;
use PayPal\Api\Details;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;

$ordernum = $_REQUEST['ordernum'] ?? '';

//自定义参数
$custom = json_encode([
    'infoid' => $_REQUEST['infoid'],
    'ordernum' => $ordernum,
    'paidtime' => $_SERVER['REQUEST_TIME'],
    'returnUrl' => $retUrl,
]);

$amount = new Amount();
$amount->setCurrency("CAD")->setTotal($_REQUEST['payprice']);

$transaction = new Transaction();
$transaction->setAmount($amount)->setDescription($_REQUEST['desc'])->setCustom($custom)->setInvoiceNumber(uniqid());
$baseUrl = getBaseUrl();

$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl($baseUrl . '/ExecutePayment.php?success=true&paytype=paypal&ordernum=' . $ordernum . '&infoid=' . $_REQUEST['infoid'])->setCancelUrl($baseUrl . '/ExecutePayment.php?success=false&paytype=paypal&ordernum=' . $ordernum . '&infoid=' . $_REQUEST['infoid']);

$payer = new Payer();
$payer->setPaymentMethod("paypal");

$payment = new Payment();
$payment->setIntent("sale")->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions(array($transaction));
$request = clone $payment;
try {
    $payment->create($apiContext);
} catch (Exception $ex) {
    ResultPrinter::printError("Created Payment Using PayPal. Please visit the URL to Approve.", "Payment", null, $request, $ex);
    exit(1);
}
$approvalUrl = $payment->getApprovalLink();
header('Location:' . $approvalUrl);

支付回调程序

ExecutePayment.php

<?php
// #Execute Agreement
// This is the second part of CreateAgreement Sample.
// Use this call to execute an agreement after the buyer approves it

require 'bootstrap.php';

// ## Approval Status
use PayPal\Api\ExecutePayment;
use PayPal\Api\Payment;
use PayPal\Api\PaymentExecution;

// echo '<script>var FROM = "' . ($_GET['os'] ? 'app' : '') . '; var OS = "' . $_GET['os'] . '";</script>';
// Determine if the user accepted or denied the request
$infoid = (int)($_GET['infoid'] ?? 0);
$paymentId = Mstr()->encode($_GET['paymentId'] ?? '');
$ordernum = Mstr()->encode($_GET['ordernum'] ?? '');
if (isset($_GET['success']) && $_GET['success'] == 'true') {
    try {
        $payment = Payment::get($paymentId, $apiContext);
        $execution = new PaymentExecution();
        $execution->setPayerId(Mstr()->encode($_GET['PayerID'] ?? ''));
        $result = $payment->execute($execution, $apiContext); //这里如果支付失败,或异常则会抛出异常throw Exception,下面语句不会执行
        //记录支付成功状态程序
        echo "<script>goto('" . $returnUrl . "', 1, 1);</script>";
    } catch (Exception $ex) {
        echo "<script>goto('" . $returnUrl . "', 1, 1);</script>";
    }
}

webhook 签名验证和确认订单支付成功,修改订单状态

webhooks.php

<?php
//webhook 确认订单支付成功,修改订单状态

$headers = getallheaders();
$headers = array_change_key_case($headers, CASE_UPPER);
$body = file_get_contents('php://input');
$returnData = json_decode($body, true);

// 创建了webhook在PayPal开发者后台查找webhookId
$webhookId = '5BM77961TW281551X';
// 签名字符串
$signData = $headers['PAYPAL-TRANSMISSION-ID'] . '|' . $headers['PAYPAL-TRANSMISSION-TIME'] . '|' . $webhookId . '|' . crc32($body);

// 加载证书并提取公钥
$pubKey = openssl_pkey_get_public(file_get_contents($headers['PAYPAL-CERT-URL']));
$key = openssl_pkey_get_details($pubKey)['key'];

$signature = base64_decode($headers['PAYPAL-TRANSMISSION-SIG']);
//根据提供的签名验证数据
$verifyResult = openssl_verify(
    $signData,
    $signature,
    $key,
    'sha256WithRSAEncryption'
);

//签名验证成功
if ($verifyResult == 1) {
    //订单支付完成
    if ($returnData['event_type'] == 'PAYMENT.SALE.COMPLETED') {
        $ordernum = $returnData['resource']['invoice_number'];

        //由于webhook不能file_put_contents写入文件,将调试日志记录在数据库
        M('c')->insert('test_paypal', [
            'content' => json_encode($returnData),
            'log' => 'sigData:' . $signData . ' ++++ verifyResult:' . $verifyResult . ' ++++ key:' . $key . ' ++++ orderNo:' . $ordernum . ' ++++ headers:' . json_encode($headers),
        ]);

        //以下是支付成功修改订单状态程序
    }
    else {
        return 'Not Completed';
    }
}
else {
    return 'sign error';//签名验证失败 或请求错误
}
return 'success';

退款

function returnMoney()
{
    try {
        $txn_id = "xxxxxxx";  //异步加调中拿到的id
        $amt = new Amount();
        $amt->setCurrency('USD')->setTotal('99');  // 退款的费用
        $refund = new Refund();
        $refund->setAmount($amt);

        $sale = new Sale();
        $sale->setId($txn_id);

        $refundedSale = $sale->refund($refund, $this->PayPal);
    } catch (\Exception $e) {
        // PayPal无效退款
        return json_decode(json_encode(['message' => $e->getMessage(), 'code' => $e->getCode(), 'state' => $e->getMessage()]));  // to object
    }
    // 退款完成
    return $refundedSale;
}
 类似资料: