first commit
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
class paypal_plugin
|
||||
{
|
||||
static public $info = [
|
||||
'name' => 'paypal', //支付插件英文名称,需和目录名称一致,不能有重复
|
||||
'showname' => 'PayPal', //支付插件显示名称
|
||||
'author' => 'PayPal', //支付插件作者
|
||||
'link' => 'https://www.paypal.com/', //支付插件作者链接
|
||||
'types' => ['paypal'], //支付插件支持的支付方式,可选的有alipay,qqpay,wxpay,bank
|
||||
'inputs' => [ //支付插件要求传入的参数以及参数显示名称,可选的有appid,appkey,appsecret,appurl,appmchid
|
||||
'appid' => [
|
||||
'name' => 'ClientId',
|
||||
'type' => 'input',
|
||||
'note' => '',
|
||||
],
|
||||
'appkey' => [
|
||||
'name' => 'ClientSecret',
|
||||
'type' => 'input',
|
||||
'note' => '',
|
||||
],
|
||||
'appswitch' => [
|
||||
'name' => '模式选择',
|
||||
'type' => 'select',
|
||||
'options' => [0=>'线上模式',1=>'沙盒模式'],
|
||||
],
|
||||
'currency_code' => [
|
||||
'name' => '结算货币',
|
||||
'type' => 'select',
|
||||
'options' => [
|
||||
'USD' => '美元 (USD)',
|
||||
'AUD' => '澳元 (AUD)',
|
||||
'BRL' => '巴西雷亚尔 (BRL)',
|
||||
'CAD' => '加拿大元 (CAD)',
|
||||
'CNY' => '人民币 (CNY)',
|
||||
'CZK' => '克朗 (CZK)',
|
||||
'DKK' => '丹麦克朗(DKK)',
|
||||
'EUR' => '欧元 (EUR)',
|
||||
'HKD' => '港币 (HKD)',
|
||||
'HUF' => '匈牙利福林 (HUF)',
|
||||
'INR' => '印度卢比 (INR)',
|
||||
'ILS' => '以色列新谢克尔 (ILS)',
|
||||
'JPY' => '日元 (JPY)',
|
||||
'MYR' => '马来西亚林吉特 (MYR)',
|
||||
'MXN' => '墨西哥比索 (MXN)',
|
||||
'TWD' => '新台币 (TWD)',
|
||||
'NZD' => '新西兰元 (NZD)',
|
||||
'NOK' => '挪威克朗 (NOK)',
|
||||
'PHP' => '菲律宾比索 (PHP)',
|
||||
'PLN' => '波兰兹罗提 (PLN)',
|
||||
'GBP' => '英镑 (GBP)',
|
||||
'RUB' => '俄罗斯卢布 (RUB)',
|
||||
'SGD' => '新加坡元 (SGD)',
|
||||
'SEK' => '瑞典克朗 (SEK)',
|
||||
'CHF' => '瑞士法郎 (CHF)',
|
||||
'THB' => '泰铢 (THB)',
|
||||
],
|
||||
],
|
||||
'currency_rate' => [
|
||||
'name' => '货币汇率',
|
||||
'type' => 'input',
|
||||
'note' => '例如1元人民币兑换0.137美元(USD),则此处填0.137',
|
||||
],
|
||||
],
|
||||
'select' => null,
|
||||
'note' => '', //支付密钥填写说明
|
||||
'bindwxmp' => false, //是否支持绑定微信公众号
|
||||
'bindwxa' => false, //是否支持绑定微信小程序
|
||||
];
|
||||
|
||||
static public function submit(){
|
||||
global $siteurl, $channel, $order, $ordername, $sitename, $conf, $DB;
|
||||
|
||||
require_once(PAY_ROOT."inc/PayPalClient.php");
|
||||
|
||||
if(!$channel['currency_rate']) $channel['currency_rate'] = 1;
|
||||
$money = round($order['realmoney'] * $channel['currency_rate'], 2);
|
||||
|
||||
$parameter = [
|
||||
'intent' => 'CAPTURE',
|
||||
'purchase_units' => [
|
||||
[
|
||||
'amount' => [
|
||||
'currency_code' => $channel['currency_code'],
|
||||
'value' => $money,
|
||||
],
|
||||
'description' => $order['name'],
|
||||
'custom_id' => TRADE_NO,
|
||||
'invoice_id' => TRADE_NO,
|
||||
],
|
||||
],
|
||||
'application_context'=> [
|
||||
'cancel_url' => $siteurl.'pay/cancel/'.TRADE_NO.'/',
|
||||
'return_url' => $siteurl.'pay/return/'.TRADE_NO.'/',
|
||||
],
|
||||
];
|
||||
|
||||
try {
|
||||
$approvalUrl = \lib\Payment::lockPayData(TRADE_NO, function() use($channel, $parameter) {
|
||||
$client = new PayPalClient($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
||||
$result = $client->createOrder($parameter);
|
||||
|
||||
$approvalUrl = null;
|
||||
foreach($result['links'] as $link){
|
||||
if($link['rel'] == 'approve'){
|
||||
$approvalUrl = $link['href'];
|
||||
}
|
||||
}
|
||||
if(empty($approvalUrl)){
|
||||
throw new Exception('获取支付链接失败');
|
||||
}
|
||||
return $approvalUrl;
|
||||
});
|
||||
|
||||
return ['type'=>'jump','url'=>$approvalUrl];
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
sysmsg('PayPal下单失败:'.$ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
//同步回调
|
||||
static public function return(){
|
||||
global $channel, $order;
|
||||
|
||||
require_once(PAY_ROOT."inc/PayPalClient.php");
|
||||
|
||||
if (isset($_GET['token']) && isset($_GET['PayerID'])) {
|
||||
|
||||
$token = $_GET['token'];
|
||||
try {
|
||||
$client = new PayPalClient($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
||||
$result = $client->captureOrder($token);
|
||||
} catch (Exception $ex) {
|
||||
return ['type'=>'error','msg'=>'支付订单失败 '.$ex->getMessage()];
|
||||
}
|
||||
|
||||
$captures = $result['purchase_units'][0]['payments']['captures'][0];
|
||||
$amount = $captures['seller_receivable_breakdown']['gross_amount']['value'];
|
||||
$trade_no = $captures['id'];
|
||||
$out_trade_no = $captures['invoice_id'];
|
||||
$buyer = $result['payer']['email_address'];
|
||||
|
||||
if($out_trade_no == TRADE_NO){
|
||||
processReturn($order, $trade_no, $buyer);
|
||||
}else{
|
||||
return ['type'=>'error','msg'=>'订单信息校验失败'];
|
||||
}
|
||||
} else {
|
||||
return ['type'=>'error','msg'=>'PayPal返回参数错误'];
|
||||
}
|
||||
}
|
||||
|
||||
static public function cancel(){
|
||||
return ['type'=>'page','page'=>'error'];
|
||||
}
|
||||
|
||||
static public function webhook(){
|
||||
global $channel, $order;
|
||||
$json = file_get_contents('php://input');
|
||||
$arr = json_decode($json, true);
|
||||
if(!$arr || empty($arr['event_type'])){
|
||||
exit('事件类型为空');
|
||||
}
|
||||
if(!in_array($arr['event_type'], ['PAYMENT.CAPTURE.COMPLETED'])){
|
||||
exit('其他事件('.$arr['event_type'].':'.$arr['summary'].')');
|
||||
}
|
||||
if(empty($channel['appsecret'])){
|
||||
exit('未配置webhookid');
|
||||
}
|
||||
|
||||
$crc32 = crc32($json);
|
||||
if (empty($_SERVER['HTTP_PAYPAL_TRANSMISSION_ID']) || empty($_SERVER['HTTP_PAYPAL_TRANSMISSION_TIME']) || empty($crc32)) {
|
||||
exit('签名数据为空');
|
||||
}
|
||||
$sign_string = $_SERVER['HTTP_PAYPAL_TRANSMISSION_ID'].'|'.$_SERVER['HTTP_PAYPAL_TRANSMISSION_TIME'].'|'.$channel['appsecret'].'|'.$crc32;
|
||||
|
||||
// 通过PAYPAL-CERT-URL头信息去拿公钥
|
||||
$public_key = openssl_pkey_get_public(get_curl($_SERVER['HTTP_PAYPAL_CERT_URL']));
|
||||
$details = openssl_pkey_get_details($public_key);
|
||||
$verify = openssl_verify($sign_string, base64_decode($_SERVER['HTTP_PAYPAL_TRANSMISSION_SIG']), $details['key'], 'SHA256');
|
||||
if($verify != 1)
|
||||
{
|
||||
exit('签名验证失败');
|
||||
}
|
||||
|
||||
$resource = $arr['resource'];
|
||||
$amount = $resource['amount']['value'];
|
||||
$trade_no = $resource['id'];
|
||||
$out_trade_no = $resource['invoice_id'];
|
||||
}
|
||||
|
||||
//退款
|
||||
static public function refund($order){
|
||||
global $channel;
|
||||
if(empty($order))exit();
|
||||
|
||||
require_once(PAY_ROOT."inc/PayPalClient.php");
|
||||
|
||||
if(!$channel['currency_rate']) $channel['currency_rate'] = 1;
|
||||
$money = round($order['refundmoney'] * $channel['currency_rate'], 2);
|
||||
|
||||
$parameter = [
|
||||
'amount' => [
|
||||
'currency_code' => $channel['currency_code'],
|
||||
'value' => $money,
|
||||
],
|
||||
];
|
||||
|
||||
try{
|
||||
$client = new PayPalClient($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
||||
$res = $client->refundPayment($order['api_trade_no'], $parameter);
|
||||
$result = ['code'=>0, 'trade_no'=>$res['id'], 'refund_fee'=>$res['amount']['value']];
|
||||
}catch(Exception $e){
|
||||
$result = ['code'=>-1, 'msg'=>$e->getMessage()];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user