支付前准备工作:

* 申请小程序开发者账号 APP_ID

* 申请支付商户号 MCH_ID

* 获取商户秘钥 MCH_KEY


公共配置文件中,配置好参数值:



自定义统一下单方法:

/**
 * 首先在服务器端调用微信【统一下单】接口
 *     返回prepay_id和sign签名等信息给前端,前端调用微信支付接口
 * @param               [type] $payFee   支付金额
 * @param               [type] $openid   OPENID
 * @param               [type] $orderNo  订单编号
 * @author 凉笙墨染 2019-04-23
 */
public function pay($payFee, $openid, $orderNo){
    $appId = config('WX_APP_ID');
    $mchId = config('MCH_ID');
    $mchKey = config('MCH_KEY');

    if ( empty($mchId) ) return [[], 0, '请配置微信支付商户号'];
    if ( empty($mchKey) ) return [[], 0, '请配置微信支付商户秘钥'];

    $nonceStr = pay_nonce_str();
    $signParam = [
        'appid'            => $appId,
        'mch_id'           => $mchId,
        'nonce_str'        => $nonceStr,
        'body'             => '小程序支付订单',
        'out_trade_no'     => $orderNo,
        'total_fee'        => intval($payFee),
        'spbill_create_ip' => $_SERVER['SERVER_ADDR'],
        'notify_url'       => $this->request->domain().'/wxpaynotify',
        'trade_type'       => 'JSAPI',
        'openid'           => $openid,
    ];

    // 获取支付签名
    $signStr = pay_sign($signParam, $mchKey);

    $signParam['sign'] = $signStr;
    $xml = array_to_xml($signParam);

    /**
     * POST 发起请求 统一下单接口prepay_id
     * @var string
     * <xml>
     *     <return_code><![CDATA[SUCCESS]]></return_code>
     *     <return_msg><![CDATA[OK]]></return_msg>
     *     <appid><![CDATA[wxb894baf67da7b043]]></appid>
     *     <mch_id><![CDATA[1517273941]]></mch_id>
     *     <nonce_str><![CDATA[MtwS7SGqRIBat6yT]]></nonce_str>
     *     <sign><![CDATA[BA27C3FA17ED3BFCC2CFEA0CAC418F73]]></sign>
     *     <result_code><![CDATA[SUCCESS]]></result_code>
     *     <prepay_id><![CDATA[wx25162041735041e7f92689191844942960]]></prepay_id>
     *     <trade_type><![CDATA[JSAPI]]></trade_type>
     * </xml>
     */
    $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    $ret = curl_request($url, $xml);

    /**
     * {
     *     APPID:"wxb894baf67da7b043",
     *     MCH_ID: 1517273941,
     *     NONCE_STR: "MtwS7SGqRIBat6yT",
     *     PREPAY_ID: "wx25162041735041e7f92689191844942960",
     *     RESULT_CODE:"SUCCESS",
     *     RETRUN_CODE:"SUCCESS",
     *     RETURN_MSG:"OK",
     *     SIGN:"243872A3A46265CE6704879B203CE58A",
     *     TRADE_TYPE:"JSAPI"
     * }
     */
    $res = xml_to_array($ret);

    if ($res['RETURN_CODE'] == 'SUCCESS' && $res['RESULT_CODE'] == 'SUCCESS') {
        // 支付成功
        $timeStamp = time();

        // 参与签名参数: appId, nonceStr, package, signType, timeStamp
        $data = [
            'appId'     => $res['APPID'],
            'nonceStr'  => $res['NONCE_STR'],
            'package'   => 'prepay_id='.$res['PREPAY_ID'],
            'signType'  => 'MD5',
            'timeStamp' => $timeStamp
        ];

        $res['TIMESTAMP']= (string)$timeStamp; // must be string
        $res['PACKAGE']  = 'prepay_id='.$res['PREPAY_ID'];
        $res['SIGNTYPE'] = 'MD5';
        $res['PAYSIGN']  = pay_sign($data, $mchKey);

        // 其他参数
        $res['ORDERNO']= $orderNo;
    } else {
        $res['CODE'] = 0;
        $res['RETURN_CODE'] = $res['RETURN_CODE'];
        $res['RETURN_MSG'] = $res['RETURN_MSG'];
    }
    return $res;
}


公共函数:

① pay_nonce_str()

② pay_sign()

③ array_to_xml()

④ xml_to_array() 注:③④请查看PHP实现JSON字符串、数组和XML互相转换示例,解决小程序支付签名问题

⑤ curl_request()  注:请查看万能的CURL发起HTTP(GET/POST)请求

① 获取签名随机字符串:

/**
 * 为支付签名产生随机字符串
 * @return              [type] [description]
 * @author 凉笙墨染 2019-04-20
 */
function pay_nonce_str(){
    $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $noceStr = "";
    for($i = 0; $i < 32; $i++){
        $noceStr .= $chars[ mt_rand(0, strlen($chars) - 1) ];
    }
    return $noceStr;
}


 获取签名函数:

/**
 * 生成支付签名
 * @param               [type] $params  参数按照key=value的格式 并按照参数名ASCII字典序排序
 * @param               [type] $key     商户平台设置的密钥key
 * @author 凉笙墨染 2019-04-20
 */
function pay_sign($params, $key){
    //签名步骤一:按字典序排序数组参数
    ksort($params);
    //签名步骤二:在string后加入KEY
    $params['key'] = $key;
    $string = '';
    $array = array();
    foreach( $params as $key => $value ){
        $array[] = $key.'='.$value;
    }
    $string = implode("&",$array);
    //签名步骤三:MD5加密
    $string = md5($string);
    //签名步骤四:所有字符转为大写
    $string = strtoupper($string);
    return $string;
}

注意:微信小程序签名规范