«

微信公众号支付代码 PHP 单文件精简版

刚子 发布于 阅读:99


一共需要配置好4个参数。

<?php
/*下单参数:
公众账号ID  字段: appid
商户号     字段: mch_id
随机字符串   字段: nonce_str
签名     字段: sign
签名类型    字段: sign_type  "MD5"
商品描述    字段: body
商户订单号   字段: out_trade_no
标价金额    字段: total_fee
终端IP       字段: spbill_create_ip
通知地址    字段: notify_url
交易类型    字段: trade_type  "JSAPI"

转化为以下格式:

<xml>
   <appid>wx2421b1c4370ec43b</appid>
   <attach>支付测试</attach>
   <body>JSAPI支付测试</body>
   <mch_id>10000100</mch_id>
   <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail>
   <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
   <notify_url>https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>
   <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
   <out_trade_no>1415659990</out_trade_no>
   <spbill_create_ip>14.23.150.211</spbill_create_ip>
   <total_fee>1</total_fee>
   <trade_type>JSAPI</trade_type>
   <sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>

返回值:
返回状态码   字段: return_code 返回值:  SUCCESS/FAIL
返回信息    字段: return_msg  返回值: OK

成功的话,在return_code为SUCCESS的时候有返回:
公众账号ID  字段: appid
商户号 字段: mch_id
签名  字段: sign
业务结果    字段: result_code
错误代码    字段: err_code  返回值: SUCCESS/FAIL(错误的时候返回)

错误码解析:

INVALID_REQUEST 参数错误    参数格式有误或者未按规则上传  订单重入时,要求参数值与原请求一致,请确认参数问题
NOAUTH  商户无此接口权限    商户未开通此接口权限  请商户前往申请此接口权限
NOTENOUGH   余额不足    用户账号余额不足    用户账号余额不足,请用户充值或更换支付卡后再支付
ORDERPAID   商户订单已支付 商户订单已支付,无需重复操作  商户订单已支付,无需更多操作
ORDERCLOSED 订单已关闭   当前订单已关闭,无法支付    当前订单已关闭,请重新下单
SYSTEMERROR 系统错误    系统超时    系统异常,请用相同参数重新调用
APPID_NOT_EXIST APPID不存在    参数中缺少APPID  请检查APPID是否正确
MCHID_NOT_EXIST MCHID不存在    参数中缺少MCHID  请检查MCHID是否正确
APPID_MCHID_NOT_MATCH   appid和mch_id不匹配 appid和mch_id不匹配 请确认appid和mch_id是否匹配
LACK_PARAMS 缺少参数    缺少必要的请求参数   请检查参数是否齐全
OUT_TRADE_NO_USED   商户订单号重复 同一笔交易不能多次提交 请核实商户订单号是否重复提交
SIGNERROR   签名错误    参数签名结果不正确   请检查签名参数和方法是否都符合签名算法要求
XML_FORMAT_ERROR    XML格式错误 XML格式错误 请检查XML参数格式是否正确
REQUIRE_POST_METHOD 请使用post方法   未使用post传递参数     请检查请求参数是否通过post方法提交
POST_DATA_EMPTY post数据为空    post数据不能为空  请检查post数据是否为空
NOT_UTF8    编码格式错误  未使用指定编码格式   请使用UTF-8编码格式

接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
*/
header('Content-type:text/html; Charset=utf-8');//设置网页编码
ini_set('date.timezone', 'Asia/Shanghai');

//商户参数
$appKey = 'xxxxxxxxxxxxxxxxxx';//公众号的APPKey
$config = array(
    'mch_id' => 'xxxxxxxxxx',//微信支付平台商户号
    'appid' => 'xxxxxxxxxxxxxxx',//公众号平台的APPID
    'key' => 'xxxxxxxxxxxxxxxxxxxxxxx' //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥V2-设置API密钥
);
//订单信息
$unified = array(
    'appid' => $config['appid'],//公众账号ID
    'attach' => '饭团',//附加数据
    'body' => "饭团子",//商品描述
    'mch_id' => $config['mch_id'],//商户号
    'nonce_str' => NoStr(),//随机字符串
    'notify_url' => "http://pay.xxxxxx.com/wxpay/api/returns.php",//通知地址
        'openid' => GetOpenid($config),
    'out_trade_no' => strval(date("YmdH").time()),//商户订单号
    'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],//终端IP
    'total_fee' => intval(0.01*100), //微信会自己减去两位数*100补回,标价金额
    'trade_type' => 'JSAPI',//交易类型
);
$unified['sign'] = getSign($unified, $config['key']);//获取签名
// echo "<pre>";print_r($unified);echo "</pre>";die;
// die(arrayToXml($unified));
$responseXml = curlPost('https://api.mch.weixin.qq.com/pay/unifiedorder', arrayToXml($unified));//转换为xml并发送
$unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);//解析XML为对象
if ($unifiedOrder === false) {
    die('parse xml error');//解析错误
}
if ($unifiedOrder->return_code != 'SUCCESS') {
    die($unifiedOrder->return_msg);//返回成功结果
}
if ($unifiedOrder->result_code != 'SUCCESS') {
    die($unifiedOrder->err_code->des);//返回失败结果
}

