沙盒环境示例
创建扩展封装类
<?php
namespace lib;
class PayPalApi
{
//clientId
private $clientId;
//clientSecret
private $clientSecret;
//服务器地址
private $host = 'https://api-m.sandbox.paypal.com/';
//主机头
private $headers = [];
//api凭证
private $token = '';
//报文主体
private $bodys = '';
/**
* 初始化类
*/
public function __construct(array $config = [])
{
$this->clientId = isset($config['clientId']) ? $config['clientId'] : '';
$this->clientSecret = isset($config['clientSecret']) ? $config['clientSecret'] : '';
$this->getAccessToken();
}
/**
* 创建订单
*/
public function create(array $data)
{
if (!$this->token) {
return [
'errcode' => 5001,
'errmsg' => '获取token失败',
];
}
if (!(is_array($data) && $data)) {
return [
'errcode' => 5002,
'errmsg' => '数据格式有误',
];
}
$trade_no = isset($data['trade_no']) ? filterTags($data['trade_no']) : '';
$trade_amount = isset($data['trade_amount']) ? sprfloat($data['trade_amount']) : 0;
$funds_item = isset($data['funds_item']) ? filterTags($data['funds_item']) : '';
$currency_code = isset($data['currency_code']) ? filterTags($data['currency_code']) : '';
if (!$trade_no) {
return [
'errcode' => 5003,
'errmsg' => '交易编号不能为空',
];
}
if ($trade_amount <= 0) {
return [
'errcode' => 5004,
'errmsg' => '交易金额无效',
];
}
$this->headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->token,
'PayPal-Request-Id: Trade-' . $trade_no,
];
$bodys = [
'intent' => 'CAPTURE',
'application_context' => [
'brand_name' => 'BKB',
'landing_page' => 'LOGIN',
'user_action' => 'PAY_NOW',
'return_url' => request()->domain() . '/pc/paypal/callback',
'cancel_url' => request()->domain() . '/pc/paypal/fail',
],
'purchase_units' => [
[
'reference_id' => $trade_no,
'description' => $funds_item,
'amount' => [
'currency_code' => $currency_code,
'value' => $trade_amount,
'breakdown' => [
'item_total' => [
'currency_code' => $currency_code,
'value' => $trade_amount,
],
'shipping' => [
'currency_code' => $currency_code,
'value' => 0,
],
'handling' => [
'currency_code' => $currency_code,
'value' => 0,
],
'tax_total' => [
'currency_code' => $currency_code,
'value' => 0,
],
'shipping_discount' => [
'currency_code' => $currency_code,
'value' => 0,
],
],
],
],
],
];
$this->bodys = json_encode($bodys, JSON_UNESCAPED_UNICODE);
$url = $this->host . 'v2/checkout/orders';
$result = json_decode($this->post($url), true);
if (!$result) {
return [
'errcode' => 5005,
'errmsg' => '远程服务器无应答',
];
}
file_put_contents(ROOT_PATH . 'paypal.log', print_r($result, true), FILE_APPEND);
if (isset($result['name']) && isset($result['message'])) {
return [
'errcode' => 5006,
'errmsg' => '[' . $result['name'] . '] - ' . $result['message'],
];
}
if (!isset($result['status'])) {
return [
'errcode' => 5007,
'errmsg' => '远程服务器响应异常',
];
}
if ('CREATED' !== $result['status']) {
$desc = isset($result['description']) ? filterTags($result['description'], 1) : $result['status'];
return [
'errcode' => 5008,
'errmsg' => $desc,
];
}
$trade_token = isset($result['id']) ? filterTags($result['id']) : '';
if (!$trade_token) {
return [
'errcode' => 5009,
'errmsg' => '远程服务器响应异常',
];
}
return [
'errcode' => 0,
'errmsg' => 'success',
'data' => [
'trade_token' => $trade_token,
],
];
}
/**
* 捕获订单
*/
public function capture(array $data)
{
if (!$this->token) {
return [
'errcode' => 5001,
'errmsg' => '获取token失败',
];
}
if (!(is_array($data) && $data)) {
return [
'errcode' => 5002,
'errmsg' => '数据格式有误',
];
}
$trade_no = isset($data['trade_no']) ? filterTags($data['trade_no']) : '';
$trade_amount = isset($data['trade_amount']) ? sprfloat($data['trade_amount']) : 0;
$trade_token = isset($data['trade_token']) ? filterTags($data['trade_token']) : '';
$funds_item = isset($data['funds_item']) ? filterTags($data['funds_item']) : '';
$currency_code = isset($data['currency_code']) ? filterTags($data['currency_code']) : '';
if (!$trade_no) {
return [
'errcode' => 5003,
'errmsg' => '交易编号不能为空',
];
}
if ($trade_amount <= 0) {
return [
'errcode' => 5004,
'errmsg' => '交易金额无效',
];
}
if (!$trade_token) {
return [
'errcode' => 5005,
'errmsg' => '交易令牌不能为空',
];
}
$this->headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->token,
'PayPal-Request-Id: Trade-' . $trade_token,
];
$bodys = [
'intent' => 'AUTHORIZE',
'application_context' => [
'brand_name' => 'BKB',
'landing_page' => 'LOGIN',
'user_action' => 'PAY_NOW',
'return_url' => request()->domain() . '/pc/paypal/callback',
'cancel_url' => request()->domain() . '/pc/paypal/fail',
],
'purchase_units' => [
[
'reference_id' => $trade_no,
'description' => $funds_item,
'amount' => [
'currency_code' => $currency_code,
'value' => $trade_amount,
'breakdown' => [
'item_total' => [
'currency_code' => $currency_code,
'value' => $trade_amount,
],
'shipping' => [
'currency_code' => $currency_code,
'value' => 0,
],
'handling' => [
'currency_code' => $currency_code,
'value' => 0,
],
'tax_total' => [
'currency_code' => $currency_code,
'value' => 0,
],
'shipping_discount' => [
'currency_code' => $currency_code,
'value' => 0,
],
],
],
],
],
];
$this->bodys = json_encode($bodys, JSON_UNESCAPED_UNICODE);
$url = $this->host . 'v2/checkout/orders/' . $trade_token . '/capture';
$result = json_decode($this->post($url), true);
if (!$result) {
return [
'errcode' => 5006,
'errmsg' => '远程服务器无应答',
];
}
file_put_contents(ROOT_PATH . 'paypal.log', print_r($result, true), FILE_APPEND);
if (!isset($result['status'])) {
return [
'errcode' => 5007,
'errmsg' => '远程服务器响应异常',
];
}
if ('COMPLETED' !== $result['status']) {
$desc = isset($result['description']) ? filterTags($result['description'], 1) : $result['status'];
return [
'errcode' => 5008,
'errmsg' => $desc,
];
}
if (!isset($result['purchase_units'][0]['payments']['captures'][0]['id'])) {
return [
'errcode' => 5009,
'errmsg' => '远程服务器响应异常',
];
}
$payment_no = filterTags($result['purchase_units'][0]['payments']['captures'][0]['id']);
if (!$payment_no) {
return [
'errcode' => 5010,
'errmsg' => '远程服务器响应异常',
];
}
$payment_time = isset($resource['update_time']) ? strtotime($resource['update_time']) : 0;
if ($payment_time <= 0) {
$payment_time = time();
}
if ($payment_time > time()) {
$payment_time = time();
}
return [
'errcode' => 0,
'errmsg' => 'success',
'data' => [
'payment_no' => $payment_no,
'payment_time' => $payment_time,
],
];
}
/**
* 退款
*/
public function refund(array $data)
{
if (!$this->token) {
return [
'errcode' => 5001,
'errmsg' => '获取token失败',
];
}
if (!(is_array($data) && $data)) {
return [
'errcode' => 5002,
'errmsg' => '数据格式有误',
];
}
$capture_id = isset($data['capture_id']) ? filterTags($data['capture_id']) : '';
$amount = isset($data['amount']) ? sprfloat($data['amount']) : 0;
$currency_code = isset($data['currency_code']) ? filterTags($data['currency_code']) : '';
if (!$capture_id) {
return [
'errcode' => 5003,
'errmsg' => '交易流水号不能为空',
];
}
if ($amount <= 0) {
return [
'errcode' => 5004,
'errmsg' => '退款金额无效',
];
}
if (!$currency_code) {
return [
'errcode' => 5005,
'errmsg' => '货币代号不能为空',
];
}
$this->headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->token,
'PayPal-Request-Id: Refund-' . $capture_id,
];
$bodys = [
'amount' => [
'value' => $amount,
'currency_code' => $currency_code,
],
];
$this->bodys = json_encode($bodys, JSON_UNESCAPED_UNICODE);
$url = $this->host . 'v2/payments/captures/' . $capture_id . '/refund';
$result = json_decode($this->post($url), true);
if (!$result) {
return [
'errcode' => 5006,
'errmsg' => '远程服务器无应答',
];
}
file_put_contents(ROOT_PATH . 'paypal.log', print_r($result, true), FILE_APPEND);
if (!isset($result['status'])) {
return [
'errcode' => 5007,
'errmsg' => '远程服务器响应异常',
];
}
if ('COMPLETED' !== $result['status']) {
$desc = isset($result['description']) ? filterTags($result['description'], 1) : $result['status'];
return [
'errcode' => 5008,
'errmsg' => $desc,
];
}
if (!isset($result['id'])) {
return [
'errcode' => 5009,
'errmsg' => '远程服务器响应异常',
];
}
$payment_no = filterTags($result['id']);
if (!$payment_no) {
return [
'errcode' => 5010,
'errmsg' => '远程服务器响应异常',
];
}
$payment_time = isset($resource['update_time']) ? strtotime($resource['update_time']) : 0;
if ($payment_time <= 0) {
$payment_time = time();
}
if ($payment_time > time()) {
$payment_time = time();
}
return [
'errcode' => 0,
'errmsg' => 'success',
'data' => [
'payment_no' => $payment_no,
'payment_time' => $payment_time,
],
];
}
/**
* 获取token
*/
private function getAccessToken()
{
$token = '';
$file = ASSETS_PATH . 'paypal/access_token.json';
if (is_file($file)) {
$data = json_decode(file_get_contents($file), true);
$time = isset($data['expired_time']) ? fnumber($data['expired_time']) : 0;
if ($time > time()) {
$token = isset($data['access_token']) ? filterTags($data['access_token']) : '';
}
}
if (!$token) {
$this->headers = [
'Content-Type: application/json',
'Accept-Language: en_US',
];
$this->bodys = 'grant_type=client_credentials';
$url = $this->host . 'v1/oauth2/token';
$result = json_decode($this->post($url, true), true);
if ($result && isset($result['access_token'])) {
$token = $result['access_token'];
$time = $result['expires_in'];
$path = dirname($file);
if (!is_dir($path)) {
mkdir($path, 0755, true);
}
file_put_contents($file, json_encode([
'access_token' => $token,
'expired_time' => time() + $time,
]));
}
}
$this->token = $token;
}
/*
* http协议发送get请求
*/
private function get(string $url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 2);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
$out = curl_exec($ch);
curl_close($ch);
return $out;
}
/*
* http协议发送post请求
*/
private function post(string $url, bool $credentials = false)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if ($credentials) {
curl_setopt($ch, CURLOPT_USERPWD, $this->clientId . ':' . $this->clientSecret);
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->bodys);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
未完待续……