ComposerUpdate

This commit is contained in:
Anyon 2020-12-26 16:46:31 +08:00
parent fa08383513
commit a28f8fb8fd
19 changed files with 723 additions and 44 deletions

View File

@ -296,6 +296,7 @@ return array(
'think\\admin\\command\\Database' => $vendorDir . '/zoujingli/think-library/src/command/Database.php',
'think\\admin\\command\\Install' => $vendorDir . '/zoujingli/think-library/src/command/Install.php',
'think\\admin\\command\\Queue' => $vendorDir . '/zoujingli/think-library/src/command/Queue.php',
'think\\admin\\command\\Replace' => $vendorDir . '/zoujingli/think-library/src/command/Replace.php',
'think\\admin\\command\\Version' => $vendorDir . '/zoujingli/think-library/src/command/Version.php',
'think\\admin\\extend\\CodeExtend' => $vendorDir . '/zoujingli/think-library/src/extend/CodeExtend.php',
'think\\admin\\extend\\DataExtend' => $vendorDir . '/zoujingli/think-library/src/extend/DataExtend.php',

View File

@ -424,6 +424,7 @@ class ComposerStaticInit4f89fd0e0503ccf740f2fa5757825d7b
'think\\admin\\command\\Database' => __DIR__ . '/..' . '/zoujingli/think-library/src/command/Database.php',
'think\\admin\\command\\Install' => __DIR__ . '/..' . '/zoujingli/think-library/src/command/Install.php',
'think\\admin\\command\\Queue' => __DIR__ . '/..' . '/zoujingli/think-library/src/command/Queue.php',
'think\\admin\\command\\Replace' => __DIR__ . '/..' . '/zoujingli/think-library/src/command/Replace.php',
'think\\admin\\command\\Version' => __DIR__ . '/..' . '/zoujingli/think-library/src/command/Version.php',
'think\\admin\\extend\\CodeExtend' => __DIR__ . '/..' . '/zoujingli/think-library/src/extend/CodeExtend.php',
'think\\admin\\extend\\DataExtend' => __DIR__ . '/..' . '/zoujingli/think-library/src/extend/DataExtend.php',

View File

@ -937,12 +937,12 @@
"source": {
"type": "git",
"url": "https://github.com/zoujingli/ThinkLibrary.git",
"reference": "f8a4e65cf6b57531c8536462b30892eae49c7809"
"reference": "e1cc4dcb049fc1cedbb99807d235e5bda3dcdf71"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/f8a4e65cf6b57531c8536462b30892eae49c7809",
"reference": "f8a4e65cf6b57531c8536462b30892eae49c7809",
"url": "https://api.github.com/repos/zoujingli/ThinkLibrary/zipball/e1cc4dcb049fc1cedbb99807d235e5bda3dcdf71",
"reference": "e1cc4dcb049fc1cedbb99807d235e5bda3dcdf71",
"shasum": "",
"mirrors": [
{
@ -959,7 +959,7 @@
"ext-mbstring": "*",
"topthink/framework": "^6.0"
},
"time": "2020-12-18T05:04:10+00:00",
"time": "2020-12-26T08:29:41+00:00",
"type": "library",
"extra": {
"think": {
@ -992,17 +992,17 @@
},
{
"name": "zoujingli/wechat-developer",
"version": "v1.2.26",
"version_normalized": "1.2.26.0",
"version": "v1.2.27",
"version_normalized": "1.2.27.0",
"source": {
"type": "git",
"url": "https://github.com/zoujingli/WeChatDeveloper.git",
"reference": "5ecafcd810627cd9217c3d7f18c7026612418278"
"reference": "94de6626f1c9e3d12f16640c30fb9319b37ff34c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zoujingli/WeChatDeveloper/zipball/5ecafcd810627cd9217c3d7f18c7026612418278",
"reference": "5ecafcd810627cd9217c3d7f18c7026612418278",
"url": "https://api.github.com/repos/zoujingli/WeChatDeveloper/zipball/94de6626f1c9e3d12f16640c30fb9319b37ff34c",
"reference": "94de6626f1c9e3d12f16640c30fb9319b37ff34c",
"shasum": "",
"mirrors": [
{
@ -1022,7 +1022,7 @@
"ext-xml": "*",
"php": ">=5.4"
},
"time": "2020-09-13T06:01:11+00:00",
"time": "2020-12-24T09:44:04+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
@ -1056,10 +1056,6 @@
"wechat",
"wechatpay",
"wepay"
],
"support": {
"issues": "https://github.com/zoujingli/WeChatDeveloper/issues",
"source": "https://github.com/zoujingli/WeChatDeveloper/tree/v1.2.26"
}
]
}
]

2
vendor/services.php vendored
View File

@ -1,5 +1,5 @@
<?php
// This file is automatically generated at:2020-12-23 16:37:11
// This file is automatically generated at:2020-12-26 16:45:15
declare (strict_types = 1);
return array (
0 => 'think\\admin\\Library',

View File

@ -18,11 +18,12 @@ namespace think\admin;
use think\admin\command\Database;
use think\admin\command\Install;
use think\admin\command\Queue;
use think\admin\command\Replace;
use think\admin\command\Version;
use think\admin\multiple\BuildUrl;
use think\admin\multiple\command\Build;
use think\admin\multiple\command\Clear;
use think\admin\multiple\Multiple;
use think\admin\multiple\BuildUrl;
use think\admin\service\AdminService;
use think\admin\service\SystemService;
use think\middleware\LoadLangPack;
@ -41,7 +42,7 @@ class Library extends Service
/**
* 版本号
*/
const VERSION = '6.0.22';
const VERSION = '6.0.23';
/**
* 启动服务
@ -62,7 +63,7 @@ class Library extends Service
// 替换 ThinkPHP 指令
$this->commands(['build' => Build::class, 'clear' => Clear::class]);
// 注册 ThinkAdmin 指令
$this->commands([Queue::class, Install::class, Version::class, Database::class]);
$this->commands([Queue::class, Install::class, Version::class, Database::class, Replace::class]);
// 动态应用运行参数
SystemService::instance()->bindRuntime();
}

View File

@ -0,0 +1,89 @@
<?php
// +----------------------------------------------------------------------
// | Library for ThinkAdmin
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: https://gitee.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | gitee 仓库地址 https://gitee.com/zoujingli/ThinkLibrary
// | github 仓库地址 https://github.com/zoujingli/ThinkLibrary
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace think\admin\command;
use think\admin\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use think\helper\Str;
/**
* 数据库字符替换
* Class Replace
* @package app\wechat\command
*/
class Replace extends Command
{
protected function configure()
{
$this->setName('xadmin:replace');
$this->addArgument('search', Argument::OPTIONAL, '查找替换的字符内容', '');
$this->addArgument('replace', Argument::OPTIONAL, '目标替换的字符内容', '');
$this->setDescription('Database Character Field Replace for ThinkAdmin');
}
/**
* 执行指令
* @param Input $input
* @param Output $output
* @throws \think\admin\Exception
* @throws \think\db\exception\DbException
*/
protected function execute(Input $input, Output $output)
{
$search = $input->getArgument('search');
$repalce = $input->getArgument('replace');
if ($search === '') $this->queue->error('查找替换字符内容不能为空!');
if ($repalce === '') $this->queue->error('目标替换字符内容不能为空!');
[$count, $used] = [count($tables = $this->getTables()), 0];
foreach ($tables as $table) {
$data = [];
$this->queue->message($count, ++$used, sprintf("准备替换数据表 %s", Str::studly($table)));
foreach ($this->app->db->table($table)->getFields() as $field => $attrs) {
if (preg_match('/char|text/', $attrs['type'])) {
$data[$field] = $this->app->db->raw(sprintf('REPLACE(`%s`,"%s","%s")', $field, $search, $repalce));
}
}
if (count($data) > 0) {
if ($this->app->db->table($table)->where('1=1')->update($data) !== false) {
$this->queue->message($count, $used, sprintf("成功替换数据表 %s", Str::studly($table)), 1);
} else {
$this->queue->message($count, $used, sprintf("失败替换数据表 %s", Str::studly($table)), 1);
}
} else {
$this->queue->message($count, $used, sprintf("无需替换数据表 %s", Str::studly($table)), 1);
}
}
$this->queue->success('批量替换成功');
}
/**
* 获取数据库的数据表
* @return array
*/
protected function getTables(): array
{
$tables = [];
foreach ($this->app->db->query("show tables") as $item) {
$tables = array_merge($tables, array_values($item));
}
return $tables;
}
}

View File

@ -28,6 +28,7 @@ use WeChat\Exceptions\InvalidInstanceException;
* @method \AliPay\Bill AliPayBill($options) static 支付宝电子面单下载
* @method \AliPay\Pos AliPayPos($options) static 支付宝刷卡支付
* @method \AliPay\Scan AliPayScan($options) static 支付宝扫码支付
* @method \AliPay\Trade AliPayTrade($options) static 支付宝标准接口
* @method \AliPay\Transfer AliPayTransfer($options) static 支付宝转账到账户
* @method \AliPay\Wap AliPayWap($options) static 支付宝手机网站支付
* @method \AliPay\Web AliPayWeb($options) static 支付宝网站支付
@ -86,7 +87,7 @@ class We
* 定义当前版本
* @var string
*/
const VERSION = '1.2.26';
const VERSION = '1.2.27';
/**
* 静态配置

View File

@ -128,21 +128,21 @@ class BasicWeChat
/**
* 设置外部接口 AccessToken
* @param string $access_token
* @param string $accessToken
* @throws \WeChat\Exceptions\LocalCacheException
* @author 高一平 <iam@gaoyiping.com>
*
* 当用户使用自己的缓存驱动时,直接实例化对象后可直接设置 AccessToekn
* 当用户使用自己的缓存驱动时,直接实例化对象后可直接设置 AccessToken
* - 多用于分布式项目时保持 AccessToken 统一
* - 使用此方法后就由用户来保证传入的 AccessToekn 为有效 AccessToekn
* - 使用此方法后就由用户来保证传入的 AccessToken 为有效 AccessToken
*/
public function setAccessToken($access_token)
public function setAccessToken($accessToken)
{
if (!is_string($access_token)) {
if (!is_string($accessToken)) {
throw new InvalidArgumentException("Invalid AccessToken type, need string.");
}
$cache = $this->config->get('appid') . '_access_token';
Tools::setCache($cache, $this->access_token = $access_token);
Tools::setCache($cache, $this->access_token = $accessToken);
}
/**
@ -169,8 +169,7 @@ class BasicWeChat
} catch (InvalidResponseException $exception) {
if (isset($this->currentMethod['method']) && empty($this->isTry)) {
if (in_array($exception->getCode(), ['40014', '40001', '41001', '42001'])) {
$this->delAccessToken();
$this->isTry = true;
[$this->delAccessToken(), $this->isTry = true];
return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
}
}

View File

@ -426,7 +426,7 @@ class Tools
return call_user_func_array(self::$cache_callable['get'], func_get_args());
}
$file = self::_getCacheName($name);
if (file_exists($file) && ($content = file_get_contents($file))) {
if (file_exists($file) && is_file($file) && ($content = file_get_contents($file))) {
$data = unserialize($content);
if (isset($data['expired']) && (intval($data['expired']) === 0 || intval($data['expired']) >= time())) {
return $data['value'];

View File

@ -16,6 +16,7 @@ namespace WePay;
use WeChat\Contracts\BasicWePay;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidDecryptException;
use WeChat\Exceptions\InvalidResponseException;
/**
@ -55,6 +56,7 @@ class Refund extends BasicWePay
/**
* 获取退款通知
* @return array
* @throws InvalidDecryptException
* @throws InvalidResponseException
*/
public function getNotify()
@ -63,16 +65,14 @@ class Refund extends BasicWePay
if (!isset($data['return_code']) || $data['return_code'] !== 'SUCCESS') {
throw new InvalidResponseException('获取退款通知XML失败');
}
if (!class_exists('Prpcrypt', false)) {
include dirname(__DIR__) . '/WeChat/Contracts/Prpcrypt.php';
try {
$key = md5($this->config->get('mch_key'));
$decrypt = base64_decode($data['req_info']);
$response = openssl_decrypt($decrypt, 'aes-256-ecb', $key, OPENSSL_RAW_DATA);
$data['result'] = Tools::xml2arr($response);
return $data;
} catch (\Exception $exception) {
throw new InvalidDecryptException($exception->getMessage(), $exception->getCode());
}
$pc = new \Prpcrypt(md5($this->config->get('mch_key')));
$array = $pc->decrypt(base64_decode($data['req_info']));
if (intval($array[0]) > 0) {
throw new InvalidResponseException($array[1], $array[0]);
}
$data['decode'] = $array[1];
return $data;
}
}

View File

@ -0,0 +1,49 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WePayV3;
use WeChat\Exceptions\InvalidResponseException;
use WePayV3\Contracts\BasicWePay;
use WePayV3\Contracts\DecryptAes;
/**
* 平台证书管理
* Class Cert
* @package WePayV3
*/
class Cert extends BasicWePay
{
/**
* 商户平台下载证书
* @throws InvalidResponseException
*/
public function download()
{
try {
$aes = new DecryptAes($this->config['mch_v3_key']);
$result = $this->doRequest('GET', '/v3/certificates');
foreach ($result['data'] as $vo) {
$this->tmpFile($vo['serial_no'], $aes->decryptToString(
$vo['encrypt_certificate']['associated_data'],
$vo['encrypt_certificate']['nonce'],
$vo['encrypt_certificate']['ciphertext']
));
}
} catch (\Exception $exception) {
throw new InvalidResponseException($exception->getMessage(), $exception->getCode());
}
}
}

View File

@ -0,0 +1,219 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WePayV3\Contracts;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidArgumentException;
use WeChat\Exceptions\InvalidResponseException;
use WeChat\Exceptions\LocalCacheException;
use WePayV3\Cert;
/**
* 微信支付基础类
* Class BasicWePay
* @package WePayV3
*/
abstract class BasicWePay
{
/**
* 接口基础地址
* @var string
*/
protected $base = 'https://api.mch.weixin.qq.com';
/**
* 实例对象静态缓存
* @var array
*/
static $cache = [];
/**
* 配置参数
* @var array
*/
protected $config = [
'appid' => '', // 微信绑定APPID需配置
'mch_id' => '', // 微信商户编号,需要配置
'mch_v3_key' => '', // 微信商户密钥,需要配置
'cert_serial' => '', // 商户证书序号,无需配置
'cert_public' => '', // 商户公钥内容,需要配置
'cert_private' => '', // 商户密钥内容,需要配置
];
/**
* BasicWePayV3 constructor.
* @param array $options [mch_id, mch_v3_key, cert_public, cert_private]
*/
public function __construct(array $options = [])
{
if (empty($options['mch_id'])) {
throw new InvalidArgumentException("Missing Config -- [mch_id]");
}
if (empty($options['mch_v3_key'])) {
throw new InvalidArgumentException("Missing Config -- [mch_v3_key]");
}
if (empty($options['cert_private'])) {
throw new InvalidArgumentException("Missing Config -- [cert_private]");
}
if (empty($options['cert_public'])) {
throw new InvalidArgumentException("Missing Config -- [cert_public]");
}
$this->config['appid'] = isset($options['appid']) ? $options['appid'] : '';
$this->config['mch_id'] = $options['mch_id'];
$this->config['mch_v3_key'] = $options['mch_v3_key'];
$this->config['cert_public'] = $options['cert_public'];
$this->config['cert_private'] = $options['cert_private'];
$this->config['cert_serial'] = openssl_x509_parse($this->config['cert_public'])['serialNumberHex'];
if (empty($this->config['cert_serial'])) {
throw new InvalidArgumentException("Failed to parse certificate public key");
}
}
/**
* 静态创建对象
* @param array $config
* @return static
*/
public static function instance(array $config)
{
$key = md5(get_called_class() . serialize($config));
if (isset(self::$cache[$key])) return self::$cache[$key];
return self::$cache[$key] = new static($config);
}
/**
* 模拟发起请求
* @param string $method 请求访问
* @param string $pathinfo 请求路由
* @param string $jsondata 请求数据
* @param bool $verify 是否验证
* @return array
* @throws InvalidResponseException
*/
public function doRequest($method, $pathinfo, $jsondata = '', $verify = false)
{
list($time, $nonce) = [time(), uniqid() . rand(1000, 9999)];
$signstr = join("\n", [$method, $pathinfo, $time, $nonce, $jsondata, '']);
// 生成数据签名TOKEN
$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
$this->config['mch_id'], $nonce, $time, $this->config['cert_serial'], $this->signBuild($signstr)
);
list($header, $content) = $this->_doRequestCurl($method, $this->base . $pathinfo, [
'data' => $jsondata, 'header' => [
"Accept: application/json", "Content-Type: application/json",
'User-Agent: https://thinkadmin.top', "Authorization: WECHATPAY2-SHA256-RSA2048 {$token}",
],
]);
if ($verify) {
$headers = [];
foreach (explode("\n", $header) as $line) {
if (stripos($line, 'Wechatpay') !== false) {
list($name, $value) = explode(':', $line);
list(, $keys) = explode('wechatpay-', strtolower($name));
$headers[$keys] = trim($value);
}
}
try {
$string = join("\n", [$headers['timestamp'], $headers['nonce'], $content, '']);
if (!$this->signVerify($string, $headers['signature'], $headers['serial'])) {
throw new InvalidResponseException("验证响应签名失败");
}
} catch (\Exception $exception) {
throw new InvalidResponseException($exception->getMessage(), $exception->getCode());
}
}
return json_decode($content, true);
}
/**
* 通过CURL模拟网络请求
* @param string $method 请求方法
* @param string $location 请求方法
* @param array $options 请求参数 [data, header]
* @return array [header,content]
*/
private function _doRequestCurl($method, $location, $options = [])
{
$curl = curl_init();
// POST数据设置
if (strtolower($method) === 'post') {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $options['data']);
}
// CURL头信息设置
if (!empty($options['header'])) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $options['header']);
}
curl_setopt($curl, CURLOPT_URL, $location);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_TIMEOUT, 60);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$content = curl_exec($curl);
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
curl_close($curl);
return [substr($content, 0, $headerSize), substr($content, $headerSize)];
}
/**
* 生成数据签名
* @param string $data 签名内容
* @return string
*/
protected function signBuild($data)
{
$pkeyid = openssl_pkey_get_private($this->config['cert_private']);
openssl_sign($data, $signature, $pkeyid, 'sha256WithRSAEncryption');
return base64_encode($signature);
}
/**
* 验证内容签名
* @param string $data 签名内容
* @param string $sign 原签名值
* @param string $serial 证书序号
* @return int
* @throws InvalidResponseException
* @throws LocalCacheException
*/
protected function signVerify($data, $sign, $serial = '')
{
$cert = $this->tmpFile($serial);
if (empty($cert)) {
Cert::instance($this->config)->download();
$cert = $this->tmpFile($serial);
}
return @openssl_verify($data, base64_decode($sign), openssl_x509_read($cert), 'sha256WithRSAEncryption');
}
/**
* 写入或读取临时文件
* @param string $name
* @param null|string $content
* @return string
* @throws LocalCacheException
*/
protected function tmpFile($name, $content = null)
{
if (is_null($content)) {
return base64_decode(Tools::getCache($name) ?: '');
} else {
return Tools::setCache($name, base64_encode($content), 7200);
}
}
}

