PHP微信公众号支付demo

备注:以下代码基于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."";
    }
    $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"]);
    }

后记

剩下的事情就交给前端了,有什么问题可以留言哈。

你可能感兴趣的:(PHP微信公众号支付demo)