禾匠V4.4.8零钱打款修改为商户打款-记录

代码路径
vendor/luweiss/wechat/src/Wechat/WechatPay.php
注意php 7以上的json_encode 溢出

<?php

namespace luweiss\Wechat;


class WechatPay extends WechatBase
{
    const SIGN_TYPE_MD5 = 'MD5';
    const TRADE_TYPE_JSAPI = 'JSAPI';
    const TRADE_TYPE_NATIVE = 'NATIVE';
    const TRADE_TYPE_APP = 'APP';
    const TRADE_TYPE_MWEB = 'MWEB';

    public $appId;
    public $mchId;
    public $key;
    public $certPemFile;
    public $keyPemFile;

    /**
     * WechatPay constructor.
     * @param array $config ['appId', 'mchId', 'key', 'certPemFile', 'keyPemFile']
     */
    public function __construct($config = [])
    {
        foreach ($config as $name => $value) {
            if (property_exists($this, $name)) {
                $this->$name = $value;
            }
        }
    }

    /**
     * @param array $result
     * @return array
     * @throws WechatException
     */
    protected function getClientResult($result)
    {
        if (!isset($result['return_code'])) {
            throw new WechatException(
                '返回数据格式不正确: ' . json_encode($result, JSON_UNESCAPED_UNICODE)
            );
        }
        if ($result['return_code'] !== 'SUCCESS') {
            $msg = 'returnCode: ' . $result['return_code'] . ', returnMsg: ' . $result['return_msg'];
            throw new WechatException($msg, 0, null, $result);
        }
        if (!isset($result['result_code'])) {
            throw new WechatException(
                '返回数据格式不正确: ' . json_encode($result, JSON_UNESCAPED_UNICODE)
            );
        }
        if ($result['result_code'] !== 'SUCCESS') {
            $msg = 'errCode: ' . $result['err_code'] . ', errCodeDes: ' . $result['err_code_des'];
            throw new WechatException($msg, 0, null, $result);
        }
        return $result;
    }

    /**
     * @param $api
     * @param $args
     * @return array
     * @throws WechatException
     */
    protected function send($api, $args)
    {
        $args['appid'] = !empty($args['appid']) ? $args['appid'] : $this->appId;
        $args['mch_id'] = !empty($args['mch_id']) ? $args['mch_id'] : $this->mchId;
        $args['nonce_str'] = !empty($args['nonce_str']) ? $args['nonce_str'] : md5(uniqid());
        $args['sign'] = $this->makeSign($args);
        $xml = WechatHelper::arrayToXml($args);
        $res = $this->getClient()->setDataType(WechatHttpClient::DATA_TYPE_XML)->post($api, $xml);
        return $this->getClientResult($res);
    }

    /**
     * @param $api
     * @param $args
     * @return array
     * @throws WechatException
     */
    protected function sendWithPem($api, $args)
    {
        $args['nonce_str'] = !empty($args['nonce_str']) ? $args['nonce_str'] : md5(uniqid());
        $args['sign'] = $this->makeSign($args);
        $xml = WechatHelper::arrayToXml($args);
        $res = $this->getClient()
            ->setDataType(WechatHttpClient::DATA_TYPE_XML)
            ->setCertPemFile($this->certPemFile)
            ->setKeyPemFile($this->keyPemFile)
            ->post($api, $xml);
        return $this->getClientResult($res);
    }

    /**
     *
     * 统一下单, <a href="https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1">
     * https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1</a>
     *
     * @param array $args ['body', 'out_trade_no', 'total_fee', 'notify_url', 'trade_type', 'openid']
     * @return array
     * @throws WechatException
     */
    public function unifiedOrder($args)
    {
        $args['spbill_create_ip'] = !empty($args['spbill_create_ip']) ? $args['spbill_create_ip'] : '127.0.0.1';
        $api = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        return $this->send($api, $args);
    }

