首先需要申请微信公众号支付,配置授权域名及授权目录。以下是可运行的代码:
前台 ajax 调用支付数据:
<div class="apply" onclick="callBack()">微信支付</div>
function onBridgeReady(){
var amount = $('#amount').val();
$.post(url,data,function(result){
result = JSON.parse(result);
if(result.code == 0) {
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
result.data,
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {window.location.href = "成功支付跳转url"} // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
});
} else {
alert(result.msg);
return;
}
})
}
function callBack() {
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
}
后台返回支付数据, 引入 pay 类文件(在最后):
$Pay = new Pay($config);
$order = [
"body"=>"支付0.01元",
"out_trade_no"=>"123456", #商户支付单号
"total_fee"=>"0.01",
"openid"=>openid
];
$pay_params = $Pay->wxPayOrder($order);
if($pay_params) {
$data["code"] = 0;
$data["msg"] = "成功";
$data["data"]["appId"] = $pay_params["appId"];
$data["data"]["timeStamp"] = $pay_params["timeStamp"];
$data["data"]["nonceStr"] = $pay_params["nonceStr"];
$data["data"]["signType"] = 'MD5';
$data["data"]["package"] = $pay_params["package"];
$data["data"]["paySign"] = $pay_params["sign"];
echo json_encode($data);exit;
}
pay 类文件(抽离通用方法做扩展文件):
class Pay
{
//应用ID
protected $appId;
//商户号
protected $mch_id;
//商户秘钥
protected $mch_key;
//通知地址
protected $notify_url;
//证书路径
protected $apiclient_cert_path;
//证书路径
protected $apiclient_key_path;
#微信公众号支付
public function wxPayOrder($order)
{
$prepayid = $this->wxunifiedorder($order);
if ($prepayid !== false) {
return $this->wxcallPayParams($prepayid);
} else {
return [];
}
}
#微信公众号统一下单
public function wxunifiedorder($order)
{
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$requestData = [
"appid" => $this->appId,
"mch_id" => $this->mch_id,
"nonce_str" => getRandom("32", "0123456789"),
"sign" => "",
"body" => $order["body"],
"out_trade_no" => $order["out_trade_no"],
"total_fee" => $order["total_fee"] * 100,
"spbill_create_ip" => getClientIP(),//获取ip
"notify_url" => $this->notify_url,
"trade_type" => "JSAPI",
"openid" => $order["openid"]
];
$requestData["sign"] = $this->sign($requestData);
$postStr = $this->http_curl($url, "post", $this->array2xml($requestData));
try {
if ($postStr) {
$rs = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($rs["return_code"] == "SUCCESS") {
if ($rs["result_code"] == "SUCCESS") {
return $rs["prepay_id"];
} else {
throw new \Exception($rs["err_code_des"]);
}
} else {
throw new \Exception($rs["return_msg"]);
}
} else {
throw new \Exception("统一下单调用失败");
}
} catch (\Exception $e) {
$this->error = $e->getMessage();
return false;
}
}
#公众号调起支付接口参数
public function wxcallPayParams($prepayid)
{
$requestData = [
"appId" => $this->appId,
"package" => "prepay_id=".$prepayid,
"nonceStr" => getRandom(32, "0123456789"),#获取32位随机数字
"timeStamp" => (string)time(),
"signType" => "MD5"
];
$requestData["sign"] = $this->sign($requestData);
return $requestData;
}
//签名
public function sign($data)
{
$params = array();
foreach ($data as $k => $v) {
if (!empty($data[$k]) && $k != "sign") {
$params[$k] = $v;
}
}
ksort($params);
$stringSignTemp = "";
$i = 0;
foreach ($params as $k => $v) {
if ($i == 0) {
$stringSignTemp .= $k . "=" . $v;
} else {
$stringSignTemp .= "&" . $k . "=" . $v;
}
$i++;
}
$stringSignTemp .= "&key=" . $this->mch_key;
$sign = strtoupper(md5($stringSignTemp));
return $sign;
}
//验证签名
public function validateSign($data){
$sign = $data["sign"];
if($sign==$this->sign($data)){
return true;
}else{
return false;
}
}
private function http_curl($url, $type = "get", $data = "")
{
$ch = curl_init(); //初始化curl
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0); //是否获取response header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书下同
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //
if (strtolower($type) == "post") {
curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
$rs = curl_exec($ch); //运行curl
curl_close($ch);
return $rs;
}
private function http_curl_ssl($url, $type = "get", $data = "")
{
$ch = curl_init(); //初始化curl
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0); //是否获取response header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //不验证证书下同
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, $this->apiclient_cert_path);
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, $this->apiclient_key_path);
if (strtolower($type) == "post") {
curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}
$rs = curl_exec($ch); //运行curl
Log::record("支付日志".var_export($rs,true));
curl_close($ch);
return $rs;
}
public function getError()
{
return $this->error;
}
public function array2xml($data){
$xml = "<xml>";
foreach($data as $k=>$v){
$xml .= "<$k>".$v."</$k>";
}
$xml .= "</xml>";
return $xml;
}
}
如有侵权请邮件通知