备注:以下代码基于PHP laravel框架,引用了自带的函数。array_get($array, "key")
为数组中取元素,类似于$array["key"]
后端发起支付
/**
* 微信公众号支付请求
* @param $userOpenId 用户uid
* @param $orderNumber 商户订单编号
* @param $money 支付金额,元为单位
* @param $notify_url 回调地址
* @param $body 支付提醒文案
* @param $wechatConfig
* @return array|bool
*/
function wechatPay($userOpenId, $orderNumber, $money, $notify_url, $body, $wechatConfig)
{
//将预支付订单提交到微信支付
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //微信统一下单请求地址
$data = [
"openid" => $userOpenId,
"appid" => array_get($wechatConfig, "app_id"), //微信appId
"mch_id" => array_get($wechatConfig, "merchant_id"), //微信商户id
"nonce_str" => uniqid(),
"body" => $body,
"out_trade_no" => $orderNumber,
"total_fee" => $money * 100, //微信订单金额以分为单位
"spbill_create_ip" => getClientIP(),
"notify_url" => $notify_url,
"trade_type" => "JSAPI",
];
$signData = wechat_sign($data, array_get($wechatConfig, "pay_miyao")); //获取签名,需要进入商户平台配置好支付秘钥
$data['sign'] = $signData;
$result = postXmlCurl(arrayToXml($data), $url, false, 30);
$result = xmlToArray($result);
if (array_get($result, "return_code") != "SUCCESS" && array_get($result, "result_code") != "SUCCESS") {
return false; //请求支付失败
}
$data = [
"appId" => array_get($wechatConfig, "app_id"),
"timeStamp" => (string)time(),
"nonceStr" => uniqid(),
"package" => "prepay_id=".array_get($result, "prepay_id"),
"signType" => "MD5",
];
$sign = wechat_sign($data, array_get($wechatConfig, "pay_miyao"));
$data["paySign"] = $sign;
return $data;
}
/**
* 微信支付签名
* @param $data 要加密的参数
* @param $pay_miyao 微信支付秘钥
* @return string
*/
function wechat_sign($data, $pay_miyao)
{
ksort($data);
$res = "";
foreach ($data as $key => $value) {
if (!$value) continue; //参数值为空时不参与签名
$res .= $key."=".$value."&";
}
$stringSignTemp = $res."key=".$pay_miyao;
return strtoupper(md5($stringSignTemp));
}
/**
* xml to array
* @param $result
*/
function xmlToArray($xml)
{
libxml_disable_entity_loader(true);
$result = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
}
/**
* @param $arr
* @return string
*/
function arrayToXml($arr)
{
$xml = "";
foreach ($arr as $key=>$val) {
$xml.="<".$key.">".$val."".$key.">";
}
$xml.=" ";
return $xml;
}
/**
* 微信支付xml请求
* @param $xml
* @param $url
* @param bool $useCert
* @param int $second
* @return mixed
* @throws \Exception
*/
function postXmlCurl($xml, $url, $useCert = false, $second = 30)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);//严格校验
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if($useCert == true){
//设置证书 微信支付不需要证书,此处证书验证可以忽略
//使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, base_path("public/xxx/apiclient_cert.pem"));
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, base_path("public/xxx/apiclient_key.pem"));
}
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new \Exception("curl出错,错误码:$error");
}
}
发起成功,微信正常返回demo
返回示例
{
"code": "0",
"msg": "请求成功",
"data": {
"payInfo": {
"appId": "wx04134e1774abedc3",
"timeStamp": "1561415899",
"nonceStr": "5d1150db6d2f1",
"package": "prepay_id=wx24153838009174ad41d109091656422500",
"signType": "MD5",
"paySign": "7D459540ACBA6A48BB3CA2E0DDB9453F"
}
}
}
微信支付回调
/**
* 微信支付回调
* @return string
*/
public function notify()
{
$request = file_get_contents("php://input");
$notifyArrData = xmlToArray($request);
//将回调签名单独拿出来
$sign = array_get($notifyArrData, "sign");
unset($notifyArrData['sign']);
//签名验证(商户平台配置,和请求支付的秘钥为同一个)
$miyao = "";
$signData = wechat_sign($notifyArrData, $miyao);
if ($signData != $sign) {
return arrayToXml(["return_code" => "FAIL", "return_msg" => "FAIL"]);
}
//支付结果验证
$resultCode = array_get($notifyArrData, "result_code");
$returnCode = array_get($notifyArrData, "return_code");
if ($resultCode != "SUCCESS" || $returnCode != "SUCCESS") {
return arrayToXml(["return_code" => "FAIL", "return_msg" => "FAIL"]);
}
$payOrderNumber = array_get($notifyArrData, "out_trade_no"); //获取商户支付订单号
$outOrderNumber = array_get($notifyArrData, "transaction_id"); //获取微信订单号
//设置订单支付成功(处理订单支付完成以后的业务逻辑)
$result = true;
if ($result) {
return arrayToXml(["return_code" => "SUCCESS", "return_msg" => "OK"]);
}
return arrayToXml(["return_code" => "FAIL", "return_msg" => "FAIL"]);
}
后记
剩下的事情就交给前端了,有什么问题可以留言哈。