    /**
     *
     * 查询订单, <a href="https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_2">
     * https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_2</a>
     *
     * @param array $args ['out_trade_no']
     * @return array
     * @throws WechatException
     */
    public function orderQuery($args)
    {
        $api = 'https://api.mch.weixin.qq.com/pay/orderquery';
        return $this->send($api, $args);
    }

    /**
     *
     * 关闭订单, <a href="https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_3">
     * https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_3</a>
     *
     * @param array $args
     * @return array
     * @throws WechatException
     */
    public function closeOrder($args)
    {
        $api = 'https://api.mch.weixin.qq.com/pay/closeorder';
        return $this->send($api, $args);
    }

    /**
     *
     * 申请退款, <a href="https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4">
     * https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4</a>
     *
     * @param array $args
     * @return array
     * @throws WechatException
     */
    public function refund($args)
    {
        $args['appid'] = !empty($args['appid']) ? $args['appid'] : $this->appId;
        $args['mch_id'] = !empty($args['mch_id']) ? $args['mch_id'] : $this->mchId;
        $api = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
        return $this->sendWithPem($api, $args);
    }

    /**
     *
     * 查询退款, <a href="https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_5">
     * https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_5</a>
     *
     * @param array $args
     * @return array
     * @throws WechatException
     */
    public function refundQuery($args)
    {
        $api = 'https://api.mch.weixin.qq.com/pay/refundquery';
        return $this->send($api, $args);
    }

    /**
     *
     * 企业付款, <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2">
     * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2</a>
     *
     * @param array $args ['partner_trade_no', 'openid', 'amount', 'desc']
     * @return array
     * @throws WechatException
     */
    public function transfers($args)
    {
        $arg = [];
        $arg['out_batch_no'] = $args['out_detail_no'];
        $arg['batch_name'] = date("Y-m-d H:i:s").$args['transfer_remark'];
        $arg['appid'] = !empty($args['mch_appid']) ? $args['mch_appid'] : $this->appId;
        $arg['batch_remark'] = date("Y-m-d H:i:s").$args['transfer_remark'];
        $arg['total_amount'] = intval($args['transfer_amount']);
        $arg['total_num'] = 1;
        $arg['transfer_detail_list'][]=$args;
        $api = 'https://api.mch.weixin.qq.com/v3/transfer/batches';
        $token  = $this->getToken($arg);//获取token
        return $this->https_request($api, json_encode($arg),$token);
    }
    
    protected function sendBatches($api, $arg)
    {
        $res = $this->getClient()
            ->setDataType(WechatHttpClient::DATA_TYPE_JSON)
            ->setCertPemFile($this->certPemFile)
            ->setKeyPemFile($this->keyPemFile)
            ->post($api, $arg);
        return $this->getClientResult($res);
    }
  public  function https_request($url,$data = null,$token){
      try {
          $curl = curl_init();
          curl_setopt($curl, CURLOPT_URL, (string)$url);
          curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
          curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
          if (!empty($data)) {
              curl_setopt($curl, CURLOPT_POST, 1);
              curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
          }
          curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
          //添加请求头
          $headers = [
              'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $token,
              'Accept: application/json',
              'Content-Type: application/json; charset=utf-8',
              'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
          ];
          if (!empty($headers)) {
              curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
          }
          $output = curl_exec($curl);
          curl_close($curl);
          $data = json_decode($output,true);
          if($data['code']!=200&&isset($data['code'])){
              $data['err_code_des'] = $data['message'];
              throw new WechatException($data['message'], 0, null, $data);
          }
          return $data;
      }catch (WechatException $exception) {
          throw $exception;
      }
    }
    public function getToken($pars)
    {
        $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches';
        $http_method = 'POST';//请求方法(GET,POST,PUT)
        $timestamp   = time();//请求时间戳
        $url_parts   = parse_url($url);//获取请求的绝对URL
        $nonce       = $timestamp.rand('10000','99999');//请求随机串
        $body        = json_encode((object)$pars);//请求报文主体
        $stream_opts = [
            "ssl" => [
                "verify_peer"=>false,
                "verify_peer_name"=>false,
            ]
        ];

        $apiclient_cert_path = $this->certPemFile;
        $apiclient_key_path  = $this->keyPemFile;

        $apiclient_cert_arr = openssl_x509_parse(file_get_contents($apiclient_cert_path,false, stream_context_create($stream_opts)));
        $serial_no          = $apiclient_cert_arr['serialNumberHex'];//证书序列号
        $mch_private_key    = file_get_contents($apiclient_key_path,false, stream_context_create($stream_opts));//密钥
        $merchant_id = !empty($args['mch_id']) ? $args['mch_id'] : $this->mchId;//商户id
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $message = $http_method."\n".
            $canonical_url."\n".
            $timestamp."\n".
            $nonce."\n".
            $body."\n";
        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);//签名
        $schema = 'WECHATPAY2-SHA256-RSA2048';
        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $merchant_id, $nonce, $timestamp, $serial_no, $sign);//微信返回token
        return $token;
    }