View File

@ -0,0 +1,81 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WePayV3\Contracts;
use WeChat\Exceptions\InvalidArgumentException;
use WeChat\Exceptions\InvalidDecryptException;
/**
* Aes 解密工具类
* Class DecryptAes
* @package WePayV3\Contracts
*/
class DecryptAes
{
private $aesKey;
const KEY_LENGTH_BYTE = 32;
const AUTH_TAG_LENGTH_BYTE = 16;
/**
* Constructor
* @param string $aesKey
*/
public function __construct($aesKey)
{
if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
throw new InvalidArgumentException('无效的ApiV3Key长度应为32个字节');
}
$this->aesKey = $aesKey;
}
/**
* Decrypt AEAD_AES_256_GCM ciphertext
* @param string $associatedData AES GCM additional authentication data
* @param string $nonceStr AES GCM nonce
* @param string $ciphertext AES GCM cipher text
* @return string|bool Decrypted string on success or FALSE on failure
* @throws InvalidDecryptException
*/
public function decryptToString($associatedData, $nonceStr, $ciphertext)
{
$ciphertext = \base64_decode($ciphertext);
if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
return false;
}
try {
// 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, $this->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, $this->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', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData);
}
} catch (\Exception $exception) {
throw new InvalidDecryptException($exception->getMessage(), $exception->getCode());
} catch (\SodiumException $exception) {
throw new InvalidDecryptException($exception->getMessage(), $exception->getCode());
}
throw new InvalidDecryptException('AEAD_AES_256_GCM 需要 PHP 7.1 以上或者安装 libsodium-php');
}
}

