参考官方文档
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_1.shtml (h5支付文档)
https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml(签名生成)
https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml(签名验证)
/**
* H5支付
* @param $total int 支付金额
* @return mixed
*/
public static function h5($out_trade_no, $body){
//请求参数(报文主体)
$config = self::config();
$body = [
'appid' => $config['appid'],
'mchid' => $config['mchid'],
'description' => $body,
'out_trade_no' => $out_trade_no,
'notify_url' => $config['notify'],
'amount' => [
'total' => 1,
'currency' => 'CNY'
],
'scene_info' => [
'payer_client_ip' => '',
'h5_info' => [
'type' => 'Wap',
],
],
];
$headers = self::sign('POST','https://api.mch.weixin.qq.com/v3/pay/transactions/h5',json_encode($body));
$result = self::curl_post('https://api.mch.weixin.qq.com/v3/pay/transactions/h5',json_encode($body),$headers);
$result = json_decode($result,true);
return $result['h5_url'];
}
/**
* 配置
*/
public static function config(){
return [
'appid' => '',
'mchid' => '',//商户号
'serial_no' => '',//证书序列号
'description' => '',//应用名称
'notify' => '',//支付回调
];
}
/**
* 签名
* @param string $http_method 请求方式GET|POST
* @param string $url url
* @param string $body 报文主体
* @return array
*/
public static function sign($http_method = 'POST',$url = '',$body = ''){
$mch_private_key = self::getMchKey();//私钥
$timestamp = time();//时间戳
$nonce = self::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 = self::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 static function getMchKey(){
//path->私钥文件存放路径
return openssl_get_privatekey(file_get_contents('私钥证书绝对路径'));
}
/**
* 获得随机字符串
* @param $len integer 需要的长度
* @param $special bool 是否需要特殊符号
* @return string 返回随机字符串
*/
public static 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;
}
//post请求
public static 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;
}