xieruidong 2 vuotta sitten
vanhempi
commit
d92cd1c827
2 muutettua tiedostoa jossa 168 lisäystä ja 2 poistoa
  1. 160 0
      application/service/WechatTransferSvc.php
  2. 8 2
      composer.json

+ 160 - 0
application/service/WechatTransferSvc.php

@@ -0,0 +1,160 @@
+<?php
+namespace app\service;
+use GuzzleHttp\Client;
+use GuzzleHttp\HandlerStack;
+use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
+use WeChatPay\Util\PemUtil;
+
+class WechatTransferSvc
+{
+    public $mchid = '你的商户id';
+    public $appid = '小程序appid';
+    public $serial_no = '6B66AFDAF3FC7D4AFDA8A51F61194B0DC8432BE1'; // 证书序列号,不知道怎么获取的看上面的图
+
+    private static function filePath($path){
+        return RUNTIME_PATH.$path;
+    }
+
+    public function __construct()
+    {
+        $this->mchid=config('site.mch_id');
+        $this->appid=config('site.sender_appid');
+        $this->serial_no=file_get_contents(self::filePath('serial_no'));
+    }
+
+    public static function client(){
+        static $client;
+        if(!$client) {
+            $merchantId = config('pay.wechat.mch_id'); // 商户号
+            $merchantSerialNumber = config('pay.wechat.serial_no'); // 商户API证书序列号
+            $merchantPrivateKey = PemUtil::loadPrivateKey(self::filePath('key')); // 商户私钥文件路径
+            $wechatpayCertificate = PemUtil::loadCertificate(self::filePath('platform.pem')); // 微信支付平台证书文件路径
+            $wechatpayMiddleware = WechatPayMiddleware::builder()
+                ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 传入商户相关配置
+                ->withWechatPay([$wechatpayCertificate]) // 可传入多个微信支付平台证书,参数类型为array
+                ->build();
+            $stack = HandlerStack::create();
+            $stack->push($wechatpayMiddleware, 'wechatpay');
+            $client = new Client(['handler' => $stack]);
+        }
+        return $client;
+    }
+
+    public function transfer($openid, $trade_no,$detail_no, $money, $desc='提现')
+    {
+        $money=$money*100;
+        $res=self::client()->post($url='https://api.mch.weixin.qq.com/v3/transfer/batches',[
+            'json'=>$body=[
+                "appid" => $this->appid,//appid
+                "out_batch_no" => $trade_no,//商家批次单号
+                "batch_name" => $desc,//批次名称
+                "batch_remark" => $desc,//批次备注
+                "total_amount" => $money,// 转账金额单位为“分”
+                "total_num" => 1, // 转账总笔数
+                "transfer_detail_list" => [
+                    [
+                        'out_detail_no' => $detail_no,
+                        'transfer_amount' => $money,
+                        'transfer_remark' => $desc,
+                        'openid' => $openid,
+                    ]
+                ]
+            ],
+            'headers'=>[
+                'Accept'=>'application/json',
+                'Authorization'=>$this->token($url,$body),
+                'Wechatpay-Serial'=>config('pay.wechat.serial_no')
+            ]
+        ]);
+        if($res->getStatusCode()!==200){
+            throw new \Exception($res->getBody()->getContents());
+        }
+        return [
+            json_decode($res->getBody()->getContents(),true),
+            [$trade_no,$detail_no],
+            $money
+        ];
+    }
+
+    public function checkDetail($trade_no,$detail_no){
+        $response=self::client()
+            ->get($url="https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/$trade_no/details/out-detail-no/$detail_no",[
+                'headers'=>[
+                    'Accept'=>'application/json',
+                    'Authorization'=>$this->token($url,''),
+                    'Wechatpay-Serial'=>config('pay.wechat.serial_no')
+                ]
+            ]);
+        if($response->getStatusCode()!==200){
+            throw new \Exception($response->getBody()->getContents());
+        }
+        $res=json_decode($response->getBody()->getContents(),true);
+        return [
+            $res['detail_status'],
+            $res
+        ];
+    }
+
+    public function getCert(){
+        $client=(new Client)
+            ->get($url='https://api.mch.weixin.qq.com/v3/certificates',[
+                'headers'=>[
+                    'Authorization'=>$this->token($url,'','GET'),
+                    'Accept'=>'application/json',
+                ]
+            ]);
+        $arr=json_decode($client->getBody()->getContents(),true);
+        $cert=$arr['data'][0]??null;
+        dd($cert);
+    }
+
+    public function token($url,$body,$http_method="POST"){
+        if(is_array($body)){
+            $body=json_encode($body,JSON_UNESCAPED_UNICODE);
+        }
+        $url_parts = parse_url($url);
+        $timestamp=time();
+        $nonce = strtoupper($this->createNonceStr(32));
+        $canonical_url = $url_parts['path'];
+        $message = $http_method."\n".
+            $canonical_url."\n".
+            $timestamp."\n".
+            $nonce."\n".
+            $body."\n";
+
+        openssl_sign($message, $raw_sign, $this->getPrivateKey(), 'sha256WithRSAEncryption');
+        $sign = base64_encode($raw_sign);
+
+        $schema = 'WECHATPAY2-SHA256-RSA2048';
+        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
+            $this->mchid, $nonce, $timestamp, $this->serial_no, $sign);
+        return "$schema $token";
+    }
+    /**
+     * 生成随机32位字符串
+     * @param $length
+     * @return string
+     */
+    public function createNonceStr($length = 16) { //生成随机16个字符的字符串
+        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+        $str = "";
+        for ($i = 0; $i < $length; $i++) {
+            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
+        }
+        return $str;
+    }
+
+    /**
+     * 获取私钥
+     * @param $filepath
+     * @return false|resource
+     */
+    private function getPrivateKey($filepath = '')
+    {
+        if (empty($filepath)) {
+            //私钥位置
+            $filepath = self::filePath('key');
+        }
+        return openssl_get_privatekey(file_get_contents($filepath));
+    }
+}

+ 8 - 2
composer.json

@@ -31,10 +31,16 @@
         "ext-pdo": "*",
         "ext-bcmath": "*",
         "txthinking/mailer": "^2.0",
-        "alibabacloud/sdk": "^1.8"
+        "alibabacloud/sdk": "^1.8",
+        "wechatpay/wechatpay": "^1.4",
+        "wechatpay/wechatpay-guzzle-middleware": "^0.2.2"
     },
     "config": {
-        "preferred-install": "dist"
+        "preferred-install": "dist",
+        "allow-plugins": {
+            "easywechat-composer/easywechat-composer": true,
+            "topthink/think-installer": true
+        }
     },
     "repositories": [
         {