View File

@ -0,0 +1,106 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WePayV3;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidArgumentException;
use WeChat\Exceptions\InvalidDecryptException;
use WeChat\Exceptions\InvalidResponseException;
use WePayV3\Contracts\BasicWePay;
use WePayV3\Contracts\DecryptAes;
/**
* 订单支付接口
* Class Order
* @package WePayV3
*/
class Order extends BasicWePay
{
const WXPAY_H5 = 'h5';
const WXPAY_APP = 'app';
const WXPAY_JSAPI = 'jsapi';
const WXPAY_NATIVE = 'native';
/**
* 创建支付订单
* @param string $type 支付类型
* @param array $data 支付参数
* @return array
* @throws InvalidResponseException
*/
public function create($type, $data)
{
$types = [
'h5' => '/v3/pay/transactions/h5',
'app' => '/v3/pay/transactions/app',
'jsapi' => '/v3/pay/transactions/jsapi',
'native' => '/v3/pay/transactions/native',
];
if (empty($types[$type])) {
throw new InvalidArgumentException("Payment {$type} not defined.");
} else {
// 创建预支付码
$result = $this->doRequest('POST', $types[$type], json_encode($data, JSON_UNESCAPED_UNICODE), true);
if (empty($result['prepay_id'])) return $result;
// 支付参数签名
$time = (string)time();
$appid = $this->config['appid'];
$prepayId = $result['prepay_id'];
$nonceStr = Tools::createNoncestr();
if ($type === 'app') {
$sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, $prepayId]));
return ['partnerId' => $this->config['mch_id'], 'prepayId' => $prepayId, 'package' => 'Sign=WXPay', 'nonceStr' => $nonceStr, 'timeStamp' => $time, 'sign' => $sign];
} elseif ($type === 'jsapi') {
$sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, "prepay_id={$prepayId}"]));
return ['appId' => $appid, 'timeStamp' => $time, 'nonceStr' => $nonceStr, 'package' => "prepay_id={$prepayId}", 'signType' => 'RSA', 'paySign' => $sign];
} else {
return $result;
}
}
}
/**
* 支付订单查询
* @param string $orderNo 订单单号
* @return array
* @throws InvalidResponseException
*/
public function query($orderNo)
{
$pathinfo = "/v3/pay/transactions/out-trade-no/{$orderNo}";
return $this->doRequest('GET', "{$pathinfo}?mchid={$this->config['mch_id']}", '', true);
}
/**
* 支付通知
* @return array
* @throws InvalidDecryptException
*/
public function notify()
{
$body = file_get_contents('php://input');
$data = json_decode($body, true);
if (isset($data['resource'])) {
$aes = new DecryptAes($this->config['mch_v3_key']);
$data['result'] = $aes->decryptToString(
$data['resource']['associated_data'],
$data['resource']['nonce'],
$data['resource']['ciphertext']
);
}
return $data;
}
}

