zoukankan      html  css  js  c++  java
  • 微信企业付款到个人

    提前说一个重要的坑,不注意掉进去,会浪费一些时间。

    1. 用户付款到商户平台的账户 与 商户付款到个人的账户是相互独立的 意思是商户要付款到个人必须用自己充值到商户平台账户的钱
    2. 企业付款到个人必须开通此功能 之后才可以使用
    3. 需要到商户平台下载支付证书 在使用时不要用官方的demo(2014年的 不怕死的用起来),在引用时直接把文件存放在服务器上的绝对路径写到函数里(相对于服务器的绝对路径)
    4. 在算签名的时候注意 ASCII的顺序  大写字母 < _ < 小写字母 (恶心的我够呛)
    5. 支付金额必须大于100 单位分

    直接上代码 提现类 并没有做验证实现了功能 代码后面有详细的流程介绍!!

    <?php
    /*
    微信企业 支付到个人
    */
    class cash
    {
    
    /**
         *  array转xml
         */
    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; } //使用证书,以post方式提交xml到对应的接口url /** * 作用:使用证书,以post方式提交xml到对应的接口url */ function curl_post_ssl($url, $vars, $second=30) {   $ch = curl_init();   //超时时间   curl_setopt($ch,CURLOPT_TIMEOUT,$second);   curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);   curl_setopt($ch,CURLOPT_URL,$url);   curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);   curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);   //以下两种方式需选择一种   /******* 此处必须为文件服务器根目录绝对路径 不可使用变量代替*********/   curl_setopt($ch,CURLOPT_SSLCERT,"/home/lizi/addons/grow/template/mobile/cash/apiclient_cert.pem");   curl_setopt($ch,CURLOPT_SSLKEY,"/home/lizi/addons/grow/template/mobile/cash/apiclient_key.pem");   curl_setopt($ch,CURLOPT_POST, 1);   curl_setopt($ch,CURLOPT_POSTFIELDS,$vars);   $data = curl_exec($ch);   if($data){     curl_close($ch);     return $data;   }else {     $error = curl_errno($ch);     echo "call faild, errorCode:$error\n";     curl_close($ch);     return false;   }
    }
    //企业向个人付款 public function payToUser($openid='oJZJ0w_N_LlTo4AHLnN-cGGtJSeM',$desc='提现成功',$amount='102') {   //微信付款到个人的接口   $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';   $params["mch_appid"] = ''; //公众账号appid   $params["mchid"] = ''; //商户号 微信支付平台账号   $params["nonce_str"] = 'longdongzhiye99'.mt_rand(100,999); //随机字符串   $params["partner_trade_no"] = mt_rand(10000000,99999999); //商户订单号   $params["amount"] = $amount; //金额   $params["desc"] = $desc; //企业付款描述   $params["openid"] = $openid; //用户openid   $params["check_name"] = 'NO_CHECK'; //不检验用户姓名   $params['spbill_create_ip'] = '123.56.48.18'; //获取IP //生成签名(签名算法后面详细介绍)   $str = 'amount='.$params["amount"].'&check_name='.$params["check_name"].'&desc='.$params["desc"].'&mch_appid='.$params["mch_appid"].'&mchid='.$params["mchid"].'&nonce_str='.$params["nonce_str"].'&openid='.$params["openid"].'&partner_trade_no='.$params["partner_trade_no"].'&spbill_create_ip='.$params['spbill_create_ip'].'&key=F5YguNW77Ao4N5yu5wZ8Lb00NKOg1Y04';   //md5加密 转换成大写   $sign = strtoupper(md5($str));   $params["sign"] = $sign;//签名   $xml = $this->arrayToXml($params);   return $this->curl_post_ssl($url, $xml); } } /* $cash = new cash; $res = $cash -> payToUser(); var_dump($res); */
    1. 要支付必须先配置服务号与微信商户平台,这里略。
    2. 登陆商户平台开通企业付款到个人
    3. 如果要实现自动付款
    4. 首先确定一个方向 就是这是微信的一个接口 带着参数post请求就好了
      1. $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'; //请求接口
      2. 参数(这个玩意可以慢慢说了)
    5. 参数包含两个部分 字符串部分 和 证书部分,到这时候你就不要想着跟别的接口似得马马虎虎拼拼就出来了,这个过程要慢慢来
              字符串部分需要 9个常规参数 + 1个签名+1个支付密钥,先说9个参数
    字段名变量名必填示例值类型描述
    公众账号appid mch_appid wx8888888888888888 String 公众号的appId
    商户号 mchid 1900000109 String(32) 微信支付平台商户号
    就是平台账号
    随机字符串 nonce_str 5K8264ILTKCH16CQ2502SI8ZNMTM67VS String(32) 随机字符串,随便随机个什么<32位
    商户订单号 partner_trade_no 10000098201411111234567890 String 订单号,保持唯一性,自定义一个随机订单号
    用户
    openid
    openid oxTWIuGaIt6gTKsQRLau2M0yL16E String 商户appid下,某用户的openid
    校验用户姓名选项 check_name NO_CHECK
    不检验 (小额推荐)
    FORCE_CHEC
    强制检验
    OPTION_CHECK
    自动检验
    String NO_CHECK:不校验真实姓名 
    FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账) 
    OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功)
    收款用户姓名 re_user_name 可选 马花花
    (如果上一个参数为强制检验此为必填项)
    String 收款用户真实姓名。 
    如果check_name设置为FORCE_CHECK或OPTION_CHECK,则必填用户真实姓名
    金额 amount 100
    单位为分
    100就是100分.
    int 企业付款金额,单位为分
    企业付款描述信息 desc 奖金啊,提现成功啊
    退款成功啊什么的
    String 企业付款操作说明信息。必填。
    Ip地址 spbill_create_ip 192.168.0.1 String(32) 调用接口的机器Ip地址服务器ip
    支付密钥
    key
    F5YguNW77Ao4N5yu5wZ8Lb00NKO987ks
    String(32)
    设置在商户平台上的支付密钥
    签名
    sign
    C380BEC2BFD727A4B6845133519F3AD6
    String(32)
    这个恶心了
    下面单独解释
    1. 签名是不是一直变动的呢?是的 每一个签名都是不一样的,别想着存起来一直用!怎么算呢?官方有一个文档,对于会的人来说就是废话,对于不会的来说就是天书。总的来说分为3部,官方有一个签名生成工具https://pay.weixin.qq.com/wiki/tools/signverify/

      1. 将你本次请求的所有参数(当然除了签名),按照一定的顺序排序成一个字符串,顺序一会再说,先说格式,比如本次的这次请求有9个参数:

        $str = "amount=100&check_name=NO_CHECK&desc=奖金啊,提现成功啊 退款成功啊什么的&mch_appid=wx8888888888888888&mchid=1900000109&nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&openid=oxTWIuGaIt6gTKsQRLau2M0yL16E&partner_trade_no=10000098201411111234567890&spbill_create_ip=192.168.0.1";

        仔细观察不难发现,字符串排列是有顺序的 为键值首字母的排列顺序。而官方为了听起来霸气,讲的是根据 参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式排序吓的我一哆嗦啊! 不就字母顺序表么!不过仔细一看发现不对了,比如 mchid和 mch_appid这尼玛前三个字母一样啊,一位一位排序下来出现一个 i  _怎么办呢? 这时候就用到ASCII码表了,不过看官也不用去查了 上面的可以直接粘去用了 而ASCII码表的顺序呢就是按照0123456789:;< = > ? @ ABCDEFGHIJKLMNOPQRSTUVWXYZ [ \ ] ^ _ ` abcdefghijklmnopqrstuvwxyz { | }~的顺序排列 那么我门就知道mch_appid应该在 mchid 前面了。
      2. 排序完这9个参数 之后再用&加上特殊参数 微信支付平台上设置的支付密钥就是

        $str = "amount=100&check_name=NO_CHECK&desc=奖金啊,提现成功啊 退款成功啊什么的&mch_appid=wx8888888888888888&mchid=1900000109&nonce_str=5K8264ILTKCH16CQ2502SI8ZNMTM67VS&openid=oxTWIuGaIt6gTKsQRLau2M0yL16E&partner_trade_no=10000098201411111234567890&spbill_create_ip=192.168.0.1&key=F5YguNW77Ao4N5yu5wZ8Lb00NKO987ks"
      3. 之后就简单了先md5加密下然后转为大写 签名就OK了

        $sign = strtoupper(md5($str));
               

            然后我们就要将这些参数填充到xml格式的字符串中去了

    官方示例为

    <xml>
    
    <mch_appid>wxe062425f740c30d8</mch_appid>
    
    <mchid>10000098</mchid>
    
    <nonce_str>3PG2J4ILTKCH16CQ2502SI8ZNMTM67VS</nonce_str>
    
    <partner_trade_no>100000982014120919616</partner_trade_no>
    
    <openid>ohO4Gt7wVPxIT1A9GjFaMYMiZY1s</openid>
    
    <check_name>OPTION_CHECK</check_name>
    
    <re_user_name>张三</re_user_name>
    
    <amount>100</amount>
    
    <desc>节日快乐!</desc>
    
    <spbill_create_ip>10.2.3.10</spbill_create_ip>
    
    <sign>C97BDBACF37622775366F38B629F45E3</sign>
    
    </xml>

    我个人还是觉的将参数都存到数组里,然后遍历拼接出来比较好例如:

    $params["mch_appid"]        = '';   //公众账号appid
    $params["mchid"]            = '';   //商户号 微信支付平台账号
    $params["nonce_str"]        = 'longdongzhiye99'.mt_rand(100,999);   //随机字符串
    $params["partner_trade_no"] = mt_rand(10000000,99999999);           //商户订单号
    $params["amount"]           = $amount;          //金额
    $params["desc"]             = $desc;            //企业付款描述
    $params["openid"]           = $openid;          //用户openid
    $params["check_name"]       = 'NO_CHECK';       //不检验用户姓名
    $params['spbill_create_ip'] = '123.56.48.18';   //获取IP
    
    //生成签名(签名算法后面详细介绍)
    $str = 'amount='.$params["amount"].'&check_name='.$params["check_name"].'&desc='.$params["desc"].'&mch_appid='.$params["mch_appid"].'&mchid='.$params["mchid"].'&nonce_str='.$params["nonce_str"].'&openid='.$params["openid"].'&partner_trade_no='.$params["partner_trade_no"].'&spbill_create_ip='.$params['spbill_create_ip'].'&key=F5YguNW77Ao4N5yu5wZ8Lb00NKOg1Y04';
    //md5加密 转换成大写
    $sign = strtoupper(md5($str));
    
    $params["sign"] = $sign;//签名

    然后拼接

    $xml = "<xml>";
    foreach ($paramsas $key => $val) {
    if (is_numeric($val)) {
      $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
    } else{
      $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
    }
    $xml .= "</xml>";

    得到$xml。

    到此字符传参数部分完成了,然后还没完呢!还有证书部分

    之后用curl函数检测证书 之后页要用curl发送请求 直接贴代码解释
    
    
    
    
    /**
         *   作用:使用证书,以post方式提交xml到对应的接口url
         */
    function curl_post_ssl($url, $xml, $second=30)
    {
      $ch = curl_init();
      //超时时间
      curl_setopt($ch,CURLOPT_TIMEOUT,$second);
      //将curl_exec()获取的信息以文件流的形式返回,而不是直接输出。
      curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
    
    
      curl_setopt($ch,CURLOPT_URL,$url);
    
      //根据curl版本有不同默认值 设置一下放心
      curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
      curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
    
      //以下两种方式需选择一种 双向检测证书
      /******* 此处必须为文件服务器根目录绝对路径 不可使用变量代替*********/
      curl_setopt($ch,CURLOPT_SSLCERT,"/home/lizi/addons/grow/template/mobile/cash/apiclient_cert.pem");
      curl_setopt($ch,CURLOPT_SSLKEY,"/home/lizi/addons/grow/template/mobile/cash/apiclient_key.pem");
    
      curl_setopt($ch,CURLOPT_POST, 1);
      curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
    
      $data = curl_exec($ch);
      if($data){
        curl_close($ch);
        return $data;
      }else {
        $error = curl_errno($ch);
        echo "call faild, errorCode:$error\n";
        curl_close($ch);
        return false;
      }
    }
    贴出成功之后返回码
    <xml>
    
    <return_code><![CDATA[SUCCESS]]></return_code>
    
    <return_msg><![CDATA[]]></return_msg>
    
    <mch_appid><![CDATA[wxec38b8ff840bd989]]></mch_appid>
    
    <mchid><![CDATA[10013274]]></mchid>
    
    <device_info><![CDATA[]]></device_info>
    
    <nonce_str><![CDATA[lxuDzMnRjpcXzxLx0q]]></nonce_str>
    
    <result_code><![CDATA[SUCCESS]]></result_code>
    
    <partner_trade_no><![CDATA[10013574201505191526582441]]></partner_trade_no>
    
    <payment_no><![CDATA[1000018301201505190181489473]]></payment_no>
    
    <payment_time><![CDATA[2015-05-19 15:26:59]]></payment_time>
    
    </xml>


    失败的返回码会提示错误信息 就不做介绍了。

    由于本人能力有限,文章可能有偏差,请批评指出,谢谢!
  • 相关阅读:
    Git 分支开发规范
    小程序技术调研
    弹性布局
    vue 自定义指令的魅力
    记一次基于 mpvue 的小程序开发及上线实战
    mpvue学习笔记-之微信小程序数据请求封装
    微信小程序开发框架 Wepy 的使用
    Hbuilder 开发微信小程序的代码高亮
    luogu3807 【模板】 卢卡斯定理
    luogu1955 [NOI2015] 程序自动分析
  • 原文地址:https://www.cnblogs.com/haizizhu/p/6875856.html
Copyright © 2011-2022 走看看