Skip to content
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);
    }
}