$arr = array(
    "appId" => $config['appid'],//公众账号ID
    "timeStamp" => strval(time()),//这里是字符串的时间戳
    "nonceStr" => NoStr(),//随机字符串
    "package" => "prepay_id=" . $unifiedOrder->prepay_id,//订单详情扩展字符串
    "signType" => 'MD5',//声明加密类型
);
$arr['paySign'] = getSign($arr, $config['key']);//获取调起支付的签名
$jsApiParameters=json_encode($arr);

?>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>FT-收银台</title>
    <script type="text/javascript">
/*
JSAPI调起支付

公众号id   appId
时间戳 timeStamp
随机字符串   nonceStr    String(32)  5K8264ILTKCH16CQ2502SI8ZNMTM67VS    随机字符串,32位。推荐随机数生成算法
订单详情扩展字符串   package String(128) prepay_id=123456789 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
签名方式    signType    MD5 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
签名  paySign 是   String(64)  C380BEC2BFD727A4B6845133519F3AD6    签名,详见签名生成算法:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
*/ 
        function jsApiCall()
        {
            WeixinJSBridge.invoke(
                'getBrandWCPayRequest',
                <?php echo $jsApiParameters; ?>,
                function(res){
                    WeixinJSBridge.log(res.err_msg);
                    alert(res.err_code+res.err_desc+res.err_msg);
                }
            );
        }
        function callpay()
        {
            if (typeof WeixinJSBridge == "undefined"){
                if( document.addEventListener ){
                    document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
                }else if (document.attachEvent){
                    document.attachEvent('WeixinJSBridgeReady', jsApiCall);
                    document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
                }
            }else{
                jsApiCall();
            }
        }
    </script>
</head>
<body>
<br/>
<font color="#9ACD32"><b>该笔订单支付金额为<span style="color:#f00;font-size:50px">0.01元</span>钱</b></font><br/><br/>
<div align="center">
    <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer;  color:white;  font-size:16px;" type="button" onclick="callpay()" >立即支付</button>
</div>
</body>
</html>

<?php
//所有的函数都在这里了

function GetOpenid(array $config){
    //通过code获得openid
    if (!isset($_GET['code'])){
        //触发微信返回code码
        $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
        $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
        $url = __CreateOauthUrlForCode($baseUrl,$config);
        Header("Location: $url");
        exit();
    } else {
        //获取code码,以获取openid
        $code = $_GET['code'];
        $openid = GetOpenidFromMp($code,$config);
        return $openid;
    }
}
function GetOpenidFromMp($code,array $config){
    $url = __CreateOauthUrlForOpenid($code,$config);
    $res = curlGet($url);
    //取出openid
    $data = json_decode($res,true);
    // $this->data = $data;
    $openid = $data['openid'];
    return $openid;
}
function __CreateOauthUrlForOpenid($code,array $config){
    $urlObj["appid"] = $config['appid'];
    $urlObj["secret"] = $GLOBALS['appKey'];
    $urlObj["code"] = $code;
    $urlObj["grant_type"] = "authorization_code";
    $bizString = toparams2($urlObj);
    return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
}

/**
 * 构造获取code的url连接
 * @param string $redirectUrl 微信服务器回跳的url,需要url编码
 * @return 返回构造好的url
 */
function __CreateOauthUrlForCode($redirectUrl,array $config){
    $urlObj["appid"] = $config['appid'];
    $urlObj["redirect_uri"] = "$redirectUrl";
    $urlObj["response_type"] = "code";
    $urlObj["scope"] = "snsapi_base";
    $urlObj["state"] = "STATE"."#wechat_redirect";
    $bizString = toparams2($urlObj);
    return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
}
function getSign($params, $key){
    //生成签名
    ksort($params, SORT_STRING);//把值作为字符串来排序
    $unSignParaString = toparams1($params, false);
    $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));//拼接字符并转换为大写
    return $signStr;
}
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;
    }
function toparams1($paraMap, $urlEncode = false){
    //签名数组排序并拼接
    $buff = "";
    ksort($paraMap);//对数组进行排序:ABCDEFG……
    foreach ($paraMap as $k => $v) {
        if (null != $v && "null" != $v) {
            if ($urlEncode) {
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
    }
    $reqPar = false;
    if (strlen($buff) > 0) {
        $reqPar = substr($buff, 0, strlen($buff) - 1);//移除多余的&
    }
    return $reqPar;
}

function toparams2($urlObj){
    //把数组转成URL参数:appid=123456&sign=xxxxxxxxxxxxxxxxx
    $buff = "";
    foreach ($urlObj as $k => $v)
    {
        if($k != "sign") $buff .= $k . "=" . $v . "&";
    }
    $buff = trim($buff, "&");//移除多余的&
    return $buff;
}

function curlGet($url = '', $options = array()){
    //get访问
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    if (!empty($options)) {
        curl_setopt_array($ch, $options);
    }
    //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;
}
function curlPost($url = '', $postData = '', $options = array()){
    //post访问
    if (is_array($postData)) {
        $postData = http_build_query($postData);//把数组转成URL参数:appid=123456&sign=xxxxxxxxxxxxxxxxx
    }
    $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); //设置cURL超时为30秒
    if (!empty($options)) {
        curl_setopt_array($ch, $options);
    }
    //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;
}
function NoStr($length = 16){
    //随机字符串默认16位
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $str = '';
    for ($i = 0; $i < $length; $i++) {
        $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $str;
}

?>