PHP开发微信企业转账到零钱(提现功能,企业转零钱,付款到零钱)

需求:
新增提现功能

文档:
1.开通条件https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1
2.开通该功能比较麻烦,我也是连续多人付款了三四十天才开通成功(每次一两分钱)

服务端接口类代码

<?php
namespace App\Libs\common;
class WeiXinWithdrawDeposit {

    private $openid;

    private $APPID;

    private $MCHID;

    private $key;

    private $partnerTradeNo;

    private $totalFee;

    private $remark;

    private $SSLCERT_PATH;

    private $SSLKEY_PATH;

    /**
     * WeiXinWithdrawDeposit constructor.
     * @param $openid   string  小程序用户的openid
     * @param $appid    string  商户账号绑定的appid
     * @param $mch_id   string  商户号
     * @param $key      string  商户秘钥
     * @param $partnerTradeNo   string(32)  商户订单号
     * @param $totalFee     float   金额
     * @param $remark   string(100)   提现备注
     * desc:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
     */
    public function __construct($openid,$appid,$mch_id,$key,$partnerTradeNo,$totalFee,$remark='余额提现'){
        //初始化退款类需要的变量
        $this->openid = $openid;//openid
        $this->APPID = $appid;
        $this->MCHID = $mch_id;
        $this->key = $key;
        $this->partnerTradeNo = $partnerTradeNo;//订单号order_sn
        $this->totalFee = $totalFee;//订单总金额
        $this->remark = $remark;//备注
        $this->SSLCERT_PATH = app_path().'/Libs/wx_cert/apiclient_cert.pem';//证书路径
        $this->SSLKEY_PATH = app_path().'/Libs/wx_cert/apiclient_key.pem';//证书路径
    }

    /*
     * 请求接口
     */
    public function withdraw_deposit(){
        //re_user_name为空时,不加入sign验证
        $param = array(
            'mch_appid' => $this->APPID,
            'mchid' => $this->MCHID,
            'nonce_str' => $this->createNoncestr(),
            'partner_trade_no' => $this->partnerTradeNo,
            'openid' => $this->openid,
            'check_name' => 'NO_CHECK',
//            're_user_name' => '',
            'amount' => floatval(($this->totalFee) * 100),
            'desc' => $this->remark,
            'spbill_create_ip'=>$_SERVER['REMOTE_ADDR']
        );

        $param['sign'] = $this->getSign($param);

        $xmldata = $this->arrayToXml($param);

        $xmlresult = $this->postXmlSSLCurl($xmldata,'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers');


        $result = $this->xmlToArray($xmlresult);

        return $result;
    }

    //需要使用证书的请求
    private function postXmlSSLCurl($xml,$url,$second=30)
    {
        $ch = curl_init();
        //超时时间
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        //这里设置代理,如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //设置证书
        //使用证书:cert 与 key 分别属于两个.pem文件
        //默认格式为PEM,可以注释
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLCERT, $this->SSLCERT_PATH);
        //默认格式为PEM,可以注释
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY, $this->SSLKEY_PATH);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        $data = curl_exec($ch);
        //返回结果
        if ($data) {
            curl_close($ch);
            return $data;
        } else {
            $error = curl_errno($ch);
            echo "curl出错,错误码:$error" . "<br>";
            curl_close($ch);
            return false;
        }
    }

    //作用:生成签名
    private function getSign($Obj) {
        foreach ($Obj as $k => $v) {
            $Parameters[$k] = $v;
        }
        //签名步骤一:按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //签名步骤二:在 string 后加入 KEY
        $String = $String . "&key=" . $this->key;
        //签名步骤三:MD5 加密
        $String = md5($String);
        //签名步骤四:所有字符转为大写
        $result_ = strtoupper($String);
        return $result_;
    }


    ///作用:格式化参数,签名过程需要使用
    private function formatBizQueryParaMap($paraMap, $urlencode) {
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v) {
            if ($urlencode) {
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar = '';
        if (strlen($buff) > 0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }

    //作用:产生随机字符串,不长于 32 位
    private function createNoncestr($length = 32) {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    //数组转换成 xml
    private function arrayToXml($arr) {

        $xml = "<xml>
                    <mch_appid>".$arr['mch_appid']."</mch_appid>
                    <mchid>".$arr['mchid']."</mchid>
                    <nonce_str>".$arr['nonce_str']."</nonce_str>
                    <partner_trade_no>".$arr['partner_trade_no']."</partner_trade_no>
                    <openid>".$arr['openid']."</openid>
                    <check_name>".$arr['check_name']."</check_name>
                    <re_user_name></re_user_name>
                    <amount>".$arr['amount']."</amount>
                    <desc>".$arr['desc']."</desc>
                    <spbill_create_ip>".$arr['spbill_create_ip']."</spbill_create_ip>
                    <sign>".$arr['sign']."</sign>
                </xml>";

        return $xml;
    }

    //xml 转换成数组
    private function xmlToArray($xml) {
        //禁止引用外部 xml 实体
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring), true);
        return $val;
    }


    /**
     * 成功返回值
     * array(9) {
    ["return_code"]=>
    string(7) "SUCCESS"
    ["return_msg"]=>
    array(0) {
    }
    ["mch_appid"]=>
    string(18) "小程序id"
    ["mchid"]=>
    string(10) "商户号"
    ["nonce_str"]=>
    string(32) "syylzwd3u7lcgwrwlylov227thb0i1x7"
    ["result_code"]=>
    string(7) "SUCCESS"
    ["partner_trade_no"]=>
    string(32) "20210702162304162521418474028374"
    ["payment_no"]=>
    string(32) "10101258300502107026041097111670"
    ["payment_time"]=>
    string(19) "2021-07-02 16:23:28"
    }
     */
}

调用接口

//'///'开头的为项目逻辑,根据自己需要及项目进行处理
public function wx_withdraw_deposit($data){

        ///验证余额(检测用户余额来源是否合法)

        //获取小程序配置信息

        //获取商户号配置

        //定义参数
        $remark = '余额提现';
        $order_sn = $this->get_order_sn();

        ///创建提现订单

        $id = DB::getPdo()->lastInsertId();//创建的订单id

        DB::beginTransaction();

        /// 扣除余额

        ///调用提现接口
        $withdraw_deposit = new WeiXinWithdrawDeposit($verify_balance['data']['wx_openid'],$mini_config['c_appid'],$mch_config['c_appid'],$mch_config['c_key'],$order_sn,$this->price_convert($data['withdrawal_price'],1),$remark);
        $res = $withdraw_deposit->withdraw_deposit();
        if ($res['result_code'] != 'SUCCESS'){
            DB::rollback();
            return ['status'=>false, 'msg'=>$res['err_code_des'], 'data'=>$res];
        }

        ///处理结果(订单改为已完成)

        DB::commit();
        return ['status'=>true, 'msg'=>'成功', 'data'=>$res];
    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容