PHP
<?php
namespace PayPal;
use think\Cache;
class Pay
{
protected $clientId;
protected $secret;
public function __construct()
{
$this->clientId = config('site.Client_ID');
$this->secret = config('site.Secret');
}
public function demo()
{
print_r($this->getAccessToken());
die;
}
/**
* @remark 获取token
*/
public function getAccessToken()
{
$cacheKey = 'paypal_access_token';
if ($token = Cache::get($cacheKey)) {
return $token;
}
$response = $this->sendRequest('https://api-m.sandbox.paypal.com/v1/oauth2/token', [
'grant_type' => 'client_credentials'
], [
'Accept: application/json',
'Accept-Language: en_US',
'Authorization: Basic ' . base64_encode($this->clientId . ':' . $this->secret),
'Content-Type: application/x-www-form-urlencoded'
]);
if ($response && isset($response['access_token'], $response['expires_in'])) {
$token = $response['access_token'];
Cache::set($cacheKey, $token, $response['expires_in'] - 60);
return $token;
}
return null;
}
/**
* @remark 创建订单
* @param $amount
* @param array $items
* @param string $returnUrl
* @param string $cancelUrl
* @return false|mixed|null
*/
public function createOrder($amount, $items = [], $returnUrl = 'https://example.com/returnUrl', $cancelUrl = 'https://example.com/cancelUrl')
{
// items 示例
// $items = [
// [
// "name" => "会员服务套餐",
// "description" => "包含 {$product['number']} 天会员服务,赠送 {$product['gold']} 虚拟金币",
// "unit_amount" => [
// "currency_code" => "USD",
// "value" => (string)$product['price']
// ],
// "quantity" => "1",
// "category" => "DIGITAL_GOODS",
// "sku" => "vip_package_{$product['id']}"
// ]
// ];
if (!$token = $this->getAccessToken()) {
return false;
}
// 确保每个商品的 category 为 DIGITAL_GOODS
foreach ($items as &$item) {
$item['category'] = 'DIGITAL_GOODS';
}
$data = [
"intent" => "CAPTURE",
"payment_source" => [
"paypal" => [
"experience_context" => [
"payment_method_preference" => "IMMEDIATE_PAYMENT_REQUIRED",
"landing_page" => "LOGIN",
"shipping_preference" => "NO_SHIPPING", // 虚拟商品无需配送
"user_action" => "PAY_NOW",
"return_url" => $returnUrl,
"cancel_url" => $cancelUrl
]
]
],
"purchase_units" => [
[
"invoice_id" => uniqid(),
"amount" => [
"currency_code" => "USD",
"value" => $amount,
"breakdown" => [
"item_total" => [
"currency_code" => "USD",
"value" => $this->calculateItemTotal($items)
],
"shipping" => [
"currency_code" => "USD",
"value" => "0.00" // 虚拟商品无运费
]
]
],
"items" => $items
]
]
];
return $this->sendRequest('https://api-m.sandbox.paypal.com/v2/checkout/orders', $data, [
'Content-Type: application/json',
'Authorization: Bearer ' . $token
]);
}
public function captureOrder($orderId)
{
if (!$token = $this->getAccessToken()) {
return false;
}
return $this->sendRequest('https://api-m.sandbox.paypal.com/v2/checkout/orders/' . $orderId . '/capture', [], [
'Content-Type: application/json',
'Authorization: Bearer ' . $token
]);
}
private function calculateItemTotal($items)
{
$total = 0;
foreach ($items as $item) {
$total += bcmul($item['unit_amount']['value'], $item['quantity'], 2);
}
return $total;
}
private function sendRequest($url, $data = [], $headers = [])
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
if ($data) {
if (in_array('Content-Type: application/x-www-form-urlencoded', $headers)) {
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
}
if ($headers) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
return null;
}
curl_close($ch);
return json_decode($result, true);
}
}