1. 程式人生 > >微信企業支付提現到使用者零錢---php

微信企業支付提現到使用者零錢---php

<?php
/**
 * topapi
 *
 * -- member.deposit.detail
 * -- 會員預存款明細
 *
 * @copyright  Copyright (c) 2014-2021 ZZY Technologies Inc. (http://www.zzymtm.com)
 * @license  http://www.zzymtm.com/ ZZY licence
 */
class topapi_api_v1_member_deposit_cashWechat implements topapi_interface_api{

    /**
     * 介面作用說明
     */
    public $apiDescription = '餘額提現微信';


    /**
     * 定義API傳入的應用級引數
     * @desc 用於在呼叫介面前,根據定義的引數,過濾必填引數是否已經參入,並且定義引數的資料型別,引數是否必填,引數的描述
     * @return array 返回傳入引數
     */
    public function setParams()
    {
        return  array(
            'amount'          => ['type'=>'float',     'valid'=>'required',     'title'=>'金額',       'desc'=>'使用者提現的金額'],

        );
    }


    public function handle($params)
    {
        return kernel::single('topapi_cashWechat')->actionAct_tixian($params);
    }

}


<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/7/16 0016
 * Time: 上午 9:46
 */
class topapi_cashWechat
{
	private $_app_id     = '******';      //appid
    private $_app_secret = '*********'; //secreat
    private $_apikey     = '';  //支付祕鑰
    private $_mchid      = '1492011202';        //商戶號
	
    /*private $app_id     = '';
    private $app_secret = '';
    private $apikey     = '';
    private $mchid      = 's';*/

    public  $error = 0;
    public $state  = '';
    //金額,需在例項化時傳入
    public $amount = '0';
    //使用者訂單號,需在例項化時傳入
    public $order_sn = '';
    //使用者openid,需在例項化時傳入
    public $openid = '';


    //微信提現操作介面-------》
    public function actionAct_tixian($params)
    {

        $this->state=md5(uniqid(rand(), TRUE));
        $this->amount=$params['amount'];//設定POST過來錢數
        $this->order_sn=rand(100,999).date('YmdHis');  //隨機數可以作為單號

        $user_id = $params['user_id'];
        $userInfo = app::get("sysuser")->model("account");
        $info = $userInfo->getRow("openid",['user_id'=>$params['user_id']]);
        $this->openid= $info['openid'];  //設定獲取POST過來使用者的OPENID

        $this->app_id=$this->_app_id;
        $this->app_secret=$this->_app_secret;
        $this->apikey=$this->_apikey;
        $this->mchid=$this->_mchid;
        $xml=$this->tiXianAction();
        $result=simplexml_load_string($xml);

        if($result->return_code=='SUCCESS' && $result->result_code=='SUCCESS') {

            $deposit = app::get('sysuser')->model('user_deposit');
            $deposit_cash = app::get('sysuser')->model('user_deposit_cash');
            $deposit_log = app::get('sysuser')->model('user_deposit_log');

            $data['user_id'] = $user_id;
            $data['amount'] = $this->amount;
            $data['create_time'] = time();
            $data['bank_name'] = '微信';
            $data['status'] = 'TO_VERIFY';
            $data['bank_cart_id'] = '';
            $data['bank_cart_owner'] = '';

            $res = $deposit->getRow('*',['user_id'=>$user_id]);
            $data1['deposit'] = $res['deposit'] - $data['amount'];

            $data2['fee'] = $data['amount'];
            $data2['user_id'] = $user_id;
            $data2['type'] = 'expense';
            $data2['message'] = '微信提現';
            $data2['operator'] = '使用者';
            $data2['logtime'] = time();


            $db = app::get('sysuser')->database();
            $transaction_status = $db->beginTransaction();
            try
            {
                if($res){
                    /*$res2 = $deposit->update($data1,['user_id'=>$user_id]);
                    $res3 = $deposit_cash->insert($data);
                    $res4 = $deposit_log->insert($data2);*/


                    /*利用已有的,也可以直接呼叫kernel::single('sysuser_data_deposit_cash')->applyCash
                      為了後期擴充套件或者與銀行卡提現區別,先分開呼叫*/

                    kernel::single('sysuser_data_deposit_cash')->__checkAmount($user_id, $this->amount);
                    //暫時遮蔽預存款密碼
                    //kernel::single('sysuser_data_deposit_password')->checkPassword($userId, $password);
                    kernel::single('sysuser_data_deposit_cashLocker')->runCash($user_id);
                    kernel::single('sysuser_data_deposit_deposit')->dedect($user_id, '使用者', $this->amount, '提現');
                    $cashId = kernel::single('sysuser_data_deposit_cash')->createCash($user_id, $this->amount, $data['bank_cart_id'], $data['bank_name'], $data['bank_cart_owner']);
                }

                $output = array('errorcode' => 0, 'data' => $result->result_code, 'msg' => '提現成功');

                $db->commit($transaction_status);

                return $output;
                //exit(json_encode($output));
            }
            catch (Exception $e)
            {
                $db->rollback();
                throw $e;
            }

        }else{

            $output = array('errorcode' => 10000, 'data' => $xml, 'msg' => '提現失敗');
            return $output;
            //exit(json_encode($output));
        }
    }
    /**
     * 提現介面操作,控制器呼叫
     * @param $openid 使用者openid 唯一標示
     * @return
     */
    //提現介面操作
    public function tiXianAction(){
        //獲取xml資料
        $data=$this->getdataXml($this->openid);
        $ch = curl_init ();
        //介面地址
        $MENU_URL="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";

        curl_setopt ( $ch, CURLOPT_URL, $MENU_URL );
        curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );

