first commit

This commit is contained in:
2026-04-15 20:16:52 +08:00
commit 8f45044411
1172 changed files with 329978 additions and 0 deletions
@@ -0,0 +1,111 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
use Yansongda\Pay\Pay;
class AlipayController extends PayController
{
/**
* 支付宝支付网关
*
* @param string $payway
* @param string $orderSN
*/
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
$config = [
'app_id' => $this->payGateway->merchant_id,
'ali_public_key' => $this->payGateway->merchant_key,
'private_key' => $this->payGateway->merchant_pem,
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
'return_url' => url('detail-order-sn', ['orderSN' => $this->order->order_sn]),
'http' => [ // optional
'timeout' => 10.0,
'connect_timeout' => 10.0,
],
];
$order = [
'out_trade_no' => $this->order->order_sn,
'total_amount' => (float)$this->order->actual_price,
'subject' => $this->order->order_sn
];
switch ($payway){
case 'zfbf2f':
case 'alipayscan':
try{
$result = Pay::alipay($config)->scan($order)->toArray();
$result['payname'] = $this->order->order_sn;
$result['actual_price'] = (float)$this->order->actual_price;
$result['orderid'] = $this->order->order_sn;
$result['jump_payuri'] = $result['qr_code'];
return $this->render('static_pages/qrpay', $result, __('dujiaoka.scan_qrcode_to_pay'));
} catch (\Exception $e) {
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
}
case 'aliweb':
try{
$result = Pay::alipay($config)->web($order);
return $result;
} catch (\Exception $e) {
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
}
case 'aliwap':
try{
$result = Pay::alipay($config)->wap($order);
return $result;
} catch (\Exception $e) {
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
}
}
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
/**
* 异步通知
*/
public function notifyUrl(Request $request)
{
$orderSN = $request->input('out_trade_no');
$order = $this->orderService->detailOrderSN($orderSN);
if (!$order) {
return 'error';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'error';
}
if($payGateway->pay_handleroute != '/pay/alipay'){
return 'fail';
}
$config = [
'app_id' => $payGateway->merchant_id,
'ali_public_key' => $payGateway->merchant_key,
'private_key' => $payGateway->merchant_pem,
];
$pay = Pay::alipay($config);
try{
// 验证签名
$result = $pay->verify();
if ($result->trade_status == 'TRADE_SUCCESS' || $result->trade_status == 'TRADE_FINISHED') {
$this->orderProcessService->completedOrder($result->out_trade_no, $result->total_amount, $result->trade_no);
}
return 'success';
} catch (\Exception $exception) {
return 'fail';
}
}
}
@@ -0,0 +1,143 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
class CoinbaseController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
//构造要请求的参数数组,无需改动
switch ($payway) {
case 'coinbase':
default:
try {
$createOrderUrl="https://api.commerce.coinbase.com/charges";
$price_amount = sprintf('%.2f', (float)$this->order->actual_price);// 只取小数点后两位
$fees = (double)$this->payGateway->merchant_id;//手续费费率 比如 0.05
if($fees>0.00)
{
$price_amount =(double)$price_amount * (1.00+$fees);// 价格 * 1 + 0.05
}
$redirect_url = url('detail-order-sn', ['orderSN' => $this->order->order_sn]); //同步地址
$cancel_url = url('detail-order-sn', ['orderSN' => $this->order->order_sn]); //同步地址
$config = [
'name'=>$this->order->title,
'description'=>$this->order->title.'需付款'.$price_amount.'元',
'pricing_type' => 'fixed_price',
'local_price' => [
'amount' => $price_amount,
'currency' => 'CNY'
],
'metadata' => [
'customer_id' => $this->order->order_sn,
'customer_name' => $this->order->title
],
'redirect_url' =>$redirect_url,
'cancel_url'=> $cancel_url
];
$header = array();
$header[] = 'Content-Type:application/json';
$header[] = 'X-CC-Api-Key:'.$this->payGateway->merchant_key; //APP key
$header[] = 'X-CC-Version: 2018-03-22';
$ch = curl_init(); //使用curl请求
curl_setopt($ch, CURLOPT_URL, $createOrderUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($config));
$coinbase_json = curl_exec($ch);
curl_close($ch);
$coinbase_date=json_decode($coinbase_json,true);
if(is_array($coinbase_date))
{
$payment_url = $coinbase_date['data']['hosted_url'];
}
else
{
return 'fail|Coinbase支付接口请求失败';
}
return redirect()->away($payment_url);
} catch (\Exception $e) {
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
}
break;
}
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
public function notifyUrl(Request $request)
{
$payload = file_get_contents( 'php://input' );
$sig = $_SERVER['HTTP_X_CC_WEBHOOK_SIGNATURE'];
$data = json_decode( $payload, true );
$event_data = $data['event']['data'];
$order = $this->orderService->detailOrderSN($event_data['metadata']['customer_id']);//
if (!$order) {
return 'fail';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'fail';
}
if($payGateway->pay_handleroute != 'pay/coinbase'){
return 'fail';
}
$secret = $payGateway->merchant_pem;//共享密钥
$sig2 = hash_hmac( 'sha256', $payload, $secret );
$result_str=array("confirmed","resolved");//返回的结果字符串数组
if (!empty( $payload ) && ($sig === $sig2))
{
foreach ($event_data['payments'] as $payment) {
//if ((strtolower($payment['status']) === 'confirmed')||(strtolower($payment['status']) === 'resolved')) {
if(in_array(strtolower($payment['status']),$result_str)){
$return_pay_amount = $payment['value']['local']['amount'];
$return_currency=$payment['value']['local']['currency'];
$return_status=strtolower($payment['status']);
}
}
if($return_currency !== 'CNY')
{
return 'error|Notify: Wrong currency:'.$return_currency;
}
$bccomp = bccomp($order->actual_price, $return_pay_amount, 2); //如果订单金额 大于 实际支付金额 返回1,抛出异常
if ($bccomp == 1) {
throw new \Exception(__('Coinbase付款金额不足'));
}
$return_merchant_order_id = $event_data['metadata']['customer_id'];//卡网订单号
$tradeid = $event_data['code'];//Coinbase订单号
//if($return_status === 'confirmed'||$return_status === 'resolved')
if(in_array(strtolower($payment['status']),$result_str)) {
$this->orderProcessService->completedOrder($return_merchant_order_id, $order->actual_price, $tradeid);// 卡网订单号,订单金额(不能传入支付金额,否则抛出订单金额不一致异常),收款平台订单号
return "{\"status\": 200}";
} else {
//不合法的数据
return 'fail';
//返回失败 继续补单
}
} else {
//不合法的数据
return 'fail|wrong sig';
//返回失败 继续补单
}
}
}
@@ -0,0 +1,104 @@
<?php
/**
* The file was created by Assimon.
*
* @author assimon<ashang@utf8.hk>
* @copyright assimon<ashang@utf8.hk>
* @link http://utf8.hk/
*/
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
class EpusdtController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
//构造要请求的参数数组,无需改动
$parameter = [
"amount" => (float)$this->order->actual_price,//原价
"order_id" => $this->order->order_sn, //可以是用户ID,站内商户订单号,用户名
'redirect_url' => route('epusdt-return', ['order_id' => $this->order->order_sn]),
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
];
$parameter['signature'] = $this->epusdtSign($parameter, $this->payGateway->merchant_id);
$client = new Client([
'headers' => [ 'Content-Type' => 'application/json' ]
]);
$response = $client->post($this->payGateway->merchant_pem, ['body' => json_encode($parameter)]);
$body = json_decode($response->getBody()->getContents(), true);
if (!isset($body['status_code']) || $body['status_code'] != 200) {
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $body['message']);
}
return redirect()->away($body['data']['payment_url']);
} catch (RuleValidationException $exception) {
} catch (GuzzleException $exception) {
return $this->err($exception->getMessage());
}
}
private function epusdtSign(array $parameter, string $signKey)
{
ksort($parameter);
reset($parameter); //内部指针指向数组中的第一个元素
$sign = '';
$urls = '';
foreach ($parameter as $key => $val) {
if ($val == '') continue;
if ($key != 'signature') {
if ($sign != '') {
$sign .= "&";
$urls .= "&";
}
$sign .= "$key=$val"; //拼接为url参数形式
$urls .= "$key=" . urlencode($val); //拼接为url参数形式
}
}
$sign = md5($sign . $signKey);//密码追加进入开始MD5签名
return $sign;
}
public function notifyUrl(Request $request)
{
$data = $request->all();
$order = $this->orderService->detailOrderSN($data['order_id']);
if (!$order) {
return 'fail';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'fail';
}
if($payGateway->pay_handleroute != 'pay/epusdt'){
return 'fail';
}
$signature = $this->epusdtSign($data, $payGateway->merchant_id);
if ($data['signature'] != $signature) { //不合法的数据
return 'fail'; //返回失败 继续补单
} else {
//合法的数据
//业务处理
$this->orderProcessService->completedOrder($data['order_id'], $data['amount'], $data['trade_id']);
return 'ok';
}
}
public function returnUrl(Request $request)
{
$oid = $request->get('order_id');
// 异步通知还没到就跳转了,所以这里休眠2秒
sleep(2);
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
}
}
@@ -0,0 +1,83 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
class MapayController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
//构造要请求的参数数组,无需改动
$parameter = array(
"id" => (int)$this->payGateway->merchant_id,//平台ID号
"price" => (float)$this->order->actual_price,//原价
"pay_id" => $this->order->order_sn, //可以是用户ID,站内商户订单号,用户名
"param" => $this->payGateway->pay_check,//自定义参数
"act" => 0,//是否开启认证版的免挂机功能
"outTime" => 120,//二维码超时设置
"page" => 1,//付款页面展示方式
'return_url' => url('detail-order-sn', ['orderSN' => $this->order->order_sn]),
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
"pay_type" => 0,//支付宝使用官方接口
"chart" => 'utf-8'//字符编码方式
//其他业务参数根据在线开发文档,添加参数.文档地址:https://codepay.fateqq.com/apiword/
//如"参数名"=>"参数值"
);
switch ($payway){
case 'mqq':
$parameter['type'] = 2;
break;
case 'mzfb':
$parameter['type'] = 1;
break;
case 'mwx':
default:
$parameter['type'] = 3;
break;
}
$quri = md5_signquery($parameter, $this->payGateway->merchant_pem);
$payurl = $this->payGateway->merchant_key . $quri; //支付页面
return redirect()->away($payurl);
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
public function notifyUrl(Request $request)
{
$data = $request->post();
$order = $this->orderService->detailOrderSN($data['pay_id']);
if (!$order) {
return 'fail';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'fail';
}
if($payGateway->pay_handleroute != '/pay/mapay'){
return 'fail';
}
$query = signquery_string($data);
if (!$data['pay_no'] || md5($query . $payGateway->merchant_pem ) != $data['sign']) { //不合法的数据
return 'fail'; //返回失败 继续补单
} else { //合法的数据
//业务处理
$this->orderProcessService->completedOrder($data['pay_id'], $data['money'], $data['pay_id']);
return 'success';
}
}
}
@@ -0,0 +1,70 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
use Xhat\Payjs\Facades\Payjs;
class PayjsController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
// 构造订单基础信息
$data = [
'body' => $this->order->order_sn, // 订单标题
'total_fee' => bcmul($this->order->actual_price, 100, 0), // 订单金额
'out_trade_no' => $this->order->order_sn, // 订单号
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
];
config(['payjs.mchid' => $this->payGateway->merchant_id, 'payjs.key' => $this->payGateway->merchant_pem]);
switch ($payway){
case 'payjswescan':
try{
$payres = Payjs::native($data);
if ($payres['return_code'] != 1) {
throw new RuleValidationException($payres['return_msg']);
}
$result['payname'] = $this->payGateway->pay_name;
$result['actual_price'] = (float)$this->order->actual_price;
$result['orderid'] = $this->order->order_sn;
$result['qr_code'] = $payres['code_url'];
return $this->render('static_pages/qrpay', $result, __('dujiaoka.scan_qrcode_to_pay'));
} catch (\Exception $e) {
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
}
break;
}
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
public function notifyUrl(Request $request)
{
$orderSN = $request->input('out_trade_no');
$order = $this->orderService->detailOrderSN($orderSN);
if (!$order) {
return 'error';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'error';
}
if($payGateway->pay_handleroute != '/pay/payjs'){
return 'fail';
}
config(['payjs.mchid' => $payGateway->merchant_id, 'payjs.key' => $payGateway->merchant_pem]);
$notify_info = Payjs::notify();
$totalFee = bcdiv($notify_info['total_fee'], 100, 2);
$this->orderProcessService->completedOrder($notify_info['out_trade_no'], $totalFee, $notify_info['payjs_order_id']);
return 'success';
}
}
@@ -0,0 +1,148 @@
<?php
namespace App\Http\Controllers\Pay;
use AmrShawky\LaravelCurrency\Facade\Currency;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use PayPal\Api\Amount;
use PayPal\Api\Details;
use PayPal\Api\Item;
use PayPal\Api\ItemList;
use PayPal\Api\Payer;
use PayPal\Api\Payment;
use PayPal\Api\PaymentExecution;
use PayPal\Api\RedirectUrls;
use PayPal\Api\Transaction;
use PayPal\Auth\OAuthTokenCredential;
use PayPal\Exception\PayPalConnectionException;
use PayPal\Rest\ApiContext;
class PaypalPayController extends PayController
{
const Currency = 'USD'; //货币单位
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
$paypal = new ApiContext(
new OAuthTokenCredential(
$this->payGateway->merchant_key,
$this->payGateway->merchant_pem
)
);
$paypal->setConfig(['mode' => 'live']);
$product = $this->order->title;
// 得到汇率
$total = Currency::convert()
->from('CNY')
->to('USD')
->amount($this->order->actual_price)
->round(2)
->get();
$shipping = 0;
$description = $this->order->title;
$payer = new Payer();
$payer->setPaymentMethod('paypal');
$item = new Item();
$item->setName($product)->setCurrency(self::Currency)->setQuantity(1)->setPrice($total);
$itemList = new ItemList();
$itemList->setItems([$item]);
$details = new Details();
$details->setShipping($shipping)->setSubtotal($total);
$amount = new Amount();
$amount->setCurrency(self::Currency)->setTotal($total)->setDetails($details);
$transaction = new Transaction();
$transaction->setAmount($amount)->setItemList($itemList)->setDescription($description)->setInvoiceNumber($this->order->order_sn);
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl(route('paypal-return', ['success' => 'ok', 'orderSN' => $this->order->order_sn]))->setCancelUrl(route('paypal-return', ['success' => 'no', 'orderSN' => $this->order->order_sn]));
$payment = new Payment();
$payment->setIntent('sale')->setPayer($payer)->setRedirectUrls($redirectUrls)->setTransactions([$transaction]);
$payment->create($paypal);
$approvalUrl = $payment->getApprovalLink();
return redirect($approvalUrl);
} catch (PayPalConnectionException $payPalConnectionException) {
return $this->err($payPalConnectionException->getMessage());
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
/**
*paypal 同步回调
*/
public function returnUrl(Request $request)
{
$success = $request->input('success');
$paymentId = $request->input('paymentId');
$payerID = $request->input('PayerID');
$orderSN = $request->input('orderSN');
if ($success == 'no' || empty($paymentId) || empty($payerID)) {
// 取消支付
redirect(url('detail-order-sn', ['orderSN' => $payerID]));
}
$order = $this->orderService->detailOrderSN($orderSN);
if (!$order) {
return 'error';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'error';
}
if($payGateway->pay_handleroute != '/pay/paypal'){
return 'error';
}
$paypal = new ApiContext(
new OAuthTokenCredential(
$payGateway->merchant_key,
$payGateway->merchant_pem
)
);
$paypal->setConfig(['mode' => 'live']);
$payment = Payment::get($paymentId, $paypal);
$execute = new PaymentExecution();
$execute->setPayerId($payerID);
try {
$payment->execute($execute, $paypal);
$this->orderProcessService->completedOrder($orderSN, $order->actual_price, $paymentId);
Log::info("paypal支付成功", ['支付成功,支付ID【' . $paymentId . '】,支付人ID【' . $payerID . '】']);
} catch (\Exception $e) {
Log::error("paypal支付失败", ['支付失败,支付ID【' . $paymentId . '】,支付人ID【' . $payerID . '】']);
}
return redirect(url('detail-order-sn', ['orderSN' => $orderSN]));
}
/**
* 异步通知
* TODO: 暂未实现,但是好像只实现同步回调即可。这个可以放在后面实现
*/
public function notifyUrl(Request $request)
{
//获取回调结果
$json_data = $this->get_JsonData();
if(!empty($json_data)){
Log::debug("paypal notify info:\r\n" . json_encode($json_data));
}else{
Log::debug("paypal notify fail:参加为空");
}
}
private function get_JsonData()
{
$json = file_get_contents('php://input');
if ($json) {
$json = str_replace("'", '', $json);
$json = json_decode($json,true);
}
return $json;
}
}
@@ -0,0 +1,113 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
class PaysapiController extends PayController
{
const PAY_URI = 'https://pay.bearsoftware.net.cn/';
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
//从网页传入price:支付价格, istype:支付渠道:1-支付宝;2-微信支付
$price = (float)$this->order->actual_price;
$orderuid = $this->order->email; //此处传入您网站用户的用户名,方便在paysapi后台查看是谁付的款,强烈建议加上。可忽略。
//校验传入的表单,确保价格为正常价格(整数,1位小数,2位小数都可以),支付渠道只能是1或者2,orderuid长度不要超过33个中英文字。
//此处就在您服务器生成新订单,并把创建的订单号传入到下面的orderid中。
$goodsname = $this->order->order_sn;
$orderid = $this->order->order_sn; //每次有任何参数变化,订单号就变一个吧。
$uid = $this->payGateway->merchant_id; //"此处填写PaysApi的uid";
$token = $this->payGateway->merchant_pem; //"此处填写PaysApi的Token";
$return_url = route('paysapi-return', ['order_id' => $this->order->order_sn]);
$notify_url = url($this->payGateway->pay_handleroute . '/notify_url');
switch ($payway){
case 'pszfb':
$istype = 1;
break;
case 'pswx':
default:
$istype = 2;
break;
}
$key = md5($goodsname. $istype . $notify_url . $orderid . $orderuid . $price . $return_url . $token . $uid);
//经常遇到有研发问为啥key值返回错误,大多数原因:1.参数的排列顺序不对;2.上面的参数少传了,但是这里的key值又带进去计算了,导致服务端key算出来和你的不一样。
$html = "
<html><head>
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">
<title>loading pay...</title>
<style type=\"text/css\">
body {margin:0;padding:0;}
p {position:absolute;
left:50%;top:50%;
width:330px;height:30px;
margin:-35px 0 0 -160px;
padding:20px;font:bold 14px/30px \"宋体\", Arial;
text-indent:22px;border:1px solid #c5d0dc;}
#waiting {font-family:Arial;}
</style>
<script>
function open_without_referrer(link){
document.body.appendChild(document.createElement('iframe')).src='javascript:\"<script>top.location.replace(\''+link+'\')<\/script>\"';
}
</script>
</head>
<body style=\"\">
<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"".self::PAY_URI."\" method=\"post\">
<input type=\"hidden\" name=\"goodsname\" value=\"".$goodsname."\">
<input type=\"hidden\" name=\"istype\" value=\"".$istype."\">
<input type=\"hidden\" name=\"key\" value=\"".$key."\">
<input type=\"hidden\" name=\"notify_url\" value=\"".$notify_url."\">
<input type=\"hidden\" name=\"orderid\" value=\"".$orderid."\">
<input type=\"hidden\" name=\"orderuid\" value=\"".$orderuid."\">
<input type=\"hidden\" name=\"price\" value=\"".$price."\">
<input type=\"hidden\" name=\"return_url\" value=\"".$return_url."\">
<input type=\"hidden\" name=\"uid\" value=\"".$uid."\">
<input type=\"submit\" value=\"正在跳转\">
</form><script>document.forms['alipaysubmit'].submit();</script></body></html>
";
return $html;
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
public function notifyUrl(Request $request)
{
$data = $request->post();
$order = $this->orderService->detailOrderSN($data['orderid']);
if (!$order) {
return 'error';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'error';
}
if($payGateway->pay_handleroute != '/pay/paysapi'){
return 'error';
}
$temps = md5($data['orderid'] . $data['orderuid'] . $data['paysapi_id'] . $data['price'] . $data['realprice'] . $payGateway->merchant_pem);
if ($temps != $data['key']){
return 'fail';
}else{
//校验key成功,是自己人。执行自己的业务逻辑:加余额,订单付款成功,装备购买成功等等。
//业务处理
$this->orderProcessService->completedOrder($data['orderid'], $data['price'], $data['paysapi_id']);
return 'success';
}
}
public function returnUrl(Request $request)
{
$oid = $request->input('order_id');
sleep(1);
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
}
}
@@ -0,0 +1,540 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Redis;
use URL;
class StripeController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
// 加载网关
$this->loadGateWay($orderSN, $payway);
//构造要请求的参数数组,无需改动
switch ($payway) {
case 'wx':
case 'alipay':
default:
try {
\Stripe\Stripe::setApiKey($this->payGateway->merchant_id);
$amount = bcmul($this->order->actual_price, 100, 2);
$price = $this->order->actual_price;
$usd = bcmul($this->getUsdCurrency($this->order->actual_price), 100, 2);
$orderid = $this->order->order_sn;
$pk = $this->payGateway->merchant_id;
$return_url = site_url() . $this->payGateway->pay_handleroute . '/return_url/?orderid=' . $this->order->order_sn;
$html = "<html class=\"js cssanimations\">
<head lang=\"en\">
<meta charset=\"UTF-8\">
<title>收银台</title>
<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
<meta name=\"format-detection\" content=\"telephone=no\">
<meta name=\"renderer\" content=\"webkit\">
<meta http-equiv=\"Cache-Control\" content=\"no-siteapp\">
<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/amazeui@2.7.2/dist/css/amazeui.min.css\">
<script src=\"https://cdn.jsdelivr.net/npm/jquery@2.1.4/dist/jquery.min.js\"></script>
<script src=\"https://cdn.jsdelivr.net/npm/jquery.qrcode@1.0.3/jquery.qrcode.min.js\"></script>
<script src=\"https://cdn.jsdelivr.net/npm/amazeui@2.7.2/dist/js/amazeui.min.js\"></script>
<script src=\"https://js.stripe.com/v3/\"></script>
<style>
@media only screen and (min-width: 641px) {
.am-offcanvas {
display: block;
position: static;
background: none;
}
.am-offcanvas-bar {
position: static;
width: auto;
background: none;
-webkit-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.am-offcanvas-bar:after {
content: none;
}
}
@media only screen and (max-width: 640px) {
.am-offcanvas-bar .am-nav > li > a {
color: #ccc;
border-radius: 0;
border-top: 1px solid rgba(0, 0, 0, .3);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05)
}
.am-offcanvas-bar .am-nav > li > a:hover {
background: #404040;
color: #fff
}
.am-offcanvas-bar .am-nav > li.am-nav-header {
color: #777;
background: #404040;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05);
text-shadow: 0 1px 0 rgba(0, 0, 0, .5);
border-top: 1px solid rgba(0, 0, 0, .3);
font-weight: 400;
font-size: 75%
}
.am-offcanvas-bar .am-nav > li.am-active > a {
background: #1a1a1a;
color: #fff;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .3)
}
.am-offcanvas-bar .am-nav > li + li {
margin-top: 0;
}
}
.my-head {
margin-top: 40px;
text-align: center;
}
.am-tab-panel {
text-align: center;
margin-top: 50px;
margin-bottom: 50px;
}
.my-footer {
border-top: 1px solid #eeeeee;
padding: 10px 0;
margin-top: 10px;
text-align: center;
}
.panel-title {
display: inline;
font-weight: bold;
}
.display-table {
display: table;
}
.display-tr {
display: table-row;
}
.display-td {
display: table-cell;
vertical-align: middle;
width: 61%;
}
.StripeElement {
box-sizing: border-box;
height: 40px;
padding: 10px 12px;
border: 1px solid transparent;
border-radius: 4px;
background-color: white;
box-shadow: 0 1px 3px 0 #e6ebf1;
-webkit-transition: box-shadow 150ms ease;
transition: box-shadow 150ms ease;
}
.StripeElement--focus {
box-shadow: 0 1px 3px 0 #cfd7df;
}
.StripeElement--invalid {
border-color: #fa755a;
}
.StripeElement--webkit-autofill {
background-color: #fefde5 !important;
}
.form-row {
width: 70%;
float: left;
}
.wrapper {
width: 670px;
margin: 0 auto;
}
label {
font-weight: 500;
font-size: 14px;
display: block;
margin-bottom: 8px;
}
.button {
border: none;
border-radius: 4px;
outline: none;
text-decoration: none;
color: #fff;
background: #32325d;
white-space: nowrap;
display: inline-block;
height: 40px;
line-height: 40px;
padding: 0 14px;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
border-radius: 4px;
font-size: 16px;
font-weight: 600;
letter-spacing: 0.025em;
text-decoration: none;
-webkit-transition: all 150ms ease;
transition: all 150ms ease;
margin-top: 10px;
}
</style>
</head>
<body>
<header class=\"am-g my-head\">
<div class=\"am-u-sm-12 am-article\">
<h1 class=\"am-article-title\">收银台</h1>
</div>
</header>
<hr class=\"am-article-divider\">
<div class=\"am-container\">
<h2>付款信息
<div class=\"am-topbar-right\"{$price}</div>
</h2>
<p><small>订单编号:$orderid</small></p>
<div class=\"am-tabs\" data-am-tabs=\"\">
<ul class=\"am-tabs-nav am-nav am-nav-tabs\">
<li class=\"am-active\"><a href=\"#alipay\">Alipay 支付宝</a></li>
<li class=\"request-wechat-pay\"><a href=\"#wcpay\">微信支付</a></li>
<li class=\"request-card-pay\"><a href=\"#cardpay\">银行卡支付</a></li>
</ul>
<div class=\"am-tabs-bd am-tabs-bd-ofv\"
style=\"touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\">
<div class=\"am-tab-panel am-active\" id=\"alipay\">
<a class=\"am-btn am-btn-lg am-btn-warning am-btn-primary\" id=\"alipaybtn\" href=\"#\">进入支付宝付款</a>
<p></p>
</div>
<div class=\"am-tab-panel am-fade\" id=\"wcpay\">
<div class=\"text-align:center; margin:0 auto; width:60%\">
<div class=\"wcpay-qrcode\" style=\"text-align: center; \" data-requested=\"0\">
正在加载中...
</div>
</div>
</div>
<div class=\"am-tab-panel am-fade\" id=\"cardpay\">
<div class=\"text-align:center; margin:0 auto; width:60%\">
<div class=\"wrapper cardpay_content\" style=\"max-width:500px\">
<div class=\"am-alert am-alert-danger\" style=\"display:none\">支付失败,请更换卡片或检查输入信息</div>
<form action=\"/pay/stripe/charge\" method=\"post\" id=\"payment-form\">
<div class=\"form-row\">
<label for=\"card-element\">
<p class='am-alert am-alert-secondary'>借记卡或信用卡</p>
</label>
<div id=\"card-element\">
<!-- A Stripe Element will be inserted here. -->
</div>
<!-- Used to display form errors. -->
<div id=\"card-errors\" role=\"alert\"></div>
</div>
<div class=\"form-row\">
<button class=\"button\">支付</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var stripe = Stripe('$pk');
var source = '';
// Create a Stripe client.
// Create an instance of Elements.
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
fontFamily: '\"Helvetica Neue\", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
// Handle real-time validation errors from the card Element.
card.on('change', function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function (event) {
event.preventDefault();
$(\".button\").attr(\"disabled\",\"true\");
$(\".button\").html(\"请稍后\");
stripe.createToken(card).then(function (result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
// Submit the form with the token ID.
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
var hiddenInput1 = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
hiddenInput1.setAttribute('type', 'hidden');
hiddenInput1.setAttribute('name', 'orderid');
hiddenInput1.setAttribute('value', '$orderid');
form.appendChild(hiddenInput);
form.appendChild(hiddenInput1);
// Submit the form
//form.submit();
$.ajax({
url: '/pay/stripe/charge/?orderid=$orderid&stripeToken=' + token.id,
type: 'GET',
success: function (result) {
if (result == \"success\") {
$(\".cardpay_content\").html(\"\");
$(\".cardpay_content\").html(\"<p class='am-alert am-alert-success'>支付成功,正在跳转页面</p>\");
window.setTimeout(function () {
location.href = \"/detail-order-sn/$orderid\"
}, 800);
} else {
$(\".am-alert\").show();
$(\".button\").removeAttr(\"disabled\");
$(\".button\").html(\"支付\");
setTimeout(\" $('.am-alert').hide();\", 3000);
}
}
});
}
(function () {
stripe.createSource({
type: 'alipay',
amount: $amount,
currency: 'cny',
// 这里你需要渲染出一些用户的信息,不然后期没法知道是谁在付钱
owner: {
name: '$orderid',
},
redirect: {
return_url: '$return_url',
},
}).then(function (result) {
$(\"#alipaybtn\").attr(\"href\", result.source.redirect.url);
});
})();
function paymentcheck() {
$.ajax({
url: '/pay/stripe/check/?orderid=$orderid&source=' + source,
type: 'GET',
success: function (result) {
if (result == \"success\") {
$(\".wcpay-qrcode\").html(\"\");
$(\".wcpay-qrcode\").html(\"<p class='am-alert am-alert-success'>支付成功,正在跳转页面</p>\");
window.setTimeout(function () {
location.href = \"/detail-order-sn/$orderid\"
}, 800);
} else {
setTimeout(\"paymentcheck()\", 1000);
}
}
});
}
$(\".request-wechat-pay\").click(function () {
if ($(\".wcpay-qrcode\").data(\"requested\") == 0) {
stripe.createSource({
type: 'wechat',
amount: $usd,
currency: 'usd',
owner: {
name: '$orderid'
},
}).then(function (result) {
if (result.source.id) {
$(\".wcpay-qrcode\").html(\"<p class='am-alert am-alert-success'>打开微信 - 扫一扫</p>\");
$(\".wcpay-qrcode\").qrcode(result.source.wechat.qr_code_url);
$(\".wcpay-qrcode\").data(\"requested\", 1);
$(\".wcpay-qrcode\").data(\"sid\", result.source.id);
$(\".wcpay-qrcode\").data(\"scs\", result.source.client_secret);
source = result.source.id;
setTimeout(\"paymentcheck()\", 3000);
} else {
alert(\"微信支付加载失败\");
$(\".wcpay-qrcode\").html(\"<p class='am-alert am-alert-danger'>加载失败,请刷新页面。</p>\");
}
// handle result.error or result.source
});
}
});
</script>
</body>
</html>";
return $html;
} catch (\Exception $e) {
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
}
break;
}
}
public function returnUrl(Request $request)
{
$data = $request->all();
$cacheord = $this->orderService->detailOrderSN($data['orderid']);
if (!$cacheord) {
return redirect(url('detail-order-sn', ['orderSN' => $data['orderid']]));
}
$payGateway = $this->payService->detail($cacheord->pay_id);
\Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
$source_object = \Stripe\Source::retrieve($data['source']);
//die($source_object);
if ($source_object->status == 'chargeable') {
\Stripe\Charge::create([
'amount' => $source_object->amount,
'currency' => $source_object->currency,
'source' => $data['source'],
]);
if ($source_object->owner->name == $data['orderid']) {
$this->orderProcessService->completedOrder($data['orderid'], $source_object->amount / 100, $source_object->id);
}
}
return redirect(url('detail-order-sn', ['orderSN' => $data['orderid']]));
}
public function check(Request $request)
{
$data = $request->all();
$cacheord = $this->orderService->detailOrderSN($data['orderid']);
if (!$cacheord) {
//可能已异步回调成功,跳转
return 'fail';
} else {
$payGateway = $this->payService->detail($cacheord->pay_id);
\Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
$source_object = \Stripe\Source::retrieve($data['source']);
if ($source_object->status == 'chargeable') {
\Stripe\Charge::create([
'amount' => $source_object->amount,
'currency' => $source_object->currency,
'source' => $data['source'],
]);
}
if ($source_object->status == 'consumed' && $source_object->owner->name == $data['orderid']) {
$this->orderProcessService->completedOrder($data['orderid'], $cacheord->actual_price, $source_object->id);
return 'success';
} else {
return 'fail';
}
}
}
public function charge(Request $request)
{
$data = $request->all();
$cacheord = $this->orderService->detailOrderSN($data['orderid']);
if (!$cacheord) {
//可能已异步回调成功,跳转
return 'fail';
} else {
try {
$payGateway = $this->payService->detail($cacheord->pay_id);
\Stripe\Stripe::setApiKey($payGateway -> merchant_pem);
$result = \Stripe\Charge::create([
'amount' => bcmul($this->getUsdCurrency($cacheord->actual_price), 100,0),
'currency' => 'usd',
'source' => $data['stripeToken'],
]);
if ($result->status == 'succeeded') {
$this->orderProcessService->completedOrder($data['orderid'], $cacheord->actual_price, $data['stripeToken']);
return 'success';
}
return $result;
} catch (\Exception $e) {
return $e->getMessage();
}
}
}
/**
* 根据RMB获取美元
* @param $cny
* @return float|int
* @throws \Exception
*/
public function getUsdCurrency($cny)
{
$client = new Client();
$res = $client->get('https://m.cmbchina.com/api/rate/fx-rate');
$fxrate = json_decode($res->getBody(), true);
$data = $fxrate['body']['data'];
if (!isset($data)) {
throw new \Exception('汇率接口异常');
}
$dfFxrate = 0.13;
foreach ($data as $item) {
if ($item['ccyNbr'] == "美元") {
$dfFxrate = bcdiv(100, $item['rtcOfr'], 2);
break;
}
}
return bcmul($cny , $dfFxrate , 2);
}
}
@@ -0,0 +1,105 @@
<?php
/**
* The file was created by LightCountry.
*
* @author https://github.com/LightCountry
* @copyright https://github.com/LightCountry
* @link https://github.com/LightCountry/TokenPay
*/
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
class TokenPayController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
//构造要请求的参数数组,无需改动
$parameter = [
"ActualAmount" => (float)$this->order->actual_price,//原价
"OutOrderId" => $this->order->order_sn,
"OrderUserKey" => $this->order->email,
"Currency" => $this->payGateway->merchant_id,
'RedirectUrl' => route('tokenpay-return', ['order_id' => $this->order->order_sn]),
'NotifyUrl' => url($this->payGateway->pay_handleroute . '/notify_url'),
];
$parameter['Signature'] = $this->VerifySign($parameter, $this->payGateway->merchant_key);
$client = new Client([
'headers' => [ 'Content-Type' => 'application/json' ]
]);
$response = $client->post($this->payGateway->merchant_pem.'/CreateOrder', ['body' => json_encode($parameter)]);
$body = json_decode($response->getBody()->getContents(), true);
if (!isset($body['success']) || $body['success'] != true) {
return $this->err(__('dujiaoka.prompt.abnormal_payment_channel') . $body['message']);
}
return redirect()->away($body['data']);
} catch (RuleValidationException $exception) {
} catch (GuzzleException $exception) {
return $this->err($exception->getMessage());
}
}
private function VerifySign(array $parameter, string $signKey)
{
ksort($parameter);
reset($parameter); //内部指针指向数组中的第一个元素
$sign = '';
$urls = '';
foreach ($parameter as $key => $val) {
if ($key != 'Signature') {
if ($sign != '') {
$sign .= "&";
$urls .= "&";
}
$sign .= "$key=$val"; //拼接为url参数形式
$urls .= "$key=" . urlencode($val); //拼接为url参数形式
}
}
$sign = md5($sign . $signKey);//密码追加进入开始MD5签名
return $sign;
}
public function notifyUrl(Request $request)
{
$data = $request->all();
$order = $this->orderService->detailOrderSN($data['OutOrderId']);
if (!$order) {
return 'fail';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'fail';
}
if($payGateway->pay_handleroute != 'pay/tokenpay'){
return 'fail';
}
//合法的数据
$signature = $this->VerifySign($data, $payGateway->merchant_key);
if ($data['Signature'] != $signature) { //不合法的数据
return 'fail'; //返回失败 继续补单
} else {
//合法的数据
//业务处理
$this->orderProcessService->completedOrder($data['OutOrderId'], $data['ActualAmount'], $data['Id']);
return 'ok';
}
}
public function returnUrl(Request $request)
{
$oid = $request->get('order_id');
// 异步通知还没到就跳转了,所以这里休眠2秒
sleep(2);
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
}
}
@@ -0,0 +1,94 @@
<?php
/**
* VpayController.php
* V免签
* Author iLay1678
* Created on 2020/5/1 11:59
*/
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
class VpayController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
//构造要请求的参数数组,无需改动
$parameter = array(
"payId" => date('YmdHis') . rand(1, 65535),//平台ID号
"price" => (float)$this->order->actual_price,//原价
'param' => $this->order->order_sn,
'returnUrl' => route('vpay-return', ['order_id' => $this->order->order_sn]),
'notifyUrl' => url($this->payGateway->pay_handleroute . '/notify_url'),
"isHtml" => 1,
);
switch ($payway) {
case 'vzfb':
$parameter['type'] = 2;
break;
case 'vwx':
default:
$parameter['type'] = 1;
break;
}
$parameter['sign'] = md5($parameter['payId'] . $parameter['param'] . $parameter['type'] . $parameter['price'] . $this->payGateway->merchant_id);
$payurl = $this->payGateway->merchant_pem . 'createOrder?' . http_build_query($parameter); //支付页面
return redirect()->away($payurl);
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
public function notifyUrl(Request $request)
{
$data = $request->all();
$order = $this->orderService->detailOrderSN($data['param']);
if (!$order) {
return 'fail';
}
$payGateway = $this->payService->detail($order->pay_id);
if($payGateway->pay_handleroute != 'pay/vpay'){
return 'fail';
}
if (!$payGateway) {
return 'fail';
}
$key = $payGateway->merchant_id;//通讯密钥
$payId = $data['payId'];//商户订单号
$param = $data['param'];//创建订单的时候传入的参数
$type = $data['type'];//支付方式 :微信支付为1 支付宝支付为2
$price = $data['price'];//订单金额
$reallyPrice = $data['reallyPrice'];//实际支付金额
$sign = $data['sign'];//校验签名,计算方式 = md5(payId + param + type + price + reallyPrice + 通讯密钥)
//开始校验签名
$_sign = md5($payId . $param . $type . $price . $reallyPrice . $key);
if ($_sign != $sign) { //不合法的数据
return 'fail'; //返回失败 继续补单
} else { //合法的数据
//业务处理
$this->orderProcessService->completedOrder($param, $price, $payId);
return 'success';
}
}
public function returnUrl(Request $request)
{
$oid = $request->get('order_id');
// 异步通知还没到就跳转了,所以这里休眠2秒
sleep(2);
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
}
}
@@ -0,0 +1,89 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Yansongda\Pay\Pay;
class WepayController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
$config = [
'app_id' => $this->payGateway->merchant_id,
'mch_id' => $this->payGateway->merchant_key,
'key' => $this->payGateway->merchant_pem,
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
'return_url' => url('detail-order-sn', ['orderSN' => $this->order->order_sn]),
'http' => [ // optional
'timeout' => 10.0,
'connect_timeout' => 10.0,
],
];
$order = [
'out_trade_no' => $this->order->order_sn,
'total_fee' => bcmul($this->order->actual_price, 100, 0),
'body' => $this->order->order_sn
];
switch ($payway){
case 'wescan':
try{
$result = Pay::wechat($config)->scan($order)->toArray();
$result['qr_code'] = $result['code_url'];
$result['payname'] =$this->payGateway->pay_name;
$result['actual_price'] = (float)$this->order->actual_price;
$result['orderid'] = $this->order->order_sn;
return $this->render('static_pages/qrpay', $result, __('dujiaoka.scan_qrcode_to_pay'));
} catch (\Exception $e) {
throw new RuleValidationException(__('dujiaoka.prompt.abnormal_payment_channel') . $e->getMessage());
}
break;
}
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
/**
* 异步通知
*/
public function notifyUrl()
{
$xml = file_get_contents('php://input');
$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
$oid = $arr['out_trade_no'];
$order = $this->orderService->detailOrderSN($oid);
if (!$order) {
return 'error';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'error';
}
if($payGateway->pay_handleroute != '/pay/wepay'){
return 'error';
}
$config = [
'app_id' => $payGateway->merchant_id,
'mch_id' => $payGateway->merchant_key,
'key' => $payGateway->merchant_pem,
];
$pay = Pay::wechat($config);
try{
// 验证签名
$result = $pay->verify();
$total_fee = bcdiv($result->total_fee, 100, 2);
$this->orderProcessService->completedOrder($result->out_trade_no, $total_fee, $result->transaction_id);
return 'success';
} catch (\Exception $exception) {
return 'fail';
}
}
}
@@ -0,0 +1,103 @@
<?php
namespace App\Http\Controllers\Pay;
use App\Exceptions\RuleValidationException;
use App\Http\Controllers\PayController;
use Illuminate\Http\Request;
class YipayController extends PayController
{
public function gateway(string $payway, string $orderSN)
{
try {
// 加载网关
$this->loadGateWay($orderSN, $payway);
//组装支付参数
$parameter = [
'pid' => $this->payGateway->merchant_id,
'type' => $payway,
'out_trade_no' => $this->order->order_sn,
'return_url' => route('yipay-return', ['order_id' => $this->order->order_sn]),
'notify_url' => url($this->payGateway->pay_handleroute . '/notify_url'),
'name' => $this->order->order_sn,
'money' => (float)$this->order->actual_price,
'sign' => $this->payGateway->merchant_pem,
'sign_type' =>'MD5'
];
ksort($parameter); //重新排序$data数组
reset($parameter); //内部指针指向数组中的第一个元素
$sign = '';
foreach ($parameter as $key => $val) {
if ($key == "sign" || $key == "sign_type" || $val == "") continue;
if ($key != 'sign') {
if ($sign != '') {
$sign .= "&";
}
$sign .= "$key=$val"; //拼接为url参数形式
}
}
$sign = md5($sign . $this->payGateway->merchant_pem);//密码追加进入开始MD5签名
$parameter['sign'] = $sign;
//待请求参数数组
$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->payGateway->merchant_key . "' method='get'>";
foreach($parameter as $key => $val) {
$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
}
//submit按钮控件请不要含有name属性
$sHtml = $sHtml."<input type='submit' value=''></form>";
$sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
return $sHtml;
} catch (RuleValidationException $exception) {
return $this->err($exception->getMessage());
}
}
public function notifyUrl(Request $request)
{
$data = $request->all();
$order = $this->orderService->detailOrderSN($data['out_trade_no']);
if (!$order) {
return 'fail';
}
$payGateway = $this->payService->detail($order->pay_id);
if (!$payGateway) {
return 'fail';
}
if($payGateway->pay_handleroute != '/pay/yipay'){
return 'fail';
}
ksort($data); //重新排序$data数组
reset($data); //内部指针指向数组中的第一个元素
$sign = '';
foreach ($data as $key => $val) {
if ($key == "sign" || $key == "sign_type" || $val == "") continue;
if ($key != 'sign') {
if ($sign != '') {
$sign .= "&";
}
$sign .= "$key=$val"; //拼接为url参数形式
}
}
if (!$data['trade_no'] || md5($sign . $payGateway->merchant_pem) != $data['sign']) { //不合法的数据
return 'fail'; //返回失败 继续补单
} else {
//合法的数据
//业务处理
$this->orderProcessService->completedOrder($data['out_trade_no'], $data['money'], $data['trade_no']);
return 'success';
}
}
public function returnUrl(Request $request)
{
$oid = $request->get('order_id');
// 有些易支付太垃了,异步通知还没到就跳转了,导致订单显示待支付,其实已经支付了,所以这里休眠2秒
sleep(2);
return redirect(url('detail-order-sn', ['orderSN' => $oid]));
}
}