zoukankan      html  css  js  c++  java
  • 分享微信h5支付经验

      1 <?php
      2 //use Flight;
      3     /**
      4      * 微信支付服务器端下单
      5      * 微信APP支付文档地址:  https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=8_6
      6      * 使用示例
      7      *  构造方法参数
      8      *      'appid'     =>  //填写微信分配的公众账号ID
      9      *      'mch_id'    =>  //填写微信支付分配的商户号
     10      *      'notify_url'=>  //填写微信支付结果回调地址
     11      *      'key'       =>  //填写微信商户支付密钥
     12      *  );
     13      *  统一下单方法
     14      *  $WechatAppPay = new wechatAppPay($options);
     15      *  $params['body'] = '商品描述';                   //商品描述
     16      *  $params['out_trade_no'] = '1217752501201407';   //自定义的订单号,不能重复
     17      *  $params['total_fee'] = '100';                   //订单金额 只能为整数 单位为分
     18      *  $params['trade_type'] = 'APP';                  //交易类型 JSAPI | NATIVE |APP | WAP 
     19      *  $wechatAppPay->unifiedOrder( $params );
     20      */
     21     class wechatAppPay
     22     {   
     23         //接口API URL前缀
     24         const API_URL_PREFIX = 'https://api.mch.weixin.qq.com';
     25         //下单地址URL
     26         const UNIFIEDORDER_URL = "/pay/unifiedorder";
     27         //查询订单URL
     28         const ORDERQUERY_URL = "/pay/orderquery";
     29         //关闭订单URL
     30         const CLOSEORDER_URL = "/pay/closeorder";
     31         //公众账号ID
     32         private $appid;
     33         //商户号
     34         private $mch_id;
     35         //随机字符串
     36         private $nonce_str;
     37         //签名
     38         private $sign;
     39         //商品描述
     40         private $body;
     41         //商户订单号
     42         private $out_trade_no;
     43         //支付总金额
     44         private $total_fee;
     45         //终端IP
     46         private $spbill_create_ip;
     47         //支付结果回调通知地址
     48         private $notify_url;
     49         //交易类型
     50         private $trade_type;
     51         //支付密钥
     52         private $key;
     53         //证书路径
     54         private $SSLCERT_PATH;
     55         private $SSLKEY_PATH;
     56         //所有参数
     57         private $params = array();
     58         public function __construct($appid, $mch_id, $notify_url, $key)
     59         {
     60             $this->appid = $appid;
     61             $this->mch_id = $mch_id;
     62             $this->notify_url = $notify_url;
     63             $this->key = $key;
     64         }
     65         /**
     66          * 下单方法
     67          * @param   $params 下单参数
     68          */
     69         public function unifiedOrder( $params ){
     70             $this->body = $params['body'];
     71             $this->out_trade_no = $params['out_trade_no'];
     72             $this->total_fee = $params['total_fee'];
     73             $this->trade_type = $params['trade_type'];
     74             $this->scene_info = $params['scene_info'];
     75             $this->nonce_str = $this->genRandomString();
     76             $this->spbill_create_ip = $_SERVER['REMOTE_ADDR'];
     77             $this->params['appid'] = $this->appid;
     78             $this->params['mch_id'] = $this->mch_id;
     79             $this->params['nonce_str'] = $this->nonce_str;
     80             $this->params['body'] = $this->body;
     81             $this->params['out_trade_no'] = $this->out_trade_no;
     82             $this->params['total_fee'] = $this->total_fee;
     83             $this->params['spbill_create_ip'] = $this->spbill_create_ip;
     84             $this->params['notify_url'] = $this->notify_url;
     85             $this->params['trade_type'] = $this->trade_type;
     86             $this->params['scene_info'] = $this->scene_info;
     87             //获取签名数据
     88             $this->sign = $this->MakeSign( $this->params );
     89             $this->params['sign'] = $this->sign;
     90             $xml = $this->data_to_xml($this->params);
     91             $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::UNIFIEDORDER_URL);
     92             if( !$response ){
     93                 return false;
     94             }
     95             $result = $this->xml_to_data( $response );
     96             if( !empty($result['result_code']) && !empty($result['err_code']) ){
     97                 $result['err_msg'] = $this->error_code( $result['err_code'] );
     98             }
     99             return $result;
    100         }
    101         /**
    102          * 查询订单信息
    103          * @param $out_trade_no     订单号
    104          * @return array
    105          */
    106         public function orderQuery( $out_trade_no ){
    107             $this->params['appid'] = $this->appid;
    108             $this->params['mch_id'] = $this->mch_id;
    109             $this->params['nonce_str'] = $this->genRandomString();
    110             $this->params['out_trade_no'] = $out_trade_no;
    111             //获取签名数据
    112             $this->sign = $this->MakeSign( $this->params );
    113             $this->params['sign'] = $this->sign;
    114             $xml = $this->data_to_xml($this->params);
    115             $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::ORDERQUERY_URL);
    116             if( !$response ){
    117                 return false;
    118             }
    119             $result = $this->xml_to_data( $response );
    120             if( !empty($result['result_code']) && !empty($result['err_code']) ){
    121                 $result['err_msg'] = $this->error_code( $result['err_code'] );
    122             }
    123             return $result;
    124         }
    125         /**
    126          * 关闭订单
    127          * @param $out_trade_no     订单号
    128          * @return array
    129          */
    130         public function closeOrder( $out_trade_no ){
    131             $this->params['appid'] = $this->appid;
    132             $this->params['mch_id'] = $this->mch_id;
    133             $this->params['nonce_str'] = $this->genRandomString();
    134             $this->params['out_trade_no'] = $out_trade_no;
    135             //获取签名数据
    136             $this->sign = $this->MakeSign( $this->params );
    137             $this->params['sign'] = $this->sign;
    138             $xml = $this->data_to_xml($this->params);
    139             $response = $this->postXmlCurl($xml, self::API_URL_PREFIX.self::CLOSEORDER_URL);
    140             if( !$response ){
    141                 return false;
    142             }
    143             $result = $this->xml_to_data( $response );
    144             return $result;
    145         }
    146         /**
    147          * 
    148          * 获取支付结果通知数据
    149          * return array
    150          */
    151         public function getNotifyData(){
    152             //获取通知的数据
    153             $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
    154             //echo 123;die;
    155             $data = array();
    156             if( empty($xml) ){
    157                 return false;
    158             }
    159             $data = $this->xml_to_data( $xml );
    160             if( !empty($data['return_code']) ){
    161                 if( $data['return_code'] == 'FAIL' ){
    162                     return false;
    163                 }
    164             }
    165             return $data;
    166         }
    167         /**
    168          * 接收通知成功后应答输出XML数据
    169          * @param string $xml
    170          */
    171         public function replyNotify(){
    172             $data['return_code'] = 'SUCCESS';
    173             $data['return_msg'] = 'OK';
    174             $xml = $this->data_to_xml( $data );
    175             echo $xml;
    176             die();
    177         }
    178          /**
    179           * 生成APP端支付参数
    180           * @param  $prepayid   预支付id
    181           */
    182          public function getAppPayParams( $prepayid ){
    183              $data['appid'] = $this->appid;
    184              $data['partnerid'] = $this->mch_id;
    185              $data['prepayid'] = $prepayid;
    186              $data['package'] = 'Sign=WXPay';
    187              $data['noncestr'] = $this->genRandomString();
    188              $data['timestamp'] = time();
    189              $data['sign'] = $this->MakeSign( $data ); 
    190              return $data;
    191          }
    192         /**
    193          * 生成签名
    194          *  @return 签名
    195          */
    196         public function MakeSign( $params ){
    197             //签名步骤一:按字典序排序数组参数
    198             ksort($params);
    199             $string = $this->ToUrlParams($params);
    200             //签名步骤二:在string后加入KEY
    201             $string = $string . "&key=".$this->key;
    202             //签名步骤三:MD5加密
    203             $string = md5($string);
    204             //签名步骤四:所有字符转为大写
    205             $result = strtoupper($string);
    206             return $result;
    207         }
    208         /**
    209          * 将参数拼接为url: key=value&key=value
    210          * @param   $params
    211          * @return  string
    212          */
    213         public function ToUrlParams( $params ){
    214             $string = '';
    215             if( !empty($params) ){
    216                 $array = array();
    217                 foreach( $params as $key => $value ){
    218                     $array[] = $key.'='.$value;
    219                 }
    220                 $string = implode("&",$array);
    221             }
    222             return $string;
    223         }
    224         /**
    225          * 输出xml字符
    226          * @param   $params     参数名称
    227          * return   string      返回组装的xml
    228          **/
    229         public function data_to_xml( $params ){
    230             if(!is_array($params)|| count($params) <= 0)
    231             {
    232                 return false;
    233             }
    234             $xml = "<xml>";
    235             foreach ($params as $key=>$val)
    236             {
    237                 if (is_numeric($val)){
    238                     $xml.="<".$key.">".$val."</".$key.">";
    239                 }else{
    240                     $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
    241                 }
    242             }
    243             $xml.="</xml>";
    244             return $xml; 
    245         }
    246         /**
    247          * 将xml转为array
    248          * @param string $xml
    249          * return array
    250          */
    251         public function xml_to_data($xml){  
    252             if(!$xml){
    253                 return false;
    254             }
    255             //将XML转为array
    256             //禁止引用外部xml实体
    257             libxml_disable_entity_loader(true);
    258             $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);        
    259             return $data;
    260         }
    261         /**
    262          * 获取毫秒级别的时间戳
    263          */
    264         private static function getMillisecond(){
    265             //获取毫秒的时间戳
    266             $time = explode ( " ", microtime () );
    267             $time = $time[1] . ($time[0] * 1000);
    268             $time2 = explode( ".", $time );
    269             $time = $time2[0];
    270             return $time;
    271         }
    272         /**
    273          * 产生一个指定长度的随机字符串,并返回给用户 
    274          * @param type $len 产生字符串的长度
    275          * @return string 随机字符串
    276          */
    277         private function genRandomString($len = 32) {
    278             $chars = array(
    279                 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
    280                 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
    281                 "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
    282                 "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
    283                 "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
    284                 "3", "4", "5", "6", "7", "8", "9"
    285             );
    286             $charsLen = count($chars) - 1;
    287             // 将数组打乱 
    288             shuffle($chars);
    289             $output = "";
    290             for ($i = 0; $i < $len; $i++) {
    291                 $output .= $chars[mt_rand(0, $charsLen)];
    292             }
    293             return $output;
    294         }
    295         /**
    296          * 以post方式提交xml到对应的接口url
    297          * 
    298          * @param string $xml  需要post的xml数据
    299          * @param string $url  url
    300          * @param bool $useCert 是否需要证书,默认不需要
    301          * @param int $second   url执行超时时间,默认30s
    302          * @throws WxPayException
    303          */
    304         private function postXmlCurl($xml, $url, $useCert = false, $second = 30){       
    305             $ch = curl_init();
    306             //设置超时
    307             curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    308             curl_setopt($ch,CURLOPT_URL, $url);
    309             curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
    310             curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);
    311             //设置header
    312             curl_setopt($ch, CURLOPT_HEADER, FALSE);
    313             //要求结果为字符串且输出到屏幕上
    314             curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    315             if($useCert == true){
    316                 //设置证书
    317                 //使用证书:cert 与 key 分别属于两个.pem文件
    318                 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
    319                 //curl_setopt($ch,CURLOPT_SSLCERT, WxPayConfig::SSLCERT_PATH);
    320                 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
    321                 //curl_setopt($ch,CURLOPT_SSLKEY, WxPayConfig::SSLKEY_PATH);
    322             }
    323             //post提交方式
    324             curl_setopt($ch, CURLOPT_POST, TRUE);
    325             curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
    326             //运行curl
    327             $data = curl_exec($ch);
    328             //返回结果
    329             if($data){
    330                 curl_close($ch);
    331                 return $data;
    332             } else { 
    333                 $error = curl_errno($ch);
    334                 curl_close($ch);
    335                 return false;
    336             }
    337         }
    338         /**
    339           * 错误代码
    340           * @param  $code       服务器输出的错误代码
    341           * return string
    342           */
    343          public function error_code( $code ){
    344              $errList = array(
    345                 'NOAUTH'                =>  '商户未开通此接口权限',
    346                 'NOTENOUGH'             =>  '用户帐号余额不足',
    347                 'ORDERNOTEXIST'         =>  '订单号不存在',
    348                 'ORDERPAID'             =>  '商户订单已支付,无需重复操作',
    349                 'ORDERCLOSED'           =>  '当前订单已关闭,无法支付',
    350                 'SYSTEMERROR'           =>  '系统错误!系统超时',
    351                 'APPID_NOT_EXIST'       =>  '参数中缺少APPID',
    352                 'MCHID_NOT_EXIST'       =>  '参数中缺少MCHID',
    353                 'APPID_MCHID_NOT_MATCH' =>  'appid和mch_id不匹配',
    354                 'LACK_PARAMS'           =>  '缺少必要的请求参数',
    355                 'OUT_TRADE_NO_USED'     =>  '同一笔交易不能多次提交',
    356                 'SIGNERROR'             =>  '参数签名结果不正确',
    357                 'XML_FORMAT_ERROR'      =>  'XML格式错误',
    358                 'REQUIRE_POST_METHOD'   =>  '未使用post传递参数 ',
    359                 'POST_DATA_EMPTY'       =>  'post数据不能为空',
    360                 'NOT_UTF8'              =>  '未使用指定编码格式',
    361              ); 
    362              if( array_key_exists( $code , $errList ) ){
    363                 return $errList[$code];
    364              }
    365          }
    366     } 

    <?php namespace weixinpayApp; include 'wechatAppPay.php'; class wxh5{ //$data 金额和订单号 public function wxh5Request($data){ $appid = 'wxdf************'; $mch_id = '*********';//商户号 $key = '32位申请时自己设置的';//商户key $notify_url = "https://www.gujia.la/wxnativepay";//回调地址 $wechatAppPay = new wechatAppPay($appid, $mch_id, $notify_url, $key); $params['body'] = '估价啦'; //商品描述 $params['out_trade_no'] = $data['oid']; //自定义的订单号 $params['total_fee'] = '1'; //订单金额 只能为整数 单位为分 $params['trade_type'] = 'MWEB'; //交易类型 JSAPI | NATIVE | APP | WAP $params['scene_info'] = '{"h5_info": {"type":"Wap","wap_url": "https://www.diugou.com","wap_name": "估价啦"}}'; $result = $wechatAppPay->unifiedOrder( $params ); $url = $result['mweb_url'].'&redirect_url=https%3A%2F%2Fwww.gujia.la ';//redirect_url 是支付完成后返回的页面 return $url; } }

    调用实例wxh5.php

    返回错误参数和状态对官方的文档一个一个排查就可以了没几个问题
     
    if($result['return_code'] == 'SUCCESS'){
      $mweb_url= $result['mweb_url'];
    }
    这里返回的是一个支付连接,请求这个链接就可以激活微信进行支付*需要注意的是不能在pc上打开连接需要在手机上打开
     
    这里需要注意不能使用 header("Location:$mweb_url");这样的方法直接请求连接,需要将返回的连接返回到前台尽心请求
    前台代码不多说了就是一个js请求跳转后台获取的支付连接
     
     
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    </head>
    <body>
    <script>
    window.location.href="<?php echo $mweb_url;?>";
    </script>
    </body>
    </html>
     
    最后声明本博客非本人原创,也是借鉴他人自己在加以修改,欢迎转载评论!
  • 相关阅读:
    个人:我的2011生活看板
    个人管理:公司做的稻盛阿米巴培训笔记
    使用TOGAF来做业务架构 价值驱动产品开发
    30天敏捷结果(21)正面失败,吸取教训,改善结果
    2010年12月blog汇总:敏捷个人
    30天敏捷结果(25):固定时间,灵活范围
    101与金根回顾敏捷个人:(11)执行力
    团队管理:设计团队的一周
    云:构建云计算的核心技术与平台
    读书笔记:千万别学英语
  • 原文地址:https://www.cnblogs.com/zhangzhijian/p/8855721.html
Copyright © 2011-2022 走看看