PHP 微信h5支付源码 手机浏览器唤醒微信app支付

类库代码 wechatH5Pay.php

  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.     } 


+++++++++++++++++++++++++++++++++++++++++++++++++++++++

调用实例wxh5.php

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


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值