        //證書地址,微信支付下面

        $apiclient_cert = __DIR__. '/cert/apiclient_cert.pem';
        $apiclient_key = __DIR__. '/cert/apiclient_key.pem';

        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLCERT, $apiclient_cert); //證書這塊大家把檔案放到哪都行、
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLKEY,  $apiclient_key);//注意證書名字千萬別寫錯、

        //$zs1=dirname(dirname(__FILE__)).'\wx_pay\apiclient_cert.pem';
        //$zs2=dirname(dirname(__FILE__)).'\wx_pay\apiclient_key.pem';
        //show_bug($zs1);

        //curl_setopt($ch,CURLOPT_SSLCERT,$zs1);
        //curl_setopt($ch,CURLOPT_SSLKEY,$zs2);
        // curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01;
        // Windows NT 5.0)');
        //curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
        curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
        $info = curl_exec ( $ch );
        //返回結果
        if($info){
            curl_close($ch);
            return $info;
        } else {
            $error = curl_errno($ch);
            curl_close($ch);
            return "curl出錯,錯誤碼:$error";
        }
    }
    /**
     * 獲取資料封裝為陣列
     * @param $openid 使用者openid 唯一標示
     * @return xml
     */

    private function getdataXml($openid){
        //封裝成資料
        $dataArr=array(
            'amount'=>$this->amount*100,//金額(以分為單位,必須大於100)
            'check_name'=>'NO_CHECK',//校驗使用者姓名選項,NO_CHECK:不校驗真實姓名 FORCE_CHECK:強校驗真實姓名(未實名認證的使用者會校驗失敗,無法轉賬)OPTION_CHECK:針對已實名認證的使用者才校驗真實姓名(未實名認證使用者不校驗,可以轉賬成功)
            'desc'=>'提現',//描述
            'mch_appid'=>$this->app_id,
            'mchid'=>$this->mchid,//商戶號
            'nonce_str'=>rand(100000, 999999),//不長於32位的隨機數
            'openid'=>$openid,//使用者唯一標識
            'partner_trade_no'=>$this->order_sn,//商戶訂單號
            're_user_name'=>'',//使用者姓名,check_name為NO_CHECK時為可選項
            'spbill_create_ip'=>$_SERVER["REMOTE_ADDR"],//伺服器ip
        );
        //獲取簽名
        $sign=$this->getSign($dataArr);
        //xml資料
        $data="<xml>
         <mch_appid>".$dataArr['mch_appid']."</mch_appid>
         <mchid>".$dataArr['mchid']."</mchid>
         <nonce_str>".$dataArr['nonce_str']."</nonce_str>
         <partner_trade_no>".$dataArr['partner_trade_no']."</partner_trade_no>
         <openid>".$dataArr['openid']."</openid>
         <check_name>".$dataArr['check_name']."</check_name>
         <re_user_name>".$dataArr['re_user_name']."</re_user_name>
         <amount>".$dataArr['amount']."</amount>
         <desc>".$dataArr['desc']."</desc>
         <spbill_create_ip>".$dataArr['spbill_create_ip']."</spbill_create_ip>
         <sign>".$sign."</sign>
         </xml>";
        return $data;

    }
    /**
     *     作用:格式化引數,簽名過程需要使用
     */
    private function formatBizQueryParaMap($paraMap, $urlencode)
    {

        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v)
        {
            if($v){
                if($urlencode)
                {
                    $v = urlencode($v);
                }

                $buff .= $k . "=" . $v . "&";
            }

        }
        $reqPar=NULL;
        if (strlen($buff) > 0)
        {
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }

        return $reqPar;
    }

    /**
     *     作用:生成簽名
     */
    private function getSign($Obj)
    {

        foreach ($Obj as $k => $v)
        {
            $Parameters[$k] = $v;
        }
        //簽名步驟一:按字典序排序引數
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //echo '【string1】'.$String.'</br>';
        //簽名步驟二:在string後加入KEY
        $String = $String."&key=".$this->apikey;
        //echo "【string2】".$String."</br>";
        //簽名步驟三:MD5加密
        $String = md5($String);
        //echo "【string3】 ".$String."</br>";
        //簽名步驟四:所有字元轉為大寫
        $result_ = strtoupper($String);
        //echo "【result】 ".$result_."</br>";
        return $result_;
    }
    //-----------
    private function http($url, $method='POST', $postfields = null, $headers = array())
    {
        header("Content-Type:text/html;charset=utf-8");
        $ch = curl_init();
        /* Curl settings */
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, "");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https請求 不驗證證書和hosts
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        switch ($method){
            case 'POST':
                curl_setopt($ch,CURLOPT_POST, true);
                break;
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
        curl_setopt($ch, CURLINFO_HEADER_OUT, true);
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);  //返回請求狀態碼
        curl_close($ch);
        return array($http_code, $response);
    }
}