微信商家转账零钱优化版【奶妈级教程】

首先你得先去申请商户,并且连续三个月 不可间断的让这个商户号有资金流水【每天存一毛钱】,也就是说 你想使用微信转账 即时起也要三个月以后!!!

1、申请完成 获得一系列的号码 如下配置中的,只有平台证书需要手动下载【你微信平台拿到的是不对的!】

2、安装 SDK : composer require wechatpay/wechatpay

3、按照下面的代码 只需修改配置文件中的参数,和 下单的参数 基本可以调通。 前提俩个重点要知道下微信不支持http交互,还需要先去设置ip白名单

 

注意点: 你就记住一点 订单里面有一个参数就是你自己系统的订单号如果有英文字母 千万不要大写!  还是不要大写! 就是不要大写! 

配置文件

<?php
return [
    'abc'   => [
        "merchant_id"                    => env('POINT_ABC_MERCHANTID'),
        "app_id"                         => env('POINT_ABC_APP_ID'),
        "merchant_private_key_file_path" => sprintf(
            "file://%s/storage/keys/apiclient_ABC_key.pem",  # 证书的绝对路径
            BASE_PATH
        ),
        "platform_certificate_file_Path" => sprintf(
            "file://%s/storage/keys/platform_apiclient_ABC_key.pem",  
            BASE_PATH
        ),
        "merchant_certificate_serial"    => env('POINT_ABC_SERIAL')
    ],
    'opq' => [
        "merchant_id"                    => env('POINT_OPQ_MERCHANTID'),
        "app_id"                         => env('POINT_OPQ_APP_ID'),
        "merchant_private_key_file_path" => sprintf(
            "file://%s/storage/keys/apiclient_OPQ_key.pem",
            BASE_PATH
        ),
        "platform_certificate_file_Path" => sprintf(
            "file://%s/storage/keys/platform_apiclient_OPQ_key.pem",
            BASE_PATH
        ),
        "merchant_certificate_serial"    => env('POINT_OPQ_SERIAL'),
    ]
];

 

 

微信支付类

<?php


namespace App\Logic\Point;


use App\Helper\Helper;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Utils\ApplicationContext;
use WeChatPay\Builder;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Util\PemUtil;

class WeChatPayUtils
{

    private $merchantId;
    private $appId;
    private $merchantCertificateSerial;
    private $merchantPrivateKeyFilePath;
    private $platformCertificateFilePath;