View File

@ -0,0 +1,75 @@
<?php
// +----------------------------------------------------------------------
// | WeChatDeveloper
// +----------------------------------------------------------------------
// | 版权所有 2014~2020 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://think.ctolog.com
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/WeChatDeveloper
// +----------------------------------------------------------------------
namespace WePayV3;
use WeChat\Contracts\Tools;
use WeChat\Exceptions\InvalidDecryptException;
use WeChat\Exceptions\InvalidResponseException;
use WePayV3\Contracts\BasicWePay;
/**
* 订单退款接口
* Class Refund
* @package WePayV3
*/
class Refund extends BasicWePay
{
/**
* 创建退款订单
* @param array $data 退款参数
* @return array
* @throws InvalidResponseException
*/
public function create($data)
{
return $this->doRequest('POST', '/v3/ecommerce/refunds/apply', json_encode($data, JSON_UNESCAPED_UNICODE), true);
}
/**
* 退款订单查询
* @param string $refundNo 退款单号
* @return array
* @throws InvalidResponseException
*/
public function query($refundNo)
{
$pathinfo = "/v3/ecommerce/refunds/out-refund-no/{$refundNo}";
return $this->doRequest('GET', "{$pathinfo}?sub_mchid={$this->config['mch_id']}", '', true);
}
/**
* 获取退款通知
* @return array
* @throws InvalidDecryptException
* @throws InvalidResponseException
*/
public function notify()
{
$data = Tools::xml2arr(file_get_contents("php://input"));
if (!isset($data['return_code']) || $data['return_code'] !== 'SUCCESS') {
throw new InvalidResponseException('获取退款通知XML失败');
}
try {
$key = md5($this->config['mch_v3_key']);
$decrypt = base64_decode($data['req_info']);
$response = openssl_decrypt($decrypt, 'aes-256-ecb', $key, OPENSSL_RAW_DATA);
$data['result'] = Tools::xml2arr($response);
return $data;
} catch (\Exception $exception) {
throw new InvalidDecryptException($exception->getMessage(), $exception->getCode());
}
}
}