//    public function transfers($args)
//    {
//        $args['mch_appid'] = !empty($args['mch_appid']) ? $args['mch_appid'] : $this->appId;
//        $args['mchid'] = !empty($args['mchid']) ? $args['mchid'] : $this->mchId;
//        $args['spbill_create_ip'] = !empty($args['spbill_create_ip']) ? $args['spbill_create_ip'] : '127.0.0.1';
//        $args['check_name'] = !empty($args['check_name']) ? $args['check_name'] : 'NO_CHECK';
//        $api = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
//        return $this->sendWithPem($api, $args);
//    }

    /**
     *
     * 查询企业付款, <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3">
     * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3</a>
     *
     * @param array $args ['partner_trade_no']
     * @return array
     * @throws WechatException
     */
    public function getTransferInfo($args)
    {
        $args['appid'] = !empty($args['appid']) ? $args['appid'] : $this->appId;
        $args['mch_id'] = !empty($args['mch_id']) ? $args['mch_id'] : $this->mchId;
        $api = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo';
        return $this->sendWithPem($api, $args);
    }

    /**
     *
     * 企业付款到银行卡, <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_2">
     * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_2</a>
     *
     * @param array $args
     * @return array
     * @throws WechatException
     */
    public function payBank($args)
    {
        $args['mch_id'] = !empty($args['mch_id']) ? $args['mch_id'] : $this->mchId;
        $api = 'https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank';
        return $this->sendWithPem($api, $args);
    }

    /**
     *
     * 查询企业付款到银行卡, <a href="https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_3">
     * https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_3</a>
     *
     * @param array $args
     * @return array
     * @throws WechatException
     */
    public function queryBank($args)
    {
        $args['mch_id'] = !empty($args['mch_id']) ? $args['mch_id'] : $this->mchId;
        $api = 'https://api.mch.weixin.qq.com/mmpaysptrans/query_bank';
        return $this->sendWithPem($api, $args);
    }

    /**
     * 通过数组数据验证签名
     * @param array $array
     * @return bool
     */
    public function validateSignByArrayResult($array)
    {
        if (!isset($array['sign'])) {
            return false;
        }
        $inputSign = $array['sign'];
        $truthSign = $this->makeSign($array);
        return $inputSign === $truthSign;
    }

    /**
     * 通过XML数据验证签名
     * @param string $xml
     * @return bool
     */
    public function validateSignByXmlResult($xml)
    {
        $array = WechatHelper::xmlToArray($xml);
        return $this->validateSignByArrayResult($array);
    }

    /**
     * 数据签名
     * @param array $args
     * @param string $signType
     * @return string
     */
    public function makeSign($args, $signType = self::SIGN_TYPE_MD5)
    {
        if (isset($args['sign'])) {
            unset($args['sign']);
        }
        ksort($args);
        $string = '';
        foreach ($args as $i => $arg) {
            if ($arg === null || $arg === '') {
                continue;
            } else {
                $string .= ($i . '=' . $arg . '&');
            }
        }
        $string = $string . "key={$this->key}";
        $string = md5($string);
        $result = strtoupper($string);
        return $result;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容