通过php composer下载sdk:
composer require paypal/rest-api-sdk-php
或github下载:
git clone https://github.com/paypal/PayPal-PHP-SDK.git
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>";
}
}
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;
}