微信支付V3
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2021/9/13
* Time: 16:26
*/
namespace app\index\controller;
use think\Controller;
use think\Request;
/**
* 微信支付V3
* Class Pay
* @package app\index\controller
*/
class Pay extends Controller
{
protected $payApi = [
'app' => 'https://api.mch.weixin.qq.com/v3/pay/transactions/app',//APP支付
'h5' => 'https://api.mch.weixin.qq.com/v3/pay/transactions/h5',//H5支付
];//支付接口列表
protected $queryApi = 'https://api.mch.weixin.qq.com/v3/pay/transactions/id/{transaction_id}';//查詢訂單接口
protected $refundApi = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';//退單接口
protected $refundNotify = '******';//退單回調自定義
public function _initialize()
{
}
/**
* 配置
*/
public function config(){
return [
'appid' => '******',
'mchid' => '******',//商戶號
'serial_no' => '******',//證書序列號
'description' => '******',//應用名稱
'notify' => '******',//支付回調
];
}
/**
* 設置支付url
* @param string $type 支付平台
* @return mixed
*/
public function getPayUrl($type = 'app'){
return $this->payApi[$type];
}
/**
* H5支付
* @param $total int 支付金額
* @return mixed
*/
public function h5Pay($total){
//請求參數(報文主體)
$config = $this->config();
$body = [
'appid' => $config['appid'],
'mchid' => $config['mchid'],
'description' => $config['description'],
'out_trade_no' => $this->getOrderNo(),
'notify_url' => $config['notify'],
'amount' => [
'total' => $total,
'currency' => 'CNY'
],
'scene_info' => [
'payer_client_ip' => Request::instance()->ip(),
'h5_info' => [
'type' => 'Wap',
],
],
];
$headers = $this->sign('POST',$this->getPayUrl('h5'),json_encode($body));
return $this->curl_post($this->getPayUrl('h5'),json_encode($body),$headers);
}
/**
* APP支付
* @param $total int 支付金額
* @return mixed
*/
public function appPay($total){
//請求參數(報文主體)
$config = $this->config();
$body = [
'appid' => $config['appid'],
'mchid' => $config['mchid'],
'description' => $config['description'],
'out_trade_no' => $this->getOrderNo(),
'notify_url' => $config['notify'],
'amount' => [
'total' => $total,
'currency' => 'CNY'
],
];
$headers = $this->sign('POST',$this->getPayUrl(),json_encode($body));
return $this->curl_post($this->getPayUrl(),json_encode($body),$headers);
}
/**
* 預下單
*/
public function preOrder(){
$res = $this->h5Pay(1);
print_r($res);die;
}
/**
* 支付回調
*/
public function notify(){
}
/**
* 退款
* @param string $transaction_id 平台訂單號
* @return mixed
*/
public function refund($transaction_id = ''){
$body = [
'transaction_id' => $transaction_id,//平台訂單號
'out_refund_no' => $this->getOrderNo(),//系統退款單號
'reason' => '退款',//退款原因
'notify_url' => '',//退款回調
'amount' => [
'refund' => 1,//退款金額
'total' => 1,//原訂單金額
'currency' => 'CNY',
],
];
$headers = $this->sign('POST',$this->refundApi,json_encode($body));
return $this->curl_post($this->refundApi,json_encode($body),$headers);
}
/**
* 退款回調
*/
public function refundNotify(){
}
/**
* 簽名
* @param string $http_method 請求方式GET|POST
* @param string $url url
* @param string $body 報文主體
* @return array
*/
public function sign($http_method = 'POST',$url = '',$body = ''){
$mch_private_key = $this->getMchKey();//私鑰
$timestamp = time();//時間戳
$nonce = $this->getRandomStr(32);//隨機串
$url_parts = parse_url($url);
$canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
//構造簽名串
$message = $http_method."\n".
$canonical_url."\n".
$timestamp."\n".
$nonce."\n".
$body."\n";//報文主體
//計算簽名值
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign);
//設置HTTP頭
$config = $this->config();
$token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
$config['mchid'], $nonce, $timestamp, $config['serial_no'], $sign);
$headers = [
'Accept: application/json',
'User-Agent: */*',
'Content-Type: application/json; charset=utf-8',
'Authorization: '.$token,
];
return $headers;
}
//私鑰
public function getMchKey(){
//path->私鑰文件存放路徑
return openssl_get_privatekey(file_get_contents('path'));
}
//post請求
public function curl_post($url , $data,$headers=array())
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
//設置header頭
curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
// POST數據
curl_setopt($ch, CURLOPT_POST, 1);
// 把post的變量加上
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
//get請求
public function curl_get($url,$headers=array())
{
$info = curl_init();
curl_setopt($info,CURLOPT_RETURNTRANSFER,true);
curl_setopt($info,CURLOPT_HEADER,0);
curl_setopt($info,CURLOPT_NOBODY,0);
curl_setopt($info,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($info,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($info,CURLOPT_SSL_VERIFYHOST,false);
//設置header頭
curl_setopt($info, CURLOPT_HTTPHEADER,$headers);
curl_setopt($info,CURLOPT_URL,$url);
$output = curl_exec($info);
curl_close($info);
return $output;
}
/**
* 獲得隨機字符串
* @param $len integer 需要的長度
* @param $special bool 是否需要特殊符號
* @return string 返回隨機字符串
*/
public function getRandomStr($len, $special=false){
$chars = array(
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
"w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
"S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
"3", "4", "5", "6", "7", "8", "9"
);
if($special){
$chars = array_merge($chars, array(
"!", "@", "#", "$", "?", "|", "{", "/", ":", ";",
"%", "^", "&", "*", "(", ")", "-", "_", "[", "]",
"}", "<", ">", "~", "+", "=", ",", "."
));
}
$charsLen = count($chars) - 1;
shuffle($chars); //打亂數組順序
$str = '';
for($i=0; $i<$len; $i++){
$str .= $chars[mt_rand(0, $charsLen)]; //隨機取出一位
}
return $str;
}
/**
* 生成訂單號
*/
public function getOrderNo(){
return date('Ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}
//H5測試支付
// public function pay(){
// $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/h5';
// $body = [
// 'appid' => '******',
// 'mchid' => '******',
// 'description' => '******',
// 'out_trade_no' => date('YmdHis').rand(1000,9999),
// 'notify_url' => "******",
// 'amount' => [
// 'total' => 100,
// 'currency' => 'CNY'
// ],
// 'scene_info' => [
// 'payer_client_ip' => Request::instance()->ip(),
// 'h5_info' => [
// 'type' => 'Wap',
// ],
// ],
// ];
// $headers = $this->sign('POST',$url,json_encode($body));
// $res = $this->curl_post($url,$body,$headers);
// print_r($res);
// }
}
簡單的寫了個支付類,沒有接通業務,其余的請自行補充