View File

@ -0,0 +1,16 @@
<?php
try {
// 1. 手动加载入口文件
include "../include.php";
// 2. 准备公众号配置参数
$config = include "./pay-v3-config.php";
$payment = \WePayV3\Cert::instance($config);
$payment->download();
} catch (\Exception $exception) {
// 出错啦,处理下吧
echo $exception->getMessage() . PHP_EOL;
}

View File

@ -0,0 +1,17 @@
<?php
return [
'appid' => '绑定的APPID',
'mch_id' => '您的商户编号',
'mch_v3_key' => '您的V3接口密码',
'cert_public' => <<<EOF
-----BEGIN CERTIFICATE-----
您的证书内容
-----END CERTIFICATE-----
EOF,
'cert_private' => <<<EOF
-----BEGIN PRIVATE KEY-----
您的证书内容
-----END PRIVATE KEY-----
EOF,
];

View File

@ -0,0 +1,30 @@
<?php
try {
// 1. 手动加载入口文件
include "../include.php";
// 2. 准备公众号配置参数
$config = include "./pay-v3-config.php";
// 3. 创建接口实例
$payment = \WePayV3\Order::instance($config);
// 4. 组装支付参数
$result = $payment->create('jsapi', [
'appid' => 'wx60a43dd8161666d4',
'mchid' => $config['mch_id'],
'description' => '商品描述',
'out_trade_no' => date("YmdHis"),
'notify_url' => 'https://thinkadmin.top',
'payer' => ['openid' => 'o38gps3vNdCqaggFfrBRCRikwlWY'],
'amount' => ['total' => 1, 'currency' => 'CNY'],
]);
echo '<pre>';
echo "\n--- 创建支付参数 ---\n";
var_export($result);
} catch (\Exception $exception) {
// 出错啦,处理下吧
echo $exception->getMessage() . PHP_EOL;
}

View File

@ -11,6 +11,7 @@ WeChatDeveloper for PHP
* 微信的部分接口需要缓存数据在本地,因此对目录需要有写权限;
* 我们鼓励大家使用 composer 来管理您的第三方库,方便后期更新操作;
* WeChatDeveloper 已历经数个线上项目考验,欢迎 fork 或 star 此项目。
* 微信商户支持已经支持 v2 接口,组件开发版支持 v3 接口。
功能描述
----
@ -260,8 +261,5 @@ try {
* WeChatDeveloper 基于`MIT`协议发布,任何人可以用在任何地方,不受约束
* WeChatDeveloper 部分代码来自互联网,若有异议,可以联系作者进行删除
赞助支持
----
![赞助](http://static.thinkadmin.top/pay.png)
## 赞助打赏
![赞助](https://thinkadmin.top/static/img/pay.png)