    /**
     * 初始化
     * @param string $name
     * @return WeChatPayUtils
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public static function getInsance($name = 'abc')
    {
        $config = ApplicationContext::getContainer()
            ->get(ConfigInterface::class)
            ->get('pay');

        $o                              = new self();
        $o->merchantId                  = $config[$name]['merchant_id'];
        $o->appId                       = $config[$name]['app_id'];
        $o->merchantCertificateSerial   = $config[$name]['merchant_certificate_serial'];
        $o->merchantPrivateKeyFilePath  = $config[$name]['merchant_private_key_file_path'];
        $o->platformCertificateFilePath = $config[$name]['platform_certificate_file_Path'];

        return $o;
    }

    /**
     * 构造一个 APIv3 客户端实例
     * @return \WeChatPay\BuilderChainable
     */
    public function getBuilder()
    {
        # 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
        $merchantPrivateKeyInstance = Rsa::from($this->merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE);

        # 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名
        $platformPublicKeyInstance = Rsa::from($this->platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        # 从「微信支付平台证书」中获取「证书序列号」
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($this->platformCertificateFilePath);

        // 构造一个 APIv3 客户端实例
        return Builder::factory([
            'mchid'      => $this->merchantId,                # 商户号
            'serial'     => $this->merchantCertificateSerial, # 「商户API证书」的「证书序列号」
            'privateKey' => $merchantPrivateKeyInstance,      # 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名
            'certs'      => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
    }

  /**
   * 实名制加密
   * @param $realName
   */
  public function getEncryptor($realName) { $platformPublicKeyInstance = Rsa::from($this->platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC); return Rsa::encrypt($realName, $platformPublicKeyInstance); } /** * 转账 * @param $PayData * @param $url * @return \Psr\Http\Message\ResponseInterface */ public function payMent($PayData, $url) { $PayData['json']['appid'] = $this->appId; # 实名制 $PayData['headers'] = [ 'Wechatpay-Serial' => $this->merchantCertificateSerial, # 平台证书序列号 ]; $logger = Helper::getLogger(); $logger->error("wx_pay_send_data", [ 'info' => json_encode($PayData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ]); return self::getBuilder()->chain($url)->post($PayData); } /** * 查询订单批次详情 * @param array $query * @param string $url * @return \Psr\Http\Message\ResponseInterface */ public function getPointCheckWXPayDetail(array $query, string $url) { return self::getBuilder()->chain($url)->get($query); } /** * 查询详情 * @param string $url * @return \Psr\Http\Message\ResponseInterface */ public function getBatchDetailEveryLast(string $url) { return self::getBuilder()->chain($url)->get(); } }

 

逻辑层

class WeChatPay
{
    /**
     * @Inject
     * @var PointExchangeOrderRepository
     */
    private $order;

    /**
     * 支付转账
     * @param $batch_num
     * @return string[]
     * @throws \Hyperf\Mongodb\Exception\MongoDBException
     */
    public function payment($batch_num)
    {
        $Data = $this->order->downLoadFinances($batch_num);

        $Collection = 'point-log' . date('Y-m-d');

        $mongoDb = Helper::getMongoClient('point');

        if ($Data) {
            # 获取总额度
            $columns = array_column($Data, 'grant_money');

            $TotalMoney = array_sum($columns);

            $TotalCount = count($columns);

            $typeName = $Data[0]['user_type'] == 1 ? 'abc' : 'opq';

            # 初始化 支付类
            $instance = WeChatPayUtils::getInsance($typeName);

            $PayData ['json']['out_batch_no'] = $Data[0]['batch_num'];

            $PayData ['json']['batch_name'] = '批次名称';

            $PayData ['json']['batch_remark'] = 'xxx有限公司';

            $PayData ['json']['total_amount'] = (int)bcmul((string)$TotalMoney, '100', 2);

            $PayData ['json']['total_num'] = (int)$TotalCount;

            $PointReviewProcess = [];

            foreach ($Data as $k => $datum) {
                if (!$datum['real_name']) {
                    return ['status'=>'warning','msg'=>'批次内有尚未完成实名制的用户'];
                }

                # 验证转账金额 次数
                $resRedisMoney = $this->checkUserTYperPaymentInfoRedis(
                    $datum['uid'],
                    $datum['user_type'],
                    $datum['grant_money']
                );

                if ($resRedisMoney['status'] == 'warning') {
                    return $resRedisMoney;
                }

                # 构建发送数据
                $PayData['json']['transfer_detail_list'][$k] = [

                        'out_detail_no'     => $datum['order_num'],
                        # 转账金额
                        'transfer_amount'   => (int) bcmul((string) $datum['grant_money'], '100', 2),

                        'transfer_remark'   => 'xxx有限公司',

                        'openid'            => $datum['user_openid'],

                        'real_name'         => $instance->getEncryptor($datum['real_name']),    # 收款人姓名    大于2000必须实名制
                ];

                # 记录流程
                $PointReviewProcess[] = [
                    'order_num'      => $datum['order_num'],
                    'status'         => OrderStatus::POINTPAYING,
                    'operator_id'    => Db::raw("null"),
                    'operation_desc' => '转账中',
                    'created_at'     => date('Y-m-d H:i:s'),
                ];
            }

            try {
                $resp = $instance->payMent($PayData, "v3/transfer/batches");

                # 推送队列
                $wechatPayDelayQueue = new WechatPayDelayQueue();
                $wechatPayDelayQueue->setBatchNum($Data[0]['batch_num']);
                $nsq = make(Nsq::class);
                TaskManageLogic::create(0, $wechatPayDelayQueue, "wechat_pay_delay_queue")->push(60, $nsq);

                $body = (string)$resp->getBody();

                $this->order->updateBatch($batch_num, json_decode($body, true));

                PointReviewProcess::insert($PointReviewProcess);

                $mongoDb->insert($Collection, [
                    'cr_dt'         => date('Y-m-d H:i:s'),
                    'batch_num'     => $Data[0]['batch_num'],
                    'status'        => 'normal',
                    'response_code' => $resp->getStatusCode(),
                    'response_body' => $body,
                    'send_data'     => json_encode($PayData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
                ]);

                return ['status' => 'success', 'msg' => ''];
            } catch (\Exception $e) {
                // 进行错误处理
                $Message = $e->getMessage();

                $code = $Phrase = $Body = $TraceAsString = '';

                if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                    $r      = $e->getResponse();
                    $code   = $r->getStatusCode();
                    $Phrase = $r->getReasonPhrase();
                    $Body   = $r->getBody();
                }

                $mongoDb->insert($Collection, [
                    'cr_dt'         => date('Y-m-d H:i:s'),
                    'batch_num'     => $Data[0]['batch_num'],
                    'status'        => 'error',
                    'response_code' => $code . ' -- ' . $Phrase,
                    'response_body' => $Body . ' MSG:' . $Message,
                    'send_data'     => json_encode($PayData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                ]);
            }

            $msg = json_decode((string)$Body, true);
            return ['status' => 'warning', 'msg' => $msg['message']];
        } else {
            return ['status' => 'warning', 'msg' => '数据不存在'];
        }
    }


    /**
     * @param $uid
     * @param $user_type
     * @param $money
     * @return string[]
     */
    private function checkUserTYperPaymentInfoRedis($uid, $user_type, $money)
    {
        $containerRedis = ApplicationContext::getContainer();

        $redis = $containerRedis->get(PointPaymentRedis::class);

        $nextDay = strtotime('+1 day', strtotime(date('Y-m-d')));

        $ttl = $nextDay - time();

        $TotalMoneyTypeKey = 'point_payment:total_money:t_:' . $user_type . ':' . date("Ymd");  # 账户总额度

        $TotalNumTypeKey = 'point_payment:total_num:t_' . $user_type . ':' . date("Ymd");      # 账户总次数

        $UserMoneyTypeKey = 'point_payment:total_money:user' . $uid . $user_type . ':' . date("Ymd");    # 用户总额度

        $UserNumTypeKey = 'point_payment:total_num:user:' . $uid . $user_type . ':' . date("Ymd");        # 用户总次数


        $TotalNumTypeExc = $redis->get($TotalNumTypeKey);

        $UserNumTypeKeyExc = $redis->get($UserNumTypeKey);

        $TotalMoneyTypeExc = $redis->get($TotalMoneyTypeKey);

        $UserMoneyTypeExc = $redis->get($UserMoneyTypeKey);


        $TotalNumTypeRds = $TotalNumTypeExc ? $TotalNumTypeExc : 0;

        $UserNumTypeKeyRds = $UserNumTypeKeyExc ? $UserNumTypeKeyExc : 0;

        $TotalMoneyTypeRds = $TotalMoneyTypeExc ? $TotalMoneyTypeExc : 0;

        $UserMoneyTypeRds = $UserMoneyTypeExc ? $UserMoneyTypeExc : 0;

        # 账户当日转账总次数
        if (++$TotalNumTypeRds > env('GRANT_TOTALNUM_USER_TYPE')) {
            return ['status' => 'warning', 'msg' => '该账户已到达当日转账次数上限'];
        } else {
            # 当前用户转账总次数
            if (++$UserNumTypeKeyRds <= env('GRANT_NUM_USER')) {
                # 检查当日账户转账总金额
                if (($TotalMoneyTypeRds + $money) <= env('GRANT_TOTALMONEY_USER_TYPE')) {
                    # 检查当日用户转账总金额
                    if (($UserMoneyTypeRds + $money) <= env('GRANT_TOTALMONEY_USER')) {
                        # 设置缓存
                        # 账户总次数
                        //                        $TotalNumTypeRds ++;
                        $redis->set($TotalNumTypeKey, $TotalNumTypeRds);
                        $redis->expire($TotalNumTypeKey, $ttl);

                        # 用户总次数
                        //                        $UserNumTypeKeyRds ++;
                        $redis->set($UserNumTypeKey, $UserNumTypeKeyRds);
                        $redis->expire($UserNumTypeKey, $ttl);

                        # 账户总额度
                        $TotalMoneyTypeRds += $money;
                        $redis->set($TotalMoneyTypeKey, $TotalMoneyTypeRds);
                        $redis->expire($TotalMoneyTypeKey, $ttl);

                        # 用户总金额
                        $UserMoneyTypeRds += $money;
                        $redis->set($UserMoneyTypeKey, $UserMoneyTypeRds);
                        $redis->expire($UserMoneyTypeKey, $ttl);

                        return ['status' => 'success', 'msg' => ''];
                    } else {
                        return ['status' => 'warning', 'msg' => '该用户已到达当日转账总额度上限'];
                    }
                } else {
                    return ['status' => 'warning', 'msg' => '该账户已到达当日转账总额度上限'];
                }
            } else {
                return ['status' => 'warning', 'msg' => '该批次中用户超出当日转账次数,请择日重新提交转账申请!'];
            }
        }
    }


    /**
     * 查并确认订单
     * @throws \Hyperf\Mongodb\Exception\MongoDBException
     */
    public function pointCheckWXPayDetail(string $BatchNum)
    {
        $Data = $this->order->getPointReviewBatch($BatchNum);
        if (!$Data) {
            return json_encode(
                ['status'=>'fail', 'msg'=>'该批次单号:'.$BatchNum.' 不存在'],
                JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES
            );
        }

        try {
            $again = false;
            foreach ($Data as $datum) {
                $batch_num = $datum['batch_num'];

                $order_num = $datum['order_num'];

                $batch_id = $datum['batch_id'];

                $Collection = 'point-check-log' . date('Y-m-d');

                $mongoDb = Helper::getMongoClient('point');

                $typeName = $datum['user_type'] == 1 ? 'abc' : 'opq';

                # 初始化 支付类
                $instance = WeChatPayUtils::getInsance($typeName);

                $url = 'v3/transfer/batches/out-batch-no/' . $batch_num;

                $urlArr = [
                    'need_query_detail' => true,
                    'limit'             => 100,
                    'detail_status'     => 'ALL',
                ];

                $resp = $instance->getPointCheckWXPayDetail(['query' => $urlArr], $url);

                $body = (string)$resp->getBody();

                $bodyArr = json_decode($body, true);

                if ($bodyArr && $bodyArr['transfer_detail_list']) {
                    $PointReviewProcess = [];

                    Db::connection('qa')->beginTransaction();

                    foreach ($bodyArr['transfer_detail_list'] as $everyDetail) {
                        if ($everyDetail['detail_status'] === 'FAIL') {
                            # 查询 详细中每一份订单
                            $this->getBatchDetailEveryLast(
                                $typeName,
                                $everyDetail['out_detail_no'],
                                $bodyArr['transfer_batch']['out_batch_no']
                            );

                        } elseif ($everyDetail['detail_status'] === 'WAIT_PAY' ||
                            $everyDetail['detail_status'] === 'PROCESSING') {
                            # 告诉nsq 微信转账还在处理中 需要重新投递到队列中延时再次查询
                            $again = 'again';
                        } elseif ($everyDetail['detail_status'] === 'SUCCESS') {
                            # 更新转账成功
                            $this->order->updatePointReviewBatchByOrderNumSuccess(
                                $bodyArr['transfer_batch']['out_batch_no'],
                                $everyDetail['out_detail_no']
                            );

                            # 记录流程
                            $PointReviewProcess[] = [
                                'order_num'      => $everyDetail['out_detail_no'],
                                'status'         => OrderStatus::POINTPAYPASS,
                                'operator_id'    => Db::raw("null"),
                                'operation_desc' => '转账成功',
                                'created_at'     => date('Y-m-d H:i:s'),
                            ];

                            $mongoDb->insert($Collection, [
                                'batch_num'     => $bodyArr['transfer_batch']['out_batch_no'],
                                'cr_dt'         => date('Y-m-d H:i:s'),
                                'status'        => 'normal',
                                'response_code' => $resp->getStatusCode(),
                                'response_body' => $body,
                                'send_data'     => sprintf(
                                    "batch_num:%s order_num%s batch_id%s",
                                    $batch_num,
                                    $order_num,
                                    $batch_id
                                ),
                            ]);
                        }
                    }

                    if (count($PointReviewProcess) > 0) {
                        PointReviewProcess::insert($PointReviewProcess);
                    }
                    Db::connection('qa')->commit();
                }
            }
            return json_encode(
                ['status'=>$again, 'msg'=>''],
                JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES
            );

        } catch (\Exception $e) {
            // 进行错误处理
            echo $e->getMessage(), PHP_EOL;

            $Message = $e->getMessage();

            $code = $Phrase = $Body = $TraceAsString = '';

            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r      = $e->getResponse();
                $code   = $r->getStatusCode();
                $Phrase = $r->getReasonPhrase();
                $Body   = $r->getBody();
            }

            $mongoDb->insert($Collection, [
                'cr_dt'         => date('Y-m-d H:i:s'),
                'status'        => 'error',
                'response_code' => $code . ' -- ' . $Phrase,
                'response_body' => $Body . ' MSG:' . $Message,
                'send_data'     => '',
            ]);

            Db::connection('qa')->rollBack();
        }
    }


    /**
     * 查询批次内每一份订单失败原因
     * @param array $transfer_detail_list
     * @throws \Hyperf\Mongodb\Exception\MongoDBException
     */
    private function getBatchDetailEveryLast($typeName, $out_detail_no, $out_batch_no)
    {
        $Collection = 'point-every-last-log' . date('Y-m-d');

        $mongoDb = Helper::getMongoClient('point');

        $send_data = 'batch_num:'.$out_batch_no.' order_num'. $out_detail_no;

        try {
                $url = 'v3/transfer/batches/out-batch-no/'.$out_batch_no.'/details/out-detail-no/'.$out_detail_no;

                # 初始化 支付类
                $instance = WeChatPayUtils::getInsance($typeName);

                $resp = $instance->getBatchDetailEveryLast($url);

                $body = (string)$resp->getBody();

                $bodyArr = json_decode($body, true);

                $this->order->updatePointReviewBatchByOrderNumFail(
                    $out_batch_no,
                    $out_detail_no,
                    $bodyArr['fail_reason'] ?? ''
                );

                # 记录流程
                $PointReviewProcess = [
                    'order_num'      => $out_detail_no,
                    'status'         => OrderStatus::POINTPAYFAIL,
                    'operator_id'    => Db::raw("null"),
                    'operation_desc' => '转账失败:'. $bodyArr['fail_reason'],
                    'created_at'     => date('Y-m-d H:i:s'),
                ];
                PointReviewProcess::insert($PointReviewProcess);

                $mongoDb->insert($Collection, [
                    'batch_num'     => $out_batch_no,
                    'cr_dt'         =>  date('Y-m-d H:i:s'),
                    'status'        =>  'normal',
                    'response_code' =>  $resp->getStatusCode(),
                    'response_body' =>  $body,
                    'send_data'     =>  $send_data
                ]);

        } catch (\Exception $e) {
            // 进行错误处理
            echo $e->getMessage(), PHP_EOL;

            $Message = $e->getMessage();

            $code = $Phrase = $Body = $TraceAsString = '';

            if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
                $r = $e->getResponse();
                $code = $r->getStatusCode();
                $Phrase = $r->getReasonPhrase();
                $Body = $r->getBody();
            }

            $mongoDb->insert($Collection, [
                'batch_num'     => $out_batch_no,
                'cr_dt'         =>  date('Y-m-d H:i:s'),
                'status'        =>  'error',
                'response_code' =>  $code.' -- '.$Phrase.' -- '.$TraceAsString,
                'response_body' =>  $Body.' MSG:'.$Message,
                'send_data'     =>  $send_data,
            ]);
        }
    }
}

 

 

下载平台证书

第一种: 【最简单 利用conposer】
composer exec CertificateDownloader.php -- -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}



第二种: 【我目前集成微信支付类用的】
  public function certificates()
    {
     // 发送请求
        $instance = WeChatPayUtils::getInsance($typeName);

        $resp = $instance->chain('v3/certificates')->get(
            ['debug' => true] // 调试模式,https://docs.guzzlephp.org/en/stable/request-options.html#debug
        );
        $body = (string) $resp->getBody();

        $result = json_decode($body, true);


        $aa = self::decryptToString(    # 解析 获取平台证书 时限约5年
            2,
            $result['data'][0]['encrypt_certificate']['associated_data'],
            $result['data'][0]['encrypt_certificate']['nonce'],
            $result['data'][0]['encrypt_certificate']['ciphertext']
        );

        var_dump($result);
}



第三种:【最繁琐 需要以下几个方法使用】
  public function certificates()
    {
        $url= "https://api.mch.weixin.qq.com/v3/certificates";
        $headers = self::sign(2, 'GET', $url, '');
        $response =  self::$guzzle->gHttps($url)->get($url, ['headers'=>$headers]);
        $body = $response->getBody();
        $result = json_decode($body->getContents(), true);

        $aa = self::decryptToString(    # 解析 获取平台证书 时限约5年
            2,
            $result['data'][0]['encrypt_certificate']['associated_data'],
            $result['data'][0]['encrypt_certificate']['nonce'],
            $result['data'][0]['encrypt_certificate']['ciphertext']
        );
        var_dump('  ==============  ');
        var_dump('  ==============  ');
        var_dump($aa);
    }

 public static function sign($utype, $http_method = 'POST', $url = '', $body = '')
    {
        $apiclient_key = 'apiclient_abc_key.pem';

        $name = 'ABC';

        if ($utype == 2) {
            $name = 'OPQ';

            $apiclient_key = 'apiclient_opq_key.pem';
        }

        $mch_private_key = openssl_get_privatekey(
                file_get_contents('file:///var/www/storage/keys/'.$apiclient_key)

        );   # 私钥文件存放路径 【 根据实际存放地址 】


        $timestamp = time();                    # 时间戳

        $nonce = self::getRandomStr(32);    # 随机串

        # 设置HTTP头
        $config = [
            'appid' => env('POINT_'.$name.'_APP_ID'),
            'mchid' =>  env('POINT_'.$name.'_MERCHANTID'),     # 商户号
            'serial_no' => env('POINT_'.$name.'_SERIAL'),      # 证书序列号
            'description' => 'Test',                             # 应用名称(随意)
        ];

        $url_parts = parse_url($url);
        # 构造签名串
        $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);

        $token = sprintf(
            'WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $config['mchid'],
            $nonce,
            $timestamp,
            $config['serial_no'],
            $sign
        );

        $headers = [
            'Accept'=>'application/json',
            'User-Agent'=> '*/*',
            'Content-Type'=>'application/json; charset=utf-8',
            'Authorization'=>$token,
        ];

        # 签名验证工具只支持win,
        # 下载:https://developers.weixin.qq.com/community/develop/article/doc/0000acd4888bc80ff1dcf952751413
        return $headers;
    }

 public static function getRandomStr($len, $special = false)
    {
        $chars = array(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
            "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G",
            "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2",
            "3", "4", "5", "6", "7", "8", "9"
        );

        if ($special) {
            $chars = array_merge($chars, array(
                "!", "@", "#", "$", "?", "|", "{", "/", ":", ";",
                "%", "^", "&", "*", "(", ")", "-", "_", "[", "]",
                "}", "<", ">", "~", "+", "=", ",", "."
            ));
        }

        $charsLen = count($chars) - 1;

        shuffle($chars);        # 打乱数组顺序

        $str = '';

        for ($i=0; $i<$len; $i++) {
            $str .= $chars[mt_rand(0, $charsLen)];  # 随机取出一位
        }

        return $str;
    }

 

 

解析证书加密串

 
const AUTH_TAG_LENGTH_BYTE = 16;
const KEY_LENGTH_BYTE = 32;

public function decryptToString($utype, $associatedData, $nonceStr, $ciphertext) { $aesKey = env('POINT_ABC_AESKEY'); # v3 版本密钥 if ($utype == 2) { $aesKey = env('POINT_OPQ_AESKEY'); } $ciphertext = \base64_decode($ciphertext); if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) { return false; } // ext-sodium (default installed on >= PHP 7.2) if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') && \sodium_crypto_aead_aes256gcm_is_available() ) { return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey); } // ext-libsodium (need install libsodium-php 1.x via pecl) if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') && \Sodium\crypto_aead_aes256gcm_is_available() ) { return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey); } // openssl (PHP >= 7.1 support AEAD) if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) { $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE); $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE); return \openssl_decrypt( $ctext, 'aes-256-gcm', $aesKey, \OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData ); } throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php'); }

 

posted @ 2023-06-27 14:57  现世中的素人  阅读(92)  评论(0编辑  收藏  举报