演示地址

H5支付测试地址

准备工作

登陆微信商户后台,需要准备一个网站,并开通H5支付,此过程可能需要微信工作人员人工审核,需等待几天。

在这里插入图片描述

配置支付域名
在这里插入图片描述
在这里插入图片描述

字段获取位置

  • appId 在如图获取可以,也可以在关联的公众号上查看。
    在这里插入图片描述
  • apiKey
    在这里插入图片描述
  • mchid 商户号
    在这里插入图片描述

    核心代码

     复制代码 隐藏代码
    class H5Pay
    {
    protected $appId; //appid 公众号查看
    protected $apiKey; //设置的32位的
    protected $mchid; //商户号
    protected $price; //价格单位是分
    protected $orderId; //订单号
    protected $orderName; //订单名称
    protected $notifyUrl; //异步回调地址
    protected $returnUrl; //支付成功后页面要跳转的地址
    protected $wapUrl; //网站url
    protected $wapName; //网站名称
    public function __construct($mchid, $appid, $key)
    {
        $this->appId = $appid;
        $this->apiKey = $key;
        $this->mchid = $mchid;
    }
    
    //设置订单基本信息
    public function setPrice($price)
    {
        $this->price = $price;
    }
    
    public function setReturnUrl($returnUrl)
    {
        $this->returnUrl = $returnUrl;
    }
    
    public function setOrderName($orderName)
    {
        $this->orderName = $orderName;
    }
    
    public function setOrderId($orderId)
    {
        $this->orderId = $orderId;
    }
    
    public function setWapUrl($wapUrl)
    {
        $this->wapUrl = $wapUrl;
    }
    public function setWapName($wapName)
    {
        $this->wapName = $wapName;
    }
    public function setNotifyUrl($notifyUrl)
    {
        $this->notifyUrl = $notifyUrl;
    }
    
    //创建订单
    public function createOrder()
    {
        $post_data = [
            'appid' => $this->appId,
            'attach' => 'h5_pay',             //商家数据包,原样返回,如果填写中文,请注意转换为utf-8
            'body' => $this->orderName,
            'mch_id' => $this->mchid,
            'nonce_str' => $this->nonceStr(),
            'notify_url' => $this->notifyUrl,
            'out_trade_no' => $this->orderId,
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
            'total_fee' => $this->price,      
            'trade_type' => 'MWEB',
            'scene_info' => json_encode([
                'h5_info' => [
                    'type' => 'Wap',
                    'wap_url' => $this->wapUrl,
                    'wap_name' => $this->wapName,
                ]
            ])
        ];
        $post_data['sign'] = $this->calcSign($post_data);
        $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', $this->arrayToXml($post_data));
        $result = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
        if ($result->return_code != 'SUCCESS') {
            die($result->return_msg);
        }
        if ($result->mweb_url) {
            return $result->mweb_url . '&redirect_url=' . urlencode($this->returnUrl);
        }
    }
    
    //仅为参考,可自己实现
    public function nonceStr()
    {
        return  substr(md5(uniqid() . time()), 0, 16);
    }
    
    //计算签名
    public function calcSign($params)
    {
        ksort($params, SORT_STRING);
        $str = $this->self_http_build_query($params); //使用自带的可能会出现转义问题,导致签名错误
        $signStr = strtoupper(md5($str . "&key=" . $this->apiKey));
        return $signStr;
    }
    
    public function self_http_build_query($params)
    {
        $buff = "";
        ksort($params);
        foreach ($params as $k => $v) {
            if (null != $v && "null" != $v) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $reqPar = '';
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }
    
    public  function arrayToXml($arr)
    {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
        }
        $xml .= "</xml>";
        return $xml;
    }
    
    public  function curlPost($url, $postData)
    {
        is_array($postData) && $postData = http_build_query($postData);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        //https请求 不验证证书和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
    }

调用

 复制代码 隐藏代码
header('Content-type:text/html; Charset=utf-8');
$mchid = '';
$appid = '';
$apiKey = '';
$orderId = uniqid();
$price = 1;
$orderName = 'H5测试';
$notifyUrl = '';     //付款成功后的回调地址(不要有问号)
$returnUrl = '';     //付款成功后,页面跳转的地址
$wapUrl = '';   //WAP网站URL地址
$wapName = 'H5支付';       //WAP 网站名

$wxPay = new H5Pay($mchid, $appid, $apiKey);
$wxPay->setPrice($price);
$wxPay->setOrderId($orderId);
$wxPay->setOrderName($orderName);
$wxPay->setNotifyUrl($notifyUrl);
$wxPay->setReturnUrl($returnUrl);
$wxPay->setWapUrl($wapUrl);
$wxPay->setWapName($wapName);

$mwebUrl = $wxPay->createOrder($price, $orderId, $orderName, $notifyUrl);
echo "<h1><a href='{$mwebUrl}'>点击跳转至支付页面</a></h1>";
exit();

常见错误

签名错误

在拼接待签名的字符串,直接使用http_build_query, 会导致参数中的中文被转义,就会出现签名错误问题。

在这里插入图片描述

商家存在未配置的参数,请联系商家解决

1.如果你运行php的域名不是H5配置的域名会出现如下错误,也就是调试必须在线上调试。
在这里插入图片描述
2.如果你配置的是主域名,使用的是二级域名也会出现这种情况,如果www和主域名指向同一个地址,恭喜你 很容易入这个坑。要保持代码和后台配置完全一样就可以避免这个问题了。
在这里插入图片描述