| Server IP : 43.141.49.119 / Your IP : 113.219.202.44 Web Server : Apache System : Linux VM-8-5-opencloudos 6.6.34-9.oc9.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jun 19 19:35:45 CST 2024 x86_64 User : www ( 1000) PHP Version : 8.1.27 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/wwwroot/www.ucppt.com/wp-content/plugins/wpcom-member-pro/payment/ |
Upload File : |
<?php
namespace WPCOM\Member\Payments;
use WPCOM\Member\Order;
use WPCOM\Themer\Session;
defined('ABSPATH') || exit;
class PayPal extends Payment {
private $_config;
public function __construct() {
$this->id = 'paypal';
$this->title = 'PayPal';
$this->icon = WPCOM_MP_URI . 'payment/paypal.svg';
$this->color = '#0544b5';
$this->_config = [];
add_action('wp_ajax_WPCOM_PayPal_order_status', [$this, 'order_status']);
add_action('wp_ajax_nopriv_WPCOM_PayPal_order_status', [$this, 'order_status']);
parent::__construct();
}
public function init($index){
$client_id = wpcom_mp_options('paypal_client_id');
$secret = wpcom_mp_options('paypal_secret');
$currency = wpcom_mp_options('paypal_currency');
$rate = wpcom_mp_options('paypal_rate');
$sandbox = wpcom_mp_options('paypal_sandbox');
$this->modal = false;
$this->_config = [
'client_id' => $client_id && isset($client_id[$index]) ? trim($client_id[$index]) : '',
'secret' => $secret && isset($secret[$index]) ? trim($secret[$index]) : '',
'currency' => $currency && isset($currency[$index]) ? trim($currency[$index]) : 'USD',
'rate' => $rate && isset($rate[$index]) && (float) $rate[$index] > 0 ? number_format( (float) $rate[$index], 3, '.', '' ) : 1,
'sandbox' => $sandbox && isset($sandbox[$index]) && $sandbox[$index] == 1
];
$this->_config['api'] = $this->_config['sandbox'] ? 'https://api.sandbox.paypal.com/' : 'https://api.paypal.com/';
}
public function process_payment($order_id) {
$url = Order::get_checkout_payment_url($order_id);
return [
'result' => 'success',
'redirect' => $url
];
}
private function config($order_id) {
$config = $this->_config + [
//异步通知地址
'notify_url' => Order::get_checkout_notify_url($order_id, $this->id),
//同步跳转
'return_url' => Order::get_checkout_return_url($order_id, $this->id),
];
return $config;
}
public function receipt_page($order_id) {
$order = Order::get_order($order_id);
if (!$order || $order->status === 'paid') return;
// 创建PayPal订单
$paypal_order = $this->create_order( $order );
$pay_url = '';
$error = '';
if(!$paypal_order) {
$error = '发起支付失败';
}else if(is_wp_error($paypal_order)) {
$error = $paypal_order->get_error_message();
}else if ( isset( $paypal_order['id'] ) && isset( $paypal_order['links'] ) ) {
// 查找approve链接
foreach ( $paypal_order['links'] as $link ) {
if ( $link['rel'] === 'payer-action' ) {
$pay_url = $link['href'];
}
}
}else if(isset( $paypal_order['message'] )){
$error = $paypal_order['name'] . ' - ' . $paypal_order['message'];
}
?>
<div class="loading-img"></div>
<p class="loading-text"><?php echo ($error !== '' ? '<span style="color: #f66;">' . $error . '</span>' : '正在转入支付平台...');?></p>
<div class="wpcom-alipay-html">
<?php if($error === '' && $pay_url !== '') {
echo '<script> setTimeout(function(){ window.location.href = \' ' . $pay_url . '\';}, 200);</script>';
}elseif($pay_url === '' && $error === ''){
echo '支付异常,请稍后再试!';
}?>
</div>
<?php }
function return_page_render($order_id) {
$token = isset($_GET['token']) && $_GET['token'] ? sanitize_text_field($_GET['token']) : '';
$payer = isset($_GET['PayerID']) && $_GET['PayerID'] ? sanitize_text_field($_GET['PayerID']) : '';
$order = Order::get_order($order_id);
if($token !== '' && $payer !== '' && $order->status === 'unpaid'){
$config = $this->config($order->ID);
$api = $config['api'] . 'v2/checkout/orders/' . $token;
// 查询订单状态
$paypal_order = $this->api_request( $api, '', $config, 'GET' );
if(!is_wp_error($paypal_order)) self::add_log('paypal 支付返回 - ' . $order_id . ' - ' . $paypal_order['status'], $this->id);
if ( !is_wp_error($paypal_order) && isset( $paypal_order['status'] ) && $paypal_order['status'] === 'APPROVED' ) {
$capture = $this->api_request( $api . '/capture', [], $config );
if(!is_wp_error($capture)) $this->payment_complete($order, $capture);
} else if ( !is_wp_error($paypal_order) ){
$this->payment_complete($order, $paypal_order);
}
}
parent::return_page_render($order_id);
}
function check_response($data){
if(is_numeric($data)) return ;
if(isset($data['event_type']) && $data['event_type'] === 'CHECKOUT.ORDER.APPROVED') {
$order_id = isset($data['resource']['purchase_units']) ? $data['resource']['purchase_units'][0]['reference_id'] : '';
self::add_log('paypal 异步通知 - ' . $order_id . ' - ' . $data['event_type'], $this->id);
if($order_id){
$token = $data['resource']['id'];
Session::set('paypal_' . $token, $order_id);
$order = Order::get_order_by_number($order_id);
if($order && isset($order->status) && $order->status === 'unpaid'){
$config = $this->config($order->ID);
$api = $config['api'] . 'v2/checkout/orders/' . $token;
$capture = $this->api_request( $api . '/capture', [], $config );
if ( !is_wp_error($capture) ) $this->payment_complete($order, $capture);
}
}
} else if(isset($data['event_type']) && $data['event_type'] === 'PAYMENT.CAPTURE.COMPLETED') {
$token = isset($data['resource']['supplementary_data']) ? $data['resource']['supplementary_data']['related_ids']['order_id'] : '';
$order_id = $token ? Session::get('paypal_' . $token) : '';
self::add_log('paypal 异步通知 - ' . $order_id . ' - ' . $data['event_type'], $this->id);
if($order_id) {
$order = Order::get_order_by_number($order_id);
if($order && isset($order->status) && $order->status === 'unpaid'){
Order::payment_complete( $order->ID, $this->id);
self::add_log('#' . $order->number.' 订单支付完成!', $this->id);
}
}
}
}
private function payment_complete($order, $data){
if(isset($data['status']) && $data['status'] === 'COMPLETED') {
$purchase = $data['purchase_units'][0];
if($order && $order->number && $order->number == $purchase['reference_id'] && $order->status === 'unpaid'){ // 判断订单号,以及支付状态
$config = $this->config($order->ID);
$price = number_format( (float) $order->price * $config['rate'], 2, '.', '' );
$currency = $config['currency'];
$amount = isset($purchase['amount']) ? $purchase['amount'] : $purchase['payments']['captures'][0]['amount'];
if($amount['value'] == $price && strtoupper($amount['currency_code']) === strtoupper($currency)) {
Order::payment_complete( $order->ID, $this->id);
self::add_log('#' . $order->number.' 订单支付完成!', $this->id);
} else {
self::add_log('#' . $order->number.' 价格核对出错,计算价格:' . $price . ',返回价格:' . $amount['value'], $this->id);
}
}
}
}
// PayPal API 请求
private function api_request( $url, $data, $config, $method = 'POST' ) {
$access_token = $this->get_access_token($config);
if($access_token){
$args = [
'timeout' => 30,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $access_token,
]
];
if($method === 'POST' && !empty($data)) {
$args['body'] = wp_json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
$response = $method === 'GET' ? wp_remote_get( $url, $args ) : wp_remote_post( $url, $args );
if ( is_wp_error( $response ) ) return $response;
return json_decode( wp_remote_retrieve_body( $response ), true );
}else{
return new \WP_Error('access_token_error', 'Access Token 获取失败,请检查接口配置是否正确');
}
}
// 获取 PayPal access_token
private function get_access_token($config) {
$cache_key = $config['sandbox'] ? 'paypal_sandbox_access_token' : 'paypal_live_access_token';
// 先尝试取缓存
$token_data = is_multisite() ? get_network_option( 1, $cache_key ) : get_option($cache_key);
$token_data = $token_data ? json_decode($token_data, true) : [];
if ( $token_data && isset( $token_data['access_token'], $token_data['expires_at'] ) ) {
if ( time() < $token_data['expires_at'] ) {
// token未过期,直接用
return $token_data['access_token'];
}
}
// token过期或不存在,重新申请
$response = wp_remote_post($config['api'] . 'v1/oauth2/token', [
'body' => 'grant_type=client_credentials',
'timeout' => 30,
'headers' => [
'Authorization' => 'Basic ' . base64_encode( $config['client_id'] . ':' . $config['secret'] ),
'Content-Type' => 'application/x-www-form-urlencoded',
],
]);
if ( is_wp_error( $response ) ) {
return false;
}
$data = json_decode( wp_remote_retrieve_body( $response ), true );
if ( empty( $data['access_token'] ) || empty( $data['expires_in'] ) ) {
return false;
}
// 缓存token
$token_data = [
'access_token' => $data['access_token'],
'expires_at' => time() + intval( $data['expires_in'] ) - 60
];
if(is_multisite()){
update_network_option( 1, $cache_key, wp_json_encode($token_data) );
}else{
update_option( $cache_key, wp_json_encode($token_data) );
}
return $data['access_token'];
}
// 创建 PayPal 订单
private function create_order( $order ) {
$config = $this->config($order->ID);
$data = [
'intent' => 'CAPTURE',
'purchase_units' => [
[
'reference_id' => (string) $order->number,
'amount' => [
'currency_code' => $config['currency'],
'value' => number_format( (float) $order->price * $config['rate'], 2, '.', '' ),
],
]
],
'payment_source' => [
'paypal' => [
'experience_context' => [
'brand_name' => get_bloginfo( 'name' ),
'landing_page' => 'LOGIN',
'shipping_preference' => 'NO_SHIPPING',
'user_action' => 'PAY_NOW',
'return_url' => $config['return_url'],
'cancel_url' => $config['return_url'],
]
]
]
];
return $this->api_request($config['api'] . 'v2/checkout/orders', $data, $config);
}
}
new PayPal();