微信商家转账零钱优化版【奶妈级教程】
首先你得先去申请商户,并且连续三个月 不可间断的让这个商户号有资金流水【每天存一毛钱】,也就是说 你想使用微信转账 即时起也要三个月以后!!!
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'); }
作者地址:https://www.cnblogs.com/G921123/
创作也有乐趣 知识分享 转载注明出处 相互理解 谢谢!
创作也有乐趣 知识分享 转载注明出处 相互理解 谢谢!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)