diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..cf9807c
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,34 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - master
+ - '2.0'
+ pull_request:
+
+permissions:
+ contents: read
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: '8.4'
+ extensions: json, openssl, simplexml
+ coverage: none
+
+ - name: Validate composer metadata
+ run: composer validate --strict
+
+ - name: Install dependencies
+ run: composer install --no-interaction --prefer-dist --no-progress
+
+ - name: Run tests
+ run: composer test
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 20e0bad..5f50da2 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,11 +1,12 @@
+name: Create Release
+
on:
push:
- # Sequence of patterns matched against refs/tags
tags:
- - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
+ - 'v*'
-name: Create Release
-permissions: write-all
+permissions:
+ contents: write
jobs:
release:
@@ -16,50 +17,34 @@ jobs:
with:
fetch-depth: 0
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- node-version: 18
-
- - name: Install dependencies
- run: npm install -g gen-git-log
-
- - name: Find Last Tag
- id: last_tag
+ - name: Resolve previous tag
+ id: tags
+ shell: bash
run: |
-
- # 获取所有标签,按版本排序(降序)
- Tags=$(git tag --list --sort=-version:refname)
-
- # 获取最新的标签(即列表中的第一个)
- LATEST_TAG=$(echo "$Tags" | awk 'NR==1 {print $1; exit}')
-
- # 获取倒数第二个标签(如果存在)
- if [[ -n "$Tags" ]]; then
- # 使用 tail 获取除了最后一个标签之外的所有标签,然后用 head 获取第一个
- SECOND_LATEST_TAG=$(echo "$Tags" | tail -n +2 | head -n 1)
- else
- SECOND_LATEST_TAG=""
+ current="${GITHUB_REF_NAME}"
+ previous="$(git tag --list 'v*' --sort=-version:refname | grep -v "^${current}$" | head -n 1 || true)"
+ echo "current=${current}" >> "$GITHUB_OUTPUT"
+ echo "previous=${previous}" >> "$GITHUB_OUTPUT"
+
+ - name: Build release notes
+ shell: bash
+ run: |
+ current="${{ steps.tags.outputs.current }}"
+ previous="${{ steps.tags.outputs.previous }}"
+ if [ -n "$previous" ]; then
+ git log --pretty='- %s (%h)' "${previous}..${current}" > RELEASE_NOTES.md
+ else
+ git log --pretty='- %s (%h)' "${current}" > RELEASE_NOTES.md
+ fi
+ if [ ! -s RELEASE_NOTES.md ]; then
+ echo "- Release ${current}" > RELEASE_NOTES.md
fi
-
- # 设置输出变量
- echo "::set-output name=tag_last::${LATEST_TAG:-v1.0.0}"
- echo "::set-output name=tag_second::${SECOND_LATEST_TAG:-v1.0.0}"
- - name: Generate Release Notes
- run: |
- rm -rf log
- newTag=${{ steps.last_tag.outputs.tag_last }}
- git-log -m tag -f -S ${{ steps.last_tag.outputs.tag_second }} -v ${newTag#v}
-
- - name: Create Release
- id: create_release
- uses: actions/create-release@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Create GitHub release
+ uses: softprops/action-gh-release@v2
with:
- tag_name: ${{ steps.last_tag.outputs.tag_last }}
- release_name: Release ${{ steps.last_tag.outputs.tag_last }}
- body_path: log/${{steps.last_tag.outputs.tag_last}}.md
+ tag_name: ${{ steps.tags.outputs.current }}
+ name: Release ${{ steps.tags.outputs.current }}
+ body_path: RELEASE_NOTES.md
draft: false
- prerelease: false
\ No newline at end of file
+ prerelease: false
diff --git a/.gitignore b/.gitignore
index 7791a86..385f1ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,9 @@
-/.git
-/.idea
-/.DS_Store
-/vendor
-/Cache
-/Test/cert
-/nbproject
-/composer.lock
-/_test/cert
\ No newline at end of file
+.DS_Store
+.idea/
+vendor/
+composer.lock
+.phpunit.cache/
+Cache/
+Test/cert/
+_test/cert/
+nbproject/
diff --git a/AliPay/App.php b/AliPay/App.php
deleted file mode 100644
index 9cc3c3f..0000000
--- a/AliPay/App.php
+++ /dev/null
@@ -1,49 +0,0 @@
-options->set('method', 'alipay.trade.app.pay');
- $this->params->set('product_code', 'QUICK_MSECURITY_PAY');
- }
-
- /**
- * 生成APP支付参数字符串
- * @param array $options 订单参数(out_trade_no, total_amount, subject等)
- * @return string URL编码后的参数字符串(用于APP调起支付)
- */
- public function apply($options)
- {
- $this->applyData($options);
- return http_build_query($this->options->get());
- }
-}
\ No newline at end of file
diff --git a/AliPay/Bill.php b/AliPay/Bill.php
deleted file mode 100644
index 507e365..0000000
--- a/AliPay/Bill.php
+++ /dev/null
@@ -1,48 +0,0 @@
-options->set('method', 'alipay.data.dataservice.bill.downloadurl.query');
- }
-
- /**
- * 获取账单下载地址
- * @param array $options 账单参数(bill_type, bill_date 等)
- * @return array 包含 bill_download_url 的响应数据
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function apply($options)
- {
- return $this->getResult($options);
- }
-}
\ No newline at end of file
diff --git a/AliPay/Pos.php b/AliPay/Pos.php
deleted file mode 100644
index babd574..0000000
--- a/AliPay/Pos.php
+++ /dev/null
@@ -1,49 +0,0 @@
-options->set('method', 'alipay.trade.pay');
- $this->params->set('product_code', 'FACE_TO_FACE_PAYMENT');
- }
-
- /**
- * 刷卡支付(条码/声波)下单
- * @param array $options 订单参数(out_trade_no, auth_code, subject, total_amount 等)
- * @return array 支付结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function apply($options)
- {
- return $this->getResult($options);
- }
-}
\ No newline at end of file
diff --git a/AliPay/Scan.php b/AliPay/Scan.php
deleted file mode 100644
index 9a80548..0000000
--- a/AliPay/Scan.php
+++ /dev/null
@@ -1,48 +0,0 @@
-options->set('method', 'alipay.trade.precreate');
- }
-
- /**
- * 预创建扫码支付订单(返回二维码地址)
- * @param array $options 订单参数(out_trade_no, subject, total_amount 等)
- * @return array 包含 qr_code 的预下单结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function apply($options)
- {
- return $this->getResult($options);
- }
-}
\ No newline at end of file
diff --git a/AliPay/Trade.php b/AliPay/Trade.php
deleted file mode 100644
index 0c7b76b..0000000
--- a/AliPay/Trade.php
+++ /dev/null
@@ -1,81 +0,0 @@
-options->set('method', $method);
- return $this;
- }
-
- /**
- * 获取当前交易接口方法名
- * @return string
- */
- public function getMethod()
- {
- return $this->options->get('method');
- }
-
- /**
- * 设置公共参数(透传到 options)
- * @param array $option key-value 公共参数
- * @return Trade
- */
- public function setOption($option = [])
- {
- foreach ($option as $key => $vo) {
- $this->options->set($key, $vo);
- }
- return $this;
- }
-
- /**
- * 获取当前公共参数
- * @return array|string|null
- */
- public function getOption()
- {
- return $this->options->get();
- }
-
- /**
- * 执行当前设置的交易接口
- * @param array $options 业务参数(写入 biz_content)
- * @return array 接口返回结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function apply($options)
- {
- return $this->getResult($options);
- }
-}
\ No newline at end of file
diff --git a/AliPay/Transfer.php b/AliPay/Transfer.php
deleted file mode 100644
index 94d0a6a..0000000
--- a/AliPay/Transfer.php
+++ /dev/null
@@ -1,79 +0,0 @@
-options->set('method', 'alipay.fund.trans.toaccount.transfer');
- return $this->getResult($options);
- }
-
- /**
- * 新版:统一转账接口(uni.transfer)
- * @param array $options 转账参数(out_biz_no, trans_amount, product_code, payee_info 等)
- * @return array 转账结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function create($options = [])
- {
- $this->options->set('method', 'alipay.fund.trans.uni.transfer');
- return $this->getResult($options);
- }
-
- /**
- * 新版:转账业务单据查询
- * @param array $options 查询参数(out_biz_no 或 order_id)
- * @return array 查询结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryResult($options = [])
- {
- $this->options->set('method', 'alipay.fund.trans.common.query');
- return $this->getResult($options);
- }
-
- /**
- * 新版:资金账户余额查询
- * @param array $options 查询参数(alipay_user_id 或 user_id,可选 account_type)
- * @return array 账户余额等信息
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryAccount($options = [])
- {
- $this->options->set('method', 'alipay.fund.account.query');
- return $this->getResult($options);
- }
-}
\ No newline at end of file
diff --git a/AliPay/Wap.php b/AliPay/Wap.php
deleted file mode 100644
index 824e787..0000000
--- a/AliPay/Wap.php
+++ /dev/null
@@ -1,48 +0,0 @@
-options->set('method', 'alipay.trade.wap.pay');
- $this->params->set('product_code', 'QUICK_WAP_WAY');
- }
-
- /**
- * 生成 WAP 支付表单 HTML
- * @param array $options 订单参数(out_trade_no, total_amount, subject, quit_url, return_url 等)
- * @return string 自动提交的支付表单 HTML
- */
- public function apply($options)
- {
- parent::applyData($options);
- return $this->buildPayHtml();
- }
-}
\ No newline at end of file
diff --git a/AliPay/Web.php b/AliPay/Web.php
deleted file mode 100644
index 241160b..0000000
--- a/AliPay/Web.php
+++ /dev/null
@@ -1,48 +0,0 @@
-options->set('method', 'alipay.trade.page.pay');
- $this->params->set('product_code', 'FAST_INSTANT_TRADE_PAY');
- }
-
- /**
- * 生成网站支付表单HTML
- * @param array $options 订单参数(out_trade_no, total_amount, subject等)
- * @return string 支付表单HTML(自动提交到支付宝)
- */
- public function apply($options)
- {
- parent::applyData($options);
- return $this->buildPayHtml();
- }
-}
\ No newline at end of file
diff --git a/license b/LICENSE
similarity index 100%
rename from license
rename to LICENSE
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9086729
--- /dev/null
+++ b/README.md
@@ -0,0 +1,450 @@
+# WeChatDeveloper
+
+WeChatDeveloper 是一个面向 **微信** 与 **支付宝** 的轻量 PHP SDK,根命名空间为 `We`。
+
+它只维护基础认证、通用 HTTP 调用、签名验签、回调解密和统一异常,不内置业务表结构、不绑定具体框架,也不维护海量接口别名。业务系统按官方文档传入接口 path、参数和配置即可。
+
+## 特性
+
+- 支持微信公众号、小程序、微信开放平台、微信支付 APIv3。
+- 支持支付宝开放平台与支付网关调用。
+- 统一入口 `We\Client`,按通道创建客户端。
+- 配置对象实现 `ConfigInterface`,构造时完成基础校验。
+- 缓存只依赖 `StoreCacheInterface`,可用于单机文件缓存或集群 Redis 适配。
+- 开放平台授权方 refresh token 通过 `StoreTokenInterface` 由业务系统存取。
+- 返回值默认是数组,失败时抛出 `WechatException` 或其子类。
+
+## 环境要求
+
+- PHP `>= 8.4`
+- `ext-json`
+- `ext-openssl`
+- `ext-simplexml`
+- `guzzlehttp/guzzle`
+- `psr/simple-cache`
+
+## 安装
+
+稳定版发布后:
+
+```bash
+composer require zoujingli/wechat-developer:^2.0
+```
+
+开发版:
+
+```bash
+composer require zoujingli/wechat-developer:2.0.x-dev
+```
+
+源码开发:
+
+```bash
+cd WeChatDeveloper
+composer install
+composer test
+```
+
+## 快速开始
+
+```php
+wechatPlatform(new WechatPlatformConfig(
+ appid: 'wx_appid',
+ appSecret: 'app_secret',
+));
+
+$users = $official->get('cgi-bin/user/get', [
+ 'next_openid' => '',
+]);
+```
+
+`post()`、`get()`、`call()` 的 path 与官方文档保持一致,通常不需要前导 `/`。
+
+```php
+$menu = $official->post('cgi-bin/menu/create', [
+ 'button' => [
+ [
+ 'type' => 'click',
+ 'name' => '今日推荐',
+ 'key' => 'TODAY',
+ ],
+ ],
+]);
+```
+
+## 入口 Client
+
+```php
+use GuzzleHttp\ClientInterface;
+use We\Client;
+use We\Contract\StoreCacheInterface;
+use We\Contract\StoreTokenInterface;
+
+new Client(
+ ?StoreCacheInterface $cache = null,
+ ?StoreTokenInterface $authorizers = null,
+ ?ClientInterface $http = null,
+ string $cacheKeyPrefix = Client::DEFAULT_CACHE_KEY_PREFIX,
+);
+```
+
+参数说明:
+
+| 参数 | 说明 |
+|------|------|
+| `$cache` | SDK 运行态缓存,主要保存 access token;不传时默认使用 `FileCacheStore`。 |
+| `$authorizers` | 微信开放平台代调用时,读取和回写授权方 refresh token。 |
+| `$http` | 可注入自定义 Guzzle HTTP 客户端,便于统一超时、代理或单元测试。 |
+| `$cacheKeyPrefix` | 缓存键前缀,默认 `wechat_developer`;生产环境建议按项目设置。 |
+
+也可以用字符串通道创建客户端:
+
+```php
+$official = $client->get('wechat.platform', WechatPlatformConfig::fromArray($config));
+```
+
+支持的通道:
+
+| 通道 | 工厂方法 | 配置对象 |
+|------|----------|----------|
+| `wechat.platform` | `wechatPlatform()` | `WechatPlatformConfig` |
+| `wechat.wxapp` | `wechatWxapp()` | `WechatWxappConfig` |
+| `wechat.service` | `wechatService()` | `WechatServiceConfig` |
+| `wechat.payment` | `wechatPayment()` | `WechatPaymentConfig` |
+| `alipay.platform` | `alipayPlatform()` | `AlipayPlatformConfig` |
+| `alipay.payment` | `alipayPayment()` | `AlipayPaymentConfig` |
+
+## 配置对象
+
+所有配置对象都实现 `ConfigInterface`:
+
+```php
+interface ConfigInterface
+{
+ public static function fromArray(array $data): static;
+
+ public function validate(): void;
+}
+```
+
+构造函数会调用 `validate()`。缺少必填字段时会抛出 `WechatException`。
+
+示例:
+
+```php
+use We\Config\WechatWxappConfig;
+
+$config = WechatWxappConfig::fromArray([
+ 'appid' => 'wx_appid',
+ 'appsecret' => 'app_secret',
+ 'storage_scope' => 'tenant:1',
+]);
+```
+
+`storage_scope` 是可选的缓存分桶标识。同一个 appid 在多租户或多业务账号下需要隔离 token 时可以设置。
+
+## 缓存与锁
+
+access token 统一通过 `StoreCacheInterface` 存储:
+
+```php
+interface StoreCacheInterface
+{
+ public function get(string $key, mixed $default = null): mixed;
+
+ public function set(string $key, mixed $value, int $ttl): void;
+
+ public function del(string $key): void;
+
+ public function lock(string $key, int $ttl, callable $callback): mixed;
+}
+```
+
+内置实现:
+
+| 类 | 说明 |
+|----|------|
+| `We\Support\FileCacheStore` | 默认单机文件缓存,使用 JSON 文件保存数据,刷新锁使用 `flock`。 |
+| `We\Support\PsrSimpleCacheStore` | PSR-16 缓存适配器,适合 Redis、Memcached 或框架缓存。锁能力需由构造参数注入。 |
+| `We\Support\NullCacheStore` | 空缓存,适合测试或明确不缓存的场景。 |
+
+单机文件缓存:
+
+```php
+use We\Client;
+use We\Support\FileCacheStore;
+
+$client = new Client(
+ cache: new FileCacheStore(__DIR__ . '/runtime/wechat-cache'),
+ cacheKeyPrefix: 'my_app',
+);
+```
+
+PSR-16 缓存:
+
+```php
+use Psr\SimpleCache\CacheInterface;
+use We\Client;
+use We\Support\PsrSimpleCacheStore;
+
+/** @var CacheInterface $cache */
+$client = new Client(
+ cache: new PsrSimpleCacheStore(
+ cache: $cache,
+ locker: static function (string $key, int $ttl, callable $callback): mixed {
+ // 在这里接入 Redis SET NX、框架锁或其他原子锁。
+ return $callback();
+ },
+ ),
+);
+```
+
+如果使用 `PsrSimpleCacheStore` 且未配置锁回调,调用 `lock()` 会抛出明确异常。集群部署时必须使用共享缓存和可用的原子锁,避免并发刷新 access token。
+
+缓存键固定为:
+
+```text
+{cacheKeyPrefix}:{channel}:{logicalKey}
+```
+
+例如:
+
+```text
+my_app:wechat.platform:wechat:app:wx123:official:access_token
+```
+
+完整键由 `CacheKey` 生成,微信 token 逻辑键由 `TokenCacheKey` 生成。
+
+## 微信开放平台授权方 Token
+
+开放平台代调用授权方接口时,SDK 需要读取授权方 refresh token,并在刷新后把新 token 回写业务存储。业务系统实现 `StoreTokenInterface` 即可:
+
+```php
+use We\Contract\StoreTokenInterface;
+
+final class AuthorizerTokenStore implements StoreTokenInterface
+{
+ public function refreshToken(string $authorizerAppid): string
+ {
+ // 从数据库读取 authorizer_refresh_token。
+ return 'authorizer_refresh_token';
+ }
+
+ public function saveAuthorizerToken(string $authorizerAppid, array $payload): void
+ {
+ // 保存 authorizer_access_token、authorizer_refresh_token、expires_in 等平台返回数据。
+ }
+}
+```
+
+注入到根 Client:
+
+```php
+$client = new Client(
+ cache: $cache,
+ authorizers: new AuthorizerTokenStore(),
+);
+```
+
+## 微信公众号
+
+```php
+use We\Config\WechatPlatformConfig;
+
+$official = $client->wechatPlatform(new WechatPlatformConfig(
+ appid: 'wx_appid',
+ appSecret: 'app_secret',
+ token: 'message_token',
+ encodingAesKey: 'encoding_aes_key',
+));
+
+$accessToken = $official->accessToken();
+
+$result = $official->post('cgi-bin/message/custom/send', [
+ 'touser' => 'openid',
+ 'msgtype' => 'text',
+ 'text' => ['content' => 'hello'],
+]);
+```
+
+安全模式消息解密:
+
+```php
+$plain = $official->post('decrypt_message', [
+ 'body' => $rawBody,
+ 'msg_signature' => $signature,
+ 'timestamp' => $timestamp,
+ 'nonce' => $nonce,
+]);
+```
+
+## 微信小程序
+
+```php
+use We\Config\WechatWxappConfig;
+
+$wxapp = $client->wechatWxapp(new WechatWxappConfig(
+ appid: 'wx_appid',
+ appSecret: 'app_secret',
+));
+
+$result = $wxapp->get('sns/jscode2session', [
+ 'js_code' => 'login_code',
+ 'grant_type' => 'authorization_code',
+]);
+```
+
+## 微信开放平台
+
+```php
+use We\Config\WechatServiceConfig;
+
+$service = $client->wechatService(new WechatServiceConfig(
+ componentAppid: 'component_appid',
+ componentAppSecret: 'component_secret',
+ componentToken: 'component_token',
+ componentEncodingAesKey: 'component_encoding_aes_key',
+));
+
+$componentToken = $service->componentAccessToken($componentVerifyTicket);
+$preAuth = $service->createPreAuthCode($componentToken);
+$url = $service->authorizationUrl((string) $preAuth['pre_auth_code'], $redirectUri);
+```
+
+代授权方调用:
+
+```php
+$result = $service->post('cgi-bin/menu/get', [], [
+ 'authorizer_appid' => 'authorizer_appid',
+ 'component_access_token' => $componentToken,
+]);
+```
+
+## 微信支付 APIv3
+
+```php
+use We\Config\WechatPaymentConfig;
+
+$payment = $client->wechatPayment(new WechatPaymentConfig(
+ appid: 'wx_appid',
+ mchId: 'mch_id',
+ apiV3Key: 'api_v3_key',
+ merchantSerial: 'merchant_serial',
+ merchantPrivateKey: file_get_contents(__DIR__ . '/apiclient_key.pem'),
+ platformPublicKey: file_get_contents(__DIR__ . '/wechatpay_public.pem'),
+ platformSerial: 'platform_serial',
+));
+
+$refund = $payment->post('v3/refund/domestic/refunds', [
+ 'out_trade_no' => 'T202605020001',
+ 'out_refund_no' => 'R202605020001',
+ 'amount' => [
+ 'refund' => 1,
+ 'total' => 1,
+ 'currency' => 'CNY',
+ ],
+]);
+```
+
+回调验签与解密:
+
+```php
+$data = $payment->post('decrypt_notification', [], [
+ 'headers' => $headers,
+ 'body' => $body,
+]);
+```
+
+## 支付宝
+
+```php
+use We\Config\AlipayPlatformConfig;
+
+$alipay = $client->alipayPlatform(new AlipayPlatformConfig(
+ appid: 'app_id',
+ privateKey: file_get_contents(__DIR__ . '/merchant_private_key.pem'),
+ alipayPublicKey: file_get_contents(__DIR__ . '/alipay_public_key.pem'),
+));
+
+$auth = $alipay->get('auth', [
+ 'redirect_uri' => 'https://example.com/callback',
+ 'scope' => 'auth_user',
+ 'state' => 'state',
+]);
+
+$response = $alipay->post('alipay.user.info.share', [], [
+ 'auth_token' => 'auth_token',
+]);
+```
+
+支付宝支付:
+
+```php
+use We\Config\AlipayPaymentConfig;
+
+$pay = $client->alipayPayment(AlipayPaymentConfig::fromArray([
+ 'appid' => 'app_id',
+ 'private_key' => file_get_contents(__DIR__ . '/merchant_private_key.pem'),
+ 'alipay_public_key' => file_get_contents(__DIR__ . '/alipay_public_key.pem'),
+]));
+
+$page = $pay->post('page', [
+ 'out_trade_no' => 'P202605020001',
+ 'total_amount' => '0.01',
+ 'subject' => 'Test Order',
+ 'product_code' => 'FAST_INSTANT_TRADE_PAY',
+]);
+```
+
+## 异常处理
+
+SDK 抛出的异常基类为:
+
+```php
+We\Exception\WechatException
+```
+
+签名相关异常使用:
+
+```php
+We\Exception\SignatureException
+```
+
+建议在业务边界统一捕获并转换成应用自己的响应格式。不要把 app secret、access token、private key、回调密文等敏感内容写入日志。
+
+## 测试
+
+```bash
+cd WeChatDeveloper
+composer test
+```
+
+或在项目根目录:
+
+```bash
+vendor/bin/phpunit -c phpunit.xml
+```
+
+## 设计边界
+
+WeChatDeveloper 只处理协议层和 HTTP 编排:
+
+- 不提供账号、租户、菜单草稿、订单、授权记录等业务表。
+- 不托管密钥加密存储。
+- 不绑定 Hyperf、Laravel、Symfony 等框架。
+- 不保证覆盖每一个官方接口别名,通用接口通过官方 path 调用。
+
+这种边界使 SDK 更适合作为开源底层包,被后台系统、SaaS 平台或命令行工具组合使用。
+
+## License
+
+MIT
diff --git a/We.php b/We.php
deleted file mode 100644
index 5bcb5d8..0000000
--- a/We.php
+++ /dev/null
@@ -1,149 +0,0 @@
-
- * @date 2018/05/24 13:23
- *
- * ----- AliPay ----
- * @method \AliPay\App AliPayApp($options) static 支付宝App支付网关
- * @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 支付宝网站支付
- *
- * ----- WeChat -----
- * @method \WeChat\Card WeChatCard($options = []) static 微信卡券管理
- * @method \WeChat\Custom WeChatCustom($options = []) static 微信客服消息
- * @method \WeChat\Limit WeChatLimit($options = []) static 接口调用频次限制
- * @method \WeChat\Media WeChatMedia($options = []) static 微信素材管理
- * @method \WeChat\Menu WeChatMenu($options = []) static 微信菜单管理
- * @method \WeChat\Oauth WeChatOauth($options = []) static 微信网页授权
- * @method \WeChat\Pay WeChatPay($options = []) static 微信支付商户
- * @method \WeChat\Product WeChatProduct($options = []) static 微信商店管理
- * @method \WeChat\Qrcode WeChatQrcode($options = []) static 微信二维码管理
- * @method \WeChat\Receive WeChatReceive($options = [], $showEchoStr = true) static 微信推送管理
- * @method \WeChat\Scan WeChatScan($options = []) static 微信扫一扫接入管理
- * @method \WeChat\Script WeChatScript($options = []) static 微信前端支持
- * @method \WeChat\Shake WeChatShake($options = []) static 微信揺一揺周边
- * @method \WeChat\Tags WeChatTags($options = []) static 微信用户标签管理
- * @method \WeChat\Template WeChatTemplate($options = []) static 微信模板消息
- * @method \WeChat\User WeChatUser($options = []) static 微信粉丝管理
- * @method \WeChat\Wifi WeChatWifi($options = []) static 微信门店WIFI管理
- * @method \WeChat\Draft WeChatDraft($options = []) static 微信草稿箱
- * @method \WeChat\Freepublish WeChatFreepublish($options = []) static 微信发布能力
- *
- * ----- WeMini -----
- * @method \WeMini\Crypt WeMiniCrypt($options = []) static 小程序数据加密处理
- * @method \WeMini\Delivery WeMiniDelivery($options = []) static 小程序即时配送
- * @method \WeMini\Shipping WeMiniShipping($options = []) static 小程序发货信息
- * @method \WeMini\Guide WeMiniGuide($options = []) static 小程序导购助手
- * @method \WeMini\Image WeMiniImage($options = []) static 小程序图像处理
- * @method \WeMini\Live WeMiniLive($options = []) static 小程序直播接口
- * @method \WeMini\Logistics WeMiniLogistics($options = []) static 小程序物流助手
- * @method \WeMini\Message WeMiniMessage($options = []) static 小程序动态消息
- * @method \WeMini\Newtmpl WeMiniNewtmpl($options = []) static 小程序订阅消息
- * @method \WeMini\Ocr WeMiniOcr($options = []) static 小程序ORC服务
- * @method \WeMini\Operation WeMiniOperation($options = []) static 小程序运维中心
- * @method \WeMini\Plugs WeMiniPlugs($options = []) static 小程序插件管理
- * @method \WeMini\Poi WeMiniPoi($options = []) static 小程序地址管理
- * @method \WeMini\Qrcode WeMiniQrcode($options = []) static 小程序二维码管理
- * @method \WeMini\Scheme WeMiniScheme($options = []) static 小程序 URL-Scheme
- * @method \WeMini\Search WeMiniSearch($options = []) static 小程序搜索
- * @method \WeMini\Security WeMiniSecurity($options = []) static 小程序内容安全
- * @method \WeMini\Soter WeMiniSoter($options = []) static 小程序生物认证
- * @method \WeMini\Template WeMiniTemplate($options = []) static 小程序模板消息支持
- * @method \WeMini\Total WeMiniTotal($options = []) static 小程序数据接口
- *
- * ----- WePay -----
- * @method \WePay\Bill WePayBill($options = []) static 微信商户账单及评论
- * @method \WePay\Order WePayOrder($options = []) static 微信商户订单
- * @method \WePay\Coupon WePayCoupon($options = []) static 微信商户代金券
- * @method \WePay\Custom WePayCustom($options = []) static 微信商户海关
- * @method \WePay\Refund WePayRefund($options = []) static 微信商户退款
- * @method \WePay\Redpack WePayRedpack($options = []) static 微信红包支持
- * @method \WePay\Transfers WePayTransfers($options = []) static 微信商户打款到零钱
- * @method \WePay\TransfersBank WePayTransfersBank($options = []) static 微信商户打款到银行卡
- * @method \WePay\ProfitSharing WePayProfitSharing($options = []) static 微信分账
- */
-class We
-{
- /**
- * 定义当前版本
- * @var string
- */
- const VERSION = '1.2.54';
-
- /**
- * 静态配置
- * @var DataArray
- */
- private static $config;
-
- /**
- * 设置及获取参数
- * @param array $option
- * @return array
- */
- public static function config($option = null)
- {
- if (is_array($option)) {
- self::$config = new DataArray($option);
- }
- if (self::$config instanceof DataArray) {
- return self::$config->get();
- }
- return [];
- }
-
- /**
- * 静态魔术加载方法
- * @param string $name 静态类名
- * @param array $arguments 参数集合
- * @return mixed
- * @throws InvalidInstanceException
- */
- public static function __callStatic($name, $arguments)
- {
- if (substr($name, 0, 6) === 'WeChat') {
- $class = 'WeChat\\' . substr($name, 6);
- } elseif (substr($name, 0, 6) === 'WeMini') {
- $class = 'WeMini\\' . substr($name, 6);
- } elseif (substr($name, 0, 6) === 'AliPay') {
- $class = 'AliPay\\' . substr($name, 6);
- } elseif (substr($name, 0, 7) === 'WePayV3') {
- $class = 'WePayV3\\' . substr($name, 7);
- } elseif (substr($name, 0, 5) === 'WePay') {
- $class = 'WePay\\' . substr($name, 5);
- }
- if (!empty($class) && class_exists($class)) {
- $option = array_shift($arguments);
- $config = is_array($option) ? $option : self::$config->get();
- return new $class($config);
- }
- throw new InvalidInstanceException("class {$name} not found");
- }
-
-}
diff --git a/WeChat/Card.php b/WeChat/Card.php
deleted file mode 100644
index a2224a9..0000000
--- a/WeChat/Card.php
+++ /dev/null
@@ -1,641 +0,0 @@
-callPostApi($url, $data);
- }
-
- /**
- * 设置买单开关
- * @param string $cardId 卡券ID
- * @param bool $isOpen 是否开启
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setPaycell($cardId, $isOpen = true)
- {
- $url = "https://api.weixin.qq.com/card/paycell/set?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId, 'is_open' => $isOpen]);
- }
-
- /**
- * 设置自助核销
- * @param string $cardId 卡券ID
- * @param bool $isOpen 是否开启
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setConsumeCell($cardId, $isOpen = true)
- {
- $url = "https://api.weixin.qq.com/card/selfconsumecell/set?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId, 'is_open' => $isOpen]);
- }
-
- /**
- * 创建卡券二维码
- * @param array $data 二维码参数(action_name, card 等)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function createQrc(array $data)
- {
- $url = "https://api.weixin.qq.com/card/qrcode/create?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 创建卡券货架
- * @param array $data 货架参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function createLandingPage(array $data)
- {
- $url = "https://api.weixin.qq.com/card/landingpage/create?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 导入自定义 code
- * @param string $cardId 卡券ID
- * @param array $code code 列表(最多10万)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function deposit($cardId, array $code)
- {
- $url = "https://api.weixin.qq.com/card/code/deposit?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId, 'code' => $code]);
- }
-
- /**
- * 查询已导入 code 数量
- * @param string $cardId 卡券ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getDepositCount($cardId)
- {
- $url = "https://api.weixin.qq.com/card/code/getdepositcount?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId]);
- }
-
- /**
- * 校验导入的 code
- * @param string $cardId 卡券ID
- * @param array $code 自定义 code 列表(<=100)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function checkCode($cardId, array $code)
- {
- $url = "https://api.weixin.qq.com/card/code/checkcode?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId, 'code' => $code]);
- }
-
- /**
- * 获取图文群发卡券的 HTML
- * @param string $cardId 卡券ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getNewsHtml($cardId)
- {
- $url = "https://api.weixin.qq.com/card/mpnews/gethtml?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId]);
- }
-
- /**
- * 设置测试白名单
- * @param array $openids 测试 openid 列表
- * @param array $usernames 测试微信号列表
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setTestWhiteList($openids = [], $usernames = [])
- {
- $url = "https://api.weixin.qq.com/card/testwhitelist/set?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['openid' => $openids, 'username' => $usernames]);
- }
-
- /**
- * 查询 Code 状态
- * @param string $code 卡券 code
- * @param string $cardId 卡券ID(自定义 code 必填)
- * @param bool $checkConsume 是否校验核销状态
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCode($code, $cardId = null, $checkConsume = null)
- {
- $data = ['code' => $code];
- is_null($cardId) || $data['card_id'] = $cardId;
- is_null($checkConsume) || $data['check_consume'] = $checkConsume;
- $url = "https://api.weixin.qq.com/card/code/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 核销 Code
- * @param string $code 待核销的 code
- * @param null|string $card_id 卡券ID(自定义 code 必填)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function consume($code, $card_id = null)
- {
- $data = ['code' => $code];
- is_null($card_id) || $data['card_id'] = $card_id;
- $url = "https://api.weixin.qq.com/card/code/consume?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 解码加密 Code
- * @param string $encryptCode 加密 code
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function decrypt($encryptCode)
- {
- $url = "https://api.weixin.qq.com/card/code/decrypt?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['encrypt_code' => $encryptCode]);
- }
-
- /**
- * 获取用户已领取卡券
- * @param string $openid 用户 openid
- * @param null|string $cardId 卡券ID(可选)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCardList($openid, $cardId = null)
- {
- $data = ['openid' => $openid];
- is_null($cardId) || $data['card_id'] = $cardId;
- $url = "https://api.weixin.qq.com/card/user/getcardlist?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查看卡券详情
- * @param string $cardId 卡券ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCard($cardId)
- {
- $url = "https://api.weixin.qq.com/card/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId]);
- }
-
- /**
- * 批量查询卡券
- * @param int $offset 起始偏移量
- * @param int $count 拉取数量(<=50)
- * @param array $statusList 状态过滤
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function batchGet($offset, $count = 50, array $statusList = [])
- {
- $data = ['offset' => $offset, 'count' => $count];
- empty($statusList) || $data['status_list'] = $statusList;
- $url = "https://api.weixin.qq.com/card/batchget?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 更新会员卡信息
- * @param string $cardId 卡券ID
- * @param array $memberCard 会员卡内容
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function updateCard($cardId, array $memberCard)
- {
- $url = "https://api.weixin.qq.com/card/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId, 'member_card' => $memberCard]);
- }
-
- /**
- * 修改库存
- * @param string $card_id 卡券ID
- * @param int|null $increase_stock_value 增加库存
- * @param int|null $reduce_stock_value 减少库存
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function modifyStock($card_id, $increase_stock_value = null, $reduce_stock_value = null)
- {
- $data = ['card_id' => $card_id];
- is_null($reduce_stock_value) || $data['reduce_stock_value'] = $reduce_stock_value;
- is_null($increase_stock_value) || $data['increase_stock_value'] = $increase_stock_value;
- $url = "https://api.weixin.qq.com/card/modifystock?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 变更 Code
- * @param string $code 原 code
- * @param string $new_code 新 code
- * @param null|string $card_id 卡券ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function updateCode($code, $new_code, $card_id = null)
- {
- $data = ['code' => $code, 'new_code' => $new_code];
- is_null($card_id) || $data['card_id'] = $card_id;
- $url = "https://api.weixin.qq.com/card/code/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 删除卡券
- * @param string $cardId 卡券ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function deleteCard($cardId)
- {
- $url = "https://api.weixin.qq.com/card/delete?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId]);
- }
-
- /**
- * 设置卡券失效
- * @param string $code 卡券 code
- * @param string $cardId 卡券ID
- * @param null|string $reason 失效原因
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function unAvailable($code, $cardId, $reason = null)
- {
- $data = ['code' => $code, 'card_id' => $cardId];
- is_null($reason) || $data['reason'] = $reason;
- $url = "https://api.weixin.qq.com/card/code/unavailable?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 拉取卡券概况数据
- * @param string $beginDate 开始日期
- * @param string $endDate 结束日期
- * @param string $condSource 卡券来源 0|1
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCardBizuininfo($beginDate, $endDate, $condSource)
- {
- $url = "https://api.weixin.qq.com/datacube/getcardbizuininfo?access_token=ACCESS_TOKEN";
- $data = ['begin_date' => $beginDate, 'end_date' => $endDate, 'cond_source' => $condSource];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 获取免费券数据
- * @param string $beginDate 开始日期
- * @param string $endDate 结束日期
- * @param int $condSource 卡券来源 0|1
- * @param null|string $cardId 卡券ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCardCardinfo($beginDate, $endDate, $condSource, $cardId = null)
- {
- $url = "https://api.weixin.qq.com/datacube/getcardcardinfo?access_token=ACCESS_TOKEN";
- $data = ['begin_date' => $beginDate, 'end_date' => $endDate, 'cond_source' => $condSource];
- is_null($cardId) || $data['card_id'] = $cardId;
- return $this->callPostApi($url, $data);
- }
-
-
- /**
- * 激活会员卡
- * @param array $data 激活参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function activateMemberCard(array $data)
- {
- $url = 'https://api.weixin.qq.com/card/membercard/activate?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 设置开卡字段(激活表单)
- * @param array $data 表单字段
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setActivateMemberCardUser(array $data)
- {
- $url = 'https://api.weixin.qq.com/card/membercard/activateuserform/set?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 获取用户提交的激活资料
- * @param string $activateTicket 激活 ticket
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getActivateMemberCardTempinfo($activateTicket)
- {
- $url = 'https://api.weixin.qq.com/card/membercard/activatetempinfo/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['activate_ticket' => $activateTicket]);
- }
-
- /**
- * 更新会员信息
- * @param array $data 更新参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function updateMemberCardUser(array $data)
- {
- $url = 'https://api.weixin.qq.com/card/membercard/updateuser?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 拉取会员卡概况数据
- * @param string $beginDate 开始日期
- * @param string $endDate 结束日期
- * @param string $condSource 卡券来源 0|1
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCardMemberCardinfo($beginDate, $endDate, $condSource)
- {
- $url = "https://api.weixin.qq.com/datacube/getcardmembercardinfo?access_token=ACCESS_TOKEN";
- $data = ['begin_date' => $beginDate, 'end_date' => $endDate, 'cond_source' => $condSource];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 拉取单张会员卡数据
- * @param string $beginDate 开始日期
- * @param string $endDate 结束日期
- * @param string $cardId 卡券ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCardMemberCardDetail($beginDate, $endDate, $cardId)
- {
- $url = "https://api.weixin.qq.com/datacube/getcardmembercarddetail?access_token=ACCESS_TOKEN";
- $data = ['begin_date' => $beginDate, 'end_date' => $endDate, 'card_id' => $cardId];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询会员信息(积分)
- * @param string $cardId 会员卡ID
- * @param string $code 用户 code
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCardMemberCard($cardId, $code)
- {
- $data = ['card_id' => $cardId, 'code' => $code];
- $url = "https://api.weixin.qq.com/card/membercard/userinfo/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 支付后投放卡券规则
- * @param array $data 规则参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function payGiftCard(array $data)
- {
- $url = "https://api.weixin.qq.com/card/paygiftcard/add?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 删除支付后投放卡券规则
- * @param int $ruleId 规则ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function delPayGiftCard($ruleId)
- {
- $url = "https://api.weixin.qq.com/card/paygiftcard/add?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['rule_id' => $ruleId]);
- }
-
- /**
- * 查询支付后投放卡券规则
- * @param int $ruleId 规则ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getPayGiftCard($ruleId)
- {
- $url = "https://api.weixin.qq.com/card/paygiftcard/getbyid?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['rule_id' => $ruleId]);
- }
-
- /**
- * 批量查询支付后投放规则
- * @param int $offset 起始偏移
- * @param int $count 数量
- * @param bool $effective 是否仅查询生效规则
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function batchGetPayGiftCard($offset = 0, $count = 10, $effective = true)
- {
- $url = "https://api.weixin.qq.com/card/paygiftcard/batchget?access_token=ACCESS_TOKEN";
- $data = ['type' => 'RULE_TYPE_PAY_MEMBER_CARD', 'offset' => $offset, 'count' => $count, 'effective' => $effective];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 创建支付后立减金活动
- * @param array $data 活动参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function addActivity(array $data)
- {
- $url = "https://api.weixin.qq.com/card/mkt/activity/create?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 开通券点账户
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function payActivate()
- {
- $url = "https://api.weixin.qq.com/card/pay/activate?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 预估优惠券库存价格
- * @param string $cardId 卡券ID
- * @param int $quantity 兑换数量
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getPayprice($cardId, $quantity)
- {
- $url = "POST https://api.weixin.qq.com/card/pay/getpayprice?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['card_id' => $cardId, 'quantity' => $quantity]);
- }
-
- /**
- * 查询券点余额
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCoinsInfo()
- {
- $url = "https://api.weixin.qq.com/card/pay/getcoinsinfo?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 确认兑换库存
- * @param string $cardId 卡券ID
- * @param int $quantity 数量
- * @param string $orderId 批价返回的订单号
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function payConfirm($cardId, $quantity, $orderId)
- {
- $url = "https://api.weixin.qq.com/card/pay/confirm?access_token=ACCESS_TOKEN";
- $data = ['card_id' => $cardId, 'quantity' => $quantity, 'order_id' => $orderId];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 充值券点
- * @param int $coinCount 充值数量
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function payRecharge($coinCount)
- {
- $url = "https://api.weixin.qq.com/card/pay/recharge?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['coin_count' => $coinCount]);
- }
-
- /**
- * 查询券点订单详情
- * @param string $orderId 订单号
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function payGetOrder($orderId)
- {
- $url = "https://api.weixin.qq.com/card/pay/getorder?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['order_id' => $orderId]);
- }
-
- /**
- * 查询券点流水
- * @param array $data 查询参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function payGetList(array $data)
- {
- $url = "https://api.weixin.qq.com/card/pay/getorderlist?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 获取开卡插件参数
- * @param array $data 入口参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getActivateUrl(array $data)
- {
- $url = "https://api.weixin.qq.com/card/membercard/activate/geturl?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Contracts/BasicAliPay.php b/WeChat/Contracts/BasicAliPay.php
deleted file mode 100644
index 24565f4..0000000
--- a/WeChat/Contracts/BasicAliPay.php
+++ /dev/null
@@ -1,531 +0,0 @@
-gateway = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do?charset=utf-8';
- }
- $this->params = new DataArray([]);
- $this->config = new DataArray($options);
- $this->options = new DataArray([
- 'app_id' => $this->config->get('appid'),
- 'charset' => empty($options['charset']) ? 'utf-8' : $options['charset'],
- 'format' => 'JSON',
- 'version' => '1.0',
- 'sign_type' => empty($options['sign_type']) ? 'RSA2' : $options['sign_type'],
- 'timestamp' => date('Y-m-d H:i:s'),
- ]);
- if (isset($options['notify_url']) && $options['notify_url'] !== '') {
- $this->options->set('notify_url', $options['notify_url']);
- }
- if (isset($options['return_url']) && $options['return_url'] !== '') {
- $this->options->set('return_url', $options['return_url']);
- }
- if (isset($options['app_auth_token']) && $options['app_auth_token'] !== '') {
- $this->options->set('app_auth_token', $options['app_auth_token']);
- }
-
- // 证书模式读取证书
- $appCertPath = $this->config->get('app_cert_path');
- $aliRootPath = $this->config->get('alipay_root_path');
- if (!$this->config->get('app_cert') && !empty($appCertPath) && is_file($appCertPath)) {
- $this->config->set('app_cert', file_get_contents($appCertPath));
- }
- if (!$this->config->get('root_cert') && !empty($aliRootPath) && is_file($aliRootPath)) {
- $this->config->set('root_cert', file_get_contents($aliRootPath));
- }
- }
-
- /**
- * 静态创建对象
- * @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 $outTradeNo 商户订单号
- * @return array 订单查询结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query($outTradeNo = '')
- {
- $this->options->set('method', 'alipay.trade.query');
- return $this->getResult(['out_trade_no' => $outTradeNo]);
- }
-
- /**
- * 请求接口并验证访问数据
- * @param array $options 请求参数
- * @return array 接口响应数据
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function getResult($options)
- {
- $this->applyData($options);
- $method = str_replace('.', '_', $this->options['method']) . '_response';
- $data = json_decode(Tools::get($this->gateway, $this->options->get()), true);
- if (!isset($data[$method]['code']) || $data[$method]['code'] !== '10000') {
- throw new InvalidResponseException(
- "Error: " .
- (empty($data[$method]['code']) ? '' : "{$data[$method]['msg']} [{$data[$method]['code']}]\r\n") .
- (empty($data[$method]['sub_code']) ? '' : "{$data[$method]['sub_msg']} [{$data[$method]['sub_code']}]\r\n"),
- $data[$method]['code'], $data
- );
- }
- return $data[$method];
- // 返回结果签名检查
- // return $this->verify($data[$method], $data['sign']);
- }
-
- /**
- * 数据包生成及数据签名
- * @param array $options
- */
- protected function applyData($options)
- {
- if ($this->config->get('app_cert') && $this->config->get('root_cert')) {
- $this->setAppCertSnAndRootCertSn();
- }
- $this->options->set('biz_content', json_encode($this->params->merge($options), 256));
- $this->options->set('sign', $this->getSign());
- }
-
- /**
- * 新版 设置网关应用公钥证书SN、支付宝根证书SN
- */
- protected function setAppCertSnAndRootCertSn()
- {
- if (!($appCert = $this->config->get('app_cert'))) {
- throw new InvalidArgumentException('Missing Config -- [app_cert|app_cert_path]');
- }
- if (!($rootCert = $this->config->get('root_cert'))) {
- throw new InvalidArgumentException('Missing Config -- [root_cert|alipay_root_path]');
- }
- $this->options->set('app_cert_sn', $this->getAppCertSN($appCert));
- $this->options->set('alipay_root_cert_sn', $this->getRootCertSN($rootCert));
- if (!$this->options->get('app_cert_sn')) {
- throw new InvalidArgumentException('Missing options -- [app_cert_sn]');
- }
- if (!$this->options->get('alipay_root_cert_sn')) {
- throw new InvalidArgumentException('Missing options -- [alipay_root_cert_sn]');
- }
- }
-
- /**
- * 新版 从证书中提取序列号
- * @param string $sign
- * @return string
- */
- private function getAppCertSN($sign)
- {
- $ssl = openssl_x509_parse($sign, true);
- $issuer = isset($ssl['issuer']) && is_array($ssl['issuer']) ? $ssl['issuer'] : [];
- return md5($this->_arr2str(array_reverse($issuer)) . $ssl['serialNumber']);
- }
-
- /**
- * 新版 数组转字符串
- * @param array $array
- * @return string
- */
- private function _arr2str($array)
- {
- $string = [];
- if ($array && is_array($array)) {
- foreach ($array as $key => $value) {
- $string[] = $key . '=' . $value;
- }
- }
- return join(',', $string);
- }
-
- /**
- * 新版 提取根证书序列号
- * @param string $sign
- * @return string|null
- */
- private function getRootCertSN($sign)
- {
- if (strlen($sign) < 500 && file_exists($sign)) {
- $sign = file_get_contents($sign);
- }
- $sn = null;
- $array = explode('-----END CERTIFICATE-----', $sign);
- for ($i = 0; $i < count($array) - 1; $i++) {
- $ssl[$i] = openssl_x509_parse($array[$i] . '-----END CERTIFICATE-----', true);
- if (strpos($ssl[$i]['serialNumber'], '0x') === 0) {
- $ssl[$i]['serialNumber'] = $this->_hex2dec($ssl[$i]['serialNumberHex']);
- }
- if ($ssl[$i]['signatureTypeLN'] == 'sha1WithRSAEncryption' || $ssl[$i]['signatureTypeLN'] == 'sha256WithRSAEncryption') {
- $issuer = isset($ssl[$i]['issuer']) && is_array($ssl[$i]['issuer']) ? $ssl[$i]['issuer'] : [];
- if ($sn == null) {
- $sn = md5($this->_arr2str(array_reverse($issuer)) . $ssl[$i]['serialNumber']);
- } else {
- $sn = $sn . '_' . md5($this->_arr2str(array_reverse($issuer)) . $ssl[$i]['serialNumber']);
- }
- }
- }
- return $sn;
- }
-
- /**
- * 新版 0x转高精度数字
- * @param string $hex
- * @return int|string
- */
- private function _hex2dec($hex)
- {
- list($dec, $len) = [0, strlen($hex)];
- for ($i = 1; $i <= $len; $i++) {
- $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
- }
- return $dec;
- }
-
- /**
- * 获取数据签名
- * @return string
- */
- protected function getSign()
- {
- if ($this->options->get('sign_type') === 'RSA2') {
- openssl_sign($this->getSignContent($this->options->get(), true), $sign, $this->getAppPrivateKey(), OPENSSL_ALGO_SHA256);
- } else {
- openssl_sign($this->getSignContent($this->options->get(), true), $sign, $this->getAppPrivateKey(), OPENSSL_ALGO_SHA1);
- }
- return base64_encode($sign);
- }
-
- /**
- * 数据签名处理
- * @param array $data 需要进行签名数据
- * @param boolean $needSignType 是否需要sign_type字段
- * @return string
- */
- private function getSignContent(array $data, $needSignType = false)
- {
- ksort($data);
- $attrs = array();
- if (isset($data['sign'])) unset($data['sign']);
- if (empty($needSignType)) unset($data['sign_type']);
- foreach ($data as $key => $value) {
- if ($value === '' || is_null($value)) continue;
- $attrs[] = "{$key}={$value}";
- }
- return join('&', $attrs);
- }
-
- /**
- * 获取应用私钥内容
- * @return string
- */
- private function getAppPrivateKey()
- {
- $content = wordwrap($this->trimCert($this->config->get('private_key')), 64, "\n", true);
- return "-----BEGIN RSA PRIVATE KEY-----\n{$content}\n-----END RSA PRIVATE KEY-----";
- }
-
- /**
- * 去除证书前后内容及空白
- * @param string $sign
- * @return string
- */
- protected function trimCert($sign)
- {
- return preg_replace(['/\s+/', '/-{5}.*?-{5}/'], '', $sign);
- }
-
- /**
- * 支付宝订单退款操作
- * @param array|string $options 退款参数或退款商户订单号
- * @param string|null $refundAmount 退款金额
- * @return array 退款结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function refund($options, $refundAmount = null)
- {
- if (!is_array($options)) $options = ['out_trade_no' => $options, 'refund_amount' => $refundAmount];
- $this->options->set('method', 'alipay.trade.refund');
- return $this->getResult($options);
- }
-
- /**
- * 支付宝订单退款查询
- * @param array|string $options 退款参数或退款商户订单号
- * @param array|null $queryOptions 查询选项
- * @return array 退款查询结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function refundQuery($options, $queryOptions = null)
- {
- if (!is_array($options)) $options = ['out_trade_no' => $options];
- empty($queryOptions) || $options['query_options'] = $queryOptions;
- $this->options->set('method', 'alipay.trade.fastpay.refund.query');
- return $this->getResult($options);
- }
-
- /**
- * 关闭支付宝进行中的订单
- * @param array|string $options 订单参数或商户订单号
- * @return array 关闭结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function close($options)
- {
- if (!is_array($options)) $options = ['out_trade_no' => $options];
- $this->options->set('method', 'alipay.trade.close');
- return $this->getResult($options);
- }
-
- /**
- * 获取通知数据
- *
- * @param boolean $needSignType 是否需要sign_type字段
- * @param array $parameters
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function notify($needSignType = false, array $parameters = [])
- {
- $data = empty($parameters) ? $_POST : $parameters;
-
- if (empty($data) || empty($data['sign'])) {
- throw new InvalidResponseException('Illegal push request.', 0, $data);
- }
- $string = $this->getSignContent($data, $needSignType);
- if (openssl_verify($string, base64_decode($data['sign']), $this->getAliPublicKey(), OPENSSL_ALGO_SHA256) !== 1) {
- throw new InvalidResponseException('Data signature verification failed.', 0, $data);
- }
- return $data;
- }
-
- /**
- * 获取支付公钥内容
- * @return string
- */
- public function getAliPublicKey()
- {
- $cert = $this->config->get('public_key');
- if (strpos(trim($cert), '-----BEGIN CERTIFICATE-----') !== false) {
- $pkey = openssl_pkey_get_public($cert);
- $keyData = openssl_pkey_get_details($pkey);
- return trim($keyData['key']);
- } else {
- $content = wordwrap($this->trimCert($cert), 64, "\n", true);
- return "-----BEGIN PUBLIC KEY-----\n{$content}\n-----END PUBLIC KEY-----";
- }
- }
-
- /**
- * 应用数据操作
- * @param array $options
- * @return mixed
- */
- abstract public function apply($options);
-
- /**
- * 通用接口调用(支付宝开放平台)
- * @param string $apiMethod API 方法名(如 alipay.trade.query),必填
- * @param array|string $data 业务参数,数组会写入 biz_content;字符串尝试解析为 JSON
- * @param string $method GET|POST|PUT|DELETE|PATCH,默认 GET(POST 会放入表单)
- * @param bool $verify 是否验证返回签名
- * @return array 返回解析后的响应体
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function callApi($apiMethod, $data = [], $method = 'GET', $verify = false)
- {
- $method = strtoupper($method);
-
- // 验证API方法名(必填)
- if (empty($apiMethod)) {
- throw new \WeChat\Exceptions\InvalidArgumentException("Missing required parameter -- [apiMethod]");
- }
-
- // 使用gateway作为URL
- $url = $this->gateway;
-
- // 设置API方法
- $this->options->set('method', $apiMethod);
-
- // 处理数据格式并合并参数
- $params = [];
- if (is_array($data)) {
- $params = $data;
- } elseif (is_string($data) && !empty($data)) {
- $decoded = json_decode($data, true);
- if (json_last_error() === JSON_ERROR_NONE) {
- $params = $decoded;
- }
- }
- if (!empty($params)) {
- $this->params->merge($params);
- }
-
- // 处理签名(默认自动签名)
- if ($this->config->get('app_cert') && $this->config->get('root_cert')) {
- $this->setAppCertSnAndRootCertSn();
- }
- $this->options->set('biz_content', json_encode($this->params->get(), 256));
- $this->options->set('sign', $this->getSign());
-
- // 统一处理响应(减少重复代码)
- $methodKey = str_replace('.', '_', $this->options->get('method')) . '_response';
- $self = $this;
- $processResponse = function ($response) use ($verify, $methodKey, $self) {
- $data = json_decode($response, true);
- if (json_last_error() !== JSON_ERROR_NONE) {
- return $response; // JSON解析失败,返回原始响应
- }
-
- // 验证响应签名
- if ($verify && isset($data['sign']) && isset($data[$methodKey])) {
- return $self->verify($data[$methodKey], $data['sign']);
- }
-
- // 检查错误
- if (isset($data[$methodKey])) {
- if (isset($data[$methodKey]['code']) && $data[$methodKey]['code'] !== '10000') {
- $msg = isset($data[$methodKey]['msg']) ? "{$data[$methodKey]['msg']} [{$data[$methodKey]['code']}]\r\n" : '';
- $subMsg = isset($data[$methodKey]['sub_msg']) ? "{$data[$methodKey]['sub_msg']} [{$data[$methodKey]['sub_code']}]\r\n" : '';
- throw new InvalidResponseException("Error: " . $msg . $subMsg, $data[$methodKey]['code'], $data);
- }
- return $data[$methodKey];
- }
-
- return $data;
- };
-
- // GET/HEAD/OPTIONS请求
- if (in_array($method, ['GET', 'HEAD', 'OPTIONS'])) {
- $queryParams = array_merge($this->options->get(), $params);
- $response = Tools::get($url, $queryParams);
- return $processResponse($response);
- }
-
- // POST/PUT/PATCH/DELETE请求
- $postData = array_merge($this->options->get(), $params);
- $response = Tools::doRequest($method, $url, ['data' => $postData]);
- return $processResponse($response);
- }
-
- /**
- * 验证接口返回的数据签名
- * @param array $data 通知数据
- * @param null|string $sign 数据签名
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- protected function verify($data, $sign)
- {
- unset($data['sign']);
- if ($this->options->get('sign_type') === 'RSA2') {
- if (openssl_verify(json_encode($data, 256), base64_decode($sign), $this->getAliPublicKey(), OPENSSL_ALGO_SHA256) !== 1) {
- throw new InvalidResponseException('Data signature verification failed by RSA2.');
- }
- } else {
- if (openssl_verify(json_encode($data, 256), base64_decode($sign), $this->getAliPublicKey(), OPENSSL_ALGO_SHA1) !== 1) {
- throw new InvalidResponseException('Data signature verification failed by RSA.');
- }
- }
- return $data;
- }
-
- /**
- * 生成支付HTML代码
- * @return string
- */
- protected function buildPayHtml()
- {
- $html = "
- *
- * 当用户使用自己的缓存驱动时,直接实例化对象后可直接设置 AccessToken
- * - 多用于分布式项目时保持 AccessToken 统一
- * - 使用此方法后就由用户来保证传入的 AccessToken 为有效 AccessToken
- */
- public function setAccessToken($accessToken)
- {
- 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 = $accessToken);
- }
-
- /**
- * 以POST获取接口数据并转为数组
- * @param string $url 接口地址
- * @param array $data 请求数据
- * @param bool $toJson 转换JSON
- * @param array $options 请求扩展数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function httpPostForJson($url, array $data, $toJson = true, array $options = [])
- {
- try {
- $options['headers'] = isset($options['headers']) ? $options['headers'] : [];
- if ($toJson) $options['headers'][] = 'Content-Type: application/json';
- return Tools::json2arr(Tools::post($url, $toJson ? Tools::arr2json($data) : $data, $options));
- } catch (InvalidResponseException $exception) {
- if (!$this->isTry && in_array($exception->getCode(), ['40014', '40001', '41001', '42001'])) {
- $this->delAccessToken();
- $this->isTry = true;
- return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
- }
- throw new InvalidResponseException($exception->getMessage(), $exception->getCode());
- }
- }
-
- /**
- * 清理删除 AccessToken
- * @return bool
- */
- public function delAccessToken()
- {
- $this->access_token = '';
- return Tools::delCache($this->config->get('appid') . '_access_token');
- }
-
- /**
- * 通用 GET 请求(自动处理 ACCESS_TOKEN)
- * @param string $url 接口 URL
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function callGetApi($url)
- {
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpGetForJson($url);
- }
-
- /**
- * 以GET获取接口数据并转为数组
- * @param string $url 接口地址
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function httpGetForJson($url)
- {
- try {
- return Tools::json2arr(Tools::get($url));
- } 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;
- return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
- }
- }
- throw new InvalidResponseException($exception->getMessage(), $exception->getCode());
- }
- }
-
- /**
- * 通用接口调用
- * @param string $url 完整 URL 或相对路径,支持 ACCESS_TOKEN 占位符自动替换
- * @param array|string $data GET 参数或请求体,数组自动 JSON;字符串原样发送
- * @param string $method GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS,默认 GET
- * @return array 解析后的数组
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function callApi($url, $data = [], $method = 'GET')
- {
- $method = strtoupper($method);
-
- // 自动处理ACCESS_TOKEN
- if (strpos($url, 'ACCESS_TOKEN') !== false) {
- if (empty($this->access_token)) {
- $this->access_token = $this->getAccessToken();
- }
- $url = str_replace('ACCESS_TOKEN', urlencode($this->access_token), $url);
- }
-
- // GET/HEAD/OPTIONS请求(无请求体)
- if (in_array($method, ['GET', 'HEAD', 'OPTIONS'])) {
- if (!empty($data) && is_array($data)) {
- $url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($data);
- }
- return $this->httpGetForJson($url);
- }
-
- // POST/PUT/PATCH/DELETE请求(有请求体)
- $postData = is_array($data) ? $data : [];
- $toJson = is_array($data);
-
- // POST请求使用原有方法(支持自动重试)
- if ($method === 'POST') {
- return $this->httpPostForJson($url, $postData, $toJson, []);
- }
-
- // PUT/PATCH/DELETE请求直接调用
- $requestData = is_string($data) ? $data : Tools::arr2json($postData);
- $response = Tools::doRequest($method, $url, ['data' => $requestData]);
- return Tools::json2arr($response);
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Contracts/BasicWePay.php b/WeChat/Contracts/BasicWePay.php
deleted file mode 100644
index 6edbb35..0000000
--- a/WeChat/Contracts/BasicWePay.php
+++ /dev/null
@@ -1,280 +0,0 @@
-config = new DataArray($options);
- // 商户基础参数
- $this->params = new DataArray([
- 'appid' => $this->config->get('appid'),
- 'mch_id' => $this->config->get('mch_id'),
- 'nonce_str' => Tools::createNoncestr(),
- ]);
- // 商户参数支持
- if ($this->config->get('sub_appid')) {
- $this->params->set('sub_appid', $this->config->get('sub_appid'));
- }
- if ($this->config->get('sub_mch_id')) {
- $this->params->set('sub_mch_id', $this->config->get('sub_mch_id'));
- }
- }
-
- /**
- * 静态创建对象
- * @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|array $xml 可选,默认读取原始输入
- * @return array 验签通过的通知数据
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function getNotify($xml = '')
- {
- $data = is_array($xml) ? $xml : Tools::xml2arr(empty($xml) ? Tools::getRawInput() : $xml);
- if (isset($data['sign']) && $this->getPaySign($data) === $data['sign']) {
- return $data;
- }
- throw new InvalidResponseException('Invalid Notify.', '0');
- }
-
- /**
- * 生成支付签名
- * @param array $data 待签名数据
- * @param string $signType MD5|HMAC-SHA256
- * @param string $buff 签名前缀(内部使用)
- * @return string 大写签名
- */
- public function getPaySign(array $data, $signType = 'MD5', $buff = '')
- {
- ksort($data);
- if (isset($data['sign'])) unset($data['sign']);
- foreach ($data as $k => $v) {
- if ('' === $v || null === $v) continue;
- $buff .= "{$k}={$v}&";
- }
- $buff .= ("key=" . $this->config->get('mch_key'));
- if (strtoupper($signType) === 'MD5') {
- return strtoupper(md5($buff));
- }
- return strtoupper(hash_hmac('SHA256', $buff, $this->config->get('mch_key')));
- }
-
- /**
- * 获取微信支付通知成功回复 XML
- * @return string
- */
- public function getNotifySuccessReply()
- {
- return Tools::arr2xml(['return_code' => 'SUCCESS', 'return_msg' => 'OK']);
- }
-
- /**
- * 转换短链接(tools/shorturl)
- * @param string $longUrl 需转换的URL,签名用原串,传输需URLencode
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function shortUrl($longUrl)
- {
- $url = 'https://api.mch.weixin.qq.com/tools/shorturl';
- return $this->callPostApi($url, ['long_url' => $longUrl]);
- }
-
- /**
- * 基础 POST 调用(自动签名,可选双向证书)
- * @param string $url 请求地址
- * @param array $data 接口参数
- * @param bool $isCert 是否需要双向证书(退款等场景)
- * @param string $signType MD5|HMAC-SHA256
- * @param bool $needSignType 是否追加 sign_type 字段
- * @param bool $needNonceStr 是否自动附加 nonce_str
- * @return array XML 解析结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function callPostApi($url, array $data, $isCert = false, $signType = 'HMAC-SHA256', $needSignType = true, $needNonceStr = true)
- {
- $option = [];
- if ($isCert) {
- $option['ssl_p12'] = $this->config->get('ssl_p12');
- $option['ssl_cer'] = $this->config->get('ssl_cer');
- $option['ssl_key'] = $this->config->get('ssl_key');
- if (is_string($option['ssl_p12']) && file_exists($option['ssl_p12'])) {
- $content = file_get_contents($option['ssl_p12']);
- if (openssl_pkcs12_read($content, $certs, $this->config->get('mch_id'))) {
- $option['ssl_key'] = Tools::pushFile(md5($certs['pkey']) . '.pem', $certs['pkey']);
- $option['ssl_cer'] = Tools::pushFile(md5($certs['cert']) . '.pem', $certs['cert']);
- } else throw new InvalidArgumentException("P12 certificate does not match MCH_ID --- ssl_p12");
- }
- if (empty($option['ssl_cer']) || !file_exists($option['ssl_cer'])) {
- throw new InvalidArgumentException("Missing Config -- ssl_cer", '0');
- }
- if (empty($option['ssl_key']) || !file_exists($option['ssl_key'])) {
- throw new InvalidArgumentException("Missing Config -- ssl_key", '0');
- }
- }
- $params = $this->params->merge($data);
- if (!$needNonceStr) unset($params['nonce_str']);
- if ($needSignType) $params['sign_type'] = strtoupper($signType);
- $params['sign'] = $this->getPaySign($params, $signType);
- $result = Tools::xml2arr(Tools::post($url, Tools::arr2xml($params), $option));
- if ($result['return_code'] !== 'SUCCESS') {
- throw new InvalidResponseException($result['return_msg'], '0');
- }
- return $result;
- }
-
- /**
- * 数组转 XML 输出
- * @param array $data 待转换数据
- * @param bool $isReturn true 返回字符串,false 直接输出
- * @return string|void
- */
- public function toXml(array $data, $isReturn = false)
- {
- $xml = Tools::arr2xml($data);
- if ($isReturn) return $xml;
- echo $xml;
- }
-
- /**
- * 通用接口(V2)调用
- * @param string $url 完整 URL
- * @param array|string $data 请求参数,数组自动补全商户参数并签名;字符串原样发送
- * @param string $method GET|POST|PUT|DELETE|PATCH,默认 POST(GET/HEAD/OPTIONS 不带签名)
- * @param bool $isCert 是否启用双向证书
- * @param string $signType MD5|HMAC-SHA256,默认 HMAC-SHA256
- * @return array XML 解析结果
- * @throws \WeChat\Exceptions\InvalidArgumentException
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function callApi($url, $data = [], $method = 'POST', $isCert = false, $signType = 'HMAC-SHA256')
- {
- $method = strtoupper($method);
-
- // 处理数据格式
- $requestData = is_array($data) ? $data : (is_string($data) ? $data : []);
-
- // GET/HEAD/OPTIONS请求(无请求体,不签名)
- if (in_array($method, ['GET', 'HEAD', 'OPTIONS'])) {
- if (!empty($requestData) && is_array($requestData)) {
- $url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($requestData);
- }
- $response = Tools::get($url);
- $result = Tools::xml2arr($response);
- if (isset($result['return_code']) && $result['return_code'] !== 'SUCCESS') {
- throw new InvalidResponseException($result['return_msg'], '0');
- }
- return $result;
- }
-
- // POST/PUT/PATCH/DELETE请求(有请求体)
- $option = [];
- if ($isCert) {
- $option['ssl_p12'] = $this->config->get('ssl_p12');
- $option['ssl_cer'] = $this->config->get('ssl_cer');
- $option['ssl_key'] = $this->config->get('ssl_key');
- if (is_string($option['ssl_p12']) && file_exists($option['ssl_p12'])) {
- $content = file_get_contents($option['ssl_p12']);
- if (openssl_pkcs12_read($content, $certs, $this->config->get('mch_id'))) {
- $option['ssl_key'] = Tools::pushFile(md5($certs['pkey']) . '.pem', $certs['pkey']);
- $option['ssl_cer'] = Tools::pushFile(md5($certs['cert']) . '.pem', $certs['cert']);
- } else {
- throw new InvalidArgumentException("P12 certificate does not match MCH_ID --- ssl_p12");
- }
- }
- if (empty($option['ssl_cer']) || !file_exists($option['ssl_cer'])) {
- throw new InvalidArgumentException("Missing Config -- ssl_cer", '0');
- }
- if (empty($option['ssl_key']) || !file_exists($option['ssl_key'])) {
- throw new InvalidArgumentException("Missing Config -- ssl_key", '0');
- }
- }
-
- // 合并参数并处理签名(默认自动签名)
- if (is_array($requestData)) {
- $params = $this->params->merge($requestData);
- $params['sign_type'] = strtoupper($signType);
- $params['sign'] = $this->getPaySign($params, $signType);
- $option['data'] = Tools::arr2xml($params);
- } else {
- $option['data'] = $requestData;
- }
-
- // 使用doRequest支持PUT/DELETE/PATCH
- $response = Tools::doRequest($method, $url, $option);
-
- $result = Tools::xml2arr($response);
- if (isset($result['return_code']) && $result['return_code'] !== 'SUCCESS') {
- throw new InvalidResponseException($result['return_msg'], '0');
- }
- return $result;
- }
-}
diff --git a/WeChat/Contracts/BasicWeWork.php b/WeChat/Contracts/BasicWeWork.php
deleted file mode 100644
index 8b701a1..0000000
--- a/WeChat/Contracts/BasicWeWork.php
+++ /dev/null
@@ -1,42 +0,0 @@
-access_token) return $this->access_token;
- $ckey = $this->config->get('appid') . '_access_token';
- if ($this->access_token = Tools::getCache($ckey)) return $this->access_token;
- list($appid, $secret) = [$this->config->get('appid'), $this->config->get('appsecret')];
- $result = Tools::json2arr(Tools::get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$appid}&corpsecret={$secret}"));
- if (isset($result['access_token']) && $result['access_token']) Tools::setCache($ckey, $result['access_token'], 7000);
- return $this->access_token = $result['access_token'];
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Contracts/DataArray.php b/WeChat/Contracts/DataArray.php
deleted file mode 100644
index a8fa8da..0000000
--- a/WeChat/Contracts/DataArray.php
+++ /dev/null
@@ -1,130 +0,0 @@
-config = $options;
- }
-
- /**
- * 设置配置项值
- * @param string $offset
- * @param string|array|null|integer $value
- */
- public function set($offset, $value)
- {
- $this->offsetSet($offset, $value);
- }
-
- /**
- * 设置配置项值
- * @param string $offset
- * @param string|array|null|integer $value
- * @return void
- */
- #[\ReturnTypeWillChange]
- public function offsetSet($offset, $value)
- {
- if (is_null($offset)) {
- $this->config[] = $value;
- } else {
- $this->config[$offset] = $value;
- }
- }
-
- /**
- * 获取配置项参数
- * @param string|null $offset
- * @return array|string|null|mixed
- */
- public function get($offset = null)
- {
- return $this->offsetGet($offset);
- }
-
- /**
- * 获取配置项参数
- * @param string|null $offset
- * @return mixed
- */
- #[\ReturnTypeWillChange]
- public function offsetGet($offset = null)
- {
- if (is_null($offset)) return $this->config;
- return isset($this->config[$offset]) ? $this->config[$offset] : null;
- }
-
- /**
- * 合并数据到对象
- * @param array $data 需要合并的数据
- * @param bool $append 是否追加数据
- * @return array
- */
- public function merge(array $data, $append = false)
- {
- if ($append) {
- return $this->config = array_merge($this->config, $data);
- }
- return array_merge($this->config, $data);
- }
-
- /**
- * 判断配置Key是否存在
- * @param string $offset
- * @return bool
- */
- #[\ReturnTypeWillChange]
- public function offsetExists($offset)
- {
- return isset($this->config[$offset]);
- }
-
- /**
- * 清理配置项
- * @param string|null $offset
- * @return void
- */
- #[\ReturnTypeWillChange]
- public function offsetUnset($offset = null)
- {
- if (is_null($offset)) {
- $this->config = [];
- } else {
- unset($this->config[$offset]);
- }
- }
-}
\ No newline at end of file
diff --git a/WeChat/Contracts/DataError.php b/WeChat/Contracts/DataError.php
deleted file mode 100644
index 75638e9..0000000
--- a/WeChat/Contracts/DataError.php
+++ /dev/null
@@ -1,195 +0,0 @@
- '系统繁忙,此时请开发者稍候再试',
- 0 => '请求成功',
- 40001 => '获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口',
- 40002 => '不合法的凭证类型',
- 40003 => '不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID',
- 40004 => '不合法的媒体文件类型',
- 40005 => '不合法的文件类型',
- 40006 => '不合法的文件大小',
- 40007 => '不合法的媒体文件 id',
- 40008 => '不合法的消息类型',
- 40009 => '不合法的图片文件大小',
- 40010 => '不合法的语音文件大小',
- 40011 => '不合法的视频文件大小',
- 40012 => '不合法的缩略图文件大小',
- 40013 => '不合法的 AppID ,请开发者检查 AppID 的正确性,避免异常字符,注意大小写',
- 40014 => '不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口',
- 40015 => '不合法的菜单类型',
- 40016 => '不合法的按钮个数',
- 40017 => '不合法的按钮个数',
- 40018 => '不合法的按钮名字长度',
- 40019 => '不合法的按钮 KEY 长度',
- 40020 => '不合法的按钮 URL 长度',
- 40021 => '不合法的菜单版本号',
- 40022 => '不合法的子菜单级数',
- 40023 => '不合法的子菜单按钮个数',
- 40024 => '不合法的子菜单按钮类型',
- 40025 => '不合法的子菜单按钮名字长度',
- 40026 => '不合法的子菜单按钮 KEY 长度',
- 40027 => '不合法的子菜单按钮 URL 长度',
- 40028 => '不合法的自定义菜单使用用户',
- 40029 => '不合法的 oauth_code',
- 40030 => '不合法的 refresh_token',
- 40031 => '不合法的 openid 列表',
- 40032 => '不合法的 openid 列表长度',
- 40033 => '不合法的请求字符,不能包含 \\uxxxx 格式的字符',
- 40035 => '不合法的参数',
- 40038 => '不合法的请求格式',
- 40039 => '不合法的 URL 长度',
- 40050 => '不合法的分组 id',
- 40051 => '分组名字不合法',
- 40060 => '删除单篇图文时,指定的 article_idx 不合法',
- 40117 => '分组名字不合法',
- 40118 => 'media_id 大小不合法',
- 40119 => 'button 类型错误',
- 40120 => 'button 类型错误',
- 40121 => '不合法的 media_id 类型',
- 40132 => '微信号不合法',
- 40137 => '不支持的图片格式',
- 40155 => '请勿添加其他公众号的主页链接',
- 41001 => '缺少 access_token 参数',
- 41002 => '缺少 appid 参数',
- 41003 => '缺少 refresh_token 参数',
- 41004 => '缺少 secret 参数',
- 41005 => '缺少多媒体文件数据',
- 41006 => '缺少 media_id 参数',
- 41007 => '缺少子菜单数据',
- 41008 => '缺少 oauth code',
- 41009 => '缺少 openid',
- 42001 => 'access_token 超时,请检查 access_token 的有效期,请参考基础支持 - 获取 access_token 中,对 access_token 的详细机制说明',
- 42002 => 'refresh_token 超时',
- 42003 => 'oauth_code 超时',
- 42007 => '用户修改微信密码, accesstoken 和 refreshtoken 失效,需要重新授权',
- 43001 => '需要 GET 请求',
- 43002 => '需要 POST 请求',
- 43003 => '需要 HTTPS 请求',
- 43004 => '需要接收者关注',
- 43005 => '需要好友关系',
- 43019 => '需要将接收者从黑名单中移除',
- 44001 => '多媒体文件为空',
- 44002 => 'POST 的数据包为空',
- 44003 => '图文消息内容为空',
- 44004 => '文本消息内容为空',
- 45001 => '多媒体文件大小超过限制',
- 45002 => '消息内容超过限制',
- 45003 => '标题字段超过限制',
- 45004 => '描述字段超过限制',
- 45005 => '链接字段超过限制',
- 45006 => '图片链接字段超过限制',
- 45007 => '语音播放时间超过限制',
- 45008 => '图文消息超过限制',
- 45009 => '接口调用超过限制',
- 45010 => '创建菜单个数超过限制',
- 45011 => 'API 调用太频繁,请稍候再试',
- 45015 => '回复时间超过限制',
- 45016 => '系统分组,不允许修改',
- 45017 => '分组名字过长',
- 45018 => '分组数量超过上限',
- 45047 => '客服接口下行条数超过上限',
- 46001 => '不存在媒体数据',
- 46002 => '不存在的菜单版本',
- 46003 => '不存在的菜单数据',
- 46004 => '不存在的用户',
- 47001 => '解析 JSON/XML 内容错误',
- 48001 => 'api 功能未授权,请确认公众号已获得该接口,可以在公众平台官网 - 开发者中心页中查看接口权限',
- 48002 => '粉丝拒收消息(粉丝在公众号选项中,关闭了 “ 接收消息 ” )',
- 48004 => 'api 接口被封禁,请登录 mp.weixin.qq.com 查看详情',
- 48005 => 'api 禁止删除被自动回复和自定义菜单引用的素材',
- 48006 => 'api 禁止清零调用次数,因为清零次数达到上限',
- 48008 => '没有该类型消息的发送权限',
- 50001 => '用户未授权该 api',
- 50002 => '用户受限,可能是违规后接口被封禁',
- 61451 => '参数错误 (invalid parameter)',
- 61452 => '无效客服账号 (invalid kf_account)',
- 61453 => '客服帐号已存在 (kf_account exsited)',
- 61454 => '客服帐号名长度超过限制 ( 仅允许 10 个英文字符,不包括 @ 及 @ 后的公众号的微信号 )(invalid kf_acount length)',
- 61455 => '客服帐号名包含非法字符 ( 仅允许英文 + 数字 )(illegal character in kf_account)',
- 61456 => '客服帐号个数超过限制 (10 个客服账号 )(kf_account count exceeded)',
- 61457 => '无效头像文件类型 (invalid file type)',
- 61450 => '系统错误 (system error)',
- 61500 => '日期格式错误',
- 65301 => '不存在此 menuid 对应的个性化菜单',
- 65302 => '没有相应的用户',
- 65303 => '没有默认菜单,不能创建个性化菜单',
- 65304 => 'MatchRule 信息为空',
- 65305 => '个性化菜单数量受限',
- 65306 => '不支持个性化菜单的帐号',
- 65307 => '个性化菜单信息为空',
- 65308 => '包含没有响应类型的 button',
- 65309 => '个性化菜单开关处于关闭状态',
- 65310 => '填写了省份或城市信息,国家信息不能为空',
- 65311 => '填写了城市信息,省份信息不能为空',
- 65312 => '不合法的国家信息',
- 65313 => '不合法的省份信息',
- 65314 => '不合法的城市信息',
- 65316 => '该公众号的菜单设置了过多的域名外跳(最多跳转到 3 个域名的链接)',
- 65317 => '不合法的 URL',
- 9001001 => 'POST 数据参数不合法',
- 9001002 => '远端服务不可用',
- 9001003 => 'Ticket 不合法',
- 9001004 => '获取摇周边用户信息失败',
- 9001005 => '获取商户信息失败',
- 9001006 => '获取 OpenID 失败',
- 9001007 => '上传文件缺失',
- 9001008 => '上传素材的文件类型不合法',
- 9001009 => '上传素材的文件尺寸不合法',
- 9001010 => '上传失败',
- 9001020 => '帐号不合法',
- 9001021 => '已有设备激活率低于 50% ,不能新增设备',
- 9001022 => '设备申请数不合法,必须为大于 0 的数字',
- 9001023 => '已存在审核中的设备 ID 申请',
- 9001024 => '一次查询设备 ID 数量不能超过 50',
- 9001025 => '设备 ID 不合法',
- 9001026 => '页面 ID 不合法',
- 9001027 => '页面参数不合法',
- 9001028 => '一次删除页面 ID 数量不能超过 10',
- 9001029 => '页面已应用在设备中,请先解除应用关系再删除',
- 9001030 => '一次查询页面 ID 数量不能超过 50',
- 9001031 => '时间区间不合法',
- 9001032 => '保存设备与页面的绑定关系参数错误',
- 9001033 => '门店 ID 不合法',
- 9001034 => '设备备注信息过长',
- 9001035 => '设备申请参数不合法',
- 9001036 => '查询起始值 begin 不合法',
- ];
-
- /**
- * 异常代码解析描述
- * @param string $code
- * @return string
- */
- public static function toMessage($code)
- {
- return isset(self::$message[$code]) ? self::$message[$code] : $code;
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Contracts/MyCurlFile.php b/WeChat/Contracts/MyCurlFile.php
deleted file mode 100644
index 485283d..0000000
--- a/WeChat/Contracts/MyCurlFile.php
+++ /dev/null
@@ -1,78 +0,0 @@
- $v) $this->{$k} = $v;
- } else {
- $this->mimetype = $mimetype;
- $this->postname = $postname;
- $this->extension = pathinfo($filename, PATHINFO_EXTENSION);
- if (empty($this->extension)) $this->extension = 'tmp';
- if (empty($this->mimetype)) $this->mimetype = Tools::getExtMine($this->extension);
- if (empty($this->postname)) $this->postname = pathinfo($filename, PATHINFO_BASENAME);
- $this->content = base64_encode(file_get_contents($filename));
- $this->tempname = md5($this->content) . ".{$this->extension}";
- }
- }
-
- /**
- * 获取文件上传信息
- * @return \CURLFile|string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function get()
- {
- $this->filename = Tools::pushFile($this->tempname, base64_decode($this->content));
- if (class_exists('CURLFile')) {
- return new \CURLFile($this->filename, $this->mimetype, $this->postname);
- } else {
- return "@{$this->tempname};filename={$this->postname};type={$this->mimetype}";
- }
- }
-
- /**
- * 通用销毁函数清理缓存文件
- * 提前删除过期因此放到了网络请求之后
- */
- public function __destruct()
- {
- // Tools::delCache($this->tempname);
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Contracts/Tools.php b/WeChat/Contracts/Tools.php
deleted file mode 100644
index fe148e3..0000000
--- a/WeChat/Contracts/Tools.php
+++ /dev/null
@@ -1,528 +0,0 @@
- function ($name, $value, $expired = 360) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'get' => function ($name) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'del' => function ($name) {
-// var_dump(func_get_args());
-// return true;
-// },
-// 'put' => function ($name) {
-// var_dump(func_get_args());
-// return $filePath;
-// },
-// ];
-
-/**
- * 网络请求支持
- * @package WeChat\Contracts
- */
-class Tools
-{
- /**
- * 缓存路径
- * @var null
- */
- public static $cache_path = null;
-
- /**
- * 缓存读写配置
- * @var array
- */
- public static $cache_callable = [
- 'set' => null, // 写入缓存 ($name,$value='',$expired=3600):string
- 'get' => null, // 获取缓存 ($name):mixed|null
- 'del' => null, // 删除缓存 ($name):boolean
- 'put' => null, // 写入文件 ($name,$content):string
- ];
-
- /**
- * 网络缓存
- * @var array
- */
- private static $cache_curl = [];
-
- /**
- * 产生随机字符串
- * @param int $length 指定字符长度
- * @param string $str 字符串前缀
- * @return string
- */
- public static function createNoncestr($length = 32, $str = "")
- {
- $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
- for ($i = 0; $i < $length; $i++) {
- $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
- }
- return $str;
- }
-
- /**
- * 获取输入对象
- * @return string
- */
- public static function getRawInput()
- {
- if (empty($GLOBALS['HTTP_RAW_POST_DATA'])) {
- return file_get_contents('php://input');
- } else {
- return $GLOBALS['HTTP_RAW_POST_DATA'];
- }
- }
-
- /**
- * 设置输入内容
- * @param string $rawInput
- * @return void
- */
- public static function setRawInput($rawInput)
- {
- $GLOBALS['HTTP_RAW_POST_DATA'] = $rawInput;
- }
-
- /**
- * 数组转XML内容
- * @param array $data
- * @return string
- */
- public static function arr2xml($data)
- {
- return "" . self::_arr2xml($data) . "";
- }
-
- /**
- * XML内容生成
- * @param array $data 数据
- * @param string $content
- * @return string
- */
- private static function _arr2xml($data, $content = '')
- {
- foreach ($data as $key => $val) {
- is_numeric($key) && $key = 'item';
- $content .= "<{$key}>";
- if (is_array($val) || is_object($val)) {
- $content .= self::_arr2xml($val);
- } elseif (is_string($val)) {
- $content .= '';
- } else {
- $content .= $val;
- }
- $content .= "{$key}>";
- }
- return $content;
- }
-
- /**
- * 解析XML文本内容
- * @param string $xml
- * @return array|false
- */
- public static function xml3arr($xml)
- {
- $state = xml_parse($parser = xml_parser_create(), $xml, true);
- return xml_parser_free($parser) && $state ? self::xml2arr($xml) : false;
- }
-
- /**
- * 解析XML内容到数组
- * @param string $xml
- * @return array
- */
- public static function xml2arr($xml)
- {
- if (PHP_VERSION_ID < 80000) {
- $backup = libxml_disable_entity_loader(true);
- $data = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
- libxml_disable_entity_loader($backup);
- } else {
- $data = (array)simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
- }
- return json_decode(json_encode($data), true);
- }
-
- /**
- * 数组转xml内容
- * @param array $data
- * @return null|string
- */
- public static function arr2json($data)
- {
- $json = json_encode($data, JSON_UNESCAPED_UNICODE);
- return $json === '[]' ? '{}' : $json;
- }
-
- /**
- * 数组对象Emoji编译处理
- * @param array $data
- * @return array
- */
- public static function buildEnEmojiData(array $data)
- {
- foreach ($data as $key => $value) {
- if (is_array($value)) {
- $data[$key] = self::buildEnEmojiData($value);
- } elseif (is_string($value)) {
- $data[$key] = self::emojiEncode($value);
- } else {
- $data[$key] = $value;
- }
- }
- return $data;
- }
-
- /**
- * Emoji原形转换为String
- * @param string $content
- * @return string
- */
- public static function emojiEncode($content)
- {
- return json_decode(preg_replace_callback("/(\\\u[ed][0-9a-f]{3})/i", function ($string) {
- return addslashes($string[0]);
- }, json_encode($content)));
- }
-
- /**
- * 数组对象Emoji反解析处理
- * @param array $data
- * @return array
- */
- public static function buildDeEmojiData(array $data)
- {
- foreach ($data as $key => $value) {
- if (is_array($value)) {
- $data[$key] = self::buildDeEmojiData($value);
- } elseif (is_string($value)) {
- $data[$key] = self::emojiDecode($value);
- } else {
- $data[$key] = $value;
- }
- }
- return $data;
- }
-
- /**
- * Emoji字符串转换为原形
- * @param string $content
- * @return string
- */
- public static function emojiDecode($content)
- {
- return json_decode(preg_replace_callback('/\\\\\\\\/i', function () {
- return '\\';
- }, json_encode($content)));
- }
-
- /**
- * 解析JSON内容到数组
- * @param string $json
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public static function json2arr($json)
- {
- $result = json_decode($json, true);
- if (empty($result)) {
- throw new InvalidResponseException('invalid response.', '0');
- }
- if (!empty($result['errcode'])) {
- throw new InvalidResponseException($result['errmsg'], $result['errcode'], $result);
- }
- return $result;
- }
-
- /**
- * 以get访问模拟访问
- * @param string $url 访问URL
- * @param array $query GET数
- * @param array $options
- * @return boolean|string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function get($url, $query = [], $options = [])
- {
- $options['query'] = $query;
- return self::doRequest('get', $url, $options);
- }
-
- /**
- * CURL模拟网络请求
- * @param string $method 请求方法
- * @param string $url 请求方法
- * @param array $options 请求参数[headers,data,ssl_cer,ssl_key]
- * @return boolean|string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function doRequest($method, $url, $options = [])
- {
- $curl = curl_init();
- // GET参数设置
- if (!empty($options['query'])) {
- $url .= (stripos($url, '?') !== false ? '&' : '?') . http_build_query($options['query']);
- }
- // CURL头信息设置
- if (!empty($options['headers'])) {
- curl_setopt($curl, CURLOPT_HTTPHEADER, $options['headers']);
- }
- // POST/PUT/PATCH/DELETE数据设置
- $methodLower = strtolower($method);
- if (in_array($methodLower, ['post', 'put', 'patch', 'delete'])) {
- if ($methodLower === 'post') {
- curl_setopt($curl, CURLOPT_POST, true);
- } else {
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
- }
- curl_setopt($curl, CURLOPT_POSTFIELDS, self::_buildHttpData($options['data']));
- }
- // 证书文件设置
- if (!empty($options['ssl_cer'])) if (file_exists($options['ssl_cer'])) {
- curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
- curl_setopt($curl, CURLOPT_SSLCERT, $options['ssl_cer']);
- } else throw new InvalidArgumentException("Certificate files that do not exist. --- [ssl_cer]");
- // 证书文件设置
- if (!empty($options['ssl_key'])) if (file_exists($options['ssl_key'])) {
- curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
- curl_setopt($curl, CURLOPT_SSLKEY, $options['ssl_key']);
- } else throw new InvalidArgumentException("Certificate files that do not exist. --- [ssl_key]");
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_TIMEOUT, isset($options['timeout']) ? intval($options['timeout']) : 60);
- curl_setopt($curl, CURLOPT_HEADER, false);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
- curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
- $content = curl_exec($curl);
- curl_close($curl);
- // 清理 CURL 缓存文件
- if (!empty(self::$cache_curl)) foreach (self::$cache_curl as $key => $file) {
- Tools::delCache($file);
- unset(self::$cache_curl[$key]);
- }
- return $content;
- }
-
- /**
- * POST数据过滤处理
- * @param array $data 需要处理的数据
- * @param boolean $build 是否编译数据
- * @return array|string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- private static function _buildHttpData($data, $build = true)
- {
- if (!is_array($data)) return $data;
- foreach ($data as $key => $value) if ($value instanceof \CURLFile) {
- $build = false;
- } elseif (is_object($value) && isset($value->datatype) && $value->datatype === 'MY_CURL_FILE') {
- $build = false;
- $mycurl = new MyCurlFile((array)$value);
- $data[$key] = $mycurl->get();
- self::$cache_curl[] = $mycurl->tempname;
- } elseif (is_array($value) && isset($value['datatype']) && $value['datatype'] === 'MY_CURL_FILE') {
- $build = false;
- $mycurl = new MyCurlFile($value);
- $data[$key] = $mycurl->get();
- self::$cache_curl[] = $mycurl->tempname;
- } elseif (is_string($value) && class_exists('CURLFile', false) && stripos($value, '@') === 0) {
- if (($filename = realpath(trim($value, '@'))) && file_exists($filename)) {
- $build = false;
- $data[$key] = self::createCurlFile($filename);
- }
- }
- return $build ? http_build_query($data) : $data;
- }
-
- /**
- * 创建CURL文件对象
- * @param mixed $filename
- * @param string $mimetype
- * @param string $postname
- * @return \CURLFile|string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function createCurlFile($filename, $mimetype = null, $postname = null)
- {
- if (is_string($filename) && file_exists($filename)) {
- if (is_null($postname)) $postname = basename($filename);
- if (is_null($mimetype)) $mimetype = self::getExtMine(pathinfo($filename, 4));
- if (class_exists('CURLFile')) {
- return new \CURLFile($filename, $mimetype, $postname);
- } else {
- return "@{$filename};filename={$postname};type={$mimetype}";
- }
- }
- return $filename;
- }
-
- /**
- * 根据文件后缀获取文件类型
- * @param string|array $ext 文件后缀
- * @param array $mine 文件后缀MINE信息
- * @return string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function getExtMine($ext, $mine = [])
- {
- $mines = self::getMines();
- foreach (is_string($ext) ? explode(',', $ext) : $ext as $e) {
- $mine[] = isset($mines[strtolower($e)]) ? $mines[strtolower($e)] : 'application/octet-stream';
- }
- return join(',', array_unique($mine));
- }
-
- /**
- * 获取所有文件扩展的类型
- * @return array
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- private static function getMines()
- {
- $mines = self::getCache('all_ext_mine');
- if (empty($mines)) {
- $content = file_get_contents('http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types');
- preg_match_all('#^([^\s]{2,}?)\s+(.+?)$#ism', $content, $matches, PREG_SET_ORDER);
- foreach ($matches as $match) foreach (explode(" ", $match[2]) as $ext) $mines[$ext] = $match[1];
- self::setCache('all_ext_mine', $mines);
- }
- return $mines;
- }
-
- /**
- * 获取缓存内容
- * @param string $name 缓存名称
- * @return null|mixed
- */
- public static function getCache($name)
- {
- if (is_callable(self::$cache_callable['get'])) {
- return call_user_func_array(self::$cache_callable['get'], func_get_args());
- }
- $file = self::_getCacheName($name);
- 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'];
- }
- self::delCache($name);
- }
- return null;
- }
-
- /**
- * 应用缓存目录
- * @param string $name
- * @return string
- */
- private static function _getCacheName($name)
- {
- if (empty(self::$cache_path)) {
- self::$cache_path = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'Cache' . DIRECTORY_SEPARATOR;
- }
- $cachePath = rtrim((string)self::$cache_path, '/\\') . DIRECTORY_SEPARATOR;
- if (!file_exists($cachePath)) {
- mkdir($cachePath, 0755, true);
- }
- return $cachePath . $name;
- }
-
- /**
- * 移除缓存文件
- * @param string $name 缓存名称
- * @return boolean
- */
- public static function delCache($name)
- {
- if (is_callable(self::$cache_callable['del'])) {
- return call_user_func_array(self::$cache_callable['del'], func_get_args());
- }
- $file = self::_getCacheName($name);
- return !file_exists($file) || @unlink($file);
- }
-
- /**
- * 缓存配置与存储
- * @param string $name 缓存名称
- * @param string $value 缓存内容
- * @param int $expired 缓存时间(0表示永久缓存)
- * @return string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function setCache($name, $value = '', $expired = 3600)
- {
- if (is_callable(self::$cache_callable['set'])) {
- return call_user_func_array(self::$cache_callable['set'], func_get_args());
- }
- $file = self::_getCacheName($name);
- $data = ['name' => $name, 'value' => $value, 'expired' => time() + intval($expired)];
- if (!file_put_contents($file, serialize($data))) {
- throw new LocalCacheException('local cache error.', '0');
- }
- return $file;
- }
-
- /**
- * 以post访问模拟访问
- * @param string $url 访问URL
- * @param array $data POST数据
- * @param array $options
- * @return boolean|string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function post($url, $data = [], $options = [])
- {
- $options['data'] = $data;
- return self::doRequest('post', $url, $options);
- }
-
- /**
- * 写入文件
- * @param string $name 文件名称
- * @param string $content 文件内容
- * @return string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function pushFile($name, $content)
- {
- if (is_callable(self::$cache_callable['put'])) {
- return call_user_func_array(self::$cache_callable['put'], func_get_args());
- }
- $file = self::_getCacheName($name);
- if (!file_put_contents($file, $content)) {
- throw new LocalCacheException('local file write error.', '0');
- }
- return $file;
- }
-}
diff --git a/WeChat/Custom.php b/WeChat/Custom.php
deleted file mode 100644
index 4773ce2..0000000
--- a/WeChat/Custom.php
+++ /dev/null
@@ -1,228 +0,0 @@
-callPostApi($url, ['kf_account' => $kf_account, 'nickname' => $nickname]);
- }
-
- /**
- * 修改客服帐号
- * @param string $kfAccount 客服账号
- * @param string $nickname 客服昵称
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function updateAccount($kfAccount, $nickname)
- {
- $url = "https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['kf_account' => $kfAccount, 'nickname' => $nickname]);
- }
-
- /**
- * 删除客服帐号
- * @param string $kfAccount 客服账号
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function deleteAccount($kfAccount)
- {
- $url = "https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['kf_account' => $kfAccount]);
- }
-
- /**
- * 邀请绑定客服帐号
- * @param string $kfAccount 客服账号,格式 账号前缀@公众号微信号
- * @param string $invite_wx 接收绑定邀请的客服微信号
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function inviteWorker($kfAccount, $invite_wx)
- {
- $url = 'https://api.weixin.qq.com/customservice/kfaccount/inviteworker?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['kf_account' => $kfAccount, 'invite_wx' => $invite_wx]);
- }
-
- /**
- * 获取客服账号列表
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getAccountList()
- {
- $url = "https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 设置客服头像
- * @param string $kf_account 客服账号
- * @param string $image 本地图片路径
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function uploadHeadimg($kf_account, $image)
- {
- $url = "https://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account={$kf_account}";
- return $this->callPostApi($url, ['media' => Tools::createCurlFile($image)], false);
- }
-
- /**
- * 发送客服消息
- * @param array $data 消息体(touser, msgtype, content 等)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function send(array $data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 设置客服输入状态
- * @param string $openid 用户 openid
- * @param string $command Typing|CancelTyping
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function typing($openid, $command = 'Typing')
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/custom/typing?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['touser' => $openid, 'command' => $command]);
- }
-
- /**
- * 根据标签群发
- * @param array $data 群发参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function massSendAll(array $data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 根据 OpenID 列表群发
- * @param array $data 群发参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function massSend(array $data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 删除群发
- * @param int $msg_id 群发消息ID
- * @param null|int $article_idx 图文位置,0 删除全部
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function massDelete($msg_id, $article_idx = null)
- {
- $data = ['msg_id' => $msg_id];
- is_null($article_idx) || $data['article_idx'] = $article_idx;
- $url = "https://api.weixin.qq.com/cgi-bin/message/mass/delete?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 群发预览
- * @param array $data 预览参数
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function massPreview(array $data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询群发状态
- * @param int $msgId 群发消息ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function massGet($msgId)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/mass/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['msg_id' => $msgId]);
- }
-
- /**
- * 获取群发速度
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function massGetSeed()
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/mass/speed/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, []);
- }
-
- /**
- * 设置群发速度
- * @param int $speed 速度级别
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function massSetSeed($speed)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/mass/speed/set?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['speed' => $speed]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Draft.php b/WeChat/Draft.php
deleted file mode 100644
index 28fb20d..0000000
--- a/WeChat/Draft.php
+++ /dev/null
@@ -1,123 +0,0 @@
-callPostApi($url, ['articles' => $articles]);
- }
-
- /**
- * 获取草稿
- * @param string $mediaId 草稿 media_id
- * @param string $outType 可选回调处理
- * @return array 草稿内容
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function get($mediaId, $outType = null)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/draft/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['media_id' => $mediaId]);
- }
-
- /**
- * 删除草稿
- * @param string $mediaId 草稿 media_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delete($mediaId)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/draft/delete?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['media_id' => $mediaId]);
- }
-
- /**
- * 新增图文素材
- * @param array $data 图文 articles
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addNews($data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 修改草稿
- * @param string $media_id 草稿 media_id
- * @param int $index 文章序号(0 开始)
- * @param array $articles 文章内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function update($media_id, $index, $articles)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/draft/update?access_token=ACCESS_TOKEN";
- $data = ['media_id' => $media_id, 'index' => $index, 'articles' => $articles];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 获取草稿总数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getCount()
- {
- $url = "https://api.weixin.qq.com/cgi-bin/draft/count?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 获取草稿列表
- * @param int $offset 起始位置
- * @param int $count 拉取数量 1-20
- * @param int $noContent 1 不返回 content,0 返回
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function batchGet($offset = 0, $count = 20, $noContent = 0)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/draft/batchget?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['no_content' => $noContent, 'offset' => $offset, 'count' => $count]);
- }
-}
diff --git a/WeChat/Exceptions/InvalidArgumentException.php b/WeChat/Exceptions/InvalidArgumentException.php
deleted file mode 100644
index 5def2af..0000000
--- a/WeChat/Exceptions/InvalidArgumentException.php
+++ /dev/null
@@ -1,41 +0,0 @@
-raw = $raw;
- }
-}
\ No newline at end of file
diff --git a/WeChat/Exceptions/InvalidDecryptException.php b/WeChat/Exceptions/InvalidDecryptException.php
deleted file mode 100644
index c561aa9..0000000
--- a/WeChat/Exceptions/InvalidDecryptException.php
+++ /dev/null
@@ -1,41 +0,0 @@
-raw = $raw;
- }
-}
\ No newline at end of file
diff --git a/WeChat/Exceptions/InvalidInstanceException.php b/WeChat/Exceptions/InvalidInstanceException.php
deleted file mode 100644
index 710d317..0000000
--- a/WeChat/Exceptions/InvalidInstanceException.php
+++ /dev/null
@@ -1,41 +0,0 @@
-raw = $raw;
- }
-}
\ No newline at end of file
diff --git a/WeChat/Exceptions/InvalidResponseException.php b/WeChat/Exceptions/InvalidResponseException.php
deleted file mode 100644
index 20f3824..0000000
--- a/WeChat/Exceptions/InvalidResponseException.php
+++ /dev/null
@@ -1,42 +0,0 @@
-raw = $raw;
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Exceptions/LocalCacheException.php b/WeChat/Exceptions/LocalCacheException.php
deleted file mode 100644
index e0d5cb6..0000000
--- a/WeChat/Exceptions/LocalCacheException.php
+++ /dev/null
@@ -1,43 +0,0 @@
-raw = $raw;
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Freepublish.php b/WeChat/Freepublish.php
deleted file mode 100644
index d60c150..0000000
--- a/WeChat/Freepublish.php
+++ /dev/null
@@ -1,95 +0,0 @@
-callPostApi($url, ['media_id' => $mediaId]);
- }
-
- /**
- * 查询发布状态
- * @param string $publishId 发布任务 ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function get($publishId)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/freepublish/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['publish_id' => $publishId]);
- }
-
- /**
- * 删除已发布文章
- * @param string $articleId 发布返回的 article_id
- * @param int $index 图文序号,1 开始,0 删除全部
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delete($articleId, $index = 0)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/freepublish/delete?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['article_id' => $articleId, 'index' => $index]);
- }
-
- /**
- * 获取已发布文章
- * @param string $articleId article_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getArticle($articleId)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/freepublish/getarticle?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['article_id' => $articleId]);
- }
-
- /**
- * 获取已发布列表
- * @param int $offset 起始偏移
- * @param int $count 数量 1-20
- * @param int $noContent 1 不返回 content
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function batchGet($offset = 0, $count = 20, $noContent = 0)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/freepublish/batchget?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['no_content' => $noContent, 'offset' => $offset, 'count' => $count]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Limit.php b/WeChat/Limit.php
deleted file mode 100644
index 85eeb24..0000000
--- a/WeChat/Limit.php
+++ /dev/null
@@ -1,65 +0,0 @@
-callPostApi($url, ['appid' => $this->config->get('appid')]);
- }
-
- /**
- * 网络检测
- * @param string $action ping|dns|all
- * @param string $operator DEFAULT|CT|CU|CM
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function ping($action = 'all', $operator = 'DEFAULT')
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/callback/check?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['action' => $action, 'check_operator' => $operator]);
- }
-
- /**
- * 获取微信服务器 IP
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getCallbackIp()
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=ACCESS_TOKEN';
- return $this->callGetApi($url);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Media.php b/WeChat/Media.php
deleted file mode 100644
index 2b3e8f3..0000000
--- a/WeChat/Media.php
+++ /dev/null
@@ -1,195 +0,0 @@
-callPostApi($url, ['media' => Tools::createCurlFile($filename)], false);
- }
-
- /**
- * 获取临时素材
- * @param string $media_id 媒体 ID
- * @param string $outType 可选:回调处理或 'url' 仅返回 URL
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function get($media_id, $outType = null)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id={$media_id}";
- $this->registerApi($url, __FUNCTION__, func_get_args());
- if ($outType == 'url') return $url;
- $result = Tools::get($url);
- if (is_array($json = json_decode($result, true))) {
- if (!$this->isTry && isset($json['errcode']) && in_array($json['errcode'], ['40014', '40001', '41001', '42001'])) {
- [$this->delAccessToken(), $this->isTry = true];
- return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
- }
- return Tools::json2arr($result);
- }
- return is_null($outType) ? $result : $outType($result);
- }
-
- /**
- * 新增永久图文素材
- * @param array $data 图文列表 articles
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addNews($data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 更新图文素材
- * @param string $media_id 图文 media_id
- * @param int $index 文章位置(0 开始)
- * @param array $news 文章内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateNews($media_id, $index, $news)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['media_id' => $media_id, 'index' => $index, 'articles' => $news]);
- }
-
- /**
- * 上传图文消息内的图片,获取 URL
- * @param string $filename 本地文件
- * @return array 含 url
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function uploadImg($filename)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['media' => Tools::createCurlFile($filename)], false);
- }
-
- /**
- * 新增其他类型永久素材
- * @param string $filename 本地文件路径
- * @param string $type 媒体类型 image|voice|video|thumb
- * @param array $description 视频描述等
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addMaterial($filename, $type = 'image', $description = [])
- {
- if (!in_array($type, ['image', 'voice', 'video', 'thumb'])) {
- throw new InvalidResponseException('Invalid Media Type.', '0');
- }
- $url = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type={$type}";
- return $this->callPostApi($url, ['media' => Tools::createCurlFile($filename), 'description' => Tools::arr2json($description)], false);
- }
-
- /**
- * 获取永久素材
- * @param string $media_id 媒体 ID
- * @param null|string $outType 回调处理或 'url' 返回地址
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getMaterial($media_id, $outType = null)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=ACCESS_TOKEN";
- $this->registerApi($url, __FUNCTION__, func_get_args());
- if ($outType == 'url') return $url;
- $result = Tools::post($url, ['media_id' => $media_id]);
- if (is_array($json = json_decode($result, true))) {
- if (!$this->isTry && isset($json['errcode']) && in_array($json['errcode'], ['40014', '40001', '41001', '42001'])) {
- [$this->delAccessToken(), $this->isTry = true];
- return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
- }
- return Tools::json2arr($result);
- }
- return is_null($outType) ? $result : $outType($result);
- }
-
- /**
- * 删除永久素材
- * @param string $mediaId 媒体 ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delMaterial($mediaId)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=ACCESS_TOKEN";
- return $this->httpPostForJson($url, ['media_id' => $mediaId]);
- }
-
- /**
- * 获取素材总数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getMaterialCount()
- {
- $url = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 获取素材列表
- * @param string $type image|voice|video|news
- * @param int $offset 起始位置
- * @param int $count 拉取数量
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function batchGetMaterial($type = 'image', $offset = 0, $count = 20)
- {
- if (!in_array($type, ['image', 'voice', 'video', 'news'])) {
- throw new InvalidResponseException('Invalid Media Type.', '0');
- }
- $url = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['type' => $type, 'offset' => $offset, 'count' => $count]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Menu.php b/WeChat/Menu.php
deleted file mode 100644
index 81124f7..0000000
--- a/WeChat/Menu.php
+++ /dev/null
@@ -1,103 +0,0 @@
-callGetApi($url);
- }
-
- /**
- * 删除自定义菜单接口
- * @return array 操作结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delete()
- {
- $url = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 创建自定义菜单接口
- * @param array $data 菜单配置(button数组,最多3个一级菜单,每个一级菜单最多5个二级菜单)
- * @return array 操作结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function create(array $data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 创建个性化菜单接口
- * @param array $data 菜单配置(button数组和matchrule匹配规则)
- * @return array 返回menuid
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addConditional(array $data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 删除个性化菜单接口
- * @param string $menuid 菜单ID
- * @return array 操作结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delConditional($menuid)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['menuid' => $menuid]);
- }
-
- /**
- * 测试个性化菜单匹配结果接口
- * @param string $openid 用户openid
- * @return array 该用户匹配的菜单配置
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function tryConditional($openid)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/menu/trymatch?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['user_id' => $openid]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Oauth.php b/WeChat/Oauth.php
deleted file mode 100644
index 1a13e3a..0000000
--- a/WeChat/Oauth.php
+++ /dev/null
@@ -1,100 +0,0 @@
-config->get('appid');
- $redirect_uri = urlencode($redirect_url);
- return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appid}&redirect_uri={$redirect_uri}&response_type=code&scope={$scope}&state={$state}#wechat_redirect";
- }
-
- /**
- * 通过 code 换取 access_token/refresh_token/openid
- * @param string $code 授权 code,不传则取 GET 参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getOauthAccessToken($code = '')
- {
- $appid = $this->config->get('appid');
- $appsecret = $this->config->get('appsecret');
- $code = $code ? $code : (isset($_GET['code']) ? $_GET['code'] : '');
- $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$appsecret}&code={$code}&grant_type=authorization_code";
- return $this->httpGetForJson($url);
- }
-
- /**
- * 刷新网页授权 access_token
- * @param string $refresh_token 刷新 token
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getOauthRefreshToken($refresh_token)
- {
- $appid = $this->config->get('appid');
- $url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={$appid}&grant_type=refresh_token&refresh_token={$refresh_token}";
- return $this->httpGetForJson($url);
- }
-
- /**
- * 校验网页授权 access_token 是否有效
- * @param string $accessToken 网页授权 access_token
- * @param string $openid 用户 openid
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function checkOauthAccessToken($accessToken, $openid)
- {
- $url = "https://api.weixin.qq.com/sns/auth?access_token={$accessToken}&openid={$openid}";
- return $this->httpGetForJson($url);
- }
-
- /**
- * 拉取用户信息(snsapi_userinfo)
- * @param string $accessToken 网页授权 access_token
- * @param string $openid 用户 openid
- * @param string $lang zh_CN|zh_TW|en
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getUserInfo($accessToken, $openid, $lang = 'zh_CN')
- {
- $url = "https://api.weixin.qq.com/sns/userinfo?access_token={$accessToken}&openid={$openid}&lang={$lang}";
- return $this->httpGetForJson($url);
- }
-}
diff --git a/WeChat/Pay.php b/WeChat/Pay.php
deleted file mode 100644
index c463698..0000000
--- a/WeChat/Pay.php
+++ /dev/null
@@ -1,232 +0,0 @@
-config->get())->create($options);
- }
-
- /**
- * 刷卡支付(被扫)
- * @param array $options 支付参数(auth_code, out_trade_no, total_fee 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createMicropay($options)
- {
- return Order::instance($this->config->get())->micropay($options);
- }
-
- /**
- * 生成 JSAPI/H5 支付参数
- * @param string $prepay_id 统一下单返回的 prepay_id
- * @return array 前端调起参数
- */
- public function createParamsForJsApi($prepay_id)
- {
- return Order::instance($this->config->get())->jsapiParams($prepay_id);
- }
-
- /**
- * 生成 APP 支付参数
- * @param string $prepay_id 统一下单返回的 prepay_id
- * @return array APP 支付参数
- */
- public function createParamsForApp($prepay_id)
- {
- return Order::instance($this->config->get())->appParams($prepay_id);
- }
-
- /**
- * 生成 Native 支付二维码 URL
- * @param string $product_id 商品 ID 或订单号
- * @return string
- */
- public function createParamsForRuleQrc($product_id)
- {
- return Order::instance($this->config->get())->qrcParams($product_id);
- }
-
- /**
- * 查询订单
- * @param array $options 查询参数(transaction_id 或 out_trade_no)
- * @return array 订单详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryOrder(array $options)
- {
- return Order::instance($this->config->get())->query($options);
- }
-
- /**
- * 关闭订单
- * @param string $out_trade_no 商户订单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function closeOrder($out_trade_no)
- {
- return Order::instance($this->config->get())->close($out_trade_no);
- }
-
- /**
- * 申请退款
- * @param array $options 退款参数(out_trade_no/transaction_id,out_refund_no,total_fee,refund_fee 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createRefund(array $options)
- {
- return Refund::instance($this->config->get())->create($options);
- }
-
- /**
- * 查询退款
- * @param array $options 查询参数(transaction_id/out_trade_no/out_refund_no/refund_id 四选一)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryRefund(array $options)
- {
- return Refund::instance($this->config->get())->query($options);
- }
-
- /**
- * 交易保障上报
- * @param array $options 上报参数(interface_url, execute_time, return_code 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function report(array $options)
- {
- return Order::instance($this->config->get())->report($options);
- }
-
- /**
- * 授权码查询 openid
- * @param string $authCode 扫码支付授权码
- * @return array 含 openid
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryAuthCode($authCode)
- {
- return Order::instance($this->config->get())->queryAuthCode($authCode);
- }
-
- /**
- * 下载对账单
- * @param array $options 账单参数(bill_date, bill_type 等)
- * @param null|string $outType 输出处理回调,为 null 返回原始内容
- * @return bool|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function billDownload(array $options, $outType = null)
- {
- return Bill::instance($this->config->get())->download($options, $outType);
- }
-
- /**
- * 拉取订单评价数据(需证书)
- * @param array $options 查询参数(bill_date, offset, limit 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function billCommtent(array $options)
- {
- return Bill::instance($this->config->get())->comment($options);
- }
-
- /**
- * 企业付款到零钱
- * @param array $options 付款参数(partner_trade_no, openid, amount, desc 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createTransfers(array $options)
- {
- return Transfers::instance($this->config->get())->create($options);
- }
-
- /**
- * 查询企业付款到零钱
- * @param string $partner_trade_no 商户付款单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryTransfers($partner_trade_no)
- {
- return Transfers::instance($this->config->get())->query($partner_trade_no);
- }
-
- /**
- * 企业付款到银行卡
- * @param array $options 付款参数(partner_trade_no, enc_bank_no, enc_true_name, bank_code, amount 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidDecryptException
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createTransfersBank(array $options)
- {
- return TransfersBank::instance($this->config->get())->create($options);
- }
-
- /**
- * 查询企业付款到银行卡结果
- * @param string $partner_trade_no 商户付款单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryTransFresBank($partner_trade_no)
- {
- return TransfersBank::instance($this->config->get())->query($partner_trade_no);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Product.php b/WeChat/Product.php
deleted file mode 100644
index 9d6d6a7..0000000
--- a/WeChat/Product.php
+++ /dev/null
@@ -1,165 +0,0 @@
- $keystandard, 'keystr' => $keystr, 'status' => $status];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 设置测试人员白名单
- * @param array $openids openid 列表
- * @param array $usernames 微信号列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setTestWhiteList(array $openids = [], array $usernames = [])
- {
- $url = "https://api.weixin.qq.com/scan/testwhitelist/set?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['openid' => $openids, 'username' => $usernames]);
- }
-
- /**
- * 获取商品二维码
- * @param string $keystandard 编码标准
- * @param string $keystr 编码内容
- * @param int $qrcode_size 边长像素,默认100
- * @param array $extinfo 自定义扩展
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getQrcode($keystandard, $keystr, $qrcode_size, $extinfo = [])
- {
- $url = "https://api.weixin.qq.com/scan/product/getqrcode?access_token=ACCESS_TOKEN";
- $data = ['keystandard' => $keystandard, 'keystr' => $keystr, 'qrcode_size' => $qrcode_size];
- empty($extinfo) || $data['extinfo'] = $extinfo;
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询商品信息
- * @param string $keystandard 商品编码标准
- * @param string $keystr 商品编码内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getProduct($keystandard, $keystr)
- {
- $url = "https://api.weixin.qq.com/scan/product/get?access_token=ACCESS_TOKEN";
- $data = ['keystandard' => $keystandard, 'keystr' => $keystr];
- empty($extinfo) || $data['extinfo'] = $extinfo;
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 批量查询商品信息
- * @param int $offset 起始位置
- * @param int $limit 数量
- * @param null|string $status on|off|check|reject|all
- * @param string $keystr 模糊编码过滤
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getProductList($offset, $limit = 10, $status = null, $keystr = '')
- {
- $url = "https://api.weixin.qq.com/scan/product/get?access_token=ACCESS_TOKEN";
- $data = ['offset' => $offset, 'limit' => $limit];
- is_null($status) || $data['status'] = $status;
- empty($keystr) || $data['keystr'] = $keystr;
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 更新商品信息
- * @param array $data 商品数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateProduct(array $data)
- {
- $url = "https://api.weixin.qq.com/scan/product/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 清除商品信息
- * @param string $keystandard 商品编码标准
- * @param string $keystr 商品编码内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function clearProduct($keystandard, $keystr)
- {
- $url = "https://api.weixin.qq.com/scan/product/clear?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['keystandard' => $keystandard, 'keystr' => $keystr]);
- }
-
- /**
- * 检查 wxticket 参数
- * @param string $ticket
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function scanTicketCheck($ticket)
- {
- $url = "https://api.weixin.qq.com/scan/scanticket/check?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['ticket' => $ticket]);
- }
-
- /**
- * 清除扫码记录
- * @param string $keystandard 商品编码标准
- * @param string $keystr 商品编码内容
- * @param string $extinfo 获取二维码时的 extinfo
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function clearScanticket($keystandard, $keystr, $extinfo)
- {
- $url = "https://api.weixin.qq.com/scan/scanticket/check?access_token=ACCESS_TOKEN";
- $data = ['keystandard' => $keystandard, 'keystr' => $keystr, 'extinfo' => $extinfo];
- return $this->callPostApi($url, $data);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Prpcrypt/ErrorCode.php b/WeChat/Prpcrypt/ErrorCode.php
deleted file mode 100644
index fb1be61..0000000
--- a/WeChat/Prpcrypt/ErrorCode.php
+++ /dev/null
@@ -1,52 +0,0 @@
- '处理成功',
- '40001' => '校验签名失败',
- '40002' => '解析xml失败',
- '40003' => '计算签名失败',
- '40004' => '不合法的AESKey',
- '40005' => '校验AppID失败',
- '40006' => 'AES加密失败',
- '40007' => 'AES解密失败',
- '40008' => '公众平台发送的xml不合法',
- '40009' => 'Base64编码失败',
- '40010' => 'Base64解码失败',
- '40011' => '公众帐号生成回包xml失败',
- ];
-
- /**
- * 获取错误消息内容
- * @param string $code 错误代码
- * @return bool
- */
- public static function getErrText($code)
- {
- if (isset(self::$errCode[$code])) {
- return self::$errCode[$code];
- }
- return false;
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Prpcrypt/PKCS7Encoder.php b/WeChat/Prpcrypt/PKCS7Encoder.php
deleted file mode 100644
index 3192446..0000000
--- a/WeChat/Prpcrypt/PKCS7Encoder.php
+++ /dev/null
@@ -1,45 +0,0 @@
- PKCS7Encoder::$blockSize) {
- $pad = 0;
- }
- return substr($text, 0, strlen($text) - $pad);
- }
-
-}
\ No newline at end of file
diff --git a/WeChat/Prpcrypt/Prpcrypt.php b/WeChat/Prpcrypt/Prpcrypt.php
deleted file mode 100644
index f61482d..0000000
--- a/WeChat/Prpcrypt/Prpcrypt.php
+++ /dev/null
@@ -1,97 +0,0 @@
-key = base64_decode("{$key}=");
- }
-
- /**
- * 对明文进行加密
- * @param string $text 需要加密的明文
- * @param string $appid 公众号APPID
- * @return array
- */
- public function encrypt($text, $appid)
- {
- try {
- $random = $this->getRandomStr();
- $iv = substr($this->key, 0, 16);
- $pkcEncoder = new PKCS7Encoder();
- $text = $pkcEncoder->encode($random . pack("N", strlen($text)) . $text . $appid);
- $encrypted = openssl_encrypt($text, 'AES-256-CBC', substr($this->key, 0, 32), OPENSSL_ZERO_PADDING, $iv);
- return [ErrorCode::$OK, $encrypted];
- } catch (\Exception $e) {
- return [ErrorCode::$EncryptAESError, null];
- }
- }
-
- /**
- * 随机生成16位字符串
- * @param string $str
- * @return string 生成的字符串
- */
- function getRandomStr($str = "")
- {
- $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
- $max = strlen($str_pol) - 1;
- for ($i = 0; $i < 16; $i++) {
- $str .= $str_pol[mt_rand(0, $max)];
- }
- return $str;
- }
-
- /**
- * 对密文进行解密
- * @param string $encrypted 需要解密的密文
- * @return array
- */
- public function decrypt($encrypted)
- {
- try {
- $iv = substr($this->key, 0, 16);
- $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', substr($this->key, 0, 32), OPENSSL_ZERO_PADDING, $iv);
- } catch (\Exception $e) {
- return [ErrorCode::$DecryptAESError, null];
- }
- try {
- $pkcEncoder = new PKCS7Encoder();
- $result = $pkcEncoder->decode($decrypted);
- if (strlen($result) < 16) {
- return [ErrorCode::$DecryptAESError, null];
- }
- $content = substr($result, 16, strlen($result));
- $len_list = unpack("N", substr($content, 0, 4));
- $xml_len = $len_list[1];
- return [0, substr($content, 4, $xml_len), substr($content, $xml_len + 4)];
- } catch (\Exception $e) {
- return [ErrorCode::$IllegalBuffer, null];
- }
- }
-
-}
diff --git a/WeChat/Qrcode.php b/WeChat/Qrcode.php
deleted file mode 100644
index 51efb9f..0000000
--- a/WeChat/Qrcode.php
+++ /dev/null
@@ -1,75 +0,0 @@
- ['scene' => ['scene_id' => $scene]]];
- } else {
- $data = ['action_info' => ['scene' => ['scene_str' => $scene]]];
- }
- if ($expire_seconds > 0) { // 临时二维码
- $data['expire_seconds'] = $expire_seconds;
- $data['action_name'] = is_integer($scene) ? 'QR_SCENE' : 'QR_STR_SCENE';
- } else { // 永久二维码
- $data['action_name'] = is_integer($scene) ? 'QR_LIMIT_SCENE' : 'QR_LIMIT_STR_SCENE';
- }
- $url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 通过 ticket 换取二维码 URL
- * @param string $ticket 二维码 ticket
- * @return string 图片 URL
- */
- public function url($ticket)
- {
- return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" . urlencode($ticket);
- }
-
- /**
- * 长链接转短链接
- * @param string $longUrl 长链接
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function shortUrl($longUrl)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['action' => 'long2short', 'long_url' => $longUrl]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Receive.php b/WeChat/Receive.php
deleted file mode 100644
index b1d68c8..0000000
--- a/WeChat/Receive.php
+++ /dev/null
@@ -1,165 +0,0 @@
-message = [
- 'CreateTime' => time(),
- 'ToUserName' => $this->getOpenid(),
- 'FromUserName' => $this->getToOpenid(),
- 'MsgType' => 'transfer_customer_service',
- ];
- empty($account) || $this->message['TransInfo'] = ['KfAccount' => $account];
- return $this;
- }
-
- /**
- * 设置文本消息
- * @param string $content 文本内容
- * @return $this
- */
- public function text($content = '')
- {
- $this->message = [
- 'MsgType' => 'text',
- 'CreateTime' => time(),
- 'Content' => $content,
- 'ToUserName' => $this->getOpenid(),
- 'FromUserName' => $this->getToOpenid(),
- ];
- return $this;
- }
-
- /**
- * 设置图文消息
- * @param array $newsData Articles 列表
- * @return $this
- */
- public function news($newsData = [])
- {
- $this->message = [
- 'CreateTime' => time(),
- 'MsgType' => 'news',
- 'Articles' => $newsData,
- 'ToUserName' => $this->getOpenid(),
- 'FromUserName' => $this->getToOpenid(),
- 'ArticleCount' => count($newsData),
- ];
- return $this;
- }
-
- /**
- * 设置图片消息
- * @param string $mediaId 图片 media_id
- * @return $this
- */
- public function image($mediaId = '')
- {
- $this->message = [
- 'MsgType' => 'image',
- 'CreateTime' => time(),
- 'ToUserName' => $this->getOpenid(),
- 'FromUserName' => $this->getToOpenid(),
- 'Image' => ['MediaId' => $mediaId],
- ];
- return $this;
- }
-
- /**
- * 设置语音消息
- * @param string $mediaid 语音 media_id
- * @return $this
- */
- public function voice($mediaid = '')
- {
- $this->message = [
- 'CreateTime' => time(),
- 'MsgType' => 'voice',
- 'ToUserName' => $this->getOpenid(),
- 'FromUserName' => $this->getToOpenid(),
- 'Voice' => ['MediaId' => $mediaid],
- ];
- return $this;
- }
-
- /**
- * 设置视频消息
- * @param string $mediaid 视频 media_id
- * @param string $title 标题
- * @param string $description 描述
- * @return $this
- */
- public function video($mediaid = '', $title = '', $description = '')
- {
- $this->message = [
- 'CreateTime' => time(),
- 'MsgType' => 'video',
- 'ToUserName' => $this->getOpenid(),
- 'FromUserName' => $this->getToOpenid(),
- 'Video' => [
- 'Title' => $title,
- 'MediaId' => $mediaid,
- 'Description' => $description,
- ],
- ];
- return $this;
- }
-
- /**
- * 设置音乐消息
- * @param string $title 标题
- * @param string $desc 描述
- * @param string $musicurl 音乐链接
- * @param string $hgmusicurl 高清链接
- * @param string $thumbmediaid 缩略图 media_id
- * @return $this
- */
- public function music($title, $desc, $musicurl, $hgmusicurl = '', $thumbmediaid = '')
- {
- $this->message = [
- 'CreateTime' => time(),
- 'MsgType' => 'music',
- 'ToUserName' => $this->getOpenid(),
- 'FromUserName' => $this->getToOpenid(),
- 'Music' => [
- 'Title' => $title,
- 'Description' => $desc,
- 'MusicUrl' => $musicurl,
- 'HQMusicUrl' => $hgmusicurl,
- ],
- ];
- if ($thumbmediaid) {
- $this->message['Music']['ThumbMediaId'] = $thumbmediaid;
- }
- return $this;
- }
-}
\ No newline at end of file
diff --git a/WeChat/Scan.php b/WeChat/Scan.php
deleted file mode 100644
index 6f5df49..0000000
--- a/WeChat/Scan.php
+++ /dev/null
@@ -1,187 +0,0 @@
-callGetApi($url);
- }
-
- /**
- * 创建商品
- * @param array $data 商品数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addProduct(array $data)
- {
- $url = "https://api.weixin.qq.com/scan/product/create?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 商品发布/取消
- * @param string $keystandard 商品编码标准
- * @param string $keystr 商品编码内容
- * @param string $status on 提交审核 | off 取消
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function modProduct($keystandard, $keystr, $status = 'on')
- {
- $url = "https://api.weixin.qq.com/scan/product/modstatus?access_token=ACCESS_TOKEN";
- $data = ['keystandard' => $keystandard, 'keystr' => $keystr, 'status' => $status];
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 设置测试人员白名单
- * @param array $openids openid 列表
- * @param array $usernames 微信号列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setTestWhiteList($openids = [], $usernames = [])
- {
- $url = "https://api.weixin.qq.com/scan/product/modstatus?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['openid' => $openids, 'username' => $usernames]);
- }
-
- /**
- * 获取商品二维码
- * @param string $keystandard 编码标准
- * @param string $keystr 编码内容
- * @param null|string $extinfo 自定义标识
- * @param int $qrcode_size 边长像素
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getQrc($keystandard, $keystr, $extinfo = null, $qrcode_size = 64)
- {
- $url = "https://api.weixin.qq.com/scan/product/getqrcode?access_token=ACCESS_TOKEN";
- $data = ['keystandard' => $keystandard, 'keystr' => $keystr, 'qrcode_size' => $qrcode_size];
- is_null($extinfo) || $data['extinfo'] = $extinfo;
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询商品信息
- * @param string $keystandard 商品编码标准
- * @param string $keystr 商品编码内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getProductInfo($keystandard, $keystr)
- {
- $url = "https://api.weixin.qq.com/scan/product/get?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['keystandard' => $keystandard, 'keystr' => $keystr]);
- }
-
- /**
- * 批量查询商品信息
- * @param int $offset 起始位置
- * @param int $limit 数量
- * @param string $status on|off|check|reject|all
- * @param string $keystr 关键词过滤
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getProductList($offset = 1, $limit = 10, $status = null, $keystr = null)
- {
- $url = "https://api.weixin.qq.com/scan/product/getlist?access_token=ACCESS_TOKEN";
- $data = ['offset' => $offset, 'limit' => $limit];
- is_null($status) || $data['status'] = $status;
- is_null($keystr) || $data['keystr'] = $keystr;
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 更新商品信息
- * @param array $data 商品数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateProduct(array $data)
- {
- $url = "https://api.weixin.qq.com/scan/product/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 清除商品信息
- * @param string $keystandard 商品编码标准
- * @param string $keystr 商品编码内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function clearProduct($keystandard, $keystr)
- {
- $url = "https://api.weixin.qq.com/scan/product/clear?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['keystandard' => $keystandard, 'keystr' => $keystr]);
- }
-
- /**
- * 检查 wxticket 参数
- * @param string $ticket
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function checkTicket($ticket)
- {
- $url = "https://api.weixin.qq.com/scan/scanticket/check?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['ticket' => $ticket]);
- }
-
- /**
- * 清除扫码记录
- * @param string $keystandard 商品编码标准
- * @param string $keystr 商品编码内容
- * @param string $extinfo 二维码接口时的 extinfo
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function clearScanTicket($keystandard, $keystr, $extinfo)
- {
- $url = "https://api.weixin.qq.com/scan/scanticket/check?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['keystandard' => $keystandard, 'keystr' => $keystr, 'extinfo' => $extinfo]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Script.php b/WeChat/Script.php
deleted file mode 100644
index 243012a..0000000
--- a/WeChat/Script.php
+++ /dev/null
@@ -1,116 +0,0 @@
-config->get('appid');
- $cache_name = "{$appid}_ticket_{$type}";
- Tools::delCache($cache_name);
- }
-
- /**
- * 获取 JSAPI 签名
- * @param string $url 当前页面 URL(不含 #)
- * @param string $appid 可选指定 appid
- * @param string $ticket 可选指定 ticket
- * @param array $jsApiList 需注入的 API 列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getJsSign($url, $appid = null, $ticket = null, $jsApiList = null)
- {
- list($url,) = explode('#', $url);
- is_null($ticket) && $ticket = $this->getTicket('jsapi');
- is_null($appid) && $appid = $this->config->get('appid');
- is_null($jsApiList) && $jsApiList = [
- 'updateAppMessageShareData', 'updateTimelineShareData', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone',
- 'startRecord', 'stopRecord', 'onVoiceRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'onVoicePlayEnd', 'uploadVoice', 'downloadVoice',
- 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'translateVoice', 'getNetworkType', 'openLocation', 'getLocation',
- 'hideOptionMenu', 'showOptionMenu', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem',
- 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard',
- ];
- $data = ["url" => $url, "timestamp" => '' . time(), "jsapi_ticket" => $ticket, "noncestr" => Tools::createNoncestr(16)];
- return [
- 'debug' => false,
- "appId" => $appid,
- "nonceStr" => $data['noncestr'],
- "timestamp" => $data['timestamp'],
- "signature" => $this->getSignature($data, 'sha1'),
- 'jsApiList' => $jsApiList,
- ];
- }
-
- /**
- * 获取 JSAPI_TICKET
- * @param string $type jsapi|wx_card
- * @param string $appid 可选指定 appid
- * @return string ticket
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getTicket($type = 'jsapi', $appid = null)
- {
- is_null($appid) && $appid = $this->config->get('appid');
- $cache_name = "{$appid}_ticket_{$type}";
- $ticket = Tools::getCache($cache_name);
- if (empty($ticket)) {
- $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type={$type}";
- $this->registerApi($url, __FUNCTION__, func_get_args());
- $result = $this->httpGetForJson($url);
- if (empty($result['ticket'])) {
- throw new InvalidResponseException('Invalid Resoponse Ticket.', '0');
- }
- $ticket = $result['ticket'];
- Tools::setCache($cache_name, $ticket, 7000);
- }
- return $ticket;
- }
-
- /**
- * 数据生成签名
- * @param array $data 待签名数据
- * @param string $method 签名方法
- * @param array $params 额外参数
- * @return bool|string
- */
- protected function getSignature($data, $method = "sha1", $params = [])
- {
- ksort($data);
- if (!function_exists($method)) return false;
- foreach ($data as $k => $v) $params[] = "{$k}={$v}";
- return $method(join('&', $params));
- }
-}
\ No newline at end of file
diff --git a/WeChat/Shake.php b/WeChat/Shake.php
deleted file mode 100644
index 2b10278..0000000
--- a/WeChat/Shake.php
+++ /dev/null
@@ -1,340 +0,0 @@
-callPostApi($url, $data);
- }
-
- /**
- * 查询审核状态
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function auditStatus()
- {
- $url = "https://api.weixin.qq.com/shakearound/account/auditstatus?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 申请设备 ID
- * @param string $quantity 数量(>500 走人工审核)
- * @param string $apply_reason 理由
- * @param null|string $comment 备注
- * @param null|string $poi_id 门店ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createApply($quantity, $apply_reason, $comment = null, $poi_id = null)
- {
- $data = ['quantity' => $quantity, 'apply_reason' => $apply_reason];
- is_null($poi_id) || $data['poi_id'] = $poi_id;
- is_null($comment) || $data['comment'] = $comment;
- $url = "https://api.weixin.qq.com/shakearound/device/applyid?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询设备 ID 申请状态
- * @param int $applyId 批次ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getApplyStatus($applyId)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/applyid?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['apply_id' => $applyId]);
- }
-
- /**
- * 编辑设备信息
- * @param array $data 设备参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateApply(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 设备绑定门店
- * @param array $data 绑定参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function bindLocation(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/bindlocation?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询设备列表
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function search(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/search?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 创建页面
- * @param array $data 页面参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createPage(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/page/add?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 编辑页面
- * @param array $data 页面参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updatePage(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/page/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询页面列表
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function searchPage(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/page/search?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 删除页面
- * @param int $pageId 页面ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function deletePage($pageId)
- {
- $url = "https://api.weixin.qq.com/shakearound/page/delete?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['page_id' => $pageId]);
- }
-
- /**
- * 上传图片素材
- * @param string $filename 图片路径
- * @param string $type icon|license
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function upload($filename, $type = 'icon')
- {
- $url = "https://api.weixin.qq.com/shakearound/material/add?access_token=ACCESS_TOKEN&type={$type}";
- return $this->callPostApi($url, ['media' => Tools::createCurlFile($filename)], false);
- }
-
- /**
- * 配置设备与页面关联
- * @param array $data 关联参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function bindPage(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/bindpage?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 查询设备与页面关联
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryPage(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/relation/search?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 设备维度数据统计
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function totalDevice(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/statistics/device?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 批量查询设备统计
- * @param int $date 日期时间戳(秒)
- * @param int $pageIndex 页码
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function totalDeviceList($date, $pageIndex = 1)
- {
- $url = "https://api.weixin.qq.com/shakearound/statistics/devicelist?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['date' => $date, 'page_index' => $pageIndex]);
- }
-
- /**
- * 页面维度数据统计
- * @param int $pageId 页面ID
- * @param int $beginDate 起始时间戳
- * @param int $endDate 结束时间戳
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function totalPage($pageId, $beginDate, $endDate)
- {
- $url = "https://api.weixin.qq.com/shakearound/statistics/page?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['page_id' => $pageId, 'begin_date' => $beginDate, 'end_date' => $endDate]);
- }
-
- /**
- * 编辑分组信息
- * @param int $groupId 分组ID
- * @param string $groupName 分组名称
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateGroup($groupId, $groupName)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/group/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['group_id' => $groupId, 'group_name' => $groupName]);
- }
-
- /**
- * 删除分组
- * @param int $groupId 分组ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function deleteGroup($groupId)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/group/delete?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['group_id' => $groupId]);
- }
-
- /**
- * 查询分组列表
- * @param int $begin 起始索引
- * @param int $count 数量(<=1000)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGroupList($begin = 0, $count = 10)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/group/getlist?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['begin' => $begin, 'count' => $count]);
- }
-
-
- /**
- * 查询分组详情
- * @param int $group_id 分组ID
- * @param int $begin 设备起始索引
- * @param int $count 数量(<=1000)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGroupDetail($group_id, $begin = 0, $count = 100)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/group/getdetail?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['group_id' => $group_id, 'begin' => $begin, 'count' => $count]);
- }
-
- /**
- * 分组添加设备
- * @param array $data 设备参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addDeviceGroup(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/group/adddevice?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 分组移除设备
- * @param array $data 设备参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function deleteDeviceGroup(array $data)
- {
- $url = "https://api.weixin.qq.com/shakearound/device/group/deletedevice?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Tags.php b/WeChat/Tags.php
deleted file mode 100644
index 268a417..0000000
--- a/WeChat/Tags.php
+++ /dev/null
@@ -1,119 +0,0 @@
-callGetApi($url);
- }
-
- /**
- * 创建标签
- * @param string $name 标签名称
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function createTags($name)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/tags/create?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['tag' => ['name' => $name]]);
- }
-
- /**
- * 更新标签
- * @param int $id 标签ID
- * @param string $name 标签名称
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function updateTags($id, $name)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/tags/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['tag' => ['name' => $name, 'id' => $id]]);
- }
-
- /**
- * 删除标签
- * @param int $tagId 标签ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function deleteTags($tagId)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/tags/delete?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['tag' => ['id' => $tagId]]);
- }
-
- /**
- * 批量为用户打标签
- * @param array $openids openid 列表
- * @param int $tagId 标签ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function batchTagging(array $openids, $tagId)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['openid_list' => $openids, 'tagid' => $tagId]);
- }
-
- /**
- * 批量取消用户标签
- * @param array $openids openid 列表
- * @param int $tagId 标签ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function batchUntagging(array $openids, $tagId)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['openid_list' => $openids, 'tagid' => $tagId]);
- }
-
- /**
- * 获取用户标签列表
- * @param string $openid 用户 openid
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getUserTagId($openid)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['openid' => $openid]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Template.php b/WeChat/Template.php
deleted file mode 100644
index 5cbe498..0000000
--- a/WeChat/Template.php
+++ /dev/null
@@ -1,104 +0,0 @@
-callPostApi($url, ['industry_id1' => $industryId1, 'industry_id2' => $industryId2]);
- }
-
- /**
- * 获取已设置的行业信息
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getIndustry()
- {
- $url = "https://api.weixin.qq.com/cgi-bin/template/get_industry?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 领取模板 ID
- * @param string $templateIdShort 模板编号(如 TM** 或 OPENTMTM**)
- * @param array $keywordNameList 选用关键词
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function addTemplate($templateIdShort, $keywordNameList = [])
- {
- $url = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['template_id_short' => $templateIdShort, 'keyword_name_list' => $keywordNameList]);
- }
-
- /**
- * 获取私有模板列表
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getAllPrivateTemplate()
- {
- $url = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 删除模板
- * @param string $tplId 模板 ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function delPrivateTemplate($tplId)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['template_id' => $tplId]);
- }
-
- /**
- * 发送模板消息
- * @param array $data 消息内容(touser, template_id, data 等)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function send(array $data)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data);
- }
-}
\ No newline at end of file
diff --git a/WeChat/User.php b/WeChat/User.php
deleted file mode 100644
index 49155bf..0000000
--- a/WeChat/User.php
+++ /dev/null
@@ -1,139 +0,0 @@
-callPostApi($url, ['openid' => $openid, 'remark' => $remark]);
- }
-
- /**
- * 获取用户基本信息接口(包括UnionID)
- * @param string $openid 用户openid
- * @param string $lang 返回国家地区语言版本(zh_CN, zh_TW, en)
- * @return array 用户信息(nickname, headimgurl, sex, province, city, country, unionid等)
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getUserInfo($openid, $lang = 'zh_CN')
- {
- $url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid={$openid}&lang={$lang}";
- return $this->callGetApi($url);
- }
-
- /**
- * 批量获取用户基本信息接口
- * @param array $openids 用户openid列表(最多100个)
- * @param string $lang 返回国家地区语言版本
- * @return array 用户信息列表
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getBatchUserInfo(array $openids, $lang = 'zh_CN')
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN';
- $data = ['user_list' => []];
- foreach ($openids as $openid) {
- $data['user_list'][] = ['openid' => $openid, 'lang' => $lang];
- }
- return $this->callPostApi($url, $data);
- }
-
- /**
- * 获取用户列表接口
- * @param string $next_openid 第一个拉取的openid,不填默认从头开始拉取
- * @return array 用户列表(total, count, data.openid, next_openid)
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getUserList($next_openid = '')
- {
- $url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid={$next_openid}";
- return $this->callGetApi($url);
- }
-
- /**
- * 获取标签下粉丝列表接口
- * @param integer $tagid 标签ID
- * @param string $nextOpenid 第一个拉取的openid,不填默认从头开始拉取
- * @return array 粉丝列表(count, data.openid, next_openid)
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getUserListByTag($tagid, $nextOpenid = '')
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['tagid' => $tagid, 'next_openid' => $nextOpenid]);
- }
-
- /**
- * 获取公众号黑名单列表接口
- * @param string $beginOpenid 第一个拉取的openid,不填默认从头开始拉取
- * @return array 黑名单列表(total, count, data.openid, next_openid)
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getBlackList($beginOpenid = '')
- {
- $url = "https://api.weixin.qq.com/cgi-bin/tags/members/getblacklist?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['begin_openid' => $beginOpenid]);
- }
-
- /**
- * 批量拉黑用户接口
- * @param array $openids 用户openid列表(最多20个)
- * @return array 操作结果
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function batchBlackList(array $openids)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchblacklist?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['openid_list' => $openids]);
- }
-
- /**
- * 批量取消拉黑用户接口
- * @param array $openids 用户openid列表(最多20个)
- * @return array 操作结果
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function batchUnblackList(array $openids)
- {
- $url = "https://api.weixin.qq.com/cgi-bin/tags/members/batchunblacklist?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['openid_list' => $openids]);
- }
-}
\ No newline at end of file
diff --git a/WeChat/Wifi.php b/WeChat/Wifi.php
deleted file mode 100644
index 6c4ec5d..0000000
--- a/WeChat/Wifi.php
+++ /dev/null
@@ -1,285 +0,0 @@
-registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['pageindex' => $pageindex, 'pagesize' => $pagesize]);
- }
-
- /**
- * 查询门店 Wi-Fi 信息
- * @param int $shop_id 门店ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getShopWifi($shop_id)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/shop/list?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id]);
- }
-
- /**
- * 修改门店 Wi-Fi
- * @param int $shop_id 门店ID
- * @param string $old_ssid 原 SSID
- * @param string $ssid 新 SSID
- * @param string $password 可选密码
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function upShopWifi($shop_id, $old_ssid, $ssid, $password = null)
- {
- $data = ['shop_id' => $shop_id, 'old_ssid' => $old_ssid, 'ssid' => $ssid];
- is_null($password) || $data['password'] = $password;
- $url = 'https://api.weixin.qq.com/bizwifi/shop/update?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, $data);
- }
-
- /**
- * 清空门店网络与设备
- * @param int $shop_id 门店ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function clearShopWifi($shop_id)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/shop/clean?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id]);
- }
-
- /**
- * 添加密码型设备
- * @param int $shop_id 门店ID
- * @param string $ssid SSID
- * @param null|string $password 密码
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function addShopWifi($shop_id, $ssid, $password = null)
- {
- $data = ['shop_id' => $shop_id, 'ssid' => $ssid, 'password' => $password];
- $url = 'https://api.weixin.qq.com/bizwifi/device/add?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, $data);
- }
-
- /**
- * 添加 portal 型设备
- * @param int $shop_id 门店ID
- * @param string $ssid SSID
- * @param bool $reset 是否重置 secretkey
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function addShopPortal($shop_id, $ssid, $reset = false)
- {
- $data = ['shop_id' => $shop_id, 'ssid' => $ssid, 'reset' => $reset];
- $url = 'https://api.weixin.qq.com/bizwifi/apportal/register?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, $data);
- }
-
- /**
- * 查询设备
- * @param int|null $shop_id 门店ID
- * @param int|null $pageindex 页码
- * @param int|null $pagesize 数量
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function queryShopWifi($shop_id = null, $pageindex = null, $pagesize = null)
- {
- $data = [];
- is_null($pagesize) || $data['pagesize'] = $pagesize;
- is_null($pageindex) || $data['pageindex'] = $pageindex;
- is_null($shop_id) || $data['shop_id'] = $shop_id;
- $url = 'https://api.weixin.qq.com/bizwifi/device/list?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, $data);
- }
-
- /**
- * 删除设备
- * @param string $bssid 设备 MAC,冒号分隔小写
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function delShopWifi($bssid)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/device/delete?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['bssid' => $bssid]);
- }
-
- /**
- * 获取物料二维码
- * @param int $shop_id 门店ID
- * @param string $ssid SSID
- * @param int $img_id 物料样式 0|1
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getQrc($shop_id, $ssid, $img_id = 1)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/qrcode/get?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id, 'ssid' => $ssid, 'img_id' => $img_id]);
- }
-
- /**
- * 设置商家主页
- * @param int $shop_id 门店ID
- * @param int $template_id 0 默认 | 1 自定义链接
- * @param null|string $url 自定义链接(template_id=1 必填)
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setHomePage($shop_id, $template_id, $url = null)
- {
- $data = ['shop_id' => $shop_id, 'template_id' => $template_id];
- !is_null($url) && $data['struct'] = ['url' => $url];
- $url = 'https://api.weixin.qq.com/bizwifi/homepage/set?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, $data);
- }
-
- /**
- * 查询商家主页
- * @param int $shop_id 门店ID
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getHomePage($shop_id)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/homepage/get?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id]);
- }
-
- /**
- * 设置微信首页欢迎语
- * @param int $shop_id 门店ID
- * @param int $bar_type 0|1|2|3
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setBar($shop_id, $bar_type = 1)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/bar/set?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id, 'bar_type' => $bar_type]);
- }
-
- /**
- * 设置连网完成页
- * @param int $shop_id 门店ID
- * @param string $finishpage_url 完成页 URL
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setFinishPage($shop_id, $finishpage_url)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/finishpage/set?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id, 'finishpage_url' => $finishpage_url]);
- }
-
- /**
- * Wi-Fi 数据统计
- * @param string $begin_date 开始日期 yyyy-mm-dd
- * @param string $end_date 结束日期 yyyy-mm-dd
- * @param int $shop_id 门店ID,-1 总统计
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function staticList($begin_date, $end_date, $shop_id = -1)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/statistics/list?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id, 'begin_date' => $begin_date, 'end_date' => $end_date]);
- }
-
- /**
- * 设置门店卡券投放
- * @param int $shop_id 门店ID,0 表示全部
- * @param int $card_id 卡券ID
- * @param string $card_describe 描述(<=18 字符)
- * @param string $start_time 开始时间戳
- * @param string $end_time 结束时间戳
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function setCouponput($shop_id, $card_id, $card_describe, $start_time, $end_time)
- {
- $data = ['shop_id' => $shop_id, 'card_id' => $card_id, 'card_describe' => $card_describe, 'start_time' => $start_time, 'end_time' => $end_time];
- $url = 'https://api.weixin.qq.com/bizwifi/couponput/set?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, $data);
- }
-
- /**
- * 查询门店卡券投放
- * @param int $shop_id 门店ID,0 表示全部
- * @return array
- * @throws Exceptions\InvalidResponseException
- * @throws Exceptions\LocalCacheException
- */
- public function getCouponput($shop_id)
- {
- $url = 'https://api.weixin.qq.com/bizwifi/couponput/get?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['shop_id' => $shop_id]);
- }
-
-}
\ No newline at end of file
diff --git a/WeMini/Crypt.php b/WeMini/Crypt.php
deleted file mode 100644
index 139d1fc..0000000
--- a/WeMini/Crypt.php
+++ /dev/null
@@ -1,122 +0,0 @@
-session($code);
- if (empty($result['session_key'])) {
- throw new InvalidResponseException('Code 换取 SessionKey 失败', 403);
- }
- $userinfo = $this->decode($iv, $result['session_key'], $encryptedData);
- if (empty($userinfo)) {
- throw new InvalidDecryptException('用户信息解析失败', 403);
- }
- return array_merge($result, $userinfo);
- }
-
- /**
- * code 换取 session_key
- * @param string $code 登录 code
- * @return array
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function session($code)
- {
- $appid = $this->config->get('appid');
- $secret = $this->config->get('appsecret');
- $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appid}&secret={$secret}&js_code={$code}&grant_type=authorization_code";
- return json_decode(Tools::get($url), true);
- }
-
- /**
- * 解密数据
- * @param string $iv 初始向量
- * @param string $sessionKey 会话密钥
- * @param string $encryptedData 加密数据
- * @return bool|array
- */
- public function decode($iv, $sessionKey, $encryptedData)
- {
- require_once __DIR__ . DIRECTORY_SEPARATOR . 'crypt' . DIRECTORY_SEPARATOR . 'wxBizDataCrypt.php';
- $pc = new WXBizDataCrypt($this->config->get('appid'), $sessionKey);
- $data = '';
- $errCode = $pc->decryptData($encryptedData, $iv, $data);
- if ($errCode == 0) {
- return json_decode($data, true);
- }
- return false;
- }
-
- /**
- * 通过 code 获取手机号
- * @param string $code 授权码
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPhoneNumber($code)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->httpPostForJson($url, ['code' => $code], true);
- }
-
- /**
- * 支付后获取用户 UnionId
- * @param string $openid 用户 openid
- * @param null|string $transaction_id 微信支付订单号
- * @param null|string $mch_id 商户号
- * @param null|string $out_trade_no 商户订单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPaidUnionId($openid, $transaction_id = null, $mch_id = null, $out_trade_no = null)
- {
- $url = "https://api.weixin.qq.com/wxa/getpaidunionid?access_token=ACCESS_TOKEN&openid={$openid}";
- if (!is_null($mch_id)) $url .= "&mch_id={$mch_id}";
- if (!is_null($out_trade_no)) $url .= "&out_trade_no={$out_trade_no}";
- if (!is_null($transaction_id)) $url .= "&transaction_id={$transaction_id}";
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callGetApi($url);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Custom.php b/WeMini/Custom.php
deleted file mode 100644
index 39cc378..0000000
--- a/WeMini/Custom.php
+++ /dev/null
@@ -1,221 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 创建商户
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function businessRegister($data)
- {
- $url = 'https://api.weixin.qq.com/cgi‐bin/business/register?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 更新商户信息
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function businessUpdate($data)
- {
- $url = 'https://api.weixin.qq.com/cgi‐bin/business/update?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 拉取单个商户信息
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function businessGet($data)
- {
- $url = 'https://api.weixin.qq.com/cgi‐bin/business/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 拉取多个商户信息
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function businessList($data)
- {
- $url = 'https://api.weixin.qq.com/cgi‐bin/business/list?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 发送客服消息
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function businessSend($data)
- {
- $url = 'https://api.weixin.qq.com/cgi‐bin/message/custom/business/send?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 客服输入状态
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function businessTyping($data)
- {
- $url = 'https://api.weixin.qq.com/cgi‐bin/message/custom/business/typing?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 获取客服基本信息
- * @param string $business_id 客服子商户的business_id,对于普通小程序客服不需要填business_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getKfList($business_id = '')
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN';
- if (!empty($business_id)) {
- $url .= '&business_id=' . $business_id;
- }
- return $this->callGetApi($url);
- }
-
-
- /**
- * 获取在线客服列表
- * @param string $business_id 客服子商户的business_id,对于普通小程序客服不需要填business_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getOnlineKfList($business_id = '')
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/customservice/getonlinekflist?access_token=ACCESS_TOKEN';
- if (!empty($business_id)) {
- $url .= '&business_id=' . $business_id;
- }
- return $this->callGetApi($url);
- }
-
-
- /**
- * 客服输入状态
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addKfAccount($data)
- {
- $url = 'https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 删除客服账号
- * @param string $kf_openid 客服openid
- * @param string $business_id 客服子商户的business_id,对于普通小程序客服不需要填business_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delKfAccount($kf_openid, $business_id = '')
- {
- $url = 'https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN&kf_openid=' . $kf_openid;
- if (!empty($business_id)) {
- $url .= '&business_id=' . $business_id;
- }
- return $this->callGetApi($url);
- }
-
- /**
- * 设置客服管理员
- * @param string $kf_openid 客服openid
- * @param string $business_id 客服子商户的business_id,对于普通小程序客服不需要填business_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setKfAdmin($kf_openid, $business_id = '')
- {
- $url = 'https://api.weixin.qq.com/customservice/kfaccount/setadmin?access_token=ACCESS_TOKEN&kf_openid=' . $kf_openid;
- if (!empty($business_id)) {
- $url .= '&business_id=' . $business_id;
- }
- return $this->callGetApi($url);
- }
-
-
- /**
- * 取消客服管理员
- * @param string $kf_openid 客服openid
- * @param string $business_id 客服子商户的business_id,对于普通小程序客服不需要填business_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function cancelKfAdmin($kf_openid, $business_id = '')
- {
- $url = 'https://api.weixin.qq.com/customservice/kfaccount/canceladmin?access_token=ACCESS_TOKEN&kf_openid=' . $kf_openid;
- if (!empty($business_id)) {
- $url .= '&business_id=' . $business_id;
- }
- return $this->callGetApi($url);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Delivery.php b/WeMini/Delivery.php
deleted file mode 100644
index ad97902..0000000
--- a/WeMini/Delivery.php
+++ /dev/null
@@ -1,171 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 下配送单
- * @param array $data 订单信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/order/add?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 待接单订单加小费
- * @param array $data 订单与小费信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addTip($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/order/addtips?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 取消配送单
- * @param array $data 订单信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function cancelOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/order/cancel?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取配送公司列表
- * @param array $data 请求参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getAllImmeDelivery($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/delivery/getall?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 拉取已绑定账号
- * @param array $data 请求参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getBindAccount($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/shop/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询配送单
- * @param array $data 订单信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/order/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 模拟更新配送单状态
- * @param array $data 模拟参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function mockUpdateOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/test_update_order?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 预下单
- * @param array $data 订单信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function preAddOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/order/pre_add?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 预取消配送单
- * @param array $data 订单信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function preCancelOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/order/precancel?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 重新下单
- * @param array $data 订单信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function reOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/local/business/order/readd?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-}
\ No newline at end of file
diff --git a/WeMini/Guide.php b/WeMini/Guide.php
deleted file mode 100644
index c0a2241..0000000
--- a/WeMini/Guide.php
+++ /dev/null
@@ -1,527 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 删除导购
- * @param array $data 导购账号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delGuideAcct($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/delguideacct?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取导购信息
- * @param array $data 导购账号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideAcct($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguideacct?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取敏感词与自动回复配置
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideAcctConfig()
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguideacctconfig?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, [], true);
- }
-
- /**
- * 拉取导购列表
- * @param int $page 页码
- * @param int $num 数量
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideAcctList($page = 0, $num = 10)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguideacctconfig?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['page' => $page, 'num' => $num], true);
- }
-
- /**
- * 获取导购聊天记录
- * @param array $data 查询条件
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideBuyerChatRecord($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguideacct?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取导购快捷回复
- * @param array $data 导购信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideConfig($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguideconfig?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 生成导购二维码
- * @param array $data 导购信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function guideCreateQrCode($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/guidecreateqrcode?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 推送小程序路径菜单
- * @param array $data 请求参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function pushShowWxaPathMenu($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/pushshowwxapathmenu?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 设置敏感词与自动回复
- * @param array $data 配置数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setGuideAcctConfig($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/setguideacctconfig?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 设置导购快捷回复
- * @param array $data 快捷回复数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setGuideConfig($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/setguideconfig?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 更新导购昵称或头像
- * @param array $data 导购信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateGuideAcct($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/setguideconfig?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 添加展示标签
- * @param array $data 标签数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addGuideBuyerDisplayTag($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/addguidebuyerdisplaytag?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 为粉丝添加可查询标签
- * @param array $data 标签数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addGuideBuyerTag($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/addguidebuyertag?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 添加标签可选值
- * @param array $data 选项数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addGuideTagOption($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/addguidetagoption?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除粉丝标签
- * @param array $data 标签数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delGuideBuyerTag($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/delguidebuyertag?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询展示标签
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideBuyerDisplayTag($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerdisplaytag?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询粉丝标签
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideBuyerTag($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidebuyertag?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询标签可选值
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideTagOption()
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidetagoption?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, [], true);
- }
-
- /**
- * 新建可查询标签类型
- * @param array $data 标签数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function newGuideTagOption($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/newguidetagoption?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 标签筛选粉丝
- * @param array $data 标签查询条件
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryGuideBuyerByTag($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/queryguidebuyerbytag?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 导购添加粉丝
- * @param array $data 绑定数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addGuideBuyerRelation($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/addguidebuyerrelation?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除导购粉丝
- * @param array $data 解绑数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delGuideBuyerRelation($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/delguidebuyerrelation?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询粉丝绑定关系
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideBuyerRelation($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerrelation?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 通过粉丝查询绑定关系
- * @param string $openid 粉丝 openid
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideBuyerRelationByBuyer($openid)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerrelation?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, ['openid' => $openid], true);
- }
-
- /**
- * 拉取导购粉丝列表
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideBuyerRelationList($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidebuyerrelationlist?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 粉丝迁移导购
- * @param array $data 迁移数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function rebindGuideAcctForBuyer($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/rebindguideacctforbuyer?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 更新粉丝昵称
- * @param array $data 昵称数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateGuideBuyerRelation($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/updateguidebuyerrelation?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除卡片素材
- * @param array $data 素材信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delGuideCardMaterial($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/delguidecardmaterial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除图片素材
- * @param array $data 素材信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delGuideImageMaterial($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/delguideimagematerial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除文字素材
- * @param array $data 素材信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delGuideWordMaterial($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/delguidewordmaterial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取卡片素材
- * @param int $type 类型
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideCardMaterial($type = 0)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidecardmaterial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, ['type' => $type], true);
- }
-
- /**
- * 获取图片素材
- * @param int $type 类型
- * @param int $start 起始
- * @param int $num 数量
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideImageMaterial($type = 0, $start = 0, $num = 10)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguideimagematerial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, ['type' => $type, 'start' => $start, 'num' => $num], true);
- }
-
- /**
- * 获取文字素材
- * @param int $type 类型
- * @param int $start 起始
- * @param int $num 数量
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGuideWordMaterial($type = 0, $start = 0, $num = 10)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/getguidewordmaterial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, ['type' => $type, 'start' => $start, 'num' => $num], true);
- }
-
- /**
- * 添加卡片素材
- * @param array $data 素材数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setGuideCardMaterial($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/setguidecardmaterial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 添加图片素材
- * @param array $data 素材数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setGuideImageMaterial($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/setguideimagematerial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 添加文字素材
- * @param array $data 素材数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setGuideWordMaterial($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/guide/setguidewordmaterial?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->callPostApi($url, $data, true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Image.php b/WeMini/Image.php
deleted file mode 100644
index 6101baf..0000000
--- a/WeMini/Image.php
+++ /dev/null
@@ -1,69 +0,0 @@
-callPostApi($url, ['img_url' => $img_url, 'img' => $img], true);
- }
-
- /**
- * 条码/二维码识别
- * @param string $img_url 图片 URL(与 img 二选一)
- * @param string $img form-data 媒体文件(与 img_url 二选一)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function scanQRCode($img_url, $img)
- {
- $url = "https://api.weixin.qq.com/cv/img/qrcode?img_url=ENCODE_URL&access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['img_url' => $img_url, 'img' => $img], true);
- }
-
- /**
- * 图片高清化
- * @param string $img_url 图片 URL(与 img 二选一)
- * @param string $img form-data 媒体文件(与 img_url 二选一)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function superresolution($img_url, $img)
- {
- $url = "https://api.weixin.qq.com/cv/img/qrcode?img_url=ENCODE_URL&access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['img_url' => $img_url, 'img' => $img], true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Insurance.php b/WeMini/Insurance.php
deleted file mode 100644
index 18173f6..0000000
--- a/WeMini/Insurance.php
+++ /dev/null
@@ -1,208 +0,0 @@
-callPostApi($url, [], true);
- }
-
- /**
- * 查询开通状态
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryOpen()
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/query_open?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, [], true);
- }
-
- /**
- * 发货投保
- * @param array $data 投保数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createOrder($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/createorder?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 退货理赔
- * @param array $data 理赔数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function claim($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/claim?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 申请充值订单号
- * @param array $data 充值请求
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createChargeId($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/createchargeid?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 申请支付
- * @param array $data 支付数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function applyPay($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/applypay?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 拉取充值订单
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPayOrderList($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/getpayorderlist?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 保险退款
- * @param array $data 退款参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function refund($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/refund?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取保费摘要
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getSummary($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/getsummary?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 拉取保单信息
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getOrderList($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/getorderlist?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 设置告警余额
- * @param array $data 配置参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateNotifyFunds($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/insurance_freight/update_notify_funds?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 创建退货 ID
- * @param array $data 退货参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function returnAdd($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/delivery/no_worry_return/add?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询退货 ID 状态
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function returnGet($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/delivery/no_worry_return/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 解绑退货 ID
- * @param array $data 解绑参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function returnUbind($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/delivery/no_worry_return/unbind?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Live.php b/WeMini/Live.php
deleted file mode 100644
index bf7095c..0000000
--- a/WeMini/Live.php
+++ /dev/null
@@ -1,517 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 获取直播房间列表
- * @param int $start 起始
- * @param int $limit 数量
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getLiveList($start = 0, $limit = 10)
- {
- $url = 'https://api.weixin.qq.com/wxa/business/getliveinfo?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['start' => $start, 'limit' => $limit], true);
- }
-
- /**
- * 获取直播/回放信息
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getLiveInfo($data = [])
- {
- $url = 'https://api.weixin.qq.com/wxa/business/getliveinfo?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 直播间导入商品
- * @param array $data 商品列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addLiveGoods($data = [])
- {
- $url = 'https://api.weixin.qq.com/wxaapi/broadcast/room/addgoods?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 商品添加并提审
- * @param array $data 商品信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addGoods($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/add?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 撤回商品审核
- * @param array $data 商品信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function resetAuditGoods($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/resetaudit?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 重新提交商品审核
- * @param array $data 商品信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function auditGoods($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/audit?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除商品
- * @param array $data 商品信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function deleteGoods($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/delete?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 更新商品
- * @param array $data 商品信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateGoods($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/update?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取商品状态
- * @param array $data 商品ID列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function stateGoods($data)
- {
- $url = "https://api.weixin.qq.com/wxa/business/getgoodswarehouse?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取商品列表
- * @param int $offset 起始
- * @param int $status 0 未审 |1 审核中 |2 通过 |3 驳回
- * @param int $limit 数量(<=100)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getGoods($offset, $status, $limit = 30)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/getapproved?access_token=ACCESS_TOKEN&offset={$offset}&limit={$limit}&status={$status}";
- return $this->callGetApi($url);
- }
-
- /**
- * 删除直播间
- * @param array $data 房间信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delLive($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/deleteroom?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 编辑直播间
- * @param array $data 房间信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function editLive($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/editroom?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取推流地址
- * @param string $roomId 房间ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPushUrl($roomId)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/getpushurl?access_token=ACCESS_TOKEN&roomId={$roomId}";
- return $this->callGetApi($url);
- }
-
- /**
- * 获取直播间分享码
- * @param string $roomId 房间ID
- * @param string $params 自定义参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getShareCode($roomId, $params = '')
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/getsharedcode?access_token=ACCESS_TOKEN&roomId={$roomId}¶ms={$params}";
- return $this->callGetApi($url);
- }
-
- /**
- * 添加小助手
- * @param array $data 助手信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addAssistant($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/addassistant?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 修改小助手
- * @param array $data 助手信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function modifyAssistant($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/modifyassistant?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除小助手
- * @param array $data 助手信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function removeAssistant($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/removeassistant?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询小助手列表
- * @param string $roomId 房间ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getAssistantList($roomId)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/getassistantlist?access_token=ACCESS_TOKEN&roomId={$roomId}";
- return $this->callGetApi($url);
- }
-
- /**
- * 添加主播副号
- * @param array $data 副号信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addSubAnchor($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/addsubanchor?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 修改主播副号
- * @param array $data 副号信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function modifySubAnchor($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/modifysubanchor?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除主播副号
- * @param array $data 副号信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delSubAnchor($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/deletesubanchor?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询主播副号
- * @param string $roomId 房间ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getSubAnchor($roomId)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/getsubanchor?access_token=ACCESS_TOKEN&roomId={$roomId}";
- return $this->callGetApi($url);
- }
-
- /**
- * 开关官方收录
- * @param array $data 房间配置
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateFeedPublic($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatefeedpublic?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 开关回放
- * @param array $data 房间配置
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateReplay($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatereplay?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 开关客服
- * @param array $data 房间配置
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateKf($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatekf?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 开关全局禁言
- * @param array $data 房间配置
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateComment($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/room/updatecomment?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 上下架商品
- * @param array $data 商品参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function goodsOnsale($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/onsale?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 删除直播间商品
- * @param array $data 商品参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function goodsDeleteInRoom($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/deleteInRoom?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 推送商品
- * @param array $data 商品参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function goodsPush($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/push?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 商品排序
- * @param array $data 排序参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function goodsSort($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/sort?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 下载商品讲解视频
- * @param array $data 商品信息
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getVideo($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/goods/getVideo?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取长期订阅用户
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getFollowers($data)
- {
- $url = "https://api.weixin.qq.com/wxa/business/get_wxa_followers?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 长订阅群发
- * @param array $data 消息参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function pushMessage($data)
- {
- $url = "https://api.weixin.qq.com/wxa/business/push_message?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 设置成员角色
- * @param array $data 角色参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addRole($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/role/addrole?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 解除成员角色
- * @param array $data 角色参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delRole($data)
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/role/deleterole?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 查询成员角色
- * @param int $role 角色过滤,-1 全部
- * @param int $offset 起始
- * @param int $limit 数量
- * @param string $keyword 关键词
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getRole($role = -1, $offset = 0, $limit = 30, $keyword = '')
- {
- $url = "https://api.weixin.qq.com/wxaapi/broadcast/role/getrolelist?access_token=ACCESS_TOKEN&offset={$offset}&limit={$limit}&keyword={$keyword}&role={$role}";
- return $this->callGetApi($url);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Logistics.php b/WeMini/Logistics.php
deleted file mode 100644
index 596bd33..0000000
--- a/WeMini/Logistics.php
+++ /dev/null
@@ -1,236 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 取消运单
- * @param array $data 取消参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function cancelOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/order/cancel?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取快递公司列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getAllDelivery()
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/delivery/getall?access_token=ACCESS_TOKEN';
- return $this->callGetApi($url);
- }
-
- /**
- * 获取运单数据
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/order/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询运单轨迹
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPath($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/path/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取打印员列表(需使用微信打单时调用)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPrinter()
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/printer/getall?access_token=ACCESS_TOKEN';
- return $this->callGetApi($url);
- }
-
- /**
- * 获取电子面单余额(加盟类快递)
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getQuota($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/quota/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 模拟更新订单状态(测试用)
- * @param array $data 模拟参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function testUpdateOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/test_update_order?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 配置面单打印员(微信打单)
- * @param array $data 配置参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updatePrinter($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/printer/update?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取面单联系人信息
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getContact($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/delivery/contact/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 预览面单模板(调试用)
- * @param array $data 模板参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function previewTemplate($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/delivery/template/preview?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 更新商户审核结果
- * @param array $data 审核结果
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updateBusiness($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/delivery/service/business/update?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 更新运单轨迹
- * @param array $data 轨迹参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function updatePath($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/delivery/path/update?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 绑定/解绑物流账号
- * @param array $data 账号参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function bindAccount($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/account/bind?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
- /**
- * 获取已绑定的物流账号列表
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getAllAccount($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/account/getall?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 批量获取运单数据
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function batchGetOrder($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/express/business/order/batchget?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
-}
\ No newline at end of file
diff --git a/WeMini/Market.php b/WeMini/Market.php
deleted file mode 100644
index be41f43..0000000
--- a/WeMini/Market.php
+++ /dev/null
@@ -1,54 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 拉取服务结果
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function retrieve($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/servicemarketretrieve?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
-}
\ No newline at end of file
diff --git a/WeMini/Media.php b/WeMini/Media.php
deleted file mode 100644
index ecde99d..0000000
--- a/WeMini/Media.php
+++ /dev/null
@@ -1,54 +0,0 @@
-callGetApi($url);
- }
-
- /**
- * 新增图片素材
- * @param string $filename 本地文件
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function upload($filename)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=image';
- return $this->callPostApi($url, ['media' => Tools::createCurlFile($filename)], false);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Message.php b/WeMini/Message.php
deleted file mode 100644
index 5175cf8..0000000
--- a/WeMini/Message.php
+++ /dev/null
@@ -1,65 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 修改动态消息
- * @param array $data 消息数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setUpdatableMsg($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/updatablemsg/send?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 统一服务消息下发
- * @param array $data 消息内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function uniformSend($data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Newtmpl.php b/WeMini/Newtmpl.php
deleted file mode 100644
index fccb00f..0000000
--- a/WeMini/Newtmpl.php
+++ /dev/null
@@ -1,144 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 获取账号类目
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getCategory()
- {
- $url = 'https://api.weixin.qq.com/wxaapi/newtmpl/getcategory?access_token=ACCESS_TOKEN';
- return $this->callGetApi($url);
- }
-
- /**
- * 删除账号类目
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function deleteCategory()
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/wxopen/deletecategory?access_token=TOKEN';
- return $this->callPostApi($url, [], true);
- }
-
- /**
- * 获取类目下公共模板标题
- * @param string $ids 类目ID,逗号分隔
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPubTemplateTitleList($ids)
- {
- $url = 'https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatetitles?access_token=ACCESS_TOKEN';
- $url .= '&' . http_build_query(['ids' => $ids, 'start' => '0', 'limit' => '30']);
- return $this->callGetApi($url);
- }
-
- /**
- * 获取模板标题关键词
- * @param string $tid 模板标题ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getPubTemplateKeyWordsById($tid)
- {
- $url = 'https://api.weixin.qq.com/wxaapi/newtmpl/getpubtemplatekeywords?access_token=ACCESS_TOKEN';
- $url .= '&' . http_build_query(['tid' => $tid]);
- return $this->callGetApi($url);
- }
-
- /**
- * 组合模板并入库
- * @param string $tid 模板标题ID
- * @param array $kidList 关键词ID列表
- * @param string $sceneDesc 场景描述
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addTemplate($tid, array $kidList, $sceneDesc = '')
- {
- $url = 'https://api.weixin.qq.com/wxaapi/newtmpl/addtemplate?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['tid' => $tid, 'kidList' => $kidList, 'sceneDesc' => $sceneDesc], false);
- }
-
- /**
- * 获取个人模板列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getTemplateList()
- {
- $url = 'https://api.weixin.qq.com/wxaapi/newtmpl/gettemplate?access_token=ACCESS_TOKEN';
- return $this->callGetApi($url);
- }
-
- /**
- * 删除个人模板
- * @param string $priTmplId 模板ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delTemplate($priTmplId)
- {
- $url = 'https://api.weixin.qq.com/wxaapi/newtmpl/deltemplate?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['priTmplId' => $priTmplId], true);
- }
-
- /**
- * 发送订阅消息
- * @param array $data 消息数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function send(array $data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Ocr.php b/WeMini/Ocr.php
deleted file mode 100644
index 7dc4f60..0000000
--- a/WeMini/Ocr.php
+++ /dev/null
@@ -1,104 +0,0 @@
-callPostApi($url, $data, false);
- }
-
- /**
- * 营业执照 OCR
- * @param array $data 图片参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function businessLicense($data)
- {
- $url = 'https://api.weixin.qq.com/cv/ocr/bizlicense?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, false);
- }
-
- /**
- * 驾驶证 OCR
- * @param array $data 图片参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function driverLicense($data)
- {
- $url = 'https://api.weixin.qq.com/cv/ocr/drivinglicense?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, false);
- }
-
- /**
- * 身份证 OCR
- * @param array $data 图片参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function idcard($data)
- {
- $url = 'https://api.weixin.qq.com/cv/ocr/idcard?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, false);
- }
-
- /**
- * 通用印刷体 OCR
- * @param array $data 图片参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function printedText($data)
- {
- $url = 'https://api.weixin.qq.com/cv/ocr/comm?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, false);
- }
-
- /**
- * 行驶证 OCR
- * @param array $data 图片参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function vehicleLicense($data)
- {
- $url = 'https://api.weixin.qq.com/cv/ocr/driving?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, false);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Operation.php b/WeMini/Operation.php
deleted file mode 100644
index 09773e0..0000000
--- a/WeMini/Operation.php
+++ /dev/null
@@ -1,69 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 获取反馈媒体文件
- * @param array $data query 参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getFeedbackmedia($data)
- {
- $query = http_build_query($data);
- $url = 'https://api.weixin.qq.com/cgi-bin/media/getfeedbackmedia?' . $query . '&access_token=ACCESS_TOKEN';
- return $this->callGetApi($url);
- }
-
-
- /**
- * 获取用户反馈列表
- * @param array $data query 参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getFeedback($data)
- {
- $query = http_build_query($data);
- $url = 'https://api.weixin.qq.com/wxaapi/userlog/userlog_search?' . $query . '&access_token=ACCESS_TOKEN';
- return $this->callGetApi($url);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Plugs.php b/WeMini/Plugs.php
deleted file mode 100644
index ce244bf..0000000
--- a/WeMini/Plugs.php
+++ /dev/null
@@ -1,105 +0,0 @@
-callPostApi($url, ['action' => 'apply', 'plugin_appid' => $plugin_appid], true);
- }
-
- /**
- * 查询已添加插件
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getList()
- {
- $url = 'https://api.weixin.qq.com/wxa/plugin?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['action' => 'list'], true);
- }
-
- /**
- * 删除插件
- * @param string $plugin_appid 插件 appid
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function unbind($plugin_appid)
- {
- $url = 'https://api.weixin.qq.com/wxa/plugin?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['action' => 'unbind', 'plugin_appid' => $plugin_appid], true);
- }
-
- /**
- * 获取插件使用方或修改申请状态
- * @param array $data 请求参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function devplugin($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/devplugin?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 获取插件使用方列表(开发者)
- * @param int $page 页码
- * @param int $num 每页数量
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function devApplyList($page = 1, $num = 10)
- {
- $url = 'https://api.weixin.qq.com/wxa/plugin?access_token=ACCESS_TOKEN';
- $data = ['action' => 'dev_apply_list', 'page' => $page, 'num' => $num];
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 修改插件申请状态(开发者)
- * @param string $action dev_agree|dev_refuse|dev_delete
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function devAgree($action = 'dev_agree')
- {
- $url = 'https://api.weixin.qq.com/wxa/plugin?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['action' => $action], true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Poi.php b/WeMini/Poi.php
deleted file mode 100644
index bd31b37..0000000
--- a/WeMini/Poi.php
+++ /dev/null
@@ -1,87 +0,0 @@
- $related_name, 'related_credential' => $related_credential,
- 'related_address' => $related_address, 'related_proof_material' => $related_proof_material,
- ];
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查看地点列表
- * @param int $page 页码从1开始
- * @param int $page_rows 每页数量(<=1000)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getNearByPoiList($page = 1, $page_rows = 1000)
- {
- $url = "https://api.weixin.qq.com/wxa/getnearbypoilist?page={$page}&page_rows={$page_rows}&access_token=ACCESS_TOKEN";
- return $this->callGetApi($url);
- }
-
- /**
- * 删除附近地点
- * @param string $poi_id 地点ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delNearByPoiList($poi_id)
- {
- $url = "https://api.weixin.qq.com/wxa/delnearbypoi?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['poi_id' => $poi_id], true);
- }
-
- /**
- * 设置附近小程序展示
- * @param string $poi_id 地点ID
- * @param string $status 0 取消 | 1 展示
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setNearByPoiShowStatus($poi_id, $status)
- {
- $url = "https://api.weixin.qq.com/wxa/setnearbypoishowstatus?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, ['poi_id' => $poi_id, 'status' => $status], true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Qrcode.php b/WeMini/Qrcode.php
deleted file mode 100644
index 58ca8f3..0000000
--- a/WeMini/Qrcode.php
+++ /dev/null
@@ -1,119 +0,0 @@
- "0", "g" => "0", "b" => "0"];
-
- /**
- * 获取小程序码(永久有效)
- * 接口A: 适用于需要的码数量较少的业务场景
- * @param string $path 不能为空,最大长度 128 字节
- * @param integer $width 二维码的宽度
- * @param bool $autoColor 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
- * @param null|array $lineColor auto_color 为 false 时生效
- * @param boolean $isHyaline 透明底色
- * @param string|null $outType 输出类型
- * @param array $extra 其他参数
- * @return string|array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createMiniPath($path, $width = 430, $autoColor = false, $lineColor = null, $isHyaline = true, $outType = null, array $extra = [])
- {
- $url = 'https://api.weixin.qq.com/wxa/getwxacode?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- $lineColor = empty($lineColor) ? $this->lineColor : $lineColor;
- $data = ['path' => $path, 'width' => $width, 'auto_color' => $autoColor, 'line_color' => $lineColor, 'is_hyaline' => $isHyaline];
- return $this->parseResult(Tools::post($url, Tools::arr2json(array_merge($data, $extra))), $outType);
- }
-
- /**
- * 解释接口数据
- * @param bool|string $result
- * @param null|string $outType
- * @return array|mixed
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- private function parseResult($result, $outType)
- {
- if (is_array($json = json_decode($result, true))) {
- if (!$this->isTry && isset($json['errcode']) && in_array($json['errcode'], ['40014', '40001', '41001', '42001'])) {
- [$this->delAccessToken(), $this->isTry = true];
- return call_user_func_array([$this, $this->currentMethod['method']], $this->currentMethod['arguments']);
- }
- return Tools::json2arr($result);
- } else {
- return is_null($outType) ? $result : $outType($result);
- }
- }
-
- /**
- * 获取小程序码(永久有效)
- * 接口B:适用于需要的码数量极多的业务场景
- * @param string $scene 最大32个可见字符,只支持数字
- * @param string $page 必须是已经发布的小程序存在的页面
- * @param integer $width 二维码的宽度
- * @param bool $autoColor 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调
- * @param null|array $lineColor auto_color 为 false 时生效
- * @param bool $isHyaline 是否需要透明底色
- * @param null|string $outType 输出类型
- * @param array $extra 其他参数
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createMiniScene($scene, $page = '', $width = 430, $autoColor = false, $lineColor = null, $isHyaline = true, $outType = null, array $extra = [])
- {
- $url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- $lineColor = empty($lineColor) ? $this->lineColor : $lineColor;
- $data = ['scene' => $scene, 'width' => $width, 'page' => $page, 'auto_color' => $autoColor, 'line_color' => $lineColor, 'is_hyaline' => $isHyaline, 'check_path' => false];
- if (empty($page)) unset($data['page']);
- return $this->parseResult(Tools::post($url, Tools::arr2json(array_merge($data, $extra))), $outType);
- }
-
- /**
- * 获取小程序二维码(永久有效)
- * 接口C:适用于需要的码数量较少的业务场景
- * @param string $path 不能为空,最大长度 128 字节
- * @param integer $width 二维码的宽度
- * @param string|null $outType 输出类型
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function createDefault($path, $width = 430, $outType = null)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token=ACCESS_TOKEN';
- $this->registerApi($url, __FUNCTION__, func_get_args());
- return $this->parseResult(Tools::post($url, Tools::arr2json(['path' => $path, 'width' => $width])), $outType);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Scheme.php b/WeMini/Scheme.php
deleted file mode 100644
index 9ab78d8..0000000
--- a/WeMini/Scheme.php
+++ /dev/null
@@ -1,79 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 查询 URL-Scheme
- * @param string $scheme Scheme 字符串
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query($scheme)
- {
- $url = 'https://api.weixin.qq.com/wxa/queryscheme?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['scheme' => $scheme], true);
- }
-
- /**
- * 创建 URL-Link
- * @param array $data 场景参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function urlLink($data)
- {
- $url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=ACCESS_TOKEN";
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询 URL-Link
- * @param string $urllink URL-Link 字符串
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function urlQuery($urllink)
- {
- $url = 'https://api.weixin.qq.com/wxa/query_urllink?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['url_link' => $urllink], true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Search.php b/WeMini/Search.php
deleted file mode 100644
index d46abea..0000000
--- a/WeMini/Search.php
+++ /dev/null
@@ -1,39 +0,0 @@
-callPostApi($url, ['pages' => $pages], true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Security.php b/WeMini/Security.php
deleted file mode 100644
index 1a01fb0..0000000
--- a/WeMini/Security.php
+++ /dev/null
@@ -1,67 +0,0 @@
-callPostApi($url, ['media' => $media], false, ['headers' => ['Content-Type: application/octet-stream']]);
- }
-
- /**
- * 异步校验媒体(图片/音频)
- * @param string $media_url 媒体 URL
- * @param string $media_type 1 音频 | 2 图片
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function mediaCheckAsync($media_url, $media_type)
- {
- $url = 'https://api.weixin.qq.com/wxa/media_check_async?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['media_url' => $media_url, 'media_type' => $media_type], true);
- }
-
- /**
- * 文本内容安全校验
- * @param string $content 文本内容
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function msgSecCheck($content)
- {
- $url = 'https://api.weixin.qq.com/wxa/msg_sec_check?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['content' => $content], true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Shipping.php b/WeMini/Shipping.php
deleted file mode 100644
index 11522b1..0000000
--- a/WeMini/Shipping.php
+++ /dev/null
@@ -1,117 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 合单发货录入
- * @param array $data 发货数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function combined($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询发货状态
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/sec/order/get_order?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询发货订单列表
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function qlist($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/sec/order/get_order_list?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 提醒确认收货
- * @param array $data 提醒参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function confirm($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 设置消息跳转路径
- * @param array $data 路径参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function setJump($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询是否开通发货管理
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function isTrade($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/sec/order/is_trade_managed?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 查询交易结算确认状态
- * @param array $data 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function isCompleted($data)
- {
- $url = 'https://api.weixin.qq.com/wxa/sec/order/is_trade_management_confirmation_completed?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Shopping.php b/WeMini/Shopping.php
deleted file mode 100644
index 70db178..0000000
--- a/WeMini/Shopping.php
+++ /dev/null
@@ -1,94 +0,0 @@
-callPostApi($url, $data, true);
- }
-
- /**
- * 上传物流信息
- * @param array $data 物流数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function uploadShippingInfo($data)
- {
- $url = 'https://api.weixin.qq.com/user-order/orders?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 上传合单购物详情
- * @param array $data 订单数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function uploadCombinedShoppingInfo($data)
- {
- $url = 'https://api.weixin.qq.com/user-order/orders?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 上传合单物流
- * @param array $data 物流数据
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function uploadCombinedShippingInfo($data)
- {
- $url = 'https://api.weixin.qq.com/user-order/orders?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
- /**
- * 校验购物订单上传结果
- * @param array $data 校验参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function ShoppingInfoVerifyUploadResult($data)
- {
- $url = 'https://api.weixin.qq.com/user-order/shoppinginfo/verify?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-
-
-}
\ No newline at end of file
diff --git a/WeMini/Soter.php b/WeMini/Soter.php
deleted file mode 100644
index 4263436..0000000
--- a/WeMini/Soter.php
+++ /dev/null
@@ -1,39 +0,0 @@
-callPostApi($url, $data, true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Template.php b/WeMini/Template.php
deleted file mode 100644
index c41c45e..0000000
--- a/WeMini/Template.php
+++ /dev/null
@@ -1,104 +0,0 @@
-callPostApi($url, ['offset' => '0', 'count' => '20'], true);
- }
-
- /**
- * 获取模板关键词库
- * @param string $template_id 模板标题ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getTemplateLibrary($template_id)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/wxopen/template/library/get?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['id' => $template_id], true);
- }
-
- /**
- * 组合关键词并添加模板
- * @param string $template_id 模板标题ID
- * @param array $keyword_id_list 关键词 ID 列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function addTemplate($template_id, array $keyword_id_list)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/wxopen/template/add?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['id' => $template_id, 'keyword_id_list' => $keyword_id_list], true);
- }
-
- /**
- * 获取帐号模板列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getTemplateList()
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/wxopen/template/list?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['offset' => '0', 'count' => '20'], true);
- }
-
- /**
- * 删除模板
- * @param string $template_id 模板 ID
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function delTemplate($template_id)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/wxopen/template/del?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['template_id' => $template_id], true);
- }
-
- /**
- * 发送模板消息
- * @param array $data 消息体(touser, template_id, form_id, data 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function send(array $data)
- {
- $url = 'https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, $data, true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/Total.php b/WeMini/Total.php
deleted file mode 100644
index cc715ac..0000000
--- a/WeMini/Total.php
+++ /dev/null
@@ -1,166 +0,0 @@
-callPostApi($url, ['begin_date' => $beginDate, 'end_date' => $endDate], true);
- }
-
- /**
- * 访问趋势(日)
- * @param string $beginDate 开始日期
- * @param string $endDate 结束日期,需同一天
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidDailyVisittrend($beginDate, $endDate)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappiddailyvisittrend?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $beginDate, 'end_date' => $endDate], true);
- }
-
- /**
- * 访问趋势(周)
- * @param string $begin_date 周一
- * @param string $end_date 周日
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidWeeklyVisittrend($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappidweeklyvisittrend?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-
- /**
- * 访问趋势(月)
- * @param string $begin_date 月首日
- * @param string $end_date 月末日
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidMonthlyVisittrend($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyvisittrend?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-
- /**
- * 访问分布
- * @param string $begin_date 开始日期
- * @param string $end_date 结束日期,需同一天
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidVisitdistribution($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappidvisitdistribution?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-
- /**
- * 留存(日)
- * @param string $begin_date 开始日期
- * @param string $end_date 结束日期,需同一天
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidDailyRetaininfo($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappiddailyretaininfo?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-
- /**
- * 留存(周)
- * @param string $begin_date 周一
- * @param string $end_date 周日
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidWeeklyRetaininfo($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappidweeklyretaininfo?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-
- /**
- * 留存(月)
- * @param string $begin_date 月首日
- * @param string $end_date 月末日
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidMonthlyRetaininfo($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappidmonthlyretaininfo?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-
- /**
- * 访问页面数据
- * @param string $begin_date 开始日期
- * @param string $end_date 结束日期,需同一天
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidVisitPage($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappidvisitpage?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-
- /**
- * 用户画像
- * @param string $begin_date 开始日期
- * @param string $end_date 结束日期,间隔为0/6/29
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function getWeanalysisAppidUserportrait($begin_date, $end_date)
- {
- $url = 'https://api.weixin.qq.com/datacube/getweanalysisappiduserportrait?access_token=ACCESS_TOKEN';
- return $this->callPostApi($url, ['begin_date' => $begin_date, 'end_date' => $end_date], true);
- }
-}
\ No newline at end of file
diff --git a/WeMini/crypt/errorCode.php b/WeMini/crypt/errorCode.php
deleted file mode 100644
index a4f8e72..0000000
--- a/WeMini/crypt/errorCode.php
+++ /dev/null
@@ -1,20 +0,0 @@
-
- * -41001: encodingAesKey 非法
- * -41003: aes 解密失败
- * -41004: 解密后得到的buffer非法
- * -41005: base64加密失败
- * -41016: base64解密失败
- *
- */
-class ErrorCode
-{
- public static $OK = 0;
- public static $IllegalAesKey = -41001;
- public static $IllegalIv = -41002;
- public static $IllegalBuffer = -41003;
- public static $DecodeBase64Error = -41004;
-}
\ No newline at end of file
diff --git a/WeMini/crypt/wxBizDataCrypt.php b/WeMini/crypt/wxBizDataCrypt.php
deleted file mode 100644
index fde8d27..0000000
--- a/WeMini/crypt/wxBizDataCrypt.php
+++ /dev/null
@@ -1,57 +0,0 @@
-appid = $appid;
- $this->sessionKey = $sessionKey;
- include_once __DIR__ . DIRECTORY_SEPARATOR . "errorCode.php";
- }
-
- /**
- * 检验数据的真实性,并且获取解密后的明文.
- * @param $encryptedData string 加密的用户数据
- * @param $iv string 与用户数据一同返回的初始向量
- * @param $data string 解密后的原文
- *
- * @return int 成功0,失败返回对应的错误码
- */
- public function decryptData($encryptedData, $iv, &$data)
- {
- if (strlen($this->sessionKey) != 24) {
- return ErrorCode::$IllegalAesKey;
- }
- $aesKey = base64_decode($this->sessionKey);
- if (strlen($iv) != 24) {
- return ErrorCode::$IllegalIv;
- }
- $aesIV = base64_decode($iv);
- $aesCipher = base64_decode($encryptedData);
- $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
- $dataObj = json_decode($result);
- if ($dataObj == null) {
- return ErrorCode::$IllegalBuffer;
- }
- // 兼容新版本无 watermark 的情况
- if (isset($dataObj->watermark) && $dataObj->watermark->appid != $this->appid) {
- return ErrorCode::$IllegalBuffer;
- }
- $data = $result;
- return ErrorCode::$OK;
- }
-
-}
-
diff --git a/WePay/Bill.php b/WePay/Bill.php
deleted file mode 100644
index 2e4a6c9..0000000
--- a/WePay/Bill.php
+++ /dev/null
@@ -1,64 +0,0 @@
-params->set('sign_type', 'MD5');
- $params = $this->params->merge($options);
- $params['sign'] = $this->getPaySign($params, 'MD5');
- $result = Tools::post('https://api.mch.weixin.qq.com/pay/downloadbill', Tools::arr2xml($params));
- if (is_array($jsonData = Tools::xml3arr($result))) {
- if ($jsonData['return_code'] !== 'SUCCESS') {
- throw new InvalidResponseException($jsonData['return_msg'], '0');
- }
- }
- return is_null($outType) ? $result : $outType($result);
- }
-
-
- /**
- * 拉取订单评价数据(需证书)
- * @param array $options 查询参数(bill_date, offset, limit 等)
- * @return array 评价数据
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function comment(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/billcommentsp/batchquerycomment';
- return $this->callPostApi($url, $options, true);
- }
-}
\ No newline at end of file
diff --git a/WePay/Coupon.php b/WePay/Coupon.php
deleted file mode 100644
index f31101e..0000000
--- a/WePay/Coupon.php
+++ /dev/null
@@ -1,66 +0,0 @@
-callPostApi($url, $options, true, 'MD5');
- }
-
- /**
- * 查询代金券批次
- * @param array $options 查询参数(coupon_stock_id 等)
- * @return array 批次详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryStock(array $options)
- {
- $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/query_coupon_stock";
- return $this->callPostApi($url, $options, false);
- }
-
- /**
- * 查询单个代金券信息
- * @param array $options 查询参数(coupon_id, openid, stock_id 等)
- * @return array 代金券详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryInfo(array $options)
- {
- $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/query_coupon_stock";
- return $this->callPostApi($url, $options, false);
- }
-
-}
\ No newline at end of file
diff --git a/WePay/Custom.php b/WePay/Custom.php
deleted file mode 100644
index 8466833..0000000
--- a/WePay/Custom.php
+++ /dev/null
@@ -1,68 +0,0 @@
-callPostApi($url, $options, false, 'MD5', false, false);
- }
-
- /**
- * 海关申报:订单附加信息查询
- * @param array $options 查询参数(transaction_id 或 out_trade_no,customs,mch_customs_no 等)
- * @return array 申报状态
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function get(array $options = [])
- {
- $url = 'https://api.mch.weixin.qq.com/cgi-bin/mch/customs/customdeclarequery';
- return $this->callPostApi($url, $options, false, 'MD5', true, false);
- }
-
-
- /**
- * 海关申报:重推申报信息
- * @param array $options 重推参数(transaction_id 或 out_trade_no,customs,mch_customs_no 等)
- * @return array 重推结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function reset(array $options = [])
- {
- $url = 'https://api.mch.weixin.qq.com/cgi-bin/mch/newcustoms/customdeclareredeclare';
- return $this->callPostApi($url, $options, false, 'MD5', true, false);
- }
-
-}
\ No newline at end of file
diff --git a/WePay/Order.php b/WePay/Order.php
deleted file mode 100644
index 9d3a17e..0000000
--- a/WePay/Order.php
+++ /dev/null
@@ -1,174 +0,0 @@
-callPostApi($url, $options, false, 'MD5');
- }
-
- /**
- * 刷卡支付接口(被扫支付)
- * @param array $options 支付参数(auth_code, out_trade_no, body, total_fee等)
- * @return array 支付结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function micropay(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/micropay';
- return $this->callPostApi($url, $options, false, 'MD5');
- }
-
- /**
- * 查询订单接口
- * @param array $options 查询参数(transaction_id或out_trade_no二选一)
- * @return array 订单详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
- return $this->callPostApi($url, $options);
- }
-
- /**
- * 关闭订单接口
- * @param string $outTradeNo 商户订单号
- * @return array 关闭结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function close($outTradeNo)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/closeorder';
- return $this->callPostApi($url, ['out_trade_no' => $outTradeNo]);
- }
-
- /**
- * 生成JSAPI支付参数(用于前端调起支付)
- * @param string $prepayId 统一下单返回的prepay_id
- * @return array JSAPI支付所需参数(appId, timeStamp, nonceStr, package, signType, paySign)
- */
- public function jsapiParams($prepayId)
- {
- $option = [];
- $option["appId"] = $this->config->get('appid');
- $option["timeStamp"] = (string)time();
- $option["nonceStr"] = Tools::createNoncestr();
- $option["package"] = "prepay_id={$prepayId}";
- $option["signType"] = "MD5";
- $option["paySign"] = $this->getPaySign($option, 'MD5');
- $option['timestamp'] = $option['timeStamp'];
- return $option;
- }
-
- /**
- * 生成Native支付二维码URL
- * @param string $productId 商品ID或订单号
- * @return string 支付二维码URL(weixin://wxpay/bizpayurl?xxx)
- */
- public function qrcParams($productId)
- {
- $data = [
- 'appid' => $this->config->get('appid'),
- 'mch_id' => $this->config->get('mch_id'),
- 'time_stamp' => (string)time(),
- 'nonce_str' => Tools::createNoncestr(),
- 'product_id' => (string)$productId,
- ];
- $data['sign'] = $this->getPaySign($data, 'MD5');
- return "weixin://wxpay/bizpayurl?" . http_build_query($data);
- }
-
- /**
- * 生成APP支付参数(用于移动应用调起支付)
- * @param string $prepayId 统一下单返回的prepay_id
- * @return array APP支付所需参数(appid, partnerid, prepayid, package, timestamp, noncestr, sign)
- */
- public function appParams($prepayId)
- {
- $data = [
- 'appid' => $this->config->get('appid'),
- 'partnerid' => $this->config->get('mch_id'),
- 'prepayid' => (string)$prepayId,
- 'package' => 'Sign=WXPay',
- 'timestamp' => (string)time(),
- 'noncestr' => Tools::createNoncestr(),
- ];
- $data['sign'] = $this->getPaySign($data, 'MD5');
- return $data;
- }
-
- /**
- * 撤销订单接口(刷卡支付专用,需要证书)
- * @param array $options 撤销参数(transaction_id或out_trade_no二选一)
- * @return array 撤销结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function reverse(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/secapi/pay/reverse';
- return $this->callPostApi($url, $options, true);
- }
-
- /**
- * 授权码查询openid接口
- * @param string $authCode 授权码(用户微信中的条码或二维码信息)
- * @return array 包含openid等信息
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function queryAuthCode($authCode)
- {
- $url = 'https://api.mch.weixin.qq.com/tools/authcodetoopenid';
- return $this->callPostApi($url, ['auth_code' => $authCode], false, 'MD5', false);
- }
-
- /**
- * 交易保障接口(用于上报交易数据)
- * @param array $options 上报参数(interface_url, execute_time, return_code, result_code等)
- * @return array 上报结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function report(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/payitil/report';
- return $this->callPostApi($url, $options);
- }
-}
\ No newline at end of file
diff --git a/WePay/ProfitSharing.php b/WePay/ProfitSharing.php
deleted file mode 100644
index 8039e01..0000000
--- a/WePay/ProfitSharing.php
+++ /dev/null
@@ -1,144 +0,0 @@
-callPostApi($url, $options, true);
- }
-
- /**
- * 请求多次分账(需证书)
- * @param array $options 分账参数(transaction_id, out_order_no, receivers 等)
- * @return array 分账结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function multiProfitSharing(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/secapi/pay/multiprofitsharing';
- return $this->callPostApi($url, $options, true);
- }
-
- /**
- * 查询分账结果
- * @param array $options 查询参数(transaction_id 与 out_order_no)
- * @return array 分账状态
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function profitSharingQuery(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/profitsharingquery';
- return $this->callPostApi($url, $options);
- }
-
- /**
- * 添加分账接收方
- * @param array $options 接收方信息(type, account, name, relation_type 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function profitSharingAddReceiver(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver';
- return $this->callPostApi($url, $options);
- }
-
- /**
- * 删除分账接收方
- * @param array $options 接收方信息(type, account)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function profitSharingRemoveReceiver(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver';
- return $this->callPostApi($url, $options);
- }
-
- /**
- * 完结分账(需证书)
- * @param array $options 完结参数(transaction_id, out_order_no, description 等)
- * @return array 完结结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function profitSharingFinish(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish';
- return $this->callPostApi($url, $options, true);
- }
-
- /**
- * 查询订单待分账金额
- * @param array $options 查询参数(transaction_id)
- * @return array 待分账金额
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function profitSharingOrderAmountQuery(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/profitsharingorderamountquery';
- return $this->callPostApi($url, $options);
- }
-
- /**
- * 分账回退(需证书)
- * @param array $options 回退参数(out_return_no, out_order_no, return_account_type 等)
- * @return array 回退结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function profitSharingReturn(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharingreturn';
- return $this->callPostApi($url, $options, true);
- }
-
- /**
- * 回退结果查询
- * @param array $options 查询参数(out_return_no 与 out_order_no)
- * @return array 回退状态
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function profitSharingReturnQuery(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/profitsharingreturnquery';
- return $this->callPostApi($url, $options);
- }
-}
diff --git a/WePay/Redpack.php b/WePay/Redpack.php
deleted file mode 100644
index c7ccfad..0000000
--- a/WePay/Redpack.php
+++ /dev/null
@@ -1,73 +0,0 @@
-params->offsetUnset('appid');
- $this->params->set('wxappid', $this->config->get('appid'));
- $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
- return $this->callPostApi($url, $options, true, 'MD5', false);
- }
-
- /**
- * 发放裂变红包(需证书)
- * @param array $options 红包参数(mch_billno, send_name, re_openid, total_amount, total_num 等,total_num>1)
- * @return array 红包发送结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function groups(array $options)
- {
- $this->params->offsetUnset('appid');
- $this->params->set('wxappid', $this->config->get('appid'));
- $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack";
- return $this->callPostApi($url, $options, true, 'MD5', false);
- }
-
- /**
- * 查询红包记录
- * @param string $mchBillno 商户红包订单号
- * @return array 红包状态信息
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query($mchBillno)
- {
- $this->params->offsetUnset('wxappid');
- $this->params->set('appid', $this->config->get('appid'));
- $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo";
- return $this->callPostApi($url, ['mch_billno' => $mchBillno, 'bill_type' => 'MCHT'], true, 'MD5', false);
- }
-
-}
\ No newline at end of file
diff --git a/WePay/Refund.php b/WePay/Refund.php
deleted file mode 100644
index b5f5ece..0000000
--- a/WePay/Refund.php
+++ /dev/null
@@ -1,80 +0,0 @@
-callPostApi($url, $options, true);
- }
-
- /**
- * 查询退款接口
- * @param array $options 查询参数(transaction_id, out_trade_no, out_refund_no, refund_id四选一)
- * @return array 退款详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query(array $options)
- {
- $url = 'https://api.mch.weixin.qq.com/pay/refundquery';
- return $this->callPostApi($url, $options);
- }
-
- /**
- * 解析退款通知(自动解密req_info)
- * @param string|array $xml 退款通知XML数据,为空则从POST获取
- * @return array 解密后的退款通知数据
- * @throws \WeChat\Exceptions\InvalidDecryptException
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function getNotify($xml = '')
- {
- $data = is_array($xml) ? $xml : Tools::xml2arr(empty($xml) ? Tools::getRawInput() : $xml);
- if (!isset($data['return_code']) || $data['return_code'] !== 'SUCCESS') {
- throw new InvalidResponseException('获取退款通知XML失败!');
- }
- 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());
- }
- }
-}
\ No newline at end of file
diff --git a/WePay/Transfers.php b/WePay/Transfers.php
deleted file mode 100644
index 0d9248e..0000000
--- a/WePay/Transfers.php
+++ /dev/null
@@ -1,62 +0,0 @@
-params->offsetUnset('appid');
- $this->params->offsetUnset('mch_id');
- $this->params->set('mchid', $this->config->get('mch_id'));
- $this->params->set('mch_appid', $this->config->get('appid'));
- $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
- return $this->callPostApi($url, $options, true, 'MD5', false);
- }
-
- /**
- * 查询企业付款到零钱结果
- * @param string $partnerTradeNo 商户付款单号
- * @return array 付款状态
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query($partnerTradeNo)
- {
- $this->params->offsetUnset('mchid');
- $this->params->offsetUnset('mch_appid');
- $this->params->set('appid', $this->config->get('appid'));
- $this->params->set('mch_id', $this->config->get('mch_id'));
- $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo';
- return $this->callPostApi($url, ['partner_trade_no' => $partnerTradeNo], true, 'MD5', false);
- }
-
-}
\ No newline at end of file
diff --git a/WePay/TransfersBank.php b/WePay/TransfersBank.php
deleted file mode 100644
index 3d4c296..0000000
--- a/WePay/TransfersBank.php
+++ /dev/null
@@ -1,125 +0,0 @@
-params->offsetUnset('appid');
- return $this->callPostApi('https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank', [
- 'amount' => $options['amount'],
- 'bank_code' => $options['bank_code'],
- 'partner_trade_no' => $options['partner_trade_no'],
- 'enc_bank_no' => $this->rsaEncode($options['enc_bank_no']),
- 'enc_true_name' => $this->rsaEncode($options['enc_true_name']),
- 'desc' => isset($options['desc']) ? $options['desc'] : '',
- ], true, 'MD5', false);
- }
-
- /**
- * RSA 加密银行卡号/姓名
- * @param string $string 待加密字符串
- * @param string $encrypted
- * @return string base64 编码密文
- * @throws \WeChat\Exceptions\InvalidDecryptException
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- private function rsaEncode($string, $encrypted = '')
- {
- $search = ['-----BEGIN RSA PUBLIC KEY-----', '-----END RSA PUBLIC KEY-----', "\n", "\r"];
- $pkc1 = str_replace($search, '', $this->getRsaContent());
- $publicKey = '-----BEGIN PUBLIC KEY-----' . PHP_EOL .
- wordwrap('MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A' . $pkc1, 64, PHP_EOL, true) . PHP_EOL .
- '-----END PUBLIC KEY-----';
- if (!openssl_public_encrypt("{$string}", $encrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING)) {
- throw new InvalidDecryptException('Rsa Encrypt Error.');
- }
- return base64_encode($encrypted);
- }
-
- /**
- * 获取 RSA 公钥内容
- * @return string 公钥内容
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- private function getRsaContent()
- {
- $cacheKey = "pub_ras_key_" . $this->config->get('mch_id');
- if (($pub_key = Tools::getCache($cacheKey))) {
- return $pub_key;
- }
- $data = $this->callPostApi('https://fraud.mch.weixin.qq.com/risk/getpublickey', [], true, 'MD5');
- if (!isset($data['return_code']) || $data['return_code'] !== 'SUCCESS' || $data['result_code'] !== 'SUCCESS') {
- $error = 'ResultError:' . $data['return_msg'];
- $error .= isset($data['err_code_des']) ? ' - ' . $data['err_code_des'] : '';
- throw new InvalidResponseException($error, 20000, $data);
- }
- Tools::setCache($cacheKey, $data['pub_key'], 600);
- return $data['pub_key'];
- }
-
- /**
- * 查询企业付款到银行卡结果
- * @param string $partnerTradeNo 商户订单号
- * @return array 付款状态
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query($partnerTradeNo)
- {
- $this->params->offsetUnset('appid');
- $url = 'https://api.mch.weixin.qq.com/mmpaysptrans/query_bank';
- return $this->callPostApi($url, ['partner_trade_no' => $partnerTradeNo], true, 'MD5', false);
- }
-}
\ No newline at end of file
diff --git a/WePayV3/Cert.php b/WePayV3/Cert.php
deleted file mode 100644
index 32256e3..0000000
--- a/WePayV3/Cert.php
+++ /dev/null
@@ -1,66 +0,0 @@
-doRequest('GET', '/v3/certificates');
- if (empty($result['data']) && !empty($result['message'])) {
- throw new InvalidResponseException($result['message']);
- }
- $decrypt = new DecryptAes($this->config['mch_v3_key']);
- foreach ($result['data'] as $vo) {
- $certs[$vo['serial_no']] = [
- 'expire' => strtotime($vo['expire_time']),
- 'serial' => $vo['serial_no'],
- 'content' => $decrypt->decryptToString(
- $vo['encrypt_certificate']['associated_data'],
- $vo['encrypt_certificate']['nonce'],
- $vo['encrypt_certificate']['ciphertext']
- )
- ];
- }
- $this->tmpFile("{$this->config['mch_id']}_certs", $certs);
- } catch (\Exception $exception) {
- throw new InvalidResponseException($exception->getMessage(), $exception->getCode());
- }
- }
-}
\ No newline at end of file
diff --git a/WePayV3/Complaints.php b/WePayV3/Complaints.php
deleted file mode 100644
index 156ec96..0000000
--- a/WePayV3/Complaints.php
+++ /dev/null
@@ -1,146 +0,0 @@
-config['mch_id'];
- $pathinfo = "/v3/merchant-service/complaints-v2?limit={$limit}&offset={$offset}&begin_date={$begin_date}&end_date={$end_date}&complainted_mchid={$mchId}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询投诉详情
- * @param string $complaint_id 投诉单号
- * @return array|string 投诉详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function complaintDetails($complaint_id)
- {
- $pathinfo = "/v3/merchant-service/complaints-v2/{$complaint_id}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询投诉协商历史
- * @param string $complaint_id 投诉单号
- * @return array|string 协商记录
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function negotiationHistory($complaint_id)
- {
- $pathinfo = "/v3/merchant-service/complaints-v2/{$complaint_id}/negotiation-historys";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 创建投诉通知回调地址
- * @param string $url 回调地址
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function CreateComplaintsNotify($url)
- {
- return $this->doRequest('POST', '/v3/merchant-service/complaint-notifications', json_encode(['url' => $url], JSON_UNESCAPED_UNICODE), true);
-
- }
-
- /**
- * 查询投诉通知回调地址
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryComplaintsNotify()
- {
- return $this->doRequest('GET', '/v3/merchant-service/complaint-notifications', '', true);
-
- }
-
- /**
- * 更新投诉通知回调地址
- * @param string $url 回调地址
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function updateComplaintsNotify($url)
- {
- return $this->doRequest('PUT', '/v3/merchant-service/complaint-notifications', json_encode(['url' => $url], JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 删除投诉通知回调地址
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function deleteComplaintsNotify()
- {
- return $this->doRequest('DELETE', '/v3/merchant-service/complaint-notifications', '', true);
- }
-
- /**
- * 回复投诉
- * @param string $complaint_id 投诉单号
- * @param array $content 回复内容(含跳转链接、文本等)
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function replyInfo($complaint_id, array $content)
- {
- $content['complainted_mchid'] = $this->config['mch_id'];
- $pathinfo = "/v3/merchant-service/complaints-v2/{$complaint_id}/response";
- return $this->doRequest('POST', $pathinfo, json_encode($content, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 标记投诉处理完成
- * @param string $complaint_id 投诉单号
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function completeComplaints($complaint_id)
- {
- $mchId = $this->config['mch_id'];
- $pathinfo = "/v3/merchant-service/complaints-v2/{$complaint_id}/complete";
- return $this->doRequest('POST', $pathinfo, json_encode(['complainted_mchid' => $mchId], JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 下载投诉图片
- * @param string $pathinfo 文件路径(接口返回的下载地址 path)
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function downLoadImg($pathinfo)
- {
- return $this->doRequest('GET', $pathinfo, '', true, false);
- }
-
- /**
- * 上传投诉相关图片
- * @param array $imginfo 图片上传参数(文件流对应的 media 字段等)
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function uploadImg(array $imginfo)
- {
- return $this->doRequest('POST', '/v3/merchant-service/images/upload', json_encode($imginfo, JSON_UNESCAPED_UNICODE), true);
- }
-}
\ No newline at end of file
diff --git a/WePayV3/Contracts/BasicWePay.php b/WePayV3/Contracts/BasicWePay.php
deleted file mode 100644
index b880f1f..0000000
--- a/WePayV3/Contracts/BasicWePay.php
+++ /dev/null
@@ -1,535 +0,0 @@
- '', // 微信绑定APPID,需配置
- 'mch_id' => '', // 微信商户编号,需要配置
- 'mch_v3_key' => '', // 微信商户密钥,需要配置
- 'cert_serial' => '', // 商户证书序号,无需配置
- 'cert_public' => '', // 商户公钥内容,需要配置
- 'cert_private' => '', // 商户密钥内容,需要配置
- 'cert_package' => [], // 平台证书或支付证书配置
- 'mp_cert_serial' => '', // 平台证书序号,无需配置 ( 指定平台证书或支付公钥 )
- 'mp_cert_content' => '', // 平台证书内容,无需配置 ( 指定平台证书或支付公钥 )
- ];
-
- /**
- * BasicWePayV3 constructor.
- * @param array $options [mch_id, mch_v3_key, cert_public, cert_private]
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- 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_public'])) {
- throw new InvalidArgumentException("Missing Config -- [cert_public]");
- }
- if (empty($options['cert_private'])) {
- throw new InvalidArgumentException("Missing Config -- [cert_private]");
- }
-
- if (stripos($options['cert_public'], '-----BEGIN CERTIFICATE-----') === false) {
- if (file_exists($options['cert_public'])) {
- $options['cert_public'] = file_get_contents($options['cert_public']);
- } else {
- throw new InvalidArgumentException("File Non-Existent -- [cert_public]");
- }
- }
-
- if (stripos($options['cert_private'], '-----BEGIN PRIVATE KEY-----') === false) {
- if (file_exists($options['cert_private'])) {
- $options['cert_private'] = file_get_contents($options['cert_private']);
- } else {
- throw new InvalidArgumentException("File Non-Existent -- [cert_private]");
- }
- }
-
- $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'];
- if (empty($options['cert_serial'])) {
- $this->config['cert_serial'] = openssl_x509_parse($this->config['cert_public'], true)['serialNumberHex'];
- } else {
- $this->config['cert_serial'] = $options['cert_serial'];
- }
- if (empty($this->config['cert_serial'])) {
- throw new InvalidArgumentException('Failed to parse certificate public key');
- }
-
- if (!empty($options['cache_path'])) {
- Tools::$cache_path = $options['cache_path'];
- }
-
- // 批量设置自定义证书
- if (isset($options['cert_package']) && is_array($options['cert_package'])) {
- foreach ($options['cert_package'] as $key => $cert) {
- $this->withCertContent($key, $cert);
- }
- }
-
- // 自动配置平台证书或支付公钥
- if (empty($options['mp_cert_serial']) || empty($options['mp_cert_content'])) {
- if ($this->autoCert && !$this->withCertPayment()) {
- $this->_autoCert();
- }
- } elseif ($this->withCertContent($options['mp_cert_serial'], $options['mp_cert_content'])) {
- $this->config['mp_cert_serial'] = $options['mp_cert_serial'];
- $this->config['mp_cert_content'] = $options['mp_cert_content'];
- }
-
- // 服务商参数支持
-// if (!empty($options['sp_appid'])) {
-// $this->config['sp_appid'] = $options['sp_appid'];
-// }
-// if (!empty($options['sp_mchid'])) {
-// $this->config['sp_mchid'] = $options['sp_mchid'];
-// }
-// if (!empty($options['sub_appid'])) {
-// $this->config['sub_appid'] = $options['sub_appid'];
-// }
-// if (!empty($options['sub_mch_id'])) {
-// $this->config['sub_mch_id'] = $options['sub_mch_id'];
-// }
- }
-
- /**
- * 设置证书内容
- * @param string $key 证书ID或序号
- * @param string $cert 证书文本内容
- * @return string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- private function withCertContent($key, $cert)
- {
- if (substr(trim($cert), 0, 5) == '-----') {
- $this->config['cert_package'][$key] = $cert;
- } elseif (file_exists($cert)) {
- $this->config['cert_package'][$key] = file_get_contents($cert);
- } else {
- throw new InvalidResponseException("证书设置失败!");
- }
- return $cert;
- }
-
- /**
- * 获取支付证书
- * @return mixed|string
- */
- private function withCertPayment()
- {
- foreach ($this->config['cert_package'] as $key => $cert) {
- if (strpos($key, 'PUB_KEY_ID_') === 0) {
- if (empty($this->config['mp_cert_serial']) || empty($this->config['mp_cert_content'])) {
- $this->config['mp_cert_serial'] = $key;
- $this->config['mp_cert_content'] = $cert;
- }
- return $cert;
- }
- }
- return '';
- }
-
- /**
- * 自动配置平台证书
- * @return void
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function _autoCert()
- {
- $certs = $this->tmpFile("{$this->config['mch_id']}_certs");
- if (is_array($certs)) foreach ($certs as $k => $v) {
- if ($v['expire'] < time()) unset($certs[$k]);
- }
- if (empty($certs)) {
- Cert::instance($this->config)->download();
- $certs = $this->tmpFile("{$this->config['mch_id']}_certs");
- }
- if (empty($certs) || !is_array($certs)) {
- throw new InvalidResponseException("读取平台证书失败!");
- }
- foreach ($certs as $k => $v) if ($v['expire'] > time() + 10) {
- $this->config['cert_package'][$k] = $v['content'];
- if (empty($this->config['mp_cert_serial'])) {
- $this->config['mp_cert_serial'] = $k;
- $this->config['mp_cert_content'] = $v['content'];
- }
- }
- if (empty($this->config['cert_package'])) {
- throw new InvalidResponseException("自动配置平台证书失败!");
- }
- }
-
- /**
- * 写入或读取临时文件
- * @param string $name
- * @param null|array|string $content
- * @param integer $expire
- * @return array|string
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function tmpFile($name, $content = null, $expire = 7200)
- {
- if (is_null($content)) {
- $text = Tools::getCache($name);
- if (empty($text)) return '';
- $json = json_decode(Tools::getCache($name) ?: '', true);
- return isset($json[0]) ? $json[0] : '';
- } else {
- return Tools::setCache($name, json_encode([$content], JSON_UNESCAPED_UNICODE), $expire);
- }
- }
-
- /**
- * 静态创建对象
- * @param array $config
- * @return static
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public static function instance($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 $pathinfo 请求路由
- * @param string $filename 文件本地路径
- * @param boolean $verify 是否验证
- * @param boolean $isjson 返回JSON
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function doUpload($pathinfo, $filename, $verify = false, $isjson = true)
- {
- $filedata = file_get_contents($filename);
- $fileinfo = [
- 'sha256' => hash("sha256", $filedata),
- 'filename' => basename($filename)
- ];
- $jsondata = json_encode($fileinfo);
- list($time, $nonce) = [time(), uniqid() . rand(1000, 9999)];
- $signstr = join("\n", ['POST', $pathinfo, $time, $nonce, $jsondata, '']);
- // 生成签名
- $sign = $this->signBuild($signstr);
- // 生成数据签名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'], $sign
- );
- $location = (preg_match('|^https?://|', $pathinfo) ? '' : $this->base) . $pathinfo;
- $boundary = mt_rand(100000000000000000, 999999999999999999);
- $header = [
- 'Accept: application/json',
- "Content-Type: multipart/form-data; boundary={$boundary}",
- 'User-Agent: https://thinkadmin.top',
- "Authorization: WECHATPAY2-SHA256-RSA2048 {$token}",
- "serial_no: {$this->config['mp_cert_serial']}",
- "nonce_str: {$nonce}",
- "signature: {$sign}"
- ];
- $line = [];
- $line[] = "--{$boundary}";
- $line[] = "Content-Disposition: form-data; name=\"meta\"";
- $line[] = "Content-Type: application/json";
- $line[] = "";
- $line[] = $jsondata;
- $line[] = "--{$boundary}";
- $line[] = "Content-Disposition: form-data; name=\"file\"; filename=\"{$fileinfo['filename']}\";";
- $line[] = "Content-Type: image/jpg";
- $line[] = "";
- $line[] = $filedata;
- $line[] = "--{$boundary}--";
- $postdata = join("\r\n", $line);
- list($header, $content) = $this->_doRequestCurl('POST', $location, [
- 'data' => $postdata, 'header' => $header,
- ]);
- 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 {
- if (empty($headers)) {
- return $isjson ? json_decode($content, true) : $content;
- }
- $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 $isjson ? json_decode($content, true) : $content;
- }
-
- /**
- * 生成数据签名
- * @param string $data 签名内容
- * @return string
- */
- protected function signBuild($data)
- {
- $pkeyid = openssl_pkey_get_private($this->config['cert_private']);
- if ($pkeyid === false) {
- throw new InvalidArgumentException("Invalid private key -- [cert_private]");
- }
- $signature = '';
- if (!openssl_sign($data, $signature, $pkeyid, 'sha256WithRSAEncryption')) {
- $this->freeKey($pkeyid);
- throw new InvalidArgumentException("Failed to sign data with private key");
- }
- $this->freeKey($pkeyid);
- return base64_encode($signature);
- }
-
- /**
- * 兼容释放 OpenSSL 密钥资源
- * @param mixed $pkey
- * @return void
- */
- protected function freeKey($pkey)
- {
- // PHP 8+ 中 openssl_free_key 已废弃,交由运行时回收即可。
- if (version_compare(PHP_VERSION, '8.0.0', '<') && function_exists('openssl_free_key')) {
- openssl_free_key($pkey);
- }
- }
-
- /**
- * 通过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 签名内容
- * @param string $sign 原签名值
- * @param string $serial 证书序号
- * @return int
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function signVerify($data, $sign, $serial)
- {
- if (stripos($serial, 'PUB_KEY_ID_') !== false && !empty($this->config['cert_package'][$serial])) {
- return openssl_verify($data, base64_decode($sign), $this->config['cert_package'][$serial], OPENSSL_ALGO_SHA256);
- } else {
- return openssl_verify($data, base64_decode($sign), openssl_x509_read($this->_getCert($serial)), 'sha256WithRSAEncryption');
- }
- }
-
- /**
- * 获取平台证书
- * @param string $serial
- * @return string
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- protected function _getCert($serial = '')
- {
- $certs = $this->tmpFile("{$this->config['mch_id']}_certs");
- if (empty($certs) || empty($certs[$serial]['serial']) || empty($certs[$serial]['content'])) {
- Cert::instance($this->config)->download();
- $certs = $this->tmpFile("{$this->config['mch_id']}_certs");
- }
- foreach ($certs as $cert) {
- if (!empty($cert['serial']) && !empty($cert['content']) && $cert['expire'] > time()) {
- $this->config['cert_package'][$cert['serial']] = $cert['content'];
- if (empty($this->config['mp_cert_serial']) && (empty($serial) || $serial === $cert['serial'])) {
- $this->config['mp_cert_serial'] = $cert['serial'];
- $this->config['mp_cert_content'] = $cert['content'];
- }
- }
- }
- if (isset($this->config['cert_package'][$serial])) {
- return $this->config['cert_package'][$serial];
- } elseif (!empty($this->config['mp_cert_content'])) {
- return $this->config['mp_cert_content'];
- } elseif ($cert = $this->withCertPayment()) {
- return $cert;
- } else {
- throw new InvalidResponseException("读取平台证书失败!");
- }
- }
-
- /**
- * 通用接口调用(微信支付 V3)
- * @param string $url 完整 URL 或相对路径(如 /v3/pay/transactions/jsapi)
- * @param array|string $data 请求体,数组自动 JSON,字符串原样发送
- * @param string $method GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS,默认 POST
- * @param bool $verify 是否验证返回签名
- * @return array 解析后的数组
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function callApi($url, $data = '', $method = 'POST', $verify = false)
- {
- $method = strtoupper($method);
-
- // 处理数据
- if (is_array($data)) {
- $data = json_encode($data, JSON_UNESCAPED_UNICODE);
- }
-
- return $this->doRequest($method, $url, $data, $verify, true);
- }
-
- /**
- * 模拟发起请求
- * @param string $method 请求访问
- * @param string $pathinfo 请求路由
- * @param string $jsondata 请求数据
- * @param boolean $verify 是否验证
- * @param boolean $isjson 返回JSON
- * @return array|string
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function doRequest($method, $pathinfo, $jsondata = '', $verify = false, $isjson = true)
- {
- 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)
- );
- $location = (preg_match('|^https?://|', $pathinfo) ? '' : $this->base) . $pathinfo;
- list($header, $content) = $this->_doRequestCurl($method, $location, [
- 'data' => $jsondata, 'header' => [
- 'Accept: application/json',
- 'Content-Type: application/json',
- 'User-Agent: https://thinkadmin.top',
- "Authorization: WECHATPAY2-SHA256-RSA2048 {$token}",
- "Wechatpay-Serial: {$this->config['mp_cert_serial']}"
- ],
- ]);
-
- 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 {
- if (empty($headers)) {
- return $isjson ? json_decode($content, true) : $content;
- }
- $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 $isjson ? json_decode($content, true) : $content;
- }
-
- /**
- * RSA加密处理-平台证书
- * @param string $string
- * @return string
- * @throws \WeChat\Exceptions\InvalidDecryptException
- */
- protected function rsaEncode($string)
- {
- $publicKey = $this->config['mp_cert_content'];
- if (openssl_public_encrypt($string, $encrypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING)) {
- return base64_encode($encrypted);
- } else {
- throw new InvalidDecryptException('Rsa Encrypt Error.');
- }
- }
-}
diff --git a/WePayV3/Contracts/DecryptAes.php b/WePayV3/Contracts/DecryptAes.php
deleted file mode 100644
index e4dfd75..0000000
--- a/WePayV3/Contracts/DecryptAes.php
+++ /dev/null
@@ -1,81 +0,0 @@
-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 \WeChat\Exceptions\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');
- }
-}
\ No newline at end of file
diff --git a/WePayV3/Coupon.php b/WePayV3/Coupon.php
deleted file mode 100644
index 3f83d45..0000000
--- a/WePayV3/Coupon.php
+++ /dev/null
@@ -1,155 +0,0 @@
-doRequest('POST', $path, json_encode($data), true);
- }
-
- /**
- * 激活代金券批次
- * @param string $stock_id 批次号
- * @param string $stock_creator_mchid 创建批次的商户号
- * @return array|string
- * @throws InvalidResponseException
- */
- public function stocksStart($stock_id, $stock_creator_mchid)
- {
- $path = "/v3/marketing/favor/stocks/{$stock_id}/start";
- return $this->doRequest('POST', $path, json_encode(['stock_creator_mchid' => $stock_creator_mchid]), true);
- }
-
- /**
- * 暂停代金券批次
- * @param string $stock_id 批次号
- * @param string $stock_creator_mchid 创建批次的商户号
- * @return array|string
- * @throws InvalidResponseException
- */
- public function stocksPause($stock_id, $stock_creator_mchid)
- {
- $path = "/v3/marketing/favor/stocks/{$stock_id}/pause";
- return $this->doRequest('POST', $path, json_encode(['stock_creator_mchid' => $stock_creator_mchid]), true);
- }
-
- /**
- * 重启代金券批次
- * @param string $stock_id 批次号
- * @param string $stock_creator_mchid 创建批次的商户号
- * @return array|string
- * @throws InvalidResponseException
- */
- public function stocksRestart($stock_id, $stock_creator_mchid)
- {
- $path = "/v3/marketing/favor/stocks/{$stock_id}/restart";
- return $this->doRequest('POST', $path, json_encode(['stock_creator_mchid' => $stock_creator_mchid]), true);
- }
-
- /**
- * 查询批次详情
- * @param string $stock_id 批次号
- * @param string $stock_creator_mchid 创建批次的商户号
- * @return array|string 批次详情
- * @throws InvalidResponseException
- */
- public function stocksDetail($stock_id, $stock_creator_mchid)
- {
- $path = "/v3/marketing/favor/stocks/{$stock_id}?stock_creator_mchid={$stock_creator_mchid}";
- return $this->doRequest('GET', $path, '', true);
- }
-
- /**
- * 代金券批次可用商品
- * @param array $param 包含 stock_id 等
- * @return array|string
- * @throws InvalidResponseException
- */
- public function stocksItems(array $param)
- {
- $path = "/v3/marketing/favor/stocks/{$param['stock_id']}/items ";
- return $this->doRequest('POST', $path, json_encode($param), true);
- }
-
- /**
- * 设置消息通知地址
- * @param array $param 回调参数(notify_url, switch 等)
- * @return array|string
- * @throws InvalidResponseException
- */
- public function setCallbacks(array $param)
- {
- $path = "/v3/marketing/favor/callbacks";
- return $this->doRequest('POST', $path, json_encode($param), true);
- }
-
- /**
- * 发放代金券
- * @param array $param 请求参数(openid, stock_id 等)
- * @return array|string
- * @throws InvalidResponseException
- */
- public function couponsSend(array $param)
- {
- $path = "/v3/marketing/favor/users/{$param['openid']}/coupons";
- return $this->doRequest('POST', $path, json_encode($param), true);
- }
-
- /**
- * 查询用户名下券(按商户号)
- * @param array $param 请求参数(openid, appid, stock_id 等)
- * @return array|string 券列表
- * @throws InvalidResponseException
- */
- public function couponsList(array $param)
- {
- $path = "/v3/marketing/favor/users/{$param['openid']}/coupons";
- return $this->doRequest('POST', $path, json_encode($param), true);
- }
-
- /**
- * 查询单张代金券详情
- * @param string $openid 用户 openid
- * @param string $coupon_id 代金券 id
- * @param string $appid 公众账号或小程序 appid
- * @return array|string
- * @throws InvalidResponseException
- */
- public function couponsDetail($openid, $coupon_id, $appid)
- {
- $path = "/v3/marketing/favor/users/{$openid}/coupons/{$coupon_id}?appid={$appid}";
- return $this->doRequest('GET', $path, '', true);
- }
-}
diff --git a/WePayV3/Ecommerce.php b/WePayV3/Ecommerce.php
deleted file mode 100644
index e500ce1..0000000
--- a/WePayV3/Ecommerce.php
+++ /dev/null
@@ -1,775 +0,0 @@
-rsaEncode($data['id_card_info']['id_card_name']);
- if (isset($data['id_card_info']['id_card_number'])) $data['id_card_info']['id_card_number'] = $this->rsaEncode($data['id_card_info']['id_card_number']);
- }
- if (isset($data['id_doc_info'])) {
- if (isset($data['id_doc_info']['id_doc_name'])) $data['id_doc_info']['id_doc_name'] = $this->rsaEncode($data['id_doc_info']['id_doc_name']);
- if (isset($data['id_doc_info']['id_doc_number'])) $data['id_doc_info']['id_doc_number'] = $this->rsaEncode($data['id_doc_info']['id_doc_number']);
- }
- if (isset($data['contact_info'])) {
- if (isset($data['contact_info']['contact_name'])) $data['contact_info']['contact_name'] = $this->rsaEncode($data['contact_info']['contact_name']);
- if (isset($data['contact_info']['contact_id_card_number'])) $data['contact_info']['contact_id_card_number'] = $this->rsaEncode($data['contact_info']['contact_id_card_number']);
- if (isset($data['contact_info']['mobile_phone'])) $data['contact_info']['mobile_phone'] = $this->rsaEncode($data['contact_info']['mobile_phone']);
- }
- if (isset($data['account_info'])) {
- if (isset($data['account_info']['account_name'])) $data['account_info']['account_name'] = $this->rsaEncode($data['account_info']['account_name']);
- if (isset($data['account_info']['account_number'])) $data['account_info']['account_number'] = $this->rsaEncode($data['account_info']['account_number']);
- }
- if (!empty($data['ubo_info_list'])) {
- $data['ubo_info_list'] = array_map(function ($item) {
- $item['ubo_id_doc_name'] = $this->rsaEncode($item['ubo_id_doc_name']);
- $item['ubo_id_doc_number'] = $this->rsaEncode($item['ubo_id_doc_number']);
- $item['ubo_id_doc_address'] = $this->rsaEncode($item['ubo_id_doc_address']);
- return $item;
- }, $data['ubo_info_list']);
- }
- return $this->doRequest('POST', '/v3/ecommerce/applyments/', json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 按业务申请编号查询进件状态
- * @param string $out_request_no 业务申请编号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function ecommerceApplymentsByRequestNo($out_request_no)
- {
- $pathinfo = "/v3/ecommerce/applyments/out-request-no/{$out_request_no}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 按申请单 ID 查询进件状态
- * @param string $applyment_id 微信支付申请单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function ecommerceApplymentsByApplymentId($applyment_id)
- {
- $pathinfo = "/v3/ecommerce/applyments/{$applyment_id}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 修改结算账户
- * @param string $sub_mchid 特约/二级商户号
- * @param array $data 账户参数(敏感字段需 RSA)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function modifySettlement($sub_mchid, $data)
- {
- $pathinfo = "/v3/apply4sub/sub_merchants/{$sub_mchid}/modify-settlement";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询结算账户修改状态
- * @param string $sub_mchid 特约/二级商户号
- * @param string $application_no 修改结算账户申请单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function modifySettlementResult($sub_mchid, $application_no)
- {
- $pathinfo = "/v3/apply4sub/sub_merchants/{$sub_mchid}/application/{$application_no}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
-
- /**
- * 查询结算账户
- * @param string $sub_mchid 特约/二级商户号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function getSettlement($sub_mchid)
- {
- $pathinfo = "/v3/apply4sub/sub_merchants/{$sub_mchid}/settlement";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 上传进件所需图片/文件
- * @param string $filename 本地文件路径
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function mediaUpload($filename)
- {
- return $this->doUpload('/v3/merchant/media/upload', $filename, true);
- }
-
- /**
- * 合作方 APP 下单
- * @param array $data 下单参数(sp_mchid, sub_mchid, description, out_trade_no, notify_url 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function transactionsApp($data)
- {
- $pathinfo = "/v3/pay/partner/transactions/app";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 合作方 JSAPI 下单
- * @param array $data 下单参数(含 payer.openid 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function transactionsJsapi($data)
- {
- $pathinfo = "/v3/pay/partner/transactions/jsapi";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 合作方 Native 下单
- * @param array $data 下单参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function transactionsNative($data)
- {
- $pathinfo = "/v3/pay/partner/transactions/native";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 合作方 H5 下单
- * @param array $data 下单参数(含 scene_info 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function transactionsH5($data)
- {
- $pathinfo = "/v3/pay/partner/transactions/h5";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 订单查询(按微信交易号)
- * @param string $transaction_id 微信订单号
- * @param string $sub_mchid 二级商户号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function getTransactionsById($transaction_id, $sub_mchid)
- {
- $pathinfo = "/v3/pay/partner/transactions/id/{$transaction_id}";
- $pathinfo = $pathinfo . "?sp_mchid={$this->config['mch_id']}&sub_mchid={$sub_mchid}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 订单查询(按商户订单号)
- * @param string $out_trade_no 商户订单号
- * @param string $sub_mchid 二级商户号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function getTransactionsByTradeNo($out_trade_no, $sub_mchid)
- {
- $pathinfo = "/v3/pay/partner/transactions/out-trade-no/{$out_trade_no}";
- $pathinfo = $pathinfo . "?sp_mchid={$this->config['mch_id']}&sub_mchid={$sub_mchid}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 关闭订单
- * @param string $out_trade_no 商户订单号
- * @param array $data 包含 sub_mchid 等
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function transactionsClose($out_trade_no, $data)
- {
- $pathinfo = "/v3/pay/partner/transactions/out-trade-no/{$out_trade_no}/close";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
-
- }
-
- /**
- * 合单 JSAPI 下单
- * @param array $data 合单参数(combine_out_trade_no, sub_orders 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function combineTransactionsJsapi($data)
- {
- $pathinfo = "/v3/combine-transactions/jsapi";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 合单 APP 下单
- * @param array $data 合单参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function combineTransactionsApp($data)
- {
- $pathinfo = "/v3/combine-transactions/app";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 合单 H5 下单
- * @param array $data 合单参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function combineTransactionsH5($data)
- {
- $pathinfo = "/v3/combine-transactions/h5";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 合单 Native 下单
- * @param array $data 合单参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function combineTransactionsNative($data)
- {
- $pathinfo = "/v3/combine-transactions/native";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 合单查询
- * @param string $combine_out_trade_no 合单商户订单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function getCombineTransactionsByTradeNo($combine_out_trade_no)
- {
- $pathinfo = "/v3/combine-transactions/out-trade-no/{$combine_out_trade_no}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 合单关单
- * @param string $combine_out_trade_no 合单商户订单号
- * @param array $data 包含 sub_orders 等
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function combineTransactionsClose($combine_out_trade_no, $data)
- {
- $pathinfo = "/v3/combine-transactions/out-trade-no/{$combine_out_trade_no}/close";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 电商平台发起分账
- * @param array $data 分账参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function profitsharingOrders($data)
- {
- $pathinfo = "/v3/ecommerce/profitsharing/orders";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询分账结果
- * @param array $param 查询参数(sub_mchid, transaction_id, out_order_no 等)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryProfitsharingOrders($param = [])
- {
- $pathinfo = "/v3/ecommerce/profitsharing/orders?" . http_build_query($param);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 请求分账回退
- * @param array $data 回退参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function profitsharingReturnOrders($data)
- {
- $pathinfo = "/v3/ecommerce/profitsharing/returnorders";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询分账回退结果
- * @param array $param 查询参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryProfitsharingReturnOrders($param = [])
- {
- $pathinfo = "/v3/ecommerce/profitsharing/returnorders?" . http_build_query($param);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 完结分账
- * @param array $data 完结参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function profitsharingFinishOrder($data)
- {
- $pathinfo = "/v3/ecommerce/profitsharing/finish-order";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询订单待分金额
- * @param string $transaction_id 微信订单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function profitsharingReturnOrdersAmounts($transaction_id)
- {
- $pathinfo = "/v3/ecommerce/profitsharing/orders/{$transaction_id}/amounts";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 添加分账接收方
- * @param array $data 接收方参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function profitsharingReceiversAdd($data)
- {
- $pathinfo = "/v3/ecommerce/profitsharing/receivers/add";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 删除分账接收方
- * @param array $data 接收方参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function profitsharingReceiversDelete($data)
- {
- $pathinfo = "/v3/ecommerce/profitsharing/receivers/delete";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 请求补差
- * @param array $data 补差参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function subsidiesCreate($data)
- {
- $pathinfo = "/v3/ecommerce/subsidies/create";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 补差回退
- * @param array $data 回退参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function subsidiesReturn($data)
- {
- $pathinfo = "/v3/ecommerce/subsidies/return";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 取消补差
- * @param array $data 取消参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function subsidiesCancel($data)
- {
- $pathinfo = "/v3/ecommerce/subsidies/cancel";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 申请退款
- * @param array $data 退款参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function refundsApply($data)
- {
- $pathinfo = "/v3/ecommerce/refunds/apply";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询单笔退款(按微信退款号)
- * @param string $refund_id 微信退款号
- * @param string $sub_mchid 二级商户号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryRefundsById($refund_id, $sub_mchid)
- {
- $pathinfo = "/v3/ecommerce/refunds/id/{$refund_id}?sub_mchid={$$sub_mchid}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询单笔退款(按商户退款号)
- * @param string $out_refund_no 商户退款单号
- * @param string $sub_mchid 二级商户号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryRefundsByNo($out_refund_no, $sub_mchid)
- {
- $pathinfo = "/v3/ecommerce/refunds/out-refund-no/{$out_refund_no}?sub_mchid={$sub_mchid}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询垫付回补结果
- * @param string $refund_id 微信退款号
- * @param string $sub_mchid 二级商户号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryRefundsReturnAdvance($refund_id, $sub_mchid)
- {
- $pathinfo = "/v3/ecommerce/refunds/{$refund_id}/return-advance?sub_mchid={$sub_mchid}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 垫付退款回补
- * @param string $refund_id 微信退款号
- * @param array $data 回补参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function refundsReturnAdvance($refund_id, $data)
- {
- $pathinfo = "/v3/ecommerce/refunds/{$refund_id}/return-advance";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询二级商户账户实时余额API(余额查询)
- * @param string $sub_mchid
- * @param string $account_type 二级商户账户类型 BASIC: 基本账户 FEES: 手续费账户 OPERATION: 运营账户 DEPOSIT: 保证金账户
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function fundBalance($sub_mchid, $account_type = 'BASIC')
- {
- $pathinfo = "/v3/ecommerce/fund/balance/{$sub_mchid}?account_type={$account_type}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询二级商户账户日终余额API(余额查询)
- * @param string $sub_mchid
- * @param array $query
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function fundEnddayBalance($sub_mchid, $query)
- {
- $pathinfo = "/v3/ecommerce/fund/enddaybalance/{$sub_mchid}?" . http_build_query($query);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询收付通平台账户实时余额API(余额查询)
- * @param string $account_type
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function merchantFundBalance($account_type)
- {
- $pathinfo = "/v3/merchant/fund/balance/{$account_type}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询收付通平台账户日终余额API(余额查询)
- * @param string $account_type
- * @param array $query
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function merchantEnddayBalance($account_type, $query)
- {
- $pathinfo = "/v3/merchant/fund/enddaybalance/{$account_type}?" . http_build_query($query);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 二级商户预约提现(商户提现)
- * @param array $data POST请求参数
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function fundWithdraw($data)
- {
- $pathinfo = "/v3/ecommerce/fund/withdraw";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 二级商户查询预约提现状态(根据商户预约提现单号查询)(商户提现)
- * @param string $out_request_no
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryFundWithdrawByNo($out_request_no)
- {
- $pathinfo = "/v3/ecommerce/fund/withdraw/out-request-no/{$out_request_no}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 二级商户查询预约提现状态(根据微信支付预约提现单号查询)(商户提现)
- * @param string $withdraw_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryFundWithdrawById($withdraw_id)
- {
- $pathinfo = "/v3/ecommerce/fund/withdraw/{$withdraw_id}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 收付通平台预约提现(商户提现)
- * @param array $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function merchantFundWithdraw($data)
- {
- $pathinfo = "/v3/merchant/fund/withdraw";
- return $this->doRequest('POST', $pathinfo, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 收付通平台查询预约提现状态(根据商户预约提现单号查询)(商户提现)
- * @param string $out_request_no
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryMerchantFundWithdrawByNo($out_request_no)
- {
- $pathinfo = "/v3/merchant/fund/withdraw/out-request-no/{$out_request_no}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 收付通平台查询预约提现状态(根据微信支付预约提现单号查询)(商户提现)
- * @param string $withdraw_id
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function queryMerchantFundWithdrawById($withdraw_id)
- {
- $pathinfo = "/v3/merchant/fund/withdraw/withdraw-id/{$withdraw_id}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 按日下载提现异常文件(商户提现)
- * @param $bill_type
- * @param array $param
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function fundWithdrawBill($bill_type, $param = [])
- {
- $pathinfo = "/v3/merchant/fund/withdraw/bill-type/{$bill_type}?" . http_build_query($param);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 申请交易账单(下载账单)
- * @param $bill_type
- * @param array $param
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function tradeBill($bill_type, $param = [])
- {
- $pathinfo = "/v3/bill/tradebill?" . http_build_query($param);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
-
- /**
- * 申请资金账单(下载账单)
- * @param $bill_type
- * @param array $param
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function fundFlowBill($bill_type, $param = [])
- {
- $pathinfo = "/v3/bill/fundflowbill?" . http_build_query($param);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
-
- /**
- * 申请分账账单(下载账单)
- * @param string $bill_type
- * @param array $param
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function profitsharingBill($bill_type, $param = [])
- {
- $pathinfo = "/v3/profitsharing/bills?" . http_build_query($param);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
-
- /**
- * 申请二级商户资金账单(下载账单)
- * @param string $bill_type
- * @param array $param
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function subFundFlowBill($bill_type, $param = [])
- {
- $pathinfo = "/v3/ecommerce/bill/fundflowbill?" . http_build_query($param);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询支持个人业务的银行列表
- * @param int $offset
- * @param int $limit
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function personalBanking($offset, $limit)
- {
- $pathinfo = "/v3/capital/capitallhh/banks/personal-banking?" . http_build_query(['offset' => $offset, 'limit' => $limit]);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询省份列表
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function provinces()
- {
- $pathinfo = "/v3/capital/capitallhh/areas/provinces";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询城市列表
- * @param int $code
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function cities($code)
- {
- $pathinfo = "/v3/capital/capitallhh/areas/provinces/{$code}/cities";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询支行列表
- * @param int $code
- * @param $city
- * @param $offset
- * @param $limit
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function branches($code, $city, $offset, $limit)
- {
- $pathinfo = "/v3/capital/capitallhh/banks/{$code}/branches?" . http_build_query(['city_code' => $city, 'offset' => $offset, 'limit' => $limit]);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 查询支持对公业务的银行列表
- * @param int $offset
- * @param int $limit
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function corporateBanking($offset, $limit)
- {
- $pathinfo = "/v3/capital/capitallhh/banks/corporate-banking?" . http_build_query(['offset' => $offset, 'limit' => $limit]);
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 通过支付预订单ID获取支付参数
- * @param string $prepay_id 支付预订单ID
- * @param string $type 类型
- * @return array
- */
- public function getJsApiParameters($prepay_id, $type = 'jsapi')
- {
- // 支付参数签名
- $time = strval(time());
- $appid = $this->config['appid'];
- $nonceStr = Tools::createNoncestr();
- if ($type === Order::WXPAY_APP) {
- $sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, $prepay_id, '']));
- return ['partnerId' => $this->config['mch_id'], 'prepayId' => $prepay_id, 'package' => 'Sign=WXPay', 'nonceStr' => $nonceStr, 'timeStamp' => $time, 'sign' => $sign];
- } elseif ($type === Order::WXPAY_JSAPI) {
- $sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, "prepay_id={$prepay_id}", '']));
- return ['appId' => $appid, 'timestamp' => $time, 'timeStamp' => $time, 'nonceStr' => $nonceStr, 'package' => "prepay_id={$prepay_id}", 'signType' => 'RSA', 'paySign' => $sign];
- } else {
- return [];
- }
- }
-}
\ No newline at end of file
diff --git a/WePayV3/Order.php b/WePayV3/Order.php
deleted file mode 100644
index 2b18d25..0000000
--- a/WePayV3/Order.php
+++ /dev/null
@@ -1,208 +0,0 @@
- '/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 {
- // 自动填充 mchid 和 appid(如果未提供)
- if (empty($data['mchid']) && !empty($this->config['mch_id'])) {
- $data['mchid'] = $this->config['mch_id'];
- }
- if (empty($data['appid']) && !empty($this->config['appid'])) {
- $data['appid'] = $this->config['appid'];
- }
- // 创建预支付码
- $result = $this->doRequest('POST', $types[$type], json_encode($data, JSON_UNESCAPED_UNICODE), true);
- if (empty($result['h5_url']) && empty($result['code_url']) && empty($result['prepay_id'])) {
- $message = isset($result['code']) ? "[ {$result['code']} ] " : '';
- $message .= isset($result['message']) ? $result['message'] : json_encode($result, JSON_UNESCAPED_UNICODE);
- throw new InvalidResponseException($message);
- }
- // 支付参数签名
- $time = strval(time());
- $appid = $this->config['appid'];
- $nonceStr = Tools::createNoncestr();
- if ($type === self::WXPAY_APP) {
- $sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, $result['prepay_id'], '']));
- return ['appId' => $appid, 'partnerId' => $this->config['mch_id'], 'prepayId' => $result['prepay_id'], 'package' => 'Sign=WXPay', 'nonceStr' => $nonceStr, 'timeStamp' => $time, 'sign' => $sign];
- } elseif ($type === self::WXPAY_JSAPI) {
- $sign = $this->signBuild(join("\n", [$appid, $time, $nonceStr, "prepay_id={$result['prepay_id']}", '']));
- return ['appId' => $appid, 'timestamp' => $time, 'timeStamp' => $time, 'nonceStr' => $nonceStr, 'package' => "prepay_id={$result['prepay_id']}", 'signType' => 'RSA', 'paySign' => $sign];
- } else {
- return $result;
- }
- }
- }
-
- /**
- * 支付订单查询
- * @param string $tradeNo 商户订单号 out_trade_no
- * @return array 订单详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
- */
- public function query($tradeNo)
- {
- $pathinfo = "/v3/pay/transactions/out-trade-no/{$tradeNo}";
- return $this->doRequest('GET', "{$pathinfo}?mchid={$this->config['mch_id']}", '', true);
- }
-
- /**
- * 关闭支付订单
- * @param string $tradeNo 商户订单号 out_trade_no
- * @return array 关闭结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function close($tradeNo)
- {
- $data = ['mchid' => $this->config['mch_id']];
- $path = "/v3/pay/transactions/out-trade-no/{$tradeNo}/close";
- return $this->doRequest('POST', $path, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 创建退款订单(V3)
- * @param array $data 退款参数(out_trade_no 或 transaction_id,out_refund_no,amount 等)
- * @return array 退款结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
- */
- public function createRefund($data)
- {
- $path = '/v3/refund/domestic/refunds';
- return $this->doRequest('POST', $path, json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 退款订单查询
- * @param string $refundNo 商户退款单号 out_refund_no
- * @return array 退款详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_10.shtml
- */
- public function queryRefund($refundNo)
- {
- $path = "/v3/refund/domestic/refunds/{$refundNo}";
- return $this->doRequest('GET', $path, '', true);
- }
-
- /**
- * 获取退款通知
- * @param mixed $data
- * @return array
- * @throws \WeChat\Exceptions\InvalidDecryptException
- * @deprecated 直接使用 Notify 方法
- */
- public function notifyRefund($data = [])
- {
- return $this->notify($data);
- }
-
- /**
- * 支付/退款通知解析(自动解密 resource)
- * @param array|null $data 通知原文,为空则从输入流读取
- * @return array 解析后的通知数据,包含 result 字段(明文)
- * @throws \WeChat\Exceptions\InvalidDecryptException
- */
- public function notify($data = [])
- {
- if (empty($data)) {
- $data = json_decode(Tools::getRawInput(), 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;
- }
-
- /**
- * 申请交易账单
- * @param array|string $params 账单参数(bill_date, bill_type 等)或已拼好的查询串
- * @return array 含下载地址的申请结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_6.shtml
- */
- public function tradeBill($params)
- {
- $path = '/v3/bill/tradebill?' . is_array($params) ? http_build_query($params) : $params;
- return $this->doRequest('GET', $path, '', true);
- }
-
- /**
- * 申请资金账单
- * @param array|string $params 账单参数(bill_date, account_type 等)或已拼好的查询串
- * @return array 含下载地址的申请结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @document https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_3_7.shtml
- */
- public function fundflowBill($params)
- {
- $path = '/v3/bill/fundflowbill?' . is_array($params) ? http_build_query($params) : $params;
- return $this->doRequest('GET', $path, '', true);
- }
-
- /**
- * 下载账单文件
- * @param string $fileurl 申请账单返回的 download_url
- * @return string 二进制内容(gzip/CSV/Excel)
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @document https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_1.shtml
- */
- public function downloadBill($fileurl)
- {
- return $this->doRequest('GET', $fileurl, '', false, false);
- }
-}
diff --git a/WePayV3/ProfitSharing.php b/WePayV3/ProfitSharing.php
deleted file mode 100644
index 3fc63b9..0000000
--- a/WePayV3/ProfitSharing.php
+++ /dev/null
@@ -1,114 +0,0 @@
-config['appid'];
- return $this->doRequest('POST', '/v3/profitsharing/orders', json_encode($options, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询分账结果
- * @param string $outOrderNo 商户分账单号
- * @param string $transactionId 微信订单号
- * @return array 分账状态
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function query($outOrderNo, $transactionId)
- {
- $pathinfo = "/v3/profitsharing/orders/{$outOrderNo}?&transaction_id={$transactionId}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 解冻剩余资金
- * @param array $options 解冻参数(transaction_id, out_order_no, description)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function unfreeze(array $options)
- {
- return $this->doRequest('POST', '/v3/profitsharing/orders/unfreeze', json_encode($options, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询剩余待分金额
- * @param string $transactionId 微信订单号
- * @return array 待分金额
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function amounts($transactionId)
- {
- $pathinfo = "/v3/profitsharing/transactions/{$transactionId}/amounts";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 添加分账接收方
- * @param array $options 接收方信息(type, account, name 等,name 需 RSA)
- * @return array
- * @throws \WeChat\Exceptions\InvalidDecryptException
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function addReceiver(array $options)
- {
- $options['appid'] = $this->config['appid'];
- if (isset($options['name'])) {
- $options['name'] = $this->rsaEncode($options['name']);
- }
- return $this->doRequest('POST', "/v3/profitsharing/receivers/add", json_encode($options, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 删除分账接收方
- * @param array $options 接收方信息(type, account)
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function deleteReceiver(array $options)
- {
- $options['appid'] = $this->config['appid'];
- return $this->doRequest('POST', "/v3/profitsharing/receivers/delete", json_encode($options, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 请求分账回退
- * @param array $options 回退参数(out_return_no, out_order_no, return_account 等)
- * @return array 回退结果
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function backspace(array $options)
- {
- $options['appid'] = $this->config['appid'];
- return $this->doRequest('POST', "/v3/profitsharing/return-orders", json_encode($options, JSON_UNESCAPED_UNICODE), true);
- }
-}
diff --git a/WePayV3/Refund.php b/WePayV3/Refund.php
deleted file mode 100644
index 9795039..0000000
--- a/WePayV3/Refund.php
+++ /dev/null
@@ -1,82 +0,0 @@
-config)->createRefund($data);
- // return $this->doRequest('POST', '/v3/ecommerce/refunds/apply', json_encode($data, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 退款订单查询(兼容入口)
- * @param string $refundNo 商户退款单号 out_refund_no
- * @return array 退款详情
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function query($refundNo)
- {
- return Order::instance($this->config)->queryRefund($refundNo);
- // $pathinfo = "/v3/ecommerce/refunds/out-refund-no/{$refundNo}";
- // return $this->doRequest('GET', "{$pathinfo}?sub_mchid={$this->config['mch_id']}", '', true);
- }
-
- /**
- * 获取退款通知(兼容入口,转调 Order::notify)
- * @param mixed $xml 通知原文
- * @return array 解密后的通知数据
- * @throws \WeChat\Exceptions\InvalidDecryptException
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @throws \WeChat\Exceptions\LocalCacheException
- */
- public function notify($xml = [])
- {
- return Order::instance($this->config)->notify($xml);
-// $data = Tools::xml2arr(empty($xml) ? Tools::getRawInput() : $xml);
-// 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());
-// }
- }
-}
\ No newline at end of file
diff --git a/WePayV3/Transfers.php b/WePayV3/Transfers.php
deleted file mode 100644
index 43cfe9b..0000000
--- a/WePayV3/Transfers.php
+++ /dev/null
@@ -1,137 +0,0 @@
-config['appid'];
- }
- if (!empty($body['user_name'])) {
- $body['user_name'] = $this->rsaEncode($body['user_name']);
- }
- return $this->doRequest('POST', '/v3/fund-app/mch-transfer/transfer-bills', json_encode($body, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询转账结果
- * @param string $out_bill_no 商户转账单号
- * @return array|string 转账状态
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function billsQuery($out_bill_no)
- {
- return $this->doRequest('GET', "/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{$out_bill_no}", '', true);
- }
-
- /**
- * 发起商家批量转账
- * @param array $body 批量参数(out_batch_no, transfer_detail_list 等,姓名需 RSA)
- * @return array
- * @throws \WeChat\Exceptions\InvalidDecryptException
- * @throws \WeChat\Exceptions\InvalidResponseException
- * @link https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml
- */
- public function batchs($body)
- {
- if (empty($body['appid'])) {
- $body['appid'] = $this->config['appid'];
- }
- if (isset($body['transfer_detail_list']) && is_array($body['transfer_detail_list'])) {
- foreach ($body['transfer_detail_list'] as &$item) if (isset($item['user_name'])) {
- $item['user_name'] = $this->rsaEncode($item['user_name']);
- }
- if (empty($body['total_num'])) {
- $body['total_num'] = count($body['transfer_detail_list']);
- }
- if (empty($body['total_amount'])) {
- $body['total_amount'] = array_sum(array_column($body['transfer_detail_list'], 'transfer_amount'));
- }
- }
- return $this->doRequest('POST', '/v3/transfer/batches', json_encode($body, JSON_UNESCAPED_UNICODE), true);
- }
-
- /**
- * 查询批量转账批次
- * @param string $batchId 微信批次单号(二选一)
- * @param string $outBatchNo 商户批次单号(二选一)
- * @param bool $needQueryDetail 是否拉取明细
- * @param int $offset 明细起始位置
- * @param int $limit 最大明细条数
- * @param string $detailStatus 明细状态 ALL|SUCCESS|FAIL
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function query($batchId = '', $outBatchNo = '', $needQueryDetail = true, $offset = 0, $limit = 20, $detailStatus = 'ALL')
- {
- if (empty($batchId)) {
- $pathinfo = "/v3/transfer/batches/out-batch-no/{$outBatchNo}";
- } else {
- $pathinfo = "/v3/transfer/batches/batch-id/{$batchId}";
- }
- $params = http_build_query([
- 'limit' => $limit,
- 'offset' => $offset,
- 'detail_status' => $detailStatus,
- 'need_query_detail' => $needQueryDetail ? 'true' : 'false',
- ]);
- return $this->doRequest('GET', "{$pathinfo}?{$params}", '', true);
- }
-
- /**
- * 通过微信明细单号查询明细
- * @param string $batchId 微信批次单号
- * @param string $detailId 微信明细单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function detailBatchId($batchId, $detailId)
- {
- $pathinfo = "/v3/transfer/batches/batch-id/{$batchId}/details/detail-id/{$detailId}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-
- /**
- * 通过商家明细单号查询明细
- * @param string $outBatchNo 商户批次单号
- * @param string $outDetailNo 商户明细单号
- * @return array
- * @throws \WeChat\Exceptions\InvalidResponseException
- */
- public function detailOutBatchNo($outBatchNo, $outDetailNo)
- {
- $pathinfo = "/v3/transfer/batches/out-batch-no/{$outBatchNo}/details/out-detail-no/{$outDetailNo}";
- return $this->doRequest('GET', $pathinfo, '', true);
- }
-}
diff --git a/_test/alipay-app.php b/_test/alipay-app.php
deleted file mode 100644
index 155d3b4..0000000
--- a/_test/alipay-app.php
+++ /dev/null
@@ -1,46 +0,0 @@
-apply([
- 'out_trade_no' => strval(time()), // 商户订单号
- 'total_amount' => '1', // 支付金额
- 'subject' => '支付宝订单标题', // 支付订单描述
- ]);
- echo $result . PHP_EOL . '
' . PHP_EOL;
-
- // 请求关闭订单
- $result = $pay->close([
- 'out_trade_no' => strval(time())
- ]);
- echo PHP_EOL . PHP_EOL . $result;
-} catch (\Exception $e) {
- echo $e->getMessage();
-}
-
-
diff --git a/_test/alipay-bill.php b/_test/alipay-bill.php
deleted file mode 100644
index 3a8ffca..0000000
--- a/_test/alipay-bill.php
+++ /dev/null
@@ -1,47 +0,0 @@
-apply([
- 'bill_date' => date('Y-m-d', strtotime('-1 month')), // 账单时间(日账单yyyy-MM-dd,月账单 yyyy-MM)
- 'bill_type' => 'trade',
- ]);
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
\ No newline at end of file
diff --git a/_test/alipay-callapi-test.php b/_test/alipay-callapi-test.php
deleted file mode 100644
index 9ba45bd..0000000
--- a/_test/alipay-callapi-test.php
+++ /dev/null
@@ -1,163 +0,0 @@
-=== 支付宝通用接口测试 ===";
-
- // ============================================
- // 测试1: GET请求 - 查询订单
- // ============================================
- echo "测试1: GET请求 - 查询订单
";
- try {
- $result = $alipay->callApi(
- 'alipay.trade.query', // API方法名(必填,第一参数)
- [
- 'out_trade_no' => time() - 3600, // 使用一个可能存在的订单号
- ],
- 'GET',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试2: GET请求 - 查询订单(验证签名)
- // ============================================
- echo "测试2: GET请求 - 查询订单(验证签名)
";
- try {
- $result = $alipay->callApi(
- 'alipay.trade.query', // API方法名
- [
- 'out_trade_no' => time() - 3600,
- ],
- 'GET',
- true // 验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试3: POST请求 - 订单退款
- // ============================================
- echo "测试3: POST请求 - 订单退款
";
- echo "注意:此测试需要有效的订单号
";
- try {
- $result = $alipay->callApi(
- 'alipay.trade.refund', // API方法名(第一参数)
- [
- 'out_trade_no' => time() - 3600,
- 'refund_amount' => '0.01',
- ],
- 'POST',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- echo "这是正常的,因为退款需要有效的订单号
";
- }
-
- // ============================================
- // 测试4: GET请求 - 退款查询
- // ============================================
- echo "测试4: GET请求 - 退款查询
";
- try {
- $result = $alipay->callApi(
- 'alipay.trade.fastpay.refund.query', // API方法名
- [
- 'out_trade_no' => time() - 3600,
- 'out_request_no' => time() - 3600,
- ],
- 'GET',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试5: POST请求 - 关闭订单
- // ============================================
- echo "测试5: POST请求 - 关闭订单
";
- try {
- $result = $alipay->callApi(
- 'alipay.trade.close', // API方法名
- [
- 'out_trade_no' => time() - 3600,
- ],
- 'POST',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试6: PUT请求 - 更新资源(示例)
- // ============================================
- echo "测试6: PUT请求 - 更新资源(示例)
";
- echo "注意:此示例仅展示PUT请求用法,实际API可能不支持
";
- try {
- // PUT请求示例(如果API支持)
- // $result = $alipay->callApi(
- // 'alipay.some.method', // API方法名
- // ['key' => 'value'],
- // 'PUT',
- // false
- // );
- echo 'PUT请求用法示例(已注释)
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- echo "=== 所有测试完成 ===
";
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo "错误: " . $e->getMessage() . "
";
- echo "" . $e->getTraceAsString() . "
";
-}
diff --git a/_test/alipay-notify.php b/_test/alipay-notify.php
deleted file mode 100644
index 26b84f5..0000000
--- a/_test/alipay-notify.php
+++ /dev/null
@@ -1,41 +0,0 @@
-notify();
- if (in_array($data['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
- // @todo 更新订单状态,支付完成
- file_put_contents('notify.txt', "收到来自支付宝的异步通知\r\n", FILE_APPEND);
- file_put_contents('notify.txt', '订单号:' . $data['out_trade_no'] . "\r\n", FILE_APPEND);
- file_put_contents('notify.txt', '订单金额:' . $data['total_amount'] . "\r\n\r\n", FILE_APPEND);
- } else {
- file_put_contents('notify.txt', "收到异步通知\r\n", FILE_APPEND);
- }
-} catch (\Exception $e) {
- // 异常处理
- echo $e->getMessage();
-}
diff --git a/_test/alipay-pos.php b/_test/alipay-pos.php
deleted file mode 100644
index 0849795..0000000
--- a/_test/alipay-pos.php
+++ /dev/null
@@ -1,43 +0,0 @@
-apply([
- 'out_trade_no' => '4312412343', // 订单号
- 'total_amount' => '13', // 订单金额,单位:元
- 'subject' => '订单商品标题', // 订单商品标题
- 'auth_code' => '123456', // 授权码
- ]);
-
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
-
diff --git a/_test/alipay-refund.php b/_test/alipay-refund.php
deleted file mode 100644
index d880bab..0000000
--- a/_test/alipay-refund.php
+++ /dev/null
@@ -1,41 +0,0 @@
-refund($out_trade_no, $refund_fee);
-
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
\ No newline at end of file
diff --git a/_test/alipay-scan.php b/_test/alipay-scan.php
deleted file mode 100644
index 649fa91..0000000
--- a/_test/alipay-scan.php
+++ /dev/null
@@ -1,42 +0,0 @@
-apply([
- 'out_trade_no' => '14321412', // 订单号
- 'total_amount' => '13', // 订单金额,单位:元
- 'subject' => '订单商品标题', // 订单商品标题
- ]);
-
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
-
diff --git a/_test/alipay-transfer-account.php b/_test/alipay-transfer-account.php
deleted file mode 100644
index ae5a86f..0000000
--- a/_test/alipay-transfer-account.php
+++ /dev/null
@@ -1,39 +0,0 @@
-queryAccount([
- 'alipay_user_id' => $config['appid'], // 订单号
- 'account_scene_code' => 'SCENE_000_000_000',
- ]);
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
diff --git a/_test/alipay-transfer-create.php b/_test/alipay-transfer-create.php
deleted file mode 100644
index 9bf4faf..0000000
--- a/_test/alipay-transfer-create.php
+++ /dev/null
@@ -1,46 +0,0 @@
-create([
- 'out_biz_no' => time(), // 订单号
- 'trans_amount' => '10', // 转账金额
- 'product_code' => 'TRANS_ACCOUNT_NO_PWD',
- 'biz_scene' => 'DIRECT_TRANSFER',
- 'payee_info' => [
- 'identity' => 'zoujingli@qq.com',
- 'identity_type' => 'ALIPAY_LOGON_ID',
- 'name' => '邹景立',
- ],
- ]);
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
diff --git a/_test/alipay-transfer-query.php b/_test/alipay-transfer-query.php
deleted file mode 100644
index 434e0cc..0000000
--- a/_test/alipay-transfer-query.php
+++ /dev/null
@@ -1,40 +0,0 @@
-queryResult([
- 'out_biz_no' => '201808080001', // 订单号
- 'product_code' => 'TRANS_ACCOUNT_NO_PWD',
- 'biz_scene' => 'DIRECT_TRANSFER',
- ]);
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
diff --git a/_test/alipay-transfer.php b/_test/alipay-transfer.php
deleted file mode 100644
index 48feac7..0000000
--- a/_test/alipay-transfer.php
+++ /dev/null
@@ -1,45 +0,0 @@
-apply([
- 'out_biz_no' => time(), // 订单号
- 'payee_type' => 'ALIPAY_LOGONID', // 收款方账户类型(ALIPAY_LOGONID | ALIPAY_USERID)
- 'payee_account' => 'yvvfcr3065@sandbox.com', // 收款方账户
- 'amount' => '10', // 转账金额
- 'payer_show_name' => '未寒', // 付款方姓名
- 'payee_real_name' => 'yvvfcr3065', // 收款方真实姓名
- 'remark' => '张三', // 转账备注
- ]);
-
- echo '';
- var_export($result);
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
diff --git a/_test/alipay-wap.php b/_test/alipay-wap.php
deleted file mode 100644
index bcb232b..0000000
--- a/_test/alipay-wap.php
+++ /dev/null
@@ -1,44 +0,0 @@
-apply([
- 'out_trade_no' => time(), // 商户订单号
- 'total_amount' => '1', // 支付金额
- 'subject' => '支付订单描述', // 支付订单描述
- ]);
-
- echo $result;
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
-
diff --git a/_test/alipay-web.php b/_test/alipay-web.php
deleted file mode 100644
index de3cee8..0000000
--- a/_test/alipay-web.php
+++ /dev/null
@@ -1,45 +0,0 @@
-apply([
- 'out_trade_no' => time(), // 商户订单号
- 'total_amount' => '1', // 支付金额
- 'subject' => '支付订单描述', // 支付订单描述
- ]);
-
- echo $result;
-} catch (Exception $e) {
- echo $e->getMessage();
-}
-
-
diff --git a/_test/alipay.php b/_test/alipay.php
deleted file mode 100644
index 28ec6f1..0000000
--- a/_test/alipay.php
+++ /dev/null
@@ -1,58 +0,0 @@
- true,
- // 签名类型 ( RSA|RSA2 )
- 'sign_type' => 'RSA2',
- // 应用ID
- 'appid' => '2021000122667306',
- // 应用私钥内容 ( 需1行填写,特别注意:这里的应用私钥通常由支付宝密钥管理工具生成 )
- 'private_key' => 'MIIEowIBAAKCAQEAndH26KVe3Iy+8GxVxDuG9ZolYrqGNm8Jpdi9GrQdM81ad4pPyul2NVO+9C2Kr6a6jK6Qw1gyzcwYxtkUC7xoLZUSPpmSH7sH3sD6r2B7Mf5FsrVSa29lcm1+3UkyFgZjYTkx45lfbLmAFHOzOl0WfGkMW0Sq3N/5OMr074E4EnYtALdE3jVQCDf8bzqN3j/Kwe7f10Aglvxili2BrFM564silqcbiJ8U1zDmTdZvmEkP7ia/YVkmt5w3rh7ZBoaubtcM/rVGYXL2hQPwr/pquNCTu7Eh1RcWfpcnbuw+gOnaNyXmNFmZkeNlegXIifcunt1GK6a1pX090R8eFN3LjQIDAQABAoIBACrLY4OETCvL8n6pMbyLU7ZHfTm/UGN0So5xLh4OlxiT56MgmzBvjAE72zzFGKU2tcEuGM0Pnn8Vh+ZruLbR+QHbOV5GMExwX9r0Q0XJCL7uryGdb2L4iu6zaEJC9dTpGIulgbSwwyJtTqC9Gu2Jjm5f4dzhyt8n0KGozzAevwCqI9RaJSD96gGWLbMlHCyWKGy1OdBP4V/+agPyHAGZ9gqpfKY7y4L0My8gUxhWzQWOwihtFACjV66ULhutUYT2bro3j1k9UekKlX7IiWrssPmmmw2vfUbrKiNugF6zkfyStPt7jGJ0CdzAHWe3pyF72TyO5NU2NGcX8eKgYlY2crUCgYEAzOcg5Zot9X+Ao+fYH/Oq/3eGZd6krzByiXfcjuRco7mGODwmUnzt3PpPT1fPry9TxarTajt+A9LuxqWawfQ9eWAfrTGAbtDJB0LYo6CynDqUoRqBukROuNaLQiUqEreOQqt08o6VVblgVLv8475ij8s4z/6C2NSSjgUJHf0PL38CgYEAxS0bcXGI+WtempZ4Q3QMTUmp/+B3zuw9JzSV1gvbVi7MleI9V62V2IXHPSXL5mRhYOuQWR0MnVOhbo69fkEA8HpdSd1q2JjaeS+OiZ0ditcJISQJbqWtvmF2+XtQcbVwfID69GWGxyBEHHTW8AtAzIPc6T7x2izyzBw0lXDHSvMCgYEAi+Y61ckhG/9EC6TeMWKjG+21u5P6CQshCK7nzkAo6DhhZb/bwnI9zaSxxdCEom3D2rA5zMx1y5KXKNYlBcwGtPpmZk/oCsFOoECJvZ6YlIaCuERq0oyU2yrQxgat5T2iSe7a2El1uKPrG6+GiNCSZu8wCQMSv4zTy1ew0+LWHW0CgYAvX7ESRpcEZjmqprBqdH1oLGS9566hdr0SqF2/ucWPJVteP6dBY6F3Dl1aYbRlvIRxBuf9oS8gtbE5oO4CYZfaL2wujRZYyBDlwPlcMvWgIB4/aish/IiMD1rIgkpHp7JJF6w0ABiryyLSO3hQ4ENHX/85wzfUlawYQkaYCSq45QKBgCdqrv58KD8tDYn4JnaHJNE+5TgKK5cNhYLZLAsYz7x1KfPdkiC7y/hnenn3TWkm4xw8Tw1rJ1ZIJ24iZgTCTO7EEsB7jZegvg4z/4zVbSK2Y4VI1lJ7jlyqmwg0ArimXTNZFoy66h9c9t2smG40YEZCmmmTLEqVlWgyR1MU5iM5',
- // 公钥模式,支付宝公钥内容 ( 需1行填写,特别注意:这里不是应用公钥而是支付宝公钥,通常是上传应用公钥换取支付宝公钥,在网页可以复制 )
- 'public_key' => '',
- // 证书模式,应用公钥证书路径 ( 新版资金类接口转 app_cert_sn,如文件 appCertPublicKey.crt )
- 'app_cert_path' => __DIR__ . '/alipay/appPublicCert.crt', // 'app_cert' => '证书内容',
- // 证书模式,支付宝根证书路径 ( 新版资金类接口转 alipay_root_cert_sn,如文件 alipayRootCert.crt )
- 'alipay_root_path' => __DIR__ . '/alipay/alipayRootCert.crt', // 'root_cert' => '证书内容',
- // 证书模式,支付宝公钥证书路径 ( 未填写 public_key 时启用此参数,如文件 alipayPublicCert.crt )
- 'alipay_cert_path' => __DIR__ . '/alipay/alipayPublicCert.crt', // 'public_key' => '证书内容'
- // 支付成功通知地址
- 'notify_url' => '',
- // 网页支付回跳地址
- 'return_url' => '',
-];
\ No newline at end of file
diff --git a/_test/alipay/alipayPublicCert.crt b/_test/alipay/alipayPublicCert.crt
deleted file mode 100644
index 0d7d612..0000000
--- a/_test/alipay/alipayPublicCert.crt
+++ /dev/null
@@ -1,38 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDszCCApugAwIBAgIQICMFBicVvB1uC0Lc3VFbITANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
-BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv
-biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjMwNTA2MDYwMTA3WhcNMjQwNTA1MDYwMTA3WjCB
-hDELMAkGA1UEBhMCQ04xHzAdBgNVBAoMFndtaWFrdTY3NDlAc2FuZGJveC5jb20xDzANBgNVBAsM
-BkFsaXBheTFDMEEGA1UEAww65pSv5LuY5a6dKOS4reWbvSnnvZHnu5zmioDmnK/mnInpmZDlhazl
-j7gtMjA4ODcyMTAwMjg0MzQxNDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALkO9F4+
-AB7CLI47hSthHsZFFQxnOiggc4R8pbeb24BkyRc6xJVekYtzuJ8cLSsy1spEX4zguTPc+b7eza5k
-nN1j2pdAfNkzbdEg1Tt4A0b5xbMAfaQtVhwU0aohhLF+i6TTgospMmBwJnN2++Eda6LccrTqS7ff
-x8I2bhkraLlEO4C6pxUcGCyorPLVvRWOTRC/RzxDURHEaGlBPMxxOpeIzYuYNg77OK+Sqp0zb5nk
-U3PO2cpSrOCT4UlrJDmqgSZgwHE0e+9MdBuveLSo1ubG5uGvz8Vjld3hBvVywOAnEuoMBxtSrEbv
-nkz7M0MJBDmQk/D8WSekm2lMGbFDuGUCAwEAAaMSMBAwDgYDVR0PAQH/BAQDAgTwMA0GCSqGSIb3
-DQEBCwUAA4IBAQC29uyA9W6uQivhMqc3YyGXPvi4LIOThU1ijeOSpovHiRUGVfaO/qIY4eAQ2ivF
-iKIrUEqcJnWdNN8LZwWdWd6UmInyngq2i+Pf4h3a2MLkV3ZufZNZkJP5GZJxbcjkKlnKuCTKFUd5
-wJ0zo369E+mPdNGlrPLvNXw4ziUpUb4KXmEn1yOVAkQMsBP43K6QB2QVIODrtp4O+rEs80KHgUQh
-cmla+PWGyX2nuwHURxUtEeIeJblra+ntyy+bTYfCVVG8jh4BN5bPExDprRa100aZGsqyExO1xtxk
-4pu0Jag5XRvGyZpmqH27SfQX2oKcsobuDyGCwff/yvYKOZk53JZD
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDszCCApugAwIBAgIQIBkIGbgVxq210KxLJ+YA/TANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UE
-BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxJTAjBgNVBAsMHENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5IHRlc3QxNjA0BgNVBAMMLUFudCBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgUjEgdGVzdDAeFw0xOTA4MTkxMTE2MDBaFw0yNDA4MDExMTE2MDBaMIGRMQswCQYDVQQGEwJD
-TjEbMBkGA1UECgwSQW50IEZpbmFuY2lhbCB0ZXN0MSUwIwYDVQQLDBxDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSB0ZXN0MT4wPAYDVQQDDDVBbnQgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5IENsYXNzIDIgUjEgdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMh4FKYO
-ZyRQHD6eFbPKZeSAnrfjfU7xmS9Yoozuu+iuqZlb6Z0SPLUqqTZAFZejOcmr07ln/pwZxluqplxC
-5+B48End4nclDMlT5HPrDr3W0frs6Xsa2ZNcyil/iKNB5MbGll8LRAxntsKvZZj6vUTMb705gYgm
-VUMILwi/ZxKTQqBtkT/kQQ5y6nOZsj7XI5rYdz6qqOROrpvS/d7iypdHOMIM9Iz9DlL1mrCykbBi
-t25y+gTeXmuisHUwqaRpwtCGK4BayCqxRGbNipe6W73EK9lBrrzNtTr9NaysesT/v+l25JHCL9tG
-wpNr1oWFzk4IHVOg0ORiQ6SUgxZUTYcCAwEAAaMSMBAwDgYDVR0PAQH/BAQDAgTwMA0GCSqGSIb3
-DQEBCwUAA4IBAQBWThEoIaQoBX2YeRY/I8gu6TYnFXtyuCljANnXnM38ft+ikhE5mMNgKmJYLHvT
-yWWWgwHoSAWEuml7EGbE/2AK2h3k0MdfiWLzdmpPCRG/RJHk6UB1pMHPilI+c0MVu16OPpKbg5Vf
-LTv7dsAB40AzKsvyYw88/Ezi1osTXo6QQwda7uefvudirtb8FcQM9R66cJxl3kt1FXbpYwheIm/p
-j1mq64swCoIYu4NrsUYtn6CV542DTQMI5QdXkn+PzUUly8F6kDp+KpMNd0avfWNL5+O++z+F5Szy
-1CPta1D7EQ/eYmMP+mOQ35oifWIoFCpN6qQVBS/Hob1J/UUyg7BW
------END CERTIFICATE-----
diff --git a/_test/alipay/alipayRootCert.crt b/_test/alipay/alipayRootCert.crt
deleted file mode 100644
index 76417c5..0000000
--- a/_test/alipay/alipayRootCert.crt
+++ /dev/null
@@ -1,88 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQG
-EwJDTjEOMAwGA1UECgwFTlJDQUMxDzANBgNVBAMMBlJPT1RDQTAeFw0xMjA3MTQw
-MzExNTlaFw00MjA3MDcwMzExNTlaMC4xCzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVO
-UkNBQzEPMA0GA1UEAwwGUk9PVENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE
-MPCca6pmgcchsTf2UnBeL9rtp4nw+itk1Kzrmbnqo05lUwkwlWK+4OIrtFdAqnRT
-V7Q9v1htkv42TsIutzd126NdMFswHwYDVR0jBBgwFoAUTDKxl9kzG8SmBcHG5Yti
-W/CXdlgwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFEwysZfZ
-MxvEpgXBxuWLYlvwl3ZYMAwGCCqBHM9VAYN1BQADSAAwRQIgG1bSLeOXp3oB8H7b
-53W+CKOPl2PknmWEq/lMhtn25HkCIQDaHDgWxWFtnCrBjH16/W3Ezn7/U/Vjo5xI
-pDoiVhsLwg==
------END CERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIF0zCCA7ugAwIBAgIIH8+hjWpIDREwDQYJKoZIhvcNAQELBQAwejELMAkGA1UE
-BhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNVBAsMF0NlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5jaWFsIENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5IFIxMB4XDTE4MDMyMTEzNDg0MFoXDTM4MDIyODEzNDg0
-MFowejELMAkGA1UEBhMCQ04xFjAUBgNVBAoMDUFudCBGaW5hbmNpYWwxIDAeBgNV
-BAsMF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MTEwLwYDVQQDDChBbnQgRmluYW5j
-aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFIxMIICIjANBgkqhkiG9w0BAQEF
-AAOCAg8AMIICCgKCAgEAtytTRcBNuur5h8xuxnlKJetT65cHGemGi8oD+beHFPTk
-rUTlFt9Xn7fAVGo6QSsPb9uGLpUFGEdGmbsQ2q9cV4P89qkH04VzIPwT7AywJdt2
-xAvMs+MgHFJzOYfL1QkdOOVO7NwKxH8IvlQgFabWomWk2Ei9WfUyxFjVO1LVh0Bp
-dRBeWLMkdudx0tl3+21t1apnReFNQ5nfX29xeSxIhesaMHDZFViO/DXDNW2BcTs6
-vSWKyJ4YIIIzStumD8K1xMsoaZBMDxg4itjWFaKRgNuPiIn4kjDY3kC66Sl/6yTl
-YUz8AybbEsICZzssdZh7jcNb1VRfk79lgAprm/Ktl+mgrU1gaMGP1OE25JCbqli1
-Pbw/BpPynyP9+XulE+2mxFwTYhKAwpDIDKuYsFUXuo8t261pCovI1CXFzAQM2w7H
-DtA2nOXSW6q0jGDJ5+WauH+K8ZSvA6x4sFo4u0KNCx0ROTBpLif6GTngqo3sj+98
-SZiMNLFMQoQkjkdN5Q5g9N6CFZPVZ6QpO0JcIc7S1le/g9z5iBKnifrKxy0TQjtG
-PsDwc8ubPnRm/F82RReCoyNyx63indpgFfhN7+KxUIQ9cOwwTvemmor0A+ZQamRe
-9LMuiEfEaWUDK+6O0Gl8lO571uI5onYdN1VIgOmwFbe+D8TcuzVjIZ/zvHrAGUcC
-AwEAAaNdMFswCwYDVR0PBAQDAgEGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFF90
-tATATwda6uWx2yKjh0GynOEBMB8GA1UdIwQYMBaAFF90tATATwda6uWx2yKjh0Gy
-nOEBMA0GCSqGSIb3DQEBCwUAA4ICAQCVYaOtqOLIpsrEikE5lb+UARNSFJg6tpkf
-tJ2U8QF/DejemEHx5IClQu6ajxjtu0Aie4/3UnIXop8nH/Q57l+Wyt9T7N2WPiNq
-JSlYKYbJpPF8LXbuKYG3BTFTdOVFIeRe2NUyYh/xs6bXGr4WKTXb3qBmzR02FSy3
-IODQw5Q6zpXj8prYqFHYsOvGCEc1CwJaSaYwRhTkFedJUxiyhyB5GQwoFfExCVHW
-05ZFCAVYFldCJvUzfzrWubN6wX0DD2dwultgmldOn/W/n8at52mpPNvIdbZb2F41
-T0YZeoWnCJrYXjq/32oc1cmifIHqySnyMnavi75DxPCdZsCOpSAT4j4lAQRGsfgI
-kkLPGQieMfNNkMCKh7qjwdXAVtdqhf0RVtFILH3OyEodlk1HYXqX5iE5wlaKzDop
-PKwf2Q3BErq1xChYGGVS+dEvyXc/2nIBlt7uLWKp4XFjqekKbaGaLJdjYP5b2s7N
-1dM0MXQ/f8XoXKBkJNzEiM3hfsU6DOREgMc1DIsFKxfuMwX3EkVQM1If8ghb6x5Y
-jXayv+NLbidOSzk4vl5QwngO/JYFMkoc6i9LNwEaEtR9PhnrdubxmrtM+RjfBm02
-77q3dSWFESFQ4QxYWew4pHE0DpWbWy/iMIKQ6UZ5RLvB8GEcgt8ON7BBJeMc+Dyi
-kT9qhqn+lw==
------END CERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIICiDCCAgygAwIBAgIIQX76UsB/30owDAYIKoZIzj0EAwMFADB6MQswCQYDVQQG
-EwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UECwwXQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNpYWwgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkgRTEwHhcNMTkwNDI4MTYyMDQ0WhcNNDkwNDIwMTYyMDQ0
-WjB6MQswCQYDVQQGEwJDTjEWMBQGA1UECgwNQW50IEZpbmFuY2lhbDEgMB4GA1UE
-CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxMTAvBgNVBAMMKEFudCBGaW5hbmNp
-YWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRTEwdjAQBgcqhkjOPQIBBgUrgQQA
-IgNiAASCCRa94QI0vR5Up9Yr9HEupz6hSoyjySYqo7v837KnmjveUIUNiuC9pWAU
-WP3jwLX3HkzeiNdeg22a0IZPoSUCpasufiLAnfXh6NInLiWBrjLJXDSGaY7vaokt
-rpZvAdmjXTBbMAsGA1UdDwQEAwIBBjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRZ
-4ZTgDpksHL2qcpkFkxD2zVd16TAfBgNVHSMEGDAWgBRZ4ZTgDpksHL2qcpkFkxD2
-zVd16TAMBggqhkjOPQQDAwUAA2gAMGUCMQD4IoqT2hTUn0jt7oXLdMJ8q4vLp6sg
-wHfPiOr9gxreb+e6Oidwd2LDnC4OUqCWiF8CMAzwKs4SnDJYcMLf2vpkbuVE4dTH
-Rglz+HGcTLWsFs4KxLsq7MuU+vJTBUeDJeDjdA==
------END CERTIFICATE-----
-
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIUEMdk6dVgOEIS2cCP0Q43P90Ps5YwDQYJKoZIhvcNAQEF
-BQAwajELMAkGA1UEBhMCQ04xEzARBgNVBAoMCmlUcnVzQ2hpbmExHDAaBgNVBAsM
-E0NoaW5hIFRydXN0IE5ldHdvcmsxKDAmBgNVBAMMH2lUcnVzQ2hpbmEgQ2xhc3Mg
-MiBSb290IENBIC0gRzMwHhcNMTMwNDE4MDkzNjU2WhcNMzMwNDE4MDkzNjU2WjBq
-MQswCQYDVQQGEwJDTjETMBEGA1UECgwKaVRydXNDaGluYTEcMBoGA1UECwwTQ2hp
-bmEgVHJ1c3QgTmV0d29yazEoMCYGA1UEAwwfaVRydXNDaGluYSBDbGFzcyAyIFJv
-b3QgQ0EgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOPPShpV
-nJbMqqCw6Bz1kehnoPst9pkr0V9idOwU2oyS47/HjJXk9Rd5a9xfwkPO88trUpz5
-4GmmwspDXjVFu9L0eFaRuH3KMha1Ak01citbF7cQLJlS7XI+tpkTGHEY5pt3EsQg
-wykfZl/A1jrnSkspMS997r2Gim54cwz+mTMgDRhZsKK/lbOeBPpWtcFizjXYCqhw
-WktvQfZBYi6o4sHCshnOswi4yV1p+LuFcQ2ciYdWvULh1eZhLxHbGXyznYHi0dGN
-z+I9H8aXxqAQfHVhbdHNzi77hCxFjOy+hHrGsyzjrd2swVQ2iUWP8BfEQqGLqM1g
-KgWKYfcTGdbPB1MCAwEAAaNjMGEwHQYDVR0OBBYEFG/oAMxTVe7y0+408CTAK8hA
-uTyRMB8GA1UdIwQYMBaAFG/oAMxTVe7y0+408CTAK8hAuTyRMA8GA1UdEwEB/wQF
-MAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBLnUTfW7hp
-emMbuUGCk7RBswzOT83bDM6824EkUnf+X0iKS95SUNGeeSWK2o/3ALJo5hi7GZr3
-U8eLaWAcYizfO99UXMRBPw5PRR+gXGEronGUugLpxsjuynoLQu8GQAeysSXKbN1I
-UugDo9u8igJORYA+5ms0s5sCUySqbQ2R5z/GoceyI9LdxIVa1RjVX8pYOj8JFwtn
-DJN3ftSFvNMYwRuILKuqUYSHc2GPYiHVflDh5nDymCMOQFcFG3WsEuB+EYQPFgIU
-1DHmdZcz7Llx8UOZXX2JupWCYzK1XhJb+r4hK5ncf/w8qGtYlmyJpxk3hr1TfUJX
-Yf4Zr0fJsGuv
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/_test/alipay/appPublicCert.crt b/_test/alipay/appPublicCert.crt
deleted file mode 100644
index 586f341..0000000
--- a/_test/alipay/appPublicCert.crt
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDmTCCAoGgAwIBAgIQICMFBmpzKUKQGs/81YT4UDANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UE
-BhMCQ04xGzAZBgNVBAoMEkFudCBGaW5hbmNpYWwgdGVzdDElMCMGA1UECwwcQ2VydGlmaWNhdGlv
-biBBdXRob3JpdHkgdGVzdDE+MDwGA1UEAww1QW50IEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1
-dGhvcml0eSBDbGFzcyAyIFIxIHRlc3QwHhcNMjMwNTA2MDYwMTA3WhcNMjQwNTEwMDYwMTA3WjBr
-MQswCQYDVQQGEwJDTjEfMB0GA1UECgwWd21pYWt1Njc0OUBzYW5kYm94LmNvbTEPMA0GA1UECwwG
-QWxpcGF5MSowKAYDVQQDDCEyMDg4NzIxMDAyODQzNDE0LTIwMjEwMDAxMjI2NjczMDYwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCd0fbopV7cjL7wbFXEO4b1miViuoY2bwml2L0atB0z
-zVp3ik/K6XY1U770LYqvprqMrpDDWDLNzBjG2RQLvGgtlRI+mZIfuwfewPqvYHsx/kWytVJrb2Vy
-bX7dSTIWBmNhOTHjmV9suYAUc7M6XRZ8aQxbRKrc3/k4yvTvgTgSdi0At0TeNVAIN/xvOo3eP8rB
-7t/XQCCW/GKWLYGsUznriyKWpxuInxTXMOZN1m+YSQ/uJr9hWSa3nDeuHtkGhq5u1wz+tUZhcvaF
-A/Cv+mq40JO7sSHVFxZ+lydu7D6A6do3JeY0WZmR42V6BciJ9y6e3UYrprWlfT3RHx4U3cuNAgMB
-AAGjEjAQMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQsFAAOCAQEAiLA1wk7or0uqxPSD9z31
-BLJRnamf51Uz2YOSDPjUivu9VJrkjf1PsCleK9RSgOcXcpy9QWZSFIIyakFqCCWylgBdjmhSvzAv
-po86ycJXEBrd7klOM/6VFh68BqpmK1CJl0g29JOJ1fNvIKYJ/WS4ue988NSGrpsVhXbNGALhgiBL
-Gqs7KkZQSsIAySx2HNCSknFM5G5xG6IR6wUJ619khba6rMaKOJ3D7mxuv0Vjyu7DrFBsPLOSdjP1
-Jzi5WmutetJGVrbOKayVjL4xDcU7lgOWTrhTs7S54Z6GnxqRLwy8gD7RmDbXtnVyGP/mUcAgnFtE
-BPFZBe7qjqsCCkf+Zw==
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/_test/alipay2.php b/_test/alipay2.php
deleted file mode 100644
index e0fdd20..0000000
--- a/_test/alipay2.php
+++ /dev/null
@@ -1,58 +0,0 @@
- true,
- // 签名类型 ( RSA|RSA2 )
- 'sign_type' => 'RSA2',
- // 应用ID
- 'appid' => '2021000122667306',
- // 应用私钥内容 ( 需1行填写,特别注意:这里的应用私钥通常由支付宝密钥管理工具生成 )
- 'private_key' => 'MIIEowIBAAKCAQEAndH26KVe3Iy+8GxVxDuG9ZolYrqGNm8Jpdi9GrQdM81ad4pPyul2NVO+9C2Kr6a6jK6Qw1gyzcwYxtkUC7xoLZUSPpmSH7sH3sD6r2B7Mf5FsrVSa29lcm1+3UkyFgZjYTkx45lfbLmAFHOzOl0WfGkMW0Sq3N/5OMr074E4EnYtALdE3jVQCDf8bzqN3j/Kwe7f10Aglvxili2BrFM564silqcbiJ8U1zDmTdZvmEkP7ia/YVkmt5w3rh7ZBoaubtcM/rVGYXL2hQPwr/pquNCTu7Eh1RcWfpcnbuw+gOnaNyXmNFmZkeNlegXIifcunt1GK6a1pX090R8eFN3LjQIDAQABAoIBACrLY4OETCvL8n6pMbyLU7ZHfTm/UGN0So5xLh4OlxiT56MgmzBvjAE72zzFGKU2tcEuGM0Pnn8Vh+ZruLbR+QHbOV5GMExwX9r0Q0XJCL7uryGdb2L4iu6zaEJC9dTpGIulgbSwwyJtTqC9Gu2Jjm5f4dzhyt8n0KGozzAevwCqI9RaJSD96gGWLbMlHCyWKGy1OdBP4V/+agPyHAGZ9gqpfKY7y4L0My8gUxhWzQWOwihtFACjV66ULhutUYT2bro3j1k9UekKlX7IiWrssPmmmw2vfUbrKiNugF6zkfyStPt7jGJ0CdzAHWe3pyF72TyO5NU2NGcX8eKgYlY2crUCgYEAzOcg5Zot9X+Ao+fYH/Oq/3eGZd6krzByiXfcjuRco7mGODwmUnzt3PpPT1fPry9TxarTajt+A9LuxqWawfQ9eWAfrTGAbtDJB0LYo6CynDqUoRqBukROuNaLQiUqEreOQqt08o6VVblgVLv8475ij8s4z/6C2NSSjgUJHf0PL38CgYEAxS0bcXGI+WtempZ4Q3QMTUmp/+B3zuw9JzSV1gvbVi7MleI9V62V2IXHPSXL5mRhYOuQWR0MnVOhbo69fkEA8HpdSd1q2JjaeS+OiZ0ditcJISQJbqWtvmF2+XtQcbVwfID69GWGxyBEHHTW8AtAzIPc6T7x2izyzBw0lXDHSvMCgYEAi+Y61ckhG/9EC6TeMWKjG+21u5P6CQshCK7nzkAo6DhhZb/bwnI9zaSxxdCEom3D2rA5zMx1y5KXKNYlBcwGtPpmZk/oCsFOoECJvZ6YlIaCuERq0oyU2yrQxgat5T2iSe7a2El1uKPrG6+GiNCSZu8wCQMSv4zTy1ew0+LWHW0CgYAvX7ESRpcEZjmqprBqdH1oLGS9566hdr0SqF2/ucWPJVteP6dBY6F3Dl1aYbRlvIRxBuf9oS8gtbE5oO4CYZfaL2wujRZYyBDlwPlcMvWgIB4/aish/IiMD1rIgkpHp7JJF6w0ABiryyLSO3hQ4ENHX/85wzfUlawYQkaYCSq45QKBgCdqrv58KD8tDYn4JnaHJNE+5TgKK5cNhYLZLAsYz7x1KfPdkiC7y/hnenn3TWkm4xw8Tw1rJ1ZIJ24iZgTCTO7EEsB7jZegvg4z/4zVbSK2Y4VI1lJ7jlyqmwg0ArimXTNZFoy66h9c9t2smG40YEZCmmmTLEqVlWgyR1MU5iM5',
- // 公钥模式,支付宝公钥内容 ( 需1行填写,特别注意:这里不是应用公钥而是支付宝公钥,通常是上传应用公钥换取支付宝公钥,在网页可以复制 )
- 'public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuQ70Xj4AHsIsjjuFK2EexkUVDGc6KCBzhHylt5vbgGTJFzrElV6Ri3O4nxwtKzLWykRfjOC5M9z5vt7NrmSc3WPal0B82TNt0SDVO3gDRvnFswB9pC1WHBTRqiGEsX6LpNOCiykyYHAmc3b74R1rotxytOpLt9/HwjZuGStouUQ7gLqnFRwYLKis8tW9FY5NEL9HPENREcRoaUE8zHE6l4jNi5g2Dvs4r5KqnTNvmeRTc87ZylKs4JPhSWskOaqBJmDAcTR770x0G694tKjW5sbm4a/PxWOV3eEG9XLA4CcS6gwHG1KsRu+eTPszQwkEOZCT8PxZJ6SbaUwZsUO4ZQIDAQAB',
- // 证书模式,应用公钥证书路径 ( 新版资金类接口转 app_cert_sn,如文件 appCertPublicKey.crt )
- 'app_cert_path' => __DIR__ . '/alipay/appPublicCert.crt', // 'app_cert' => '证书内容',
- // 证书模式,支付宝根证书路径 ( 新版资金类接口转 alipay_root_cert_sn,如文件 alipayRootCert.crt )
- 'alipay_root_path' => __DIR__ . '/alipay/alipayRootCert.crt', // 'root_cert' => '证书内容',
- // 证书模式,支付宝公钥证书路径 ( 未填写 public_key 时启用此参数,如文件 alipayPublicCert.crt )
- // 'alipay_cert_path' => __DIR__ . '/alipay/alipayPublicCert.crt', // 'public_key' => '证书内容'
- // 支付成功通知地址
- 'notify_url' => '',
- // 网页支付回跳地址
- 'return_url' => '',
-];
\ No newline at end of file
diff --git a/_test/config.php b/_test/config.php
deleted file mode 100644
index cee0e0a..0000000
--- a/_test/config.php
+++ /dev/null
@@ -1,52 +0,0 @@
- function ($name, $value, $expired = 360) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'get' => function ($name) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'del' => function ($name) {
-// var_dump(func_get_args());
-// return true;
-// },
-// 'put' => function ($name) {
-// var_dump(func_get_args());
-// return $filePath;
-// },
-// ];
-
-return [
- 'token' => 'test',
- 'appid' => 'wx60a43dd8161666d4',
- 'appsecret' => 'b4e28746f1bd73b5c6684f5e01883c36',
- 'encodingaeskey' => 'BJIUzE0gqlWy0GxfPp4J1oPTBmOrNDIGPNav1YFH5Z5',
- // 配置缓存目录,需要拥有写权限
- 'cache_path' => '',
- // 其他支付参数可以合并在这里
- // ...
-];
\ No newline at end of file
diff --git a/_test/mini-login.php b/_test/mini-login.php
deleted file mode 100644
index 885e28c..0000000
--- a/_test/mini-login.php
+++ /dev/null
@@ -1,38 +0,0 @@
- 'wx6bb7b70258da09c6',
- 'appsecret' => '78b7b8d65bd67b078babf951d4342b42',
-];
-
-// 解码数据
-$iv = 'ltM/wT7hsAl0TijEBI4v/g==';
-$code = '013LyiTR0TwjC92QjJRR0mEsTR0LyiT3';
-$decode = 'eIoVtIC2YzLCnrwiIs1IBbXMvC0vyL8bo1IhD38fUQIRbk3lgTWa0Hdw/Ty7NTs3iu7YlqqZBti+cxd6dCfeXBUQwTO2QpbHg0WTeDAdrihsHRHm4dCWdfTx8rzDloGbNOIsKdRElIhUH5YFdiTr5AYiufUDb34cwJ4GNWLAUq4bR0dmFeVEi+3nfwe2MAjGYDl4aq719VLsHodOggK6lXZvM5wjoDyuZsK2dPqJr3/Ji30Z0mdyFq32R4uR3rtJH/h+Rj0+/QmE9QYG7Y6Z48hgPE8cpnhRQNwH49jnC/zKZ9wtDkQ/J8J3Ed2i58zcuY01v8IV+pZ8oBUKXfO5ha+APOxtBSTzyHraU/2RGo8UWtOF6h64OQZhd/UQQy362eyc/qoq8sF9JnEFRP0mRmTDJ+u9oyDhxswCu6x8V73ERWaJeEGSCyjiGpep7/DxZ6eSSBq36OB0BWBkJqsq9Q==';
-$sessionKey = 'OetNxl86B/yMpbwG6wtMEw==';
-
-// $mini = \We::WeMiniCrypt($config);
-// $mini = new WeMini\Crypt($config);
-$mini = \WeMini\Crypt::instance($config);
-
-echo '';
-//print_r($mini->session($code));
-print_r($mini->decode($iv, $sessionKey, $decode));
-//print_r($mini->userInfo($code, $iv, $decode));
\ No newline at end of file
diff --git a/_test/mini-qrc.php b/_test/mini-qrc.php
deleted file mode 100644
index 9516669..0000000
--- a/_test/mini-qrc.php
+++ /dev/null
@@ -1,39 +0,0 @@
- 'wx6bb7b70258da09c6',
- 'appsecret' => '78b7b8d65bd67b078babf951d4342b42',
-];
-
-//We::config($config);
-
-// $mini = We::WeMiniQrcode($config);
-// $mini = new WeMini\Qrcode($config);
-$mini = \WeMini\Qrcode::instance($config);
-
-//echo '';
-try {
- header('Content-type:image/jpeg'); //输出的类型
-// echo $mini->createDefault('pages/index?query=1');
-// echo $mini->createMiniScene('432432', 'pages/index/index');
- echo $mini->createMiniPath('pages/index?query=1');
-} catch (Exception $e) {
- var_dump($e->getMessage());
-}
diff --git a/_test/pay-callapi-test.php b/_test/pay-callapi-test.php
deleted file mode 100644
index f6913ab..0000000
--- a/_test/pay-callapi-test.php
+++ /dev/null
@@ -1,169 +0,0 @@
-=== 微信支付V2通用接口测试 ===";
-
- // ============================================
- // 测试1: POST请求 - 统一下单(自动签名)
- // ============================================
- echo "测试1: POST请求 - 统一下单(自动签名)
";
- try {
- $result = $pay->callApi(
- 'https://api.mch.weixin.qq.com/pay/unifiedorder',
- [
- 'body' => '测试商品',
- 'out_trade_no' => time(),
- 'total_fee' => '1',
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo', // 请替换为实际的openid
- 'trade_type' => 'JSAPI',
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'spbill_create_ip' => '127.0.0.1',
- ],
- 'POST',
- false, // 不需要证书
- 'MD5' // 签名类型:MD5
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试2: GET请求 - 查询订单(不自动签名)
- // ============================================
- echo "测试2: GET请求 - 查询订单(不自动签名)
";
- try {
- $result = $pay->callApi(
- 'https://api.mch.weixin.qq.com/pay/orderquery',
- [
- 'out_trade_no' => time() - 3600, // 使用一个可能存在的订单号
- ],
- 'GET'
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试3: POST请求 - 使用HMAC-SHA256签名
- // ============================================
- echo "测试3: POST请求 - 使用HMAC-SHA256签名
";
- try {
- $result = $pay->callApi(
- 'https://api.mch.weixin.qq.com/pay/unifiedorder',
- [
- 'body' => '测试商品',
- 'out_trade_no' => time() + 1,
- 'total_fee' => '1',
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo',
- 'trade_type' => 'JSAPI',
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'spbill_create_ip' => '127.0.0.1',
- ],
- 'POST',
- false, // 不需要证书
- 'HMAC-SHA256' // 使用HMAC-SHA256签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试4: POST请求 - 需要证书的接口(如退款)
- // ============================================
- echo "测试4: POST请求 - 需要证书的接口(如退款)
";
- echo "注意:此测试需要配置证书,如果未配置证书会报错
";
- try {
- $result = $pay->callApi(
- 'https://api.mch.weixin.qq.com/secapi/pay/refund',
- [
- 'out_trade_no' => time() - 3600,
- 'out_refund_no' => time(),
- 'total_fee' => '1',
- 'refund_fee' => '1',
- ],
- 'POST',
- true, // 需要证书
- 'MD5' // 签名类型:MD5
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- echo "这是正常的,因为退款接口需要证书且需要有效的订单号
";
- }
-
- // ============================================
- // 测试5: POST请求 - 不自动签名(手动处理)
- // ============================================
- echo "测试5: POST请求 - 不自动签名(手动处理签名)
";
- try {
- // 手动构建参数和签名
- $data = [
- 'body' => '测试商品',
- 'out_trade_no' => time() + 2,
- 'total_fee' => '1',
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo',
- 'trade_type' => 'JSAPI',
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'spbill_create_ip' => '127.0.0.1',
- ];
-
- // 手动添加签名
- $data['sign'] = $pay->getPaySign($data, 'MD5');
-
- // 注意:手动签名后,callApi仍会自动签名,所以此示例需要调整
- // 实际使用中,如果已经手动签名,应该直接使用 Tools::post 发送
- echo '注意:手动签名后,callApi仍会自动签名,建议直接使用 Tools::post 发送
';
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- echo "=== 所有测试完成 ===
";
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo "错误: " . $e->getMessage() . "
";
- echo "" . $e->getTraceAsString() . "
";
-}
diff --git a/_test/pay-config.php b/_test/pay-config.php
deleted file mode 100644
index f772a05..0000000
--- a/_test/pay-config.php
+++ /dev/null
@@ -1,54 +0,0 @@
- function ($name, $value, $expired = 360) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'get' => function ($name) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'del' => function ($name) {
-// var_dump(func_get_args());
-// return true;
-// },
-// 'put' => function ($name) {
-// var_dump(func_get_args());
-// return $filePath;
-// },
-// ];
-
-return [
- 'appid' => 'wx60a43dd8161666d4',
- // 配置商户支付参数
- 'mch_id' => "1332187001",
- 'mch_key' => 'A82DC5BD1F3359081049C568D8502BC5',
- // 配置商户支付双向证书目录 (p12 | key,cert 二选一,两者都配置时p12优先)
- 'ssl_p12' => __DIR__ . DIRECTORY_SEPARATOR . 'cert' . DIRECTORY_SEPARATOR . '1332187001_20181030_cert.p12',
- // 'ssl_key' => __DIR__ . DIRECTORY_SEPARATOR . 'cert' . DIRECTORY_SEPARATOR . '1332187001_20181030_key.pem',
- // 'ssl_cer' => __DIR__ . DIRECTORY_SEPARATOR . 'cert' . DIRECTORY_SEPARATOR . '1332187001_20181030_cert.pem',
- // 配置缓存目录,需要拥有写权限
- 'cache_path' => '',
-];
\ No newline at end of file
diff --git a/_test/pay-download-bill.php b/_test/pay-download-bill.php
deleted file mode 100644
index e1d491f..0000000
--- a/_test/pay-download-bill.php
+++ /dev/null
@@ -1,44 +0,0 @@
- '20171001',
- 'bill_type' => 'ALL',
- ];
- $result = $wechat->billDownload($options);
-
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-order-close.php b/_test/pay-order-close.php
deleted file mode 100644
index 229f78c..0000000
--- a/_test/pay-order-close.php
+++ /dev/null
@@ -1,41 +0,0 @@
-closeOrder($options);
-
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-order-create.php b/_test/pay-order-create.php
deleted file mode 100644
index 13aa563..0000000
--- a/_test/pay-order-create.php
+++ /dev/null
@@ -1,85 +0,0 @@
- '测试商品',
- 'out_trade_no' => time(),
- 'total_fee' => '1',
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo',
- 'trade_type' => 'JSAPI', // JSAPI--JSAPI支付(服务号或小程序支付)、NATIVE--Native 支付、APP--APP支付,MWEB--H5支付
- 'notify_url' => 'https://a.com/text.html',
- 'spbill_create_ip' => '127.0.0.1',
- ];
-
- // 生成预支付码
- $result = $wechat->createOrder($options);
-
- echo '';
- if ($options['trade_type'] === 'NATIVE') {
- echo '二维码 NATIVE 支付,直接使用 code_url 生成二维码即可
';
- var_export($result);
- return;
- }
-
- // 创建JSAPI参数签名
- $options = $wechat->createParamsForJsApi($result['prepay_id']);
-
- echo "--- 创建 JSAPI 预支付码 ---
";
- var_export($result);
-// array(
-// 'return_code' => 'SUCCESS',
-// 'return_msg' => 'OK',
-// 'result_code' => 'SUCCESS',
-// 'mch_id' => '1332187001',
-// 'appid' => 'wx60a43dd8161666d4',
-// 'nonce_str' => 'YIPDbGWT1jpLLM5R',
-// 'sign' => '7EBBA1B5F196CF122C920D10FA768D96',
-// 'prepay_id' => 'wx211858080224615a10c2fc9f6c824f0000',
-// 'trade_type' => 'JSAPI',
-// )
-
- echo "--- 生成 JSAPI 及 H5 支付参数 ---
";
- var_export($options);
-// array(
-// 'appId' => 'wx60a43dd8161666d4',
-// 'timeStamp' => '1669028299',
-// 'nonceStr' => '5s7h0dyp0nmzylbqytb462fpnb0tmrjg',
-// 'package' => 'prepay_id=wx21185819502283c23cca162e9d787f0000',
-// 'signType' => 'MD5',
-// 'paySign' => 'BBE0F426B8E1EEC9E45AC4459E8AE9D6',
-// 'timestamp' => '1669028299',
-// )
-
-} catch (Exception $exception) {
-
- // 出错啦,处理下吧
- echo $exception->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-order-notify.php b/_test/pay-order-notify.php
deleted file mode 100644
index cd1fc2e..0000000
--- a/_test/pay-order-notify.php
+++ /dev/null
@@ -1,46 +0,0 @@
-getNotify();
- if ($data['return_code'] === 'SUCCESS' && $data['result_code'] === 'SUCCESS') {
- // @todo 去更新下原订单的支付状态
- $order_no = $data['out_trade_no'];
-
- // 返回接收成功的回复
- ob_clean();
- echo $wechat->getNotifySuccessReply();
- }
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
diff --git a/_test/pay-order-query.php b/_test/pay-order-query.php
deleted file mode 100644
index fd75c74..0000000
--- a/_test/pay-order-query.php
+++ /dev/null
@@ -1,44 +0,0 @@
- '1008450740201411110005820873',
-// 'out_trade_no' => '商户订单号',
- ];
- $result = $wechat->queryOrder($options);
-
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-redpack-create.php b/_test/pay-redpack-create.php
deleted file mode 100644
index 0830fb3..0000000
--- a/_test/pay-redpack-create.php
+++ /dev/null
@@ -1,55 +0,0 @@
- time(),
- 're_openid' => 'o38gps3vNdCqaggFfrBRCRikwlWY',
- 'send_name' => '商户名称😍',
- 'act_name' => '活动名称',
- 'total_amount' => '100',
- 'total_num' => '1',
- 'wishing' => '感谢您参加猜灯谜活动,祝您元宵节快乐!',
- 'remark' => '猜越多得越多,快来抢!',
- 'client_ip' => '127.0.0.1',
- ];
- // 发送红包记录
- $result = $wechat->create($options);
- echo '';
- var_export($result);
- // 查询红包记录
- $result = $wechat->query($options['mch_billno']);
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-refund-create.php b/_test/pay-refund-create.php
deleted file mode 100644
index b9e6765..0000000
--- a/_test/pay-refund-create.php
+++ /dev/null
@@ -1,46 +0,0 @@
- '1008450740201411110005820873',
- 'out_refund_no' => '3241251235123',
- 'total_fee' => '1',
- 'refund_fee' => '1',
- ];
- $result = $wechat->createRefund($options);
-
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-refund-query.php b/_test/pay-refund-query.php
deleted file mode 100644
index 0b290d6..0000000
--- a/_test/pay-refund-query.php
+++ /dev/null
@@ -1,46 +0,0 @@
- '1008450740201411110005820873',
- // 'out_trade_no' => '商户订单号',
- // 'out_refund_no' => '商户退款单号'
- // 'refund_id' => '微信退款单号',
- ];
- $result = $wechat->queryRefund($options);
-
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-transfers-create.php b/_test/pay-transfers-create.php
deleted file mode 100644
index 9f45ccf..0000000
--- a/_test/pay-transfers-create.php
+++ /dev/null
@@ -1,50 +0,0 @@
- time(),
- 'openid' => 'o38gps3vNdCqaggFfrBRCRikwlWY',
- 'check_name' => 'NO_CHECK',
- 'amount' => '100',
- 'desc' => '企业付款操作说明信息',
- 'spbill_create_ip' => '127.0.0.1',
- ];
- $result = $wechat->createTransfers($options);
- echo '';
- var_export($result);
- $result = $wechat->queryTransfers($options['partner_trade_no']);
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-transfersbank-create.php b/_test/pay-transfersbank-create.php
deleted file mode 100644
index 664da8d..0000000
--- a/_test/pay-transfersbank-create.php
+++ /dev/null
@@ -1,48 +0,0 @@
- time(),
- 'enc_bank_no' => '6212263602037318102',
- 'enc_true_name' => '邹景立',
- 'bank_code' => '1002',
- 'amount' => '100',
- 'desc' => '打款测试',
- ];
- echo '';
- $result = $wechat->createTransfersBank($options);
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/pay-v3-callapi-test.php b/_test/pay-v3-callapi-test.php
deleted file mode 100644
index 7f941a7..0000000
--- a/_test/pay-v3-callapi-test.php
+++ /dev/null
@@ -1,205 +0,0 @@
-=== 微信支付V3通用接口测试 ===";
-
- // ============================================
- // 测试1: POST请求 - 使用相对路径创建订单
- // ============================================
- echo "测试1: POST请求 - 创建JSAPI支付订单(相对路径)
";
- try {
- $result = $payment->callApi(
- '/v3/pay/transactions/jsapi',
- [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '测试商品',
- 'out_trade_no' => (string)time(),
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'payer' => [
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo', // 请替换为实际的openid
- ],
- 'amount' => [
- 'total' => 1,
- 'currency' => 'CNY'
- ],
- ],
- 'POST',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试2: GET请求 - 查询订单(完整URL)
- // ============================================
- echo "测试2: GET请求 - 查询订单(完整URL)
";
- try {
- $outTradeNo = time() - 3600; // 使用一个可能存在的订单号
- $result = $payment->callApi(
- "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{$outTradeNo}?mchid={$config['mch_id']}",
- '', // GET请求数据为空
- 'GET',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试3: POST请求 - 创建H5支付订单
- // ============================================
- echo "测试3: POST请求 - 创建H5支付订单
";
- try {
- $result = $payment->callApi(
- '/v3/pay/transactions/h5',
- [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '测试商品',
- 'out_trade_no' => (string)(time() + 1),
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'amount' => [
- 'total' => 1,
- 'currency' => 'CNY'
- ],
- 'scene_info' => [
- 'h5_info' => [
- 'type' => 'Wap'
- ],
- 'payer_client_ip' => '127.0.0.1',
- ],
- ],
- 'POST',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试4: POST请求 - 创建退款(需要证书)
- // ============================================
- echo "测试4: POST请求 - 创建退款
";
- echo "注意:此测试需要有效的订单号
";
- try {
- $result = $payment->callApi(
- '/v3/refund/domestic/refunds',
- [
- 'out_trade_no' => (string)(time() - 3600),
- 'out_refund_no' => (string)time(),
- 'amount' => [
- 'refund' => 1,
- 'total' => 1,
- 'currency' => 'CNY'
- ],
- ],
- 'POST',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- echo "这是正常的,因为退款需要有效的订单号
";
- }
-
- // ============================================
- // 测试5: GET请求 - 查询退款
- // ============================================
- echo "测试5: GET请求 - 查询退款
";
- try {
- $outRefundNo = time() - 3600;
- $result = $payment->callApi(
- "/v3/refund/domestic/refunds/{$outRefundNo}",
- '',
- 'GET',
- false // 不验证响应签名
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试6: POST请求 - 使用数组数据(自动JSON编码)
- // ============================================
- echo "测试6: POST请求 - 使用数组数据(自动JSON编码)
";
- try {
- $data = [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '测试商品',
- 'out_trade_no' => (string)(time() + 2),
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'amount' => [
- 'total' => 1,
- 'currency' => 'CNY'
- ],
- ];
-
- // callApi会自动将数组转为JSON
- $result = $payment->callApi(
- '/v3/pay/transactions/jsapi',
- $data,
- 'POST'
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- echo "=== 所有测试完成 ===
";
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo "错误: " . $e->getMessage() . "
";
- echo "" . $e->getTraceAsString() . "
";
-
-}
-
diff --git a/_test/pay-v3-config-cert.php b/_test/pay-v3-config-cert.php
deleted file mode 100644
index d6393a7..0000000
--- a/_test/pay-v3-config-cert.php
+++ /dev/null
@@ -1,31 +0,0 @@
-download();
-
-} catch (\Exception $exception) {
- // 出错啦,处理下吧
- echo $exception->getMessage() . PHP_EOL;
-}
\ No newline at end of file
diff --git a/_test/pay-v3-config.php b/_test/pay-v3-config.php
deleted file mode 100644
index 26149da..0000000
--- a/_test/pay-v3-config.php
+++ /dev/null
@@ -1,92 +0,0 @@
- function ($name, $value, $expired = 360) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'get' => function ($name) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'del' => function ($name) {
-// var_dump(func_get_args());
-// return true;
-// },
-// 'put' => function ($name) {
-// var_dump(func_get_args());
-// return $filePath;
-// },
-// ];
-
-return [
- // 公众号 APPID(可选)
- 'appid' => 'wx3760xxxxxxxxxxxx',
- // 微信商户号(必填)
- 'mch_id' => '15293xxxxxx',
- // 微信商户 V3 接口密钥(必填)
- 'mch_v3_key' => '98b7fxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
-
- // 商户证书序列号(可选):用于请求签名
- 'cert_serial' => '49055D67B2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
- // 微信商户证书公钥(必填):可填写证书内容或文件路径,仅用于提取序列号
- 'cert_public' => $certPublic,
- // 微信商户证书私钥(必填):可填写证书内容或文件路径,用于请求数据签名
- 'cert_private' => $certPrivate,
-
- // 自定义证书包:支持平台证书或支付公钥(可填写文件路径或证书内容)
- 'cert_package' => [
- 'PUB_KEY_ID_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' => $certPayment
- ],
-
- // 微信平台证书或支付证书序列号(可选)
- // 'mp_cert_serial' => 'PUB_KEY_ID_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
-
- // 微信平台证书或支付证书内容(可选)
- // 'mp_cert_content' => $certPayment,
-
- // 运行时文件缓存路径(可选)
- 'cache_path' => ''
-];
\ No newline at end of file
diff --git a/_test/pay-v3-order-app.php b/_test/pay-v3-order-app.php
deleted file mode 100644
index 9e804a4..0000000
--- a/_test/pay-v3-order-app.php
+++ /dev/null
@@ -1,64 +0,0 @@
-create('app', [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '商品描述',
- 'out_trade_no' => $order,
- 'notify_url' => 'https://thinkadmin.top',
- 'amount' => ['total' => 2, 'currency' => 'CNY'],
- ]);
-
- echo '';
- echo "\n--- 创建支付参数 ---\n";
- var_export($result);
-
- // 创建退款
- $out_refund_no = strval(time());
- $result = $payment->createRefund([
- 'out_trade_no' => $order,
- 'out_refund_no' => $out_refund_no,
- 'amount' => [
- 'refund' => 2,
- 'total' => 2,
- 'currency' => 'CNY'
- ]
- ]);
- echo "\n--- 创建退款订单 ---\n";
- var_export($result);
-
- $result = $payment->queryRefund($out_refund_no);
-
- echo "\n--- 查询退款订单 ---\n";
- var_export($result);
-
-} catch (\Exception $exception) {
- // 出错啦,处理下吧
- echo $exception->getMessage() . PHP_EOL;
-}
\ No newline at end of file
diff --git a/_test/pay-v3-order-h5.php b/_test/pay-v3-order-h5.php
deleted file mode 100644
index 9284445..0000000
--- a/_test/pay-v3-order-h5.php
+++ /dev/null
@@ -1,50 +0,0 @@
-create('h5', [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '商品描述',
- 'out_trade_no' => (string)time(),
- 'notify_url' => 'https://thinkadmin.top',
- 'amount' => ['total' => 2, 'currency' => 'CNY'],
- 'scene_info' => [
- 'h5_info' => [
- 'type' => 'Wap',
- ],
- 'payer_client_ip' => '14.23.150.211',
- ],
- ]);
-
- echo '';
- echo "\n--- 创建支付参数 ---\n";
- var_export($result);
-
-} catch (\Exception $exception) {
- // 出错啦,处理下吧
- echo $exception->getMessage() . PHP_EOL;
-}
\ No newline at end of file
diff --git a/_test/pay-v3-order-jsapi.php b/_test/pay-v3-order-jsapi.php
deleted file mode 100644
index 5f2eacc..0000000
--- a/_test/pay-v3-order-jsapi.php
+++ /dev/null
@@ -1,89 +0,0 @@
-create('jsapi', [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '商品描述',
- 'out_trade_no' => $order,
- 'notify_url' => 'https://thinkadmin.top',
- 'payer' => ['openid' => 'o38gps3vNdCqaggFfrBRCRikwlWY'],
- 'amount' => ['total' => 2, 'currency' => 'CNY'],
- ]);
-
- echo '';
- echo "\n--- 创建支付参数 ---\n";
- var_export($result);
-
-// array(
-// 'appId' => 'wx60a43dd8161666d4',
-// 'timeStamp' => '1669027650',
-// 'nonceStr' => 'dfscg4lm02uqy448kjd1kjs2eo26joom',
-// 'package' => 'prepay_id=wx211847302881094d83b1917194ca880000',
-// 'signType' => 'RSA',
-// 'paySign' => '1wvvi4vmcJmP3GXB0H52mxp8lOhyqE4BtLmyi3Flg8DVKCES4fsb6+0z/L9sYkbp/TNinsnK0k7mUpTe2Yo86P1DLg18fR7zsIn5u1+3tI58boHk3VsAJl4Uhlti9ME3T7kRq1bEb4DGxp16+ixRynOqndkIkYXxrREhsrZIQlsGMfNCV0K1707s7jBTgqIm1vlkpIjNEg8nbcuG88Vzly4dR1a9K6Fux+sm0gu2rMroRwIo2R/0rgHGDANmnAZj6YEfLZlRrGTbr9r0V1+HHQPvV4BJLvTG8KXVJmJSJzBWSgq31PwrLWdOwdtpNKk7wJbY7yoScYUysYqqzM4DTQ==',
-// );
-
- echo "\n\n--- 查询支付参数 ---\n";
- $result = $payment->query($order);
- var_export($result);
-
-// array(
-// 'amount' => array('payer_currency' => 'CNY', 'total' => 2),
-// 'appid' => 'wx60a43dd8161666d4',
-// 'mchid' => '1332187001',
-// 'out_trade_no' => '1669027802',
-// 'promotion_detail' => array(),
-// 'scene_info' => array('device_id' => ''),
-// 'trade_state' => 'NOTPAY',
-// 'trade_state_desc' => '订单未支付',
-// );
-
- // 创建退款
- $out_refund_no = strval(time());
- $result = $payment->createRefund([
- 'out_trade_no' => $order,
- 'out_refund_no' => $out_refund_no,
- 'amount' => [
- 'refund' => 2,
- 'total' => 2,
- 'currency' => 'CNY'
- ]
- ]);
- echo "\n--- 创建退款订单2 ---\n";
- var_export($result);
-
- $result = $payment->queryRefund($out_refund_no);
-
- echo "\n--- 查询退款订单2 ---\n";
- var_export($result);
-
-} catch (\Exception $exception) {
- // 出错啦,处理下吧
- echo $exception->getMessage() . PHP_EOL;
-}
\ No newline at end of file
diff --git a/_test/pay-v3-order-native.php b/_test/pay-v3-order-native.php
deleted file mode 100644
index ab720e5..0000000
--- a/_test/pay-v3-order-native.php
+++ /dev/null
@@ -1,82 +0,0 @@
-create('native', [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '商品描述',
- 'out_trade_no' => $order,
- 'notify_url' => 'https://thinkadmin.top',
- 'amount' => ['total' => 2, 'currency' => 'CNY'],
- ]);
-
- echo '';
- echo "\n--- 创建支付参数 ---\n";
- var_export($result);
-
-// array('code_url' => 'weixin://wxpay/bizpayurl?pr=cdJXOVDzz');
-
-
- echo "\n\n--- 查询支付参数 ---\n";
- $result = $payment->query($order);
- var_export($result);
-
-// array(
-// 'amount' => array('payer_currency' => 'CNY', 'total' => 2),
-// 'appid' => 'wx60a43dd8161666d4',
-// 'mchid' => '1332187001',
-// 'out_trade_no' => '1669027871',
-// 'promotion_detail' => array(),
-// 'scene_info' => array('device_id' => ''),
-// 'trade_state' => 'NOTPAY',
-// 'trade_state_desc' => '订单未支付',
-// );
-
- // 创建退款
- $out_refund_no = strval(time());
- $result = $payment->createRefund([
- 'out_trade_no' => $order,
- 'out_refund_no' => $out_refund_no,
- 'amount' => [
- 'refund' => 2,
- 'total' => 2,
- 'currency' => 'CNY'
- ]
- ]);
- echo "\n--- 创建退款订单2 ---\n";
- var_export($result);
-
- $result = $payment->queryRefund($out_refund_no);
-
- echo "\n--- 查询退款订单2 ---\n";
- var_export($result);
-
-} catch (\Exception $exception) {
- // 出错啦,处理下吧
- echo $exception->getMessage() . PHP_EOL;
-}
\ No newline at end of file
diff --git a/_test/pay-v3-transfer.php b/_test/pay-v3-transfer.php
deleted file mode 100644
index 6998c79..0000000
--- a/_test/pay-v3-transfer.php
+++ /dev/null
@@ -1,48 +0,0 @@
-batchs([
- 'out_batch_no' => 'plfk2020042013',
- 'batch_name' => '2019年1月深圳分部报销单',
- 'batch_remark' => '2019年1月深圳分部报销单',
- 'total_amount' => 100,
- 'transfer_detail_list' => [
- [
- 'out_detail_no' => 'x23zy545Bd5436',
- 'transfer_amount' => 100,
- 'transfer_remark' => '2020年4月报销',
- 'openid' => 'o-MYE42l80oelYMDE34nYD456Xoy',
- 'user_name' => '小小邹'
- ]
- ]
- ]);
-
- echo "\n--- 批量打款 ---\n";
- var_export($result);
-
-} catch (\Exception $exception) {
- // 出错啦,处理下吧
- echo $exception->getMessage() . PHP_EOL;
-}
\ No newline at end of file
diff --git a/_test/wechat-callapi-test.php b/_test/wechat-callapi-test.php
deleted file mode 100644
index 1f3cf74..0000000
--- a/_test/wechat-callapi-test.php
+++ /dev/null
@@ -1,139 +0,0 @@
-=== 微信公众号通用接口测试 ===";
-
- // ============================================
- // 测试1: GET请求 - 使用完整URL(自动处理ACCESS_TOKEN)
- // ============================================
- echo "测试1: GET请求 - 获取用户列表(完整URL,自动处理ACCESS_TOKEN)
";
- try {
- $result = $wechat->callApi(
- 'https://api.weixin.qq.com/cgi-bin/user/get?ACCESS_TOKEN',
- [], // GET参数(URL中已包含)
- 'GET'
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试2: GET请求 - 使用完整URL带参数
- // ============================================
- echo "测试2: GET请求 - 获取用户信息(完整URL带参数)
";
- try {
- $result = $wechat->callApi(
- 'https://api.weixin.qq.com/cgi-bin/user/info?ACCESS_TOKEN',
- [
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo', // 请替换为实际的openid
- 'lang' => 'zh_CN'
- ],
- 'GET'
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试3: POST请求 - 批量获取用户信息
- // ============================================
- echo "测试3: POST请求 - 批量获取用户信息(自动JSON编码)
";
- try {
- $result = $wechat->callApi(
- 'https://api.weixin.qq.com/cgi-bin/user/info/batchget?ACCESS_TOKEN',
- [
- 'user_list' => [
- ['openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo'], // 请替换为实际的openid
- // ['openid' => 'o38gps3vNdCqaggFfrBRCRikwlWY'],
- ]
- ],
- 'POST'
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试4: PUT请求 - 更新资源(如果API支持)
- // ============================================
- echo "测试4: PUT请求 - 更新资源(示例)
";
- echo "注意:此示例仅展示PUT请求用法,实际API可能不支持
";
- try {
- // PUT请求示例(如果API支持)
- // $result = $wechat->callApi(
- // 'https://api.weixin.qq.com/some/api?ACCESS_TOKEN',
- // ['key' => 'value'],
- // 'PUT'
- // );
- echo 'PUT请求用法示例(已注释)
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- // ============================================
- // 测试5: 使用相对路径(需要手动拼接完整URL)
- // ============================================
- echo "测试5: GET请求 - 使用相对路径(需要完整URL)
";
- try {
- // 注意:callApi需要完整URL,相对路径需要手动拼接
- $baseUrl = 'https://api.weixin.qq.com';
- $result = $wechat->callApi(
- $baseUrl . '/cgi-bin/user/get?ACCESS_TOKEN',
- [],
- 'GET'
- );
- echo '';
- var_export($result);
- echo '
';
- } catch (Exception $e) {
- echo "错误: " . $e->getMessage() . PHP_EOL;
- }
-
- echo "=== 所有测试完成 ===
";
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo "错误: " . $e->getMessage() . "
";
- echo "" . $e->getTraceAsString() . "
";
-
-}
-
diff --git a/_test/wechat-jssdk-sign.php b/_test/wechat-jssdk-sign.php
deleted file mode 100644
index 4033146..0000000
--- a/_test/wechat-jssdk-sign.php
+++ /dev/null
@@ -1,40 +0,0 @@
-getJsSign('https://a.com/test.php');
-
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/wechat-menu-get.php b/_test/wechat-menu-get.php
deleted file mode 100644
index 6c1c34f..0000000
--- a/_test/wechat-menu-get.php
+++ /dev/null
@@ -1,40 +0,0 @@
-get();
-
- var_export($result);
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/wechat-qrcode-create.php b/_test/wechat-qrcode-create.php
deleted file mode 100644
index 949e83b..0000000
--- a/_test/wechat-qrcode-create.php
+++ /dev/null
@@ -1,44 +0,0 @@
-create('场景内容');
- echo var_export($result, true) . PHP_EOL;
-
- // 5. 创建二维码链接
- $url = $wechat->url($result['ticket']);
- echo var_export($url, true);
-
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/wechat-user-get.php b/_test/wechat-user-get.php
deleted file mode 100644
index cc43dbc..0000000
--- a/_test/wechat-user-get.php
+++ /dev/null
@@ -1,47 +0,0 @@
-getUserList();
-
- echo '';
- var_export($result);
-
- // 5. 批量获取用户资料
- foreach (array_chunk($result['data']['openid'], 100) as $item) {
- $userList = $wechat->getBatchUserInfo($item);
- var_export($userList);
- }
-
-} catch (Exception $e) {
-
- // 出错啦,处理下吧
- echo $e->getMessage() . PHP_EOL;
-
-}
\ No newline at end of file
diff --git a/_test/work-config.php b/_test/work-config.php
deleted file mode 100644
index fdf4e70..0000000
--- a/_test/work-config.php
+++ /dev/null
@@ -1,47 +0,0 @@
- function ($name, $value, $expired = 360) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'get' => function ($name) {
-// var_dump(func_get_args());
-// return $value;
-// },
-// 'del' => function ($name) {
-// var_dump(func_get_args());
-// return true;
-// },
-// 'put' => function ($name) {
-// var_dump(func_get_args());
-// return $filePath;
-// },
-// ];
-
-return [
- 'appid' => '', // 企业ID
- 'appsecret' => '', // 应用的凭证密钥
- 'cache_path' => '', // 配置缓存目录
-];
\ No newline at end of file
diff --git a/_test/work-department.php b/_test/work-department.php
deleted file mode 100644
index c36878e..0000000
--- a/_test/work-department.php
+++ /dev/null
@@ -1,32 +0,0 @@
-callGetApi($url);
- echo '';
- print_r(BasicWeWork::instance($config)->config->get());
- print_r($result);
- echo '
';
-} catch (Exception $exception) {
- echo $exception->getMessage() . PHP_EOL;
-}
diff --git a/composer.json b/composer.json
index 9bb246f..fa48d6c 100644
--- a/composer.json
+++ b/composer.json
@@ -1,47 +1,46 @@
{
- "type": "library",
"name": "zoujingli/wechat-developer",
- "homepage": "https://thinkadmin.top",
- "description": "WeChat and Alipay Platform Development",
+ "description": "Multi-platform developer SDK for WeChat and Alipay.",
+ "type": "library",
"license": "MIT",
+ "homepage": "https://github.com/zoujingli/WeChatDeveloper",
+ "keywords": [
+ "wechat",
+ "wechat-pay",
+ "alipay",
+ "sdk",
+ "php"
+ ],
"authors": [
{
"name": "Anyon",
- "email": "zoujingli@qq.com",
- "homepage": "https://thinkadmin.top"
+ "email": "zoujingli@qq.com"
}
],
- "keywords": [
- "AliPay",
- "WeMini",
- "WeChat",
- "WeChatPay",
- "WeChatDeveloper"
- ],
"require": {
- "php": ">=5.4",
- "ext-xml": "*",
+ "php": ">=8.4",
"ext-json": "*",
- "ext-curl": "*",
- "ext-bcmath": "*",
- "ext-libxml": "*",
"ext-openssl": "*",
- "ext-mbstring": "*",
- "ext-simplexml": "*"
+ "ext-simplexml": "*",
+ "guzzlehttp/guzzle": "^7.0",
+ "psr/simple-cache": "^3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.5"
},
"autoload": {
- "files": [
- "helper.php"
- ],
- "classmap": [
- "We.php"
- ],
"psr-4": {
- "WePay\\": "WePay",
- "WeChat\\": "WeChat",
- "WeMini\\": "WeMini",
- "AliPay\\": "AliPay",
- "WePayV3\\": "WePayV3"
+ "We\\": "src/"
}
- }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "We\\Tests\\": "src/Tests/"
+ }
+ },
+ "scripts": {
+ "test": "@php vendor/bin/phpunit -c phpunit.xml"
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true
}
diff --git a/helper.php b/helper.php
deleted file mode 100644
index 6a2dbec..0000000
--- a/helper.php
+++ /dev/null
@@ -1,25 +0,0 @@
-
+
+
+
+ src/Tests
+
+
+
+
+ src
+
+
+ src/Tests
+
+
+
diff --git a/readme.md b/readme.md
deleted file mode 100644
index 13b96d3..0000000
--- a/readme.md
+++ /dev/null
@@ -1,978 +0,0 @@
-# WeChatDeveloper for PHP
-
-[](https://gitcode.com/ThinkAdmin/ThinkAdmin)
-[](https://gitee.com/zoujingli/WeChatDeveloper)
-[](https://packagist.org/packages/zoujingli/wechat-developer)
-[](https://packagist.org/packages/zoujingli/wechat-developer)
-[](https://packagist.org/packages/zoujingli/wechat-developer)
-[](https://packagist.org/packages/zoujingli/wechat-developer)
-[](https://packagist.org/packages/wechat-developer)
-[](https://packagist.org/packages/zoujingli/wechat-developer)
-
-## 🚀 项目简介
-
-**WeChatDeveloper** 是一个功能全面、安全可靠的 PHP 微信和支付宝开发 SDK,基于 [wechat-php-sdk](https://github.com/zoujingli/wechat-php-sdk) 重构优化而成。项目经过全面的安全加固和代码质量提升,为开发者提供稳定、安全、易用的微信生态和支付解决方案。
-
-## ✨ 核心特性
-
-### 🔒 安全可靠
-
-- **输入验证**:全面防护 XSS 攻击,所有用户输入都经过严格过滤和验证
-- **文件安全**:文件操作前进行存在性和权限检查,防止恶意利用
-- **加密安全**:使用 SHA-256 替代 MD5,提供更强的安全防护
-- **序列化安全**:添加反序列化数据验证,防止代码执行攻击
-
-### 🎯 功能全面
-
-- **微信生态**:支持公众号、小程序、企业微信全生态开发
-- **支付功能**:支持微信支付 V2/V3、支付宝支付全场景
-- **多端支持**:覆盖 App、H5、PC、小程序等所有平台
-- **接口完整**:涵盖用户管理、消息推送、素材管理、支付等所有核心功能
-
-### ⚡ 性能优化
-
-- **自动刷新**:AccessToken 失效自动刷新机制
-- **缓存支持**:支持自定义缓存驱动,可扩展 Redis 等
-- **错误重试**:智能错误重试机制,提高接口调用成功率
-- **类型安全**:修复所有类型声明问题,提升代码质量
-- **自动缓存清理**:自动清理 CURL 临时缓存文件,适配常驻内存框架
-- **通用接口支持**:提供 `callApi()` 万能接口,支持多种 HTTP 方法,适用于所有场景
-
-### 🛠 易于使用
-
-- **统一入口**:通过`\We::`静态方法统一创建各种功能实例
-- **向后兼容**:完全保持原有 API 和参数,无需修改现有代码
-- **通用接口**:提供标准化的 `callApi()` 方法,支持 GET/POST/PUT/DELETE 等多种 HTTP 方法
-- **文档完善**:提供详细的使用文档和示例代码
-- **社区支持**:活跃的社区和持续的技术支持
-
-## 📋 系统要求
-
-- **PHP 版本**:最低要求 PHP 5.4,建议 PHP 7.0+ 以获取最佳性能
-- **扩展要求**:curl、json、xml、openssl、mbstring、bcmath
-- **权限要求**:缓存目录需要写权限
-- **推荐环境**:PHP 7.4+ / PHP 8.0+ 生产环境
-
-## 📦 快速开始
-
-### 安装方式
-
-#### 方式一:Composer 安装(推荐)
-
-```bash
-# 安装稳定版本
-composer require zoujingli/wechat-developer
-
-# 安装开发版本
-composer require zoujingli/wechat-developer dev-master
-
-# 更新到最新版本
-composer update zoujingli/wechat-developer
-```
-
-#### 方式二:直接下载
-
-```bash
-# 下载项目到本地
-git clone https://github.com/zoujingli/WeChatDeveloper.git
-
-# 在项目中引入
-include "WeChatDeveloper/include.php";
-```
-
-### 基础使用
-
-```php
- 'your_wechat_appid',
- 'appsecret' => 'your_wechat_appsecret',
- 'mch_id' => 'your_merchant_id', // 微信支付需要
- 'mch_key' => 'your_merchant_key', // 微信支付需要
- 'cache_path' => '/path/to/cache' // 可选,缓存目录
-];
-
-// 3. 创建实例并调用
-try {
- // 微信用户管理
- $user = \We::WeChatUser($config);
- $userList = $user->getUserList();
-
- // 微信支付
- $pay = \We::WePayOrder($config);
- $order = $pay->create($orderData);
-
- // 支付宝支付
- $alipay = \We::AliPayWeb($config);
- $html = $alipay->apply($payData);
-
- // 使用通用接口(万能接口)
- // 所有接口类都提供 callApi() 方法,支持多种 HTTP 方法
- $result = $user->callApi('https://api.weixin.qq.com/cgi-bin/user/get?ACCESS_TOKEN', [], 'GET');
- $result = $pay->callApi('https://api.mch.weixin.qq.com/pay/unifiedorder', $data, 'POST');
- $result = $alipay->callApi('alipay.trade.query', $params, 'GET'); // 支付宝:apiMethod 作为第一参数
-
-} catch (Exception $e) {
- echo "错误:" . $e->getMessage();
-}
-```
-
-## 🎯 功能模块
-
-### 📱 微信生态支持
-
-#### 微信公众号
-
-- **用户管理**:用户信息获取、标签管理、分组管理
-- **消息推送**:模板消息、客服消息、群发消息
-- **素材管理**:图片、语音、视频、图文素材上传和管理
-- **菜单管理**:自定义菜单创建、查询、删除
-- **网页授权**:OAuth2.0 网页授权,获取用户信息
-- **二维码**:临时二维码、永久二维码生成
-- **JSSDK**:微信前端 JS-SDK 支持
-- **卡券功能**:微信卡券接口支持
-- **门店管理**:门店 WIFI 管理、摇一摇周边
-
-#### 微信小程序
-
-- **数据加密**:小程序数据加密解密处理
-- **用户管理**:用户信息获取、登录状态管理
-- **消息推送**:订阅消息、模板消息、动态消息
-- **二维码**:小程序码生成、URL Scheme
-- **内容安全**:图片内容检测、文本内容检测
-- **物流助手**:发货信息管理、物流状态查询
-- **直播功能**:小程序直播接口支持
-- **搜索优化**:小程序页面搜索优化
-- **插件管理**:小程序插件申请、管理
-- **OCR 服务**:身份证、银行卡、驾驶证识别
-- **生物认证**:指纹、面部识别支持
-
-#### 企业微信
-
-- **部门管理**:部门信息获取、创建、更新
-- **用户管理**:企业用户信息管理
-- **消息推送**:企业消息推送功能
-
-### 💰 支付功能支持
-
-#### 微信支付
-
-- **V2 接口**:统一下单、查询、关闭、退款
-- **V3 接口**:新一代支付接口,支持更多功能
-- **支付方式**:JSAPI、APP、H5、Native、小程序支付
-- **订单管理**:订单创建、查询、关闭、退款
-- **账单管理**:对账单下载、交易明细查询
-- **企业付款**:打款到零钱、打款到银行卡
-- **分账功能**:微信分账接口支持
-- **代金券**:代金券创建、发放、核销
-- **红包功能**:微信红包发送和管理
-
-#### 支付宝支付
-
-- **支付方式**:App 支付、Web 支付、Wap 支付、扫码支付、刷卡支付
-- **订单管理**:订单创建、查询、关闭、退款
-- **转账功能**:单笔转账、批量转账
-- **账单管理**:对账单下载、交易查询
-- **证书支持**:RSA、RSA2 签名,证书模式支持
-
-## 💡 使用案例
-
-### 📱 微信公众号功能
-
-#### 用户管理
-
-```php
-getUserList();
-
-// 批量获取用户信息
-foreach (array_chunk($result['data']['openid'], 100) as $openids) {
- $userList = $user->getBatchUserInfo($openids);
- foreach ($userList['user_info_list'] as $userInfo) {
- echo "用户:" . $userInfo['nickname'] . "\n";
- }
-}
-
-// 设置用户备注
-$user->updateMark('openid', 'VIP用户');
-```
-
-#### 二维码生成
-
-```php
-create('场景内容');
-
-// 获取二维码链接
-$url = $qrcode->url($result['ticket']);
-echo "二维码链接:" . $url;
-```
-
-#### 菜单管理
-
-```php
-get();
-
-// 创建自定义菜单
-$menuData = [
- 'button' => [
- [
- 'type' => 'click',
- 'name' => '今日歌曲',
- 'key' => 'V1001_TODAY_MUSIC'
- ],
- [
- 'name' => '菜单',
- 'sub_button' => [
- [
- 'type' => 'view',
- 'name' => '搜索',
- 'url' => 'http://www.soso.com/'
- ]
- ]
- ]
- ]
-];
-$menu->create($menuData);
-```
-
-### 💰 微信支付功能
-
-#### 微信支付 V2 接口
-
-```php
- '测试商品',
- 'out_trade_no' => time(),
- 'total_fee' => '1',
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo',
- 'trade_type' => 'JSAPI', // JSAPI/NATIVE/APP/MWEB
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'spbill_create_ip' => '127.0.0.1',
-];
-
-$result = $pay->create($options);
-
-// 生成JSAPI支付参数
-$jsApiParams = $pay->createParamsForJsApi($result['prepay_id']);
-// 将 $jsApiParams 传给前端发起支付
-```
-
-#### 微信支付 V3 接口
-
-```php
-create('jsapi', [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '商品描述',
- 'out_trade_no' => $order,
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'payer' => ['openid' => 'o38gps3vNdCqaggFfrBRCRikwlWY'],
- 'amount' => ['total' => 2, 'currency' => 'CNY'],
-]);
-
-// H5支付
-$result = $payment->create('h5', [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '商品描述',
- 'out_trade_no' => $order,
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'amount' => ['total' => 2, 'currency' => 'CNY'],
- 'scene_info' => [
- 'h5_info' => ['type' => 'Wap'],
- 'payer_client_ip' => '14.23.150.211',
- ],
-]);
-
-// 查询订单
-$result = $payment->query($order);
-
-// 创建退款
-$refundResult = $payment->createRefund([
- 'out_trade_no' => $order,
- 'out_refund_no' => strval(time()),
- 'amount' => [
- 'refund' => 2,
- 'total' => 2,
- 'currency' => 'CNY'
- ]
-]);
-```
-
-#### 微信红包
-
-```php
- time(),
- 're_openid' => 'o38gps3vNdCqaggFfrBRCRikwlWY',
- 'send_name' => '商户名称',
- 'act_name' => '活动名称',
- 'total_amount' => '100',
- 'total_num' => '1',
- 'wishing' => '感谢您参加活动!',
- 'remark' => '快来抢红包!',
- 'client_ip' => '127.0.0.1',
-];
-
-$result = $redpack->create($options);
-
-// 查询红包记录
-$result = $redpack->query($options['mch_billno']);
-```
-
-### 💳 支付宝支付功能
-
-#### 网站支付
-
-```php
-apply([
- 'out_trade_no' => time(),
- 'total_amount' => '1',
- 'subject' => '支付订单描述',
-]);
-
-// 直接输出HTML表单,用户点击即可跳转支付
-echo $result;
-```
-
-#### App 支付
-
-```php
-apply([
- 'out_trade_no' => strval(time()),
- 'total_amount' => '1',
- 'subject' => '支付宝订单标题',
-]);
-
-// 返回支付参数字符串,传给App端
-echo $result;
-```
-
-#### 转账功能
-
-```php
-create([
- 'out_biz_no' => time(),
- 'trans_amount' => '10',
- 'product_code' => 'TRANS_ACCOUNT_NO_PWD',
- 'biz_scene' => 'DIRECT_TRANSFER',
- 'payee_info' => [
- 'identity' => 'zoujingli@qq.com',
- 'identity_type' => 'ALIPAY_LOGON_ID',
- 'name' => '收款人姓名',
- ],
-]);
-```
-
-### 📱 微信小程序功能
-
-#### 用户登录和数据解密
-
-```php
-session($code);
-
-// 解密用户数据
-$userInfo = $mini->userInfo($code, $iv, $encryptedData);
-
-// 直接解密数据
-$decoded = $mini->decode($iv, $sessionKey, $encryptedData);
-```
-
-#### 小程序码生成
-
-```php
-create([
- 'scene' => 'id=123',
- 'page' => 'pages/index/index',
- 'width' => 430
-]);
-```
-
-### 🔧 高级功能
-
-#### 通用接口(万能接口)
-
-所有接口类都提供了 `callApi()` 通用方法,支持多种 HTTP 方法(GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS),可以直接传入完整 URL 和参数进行请求,适用于官方新增接口或自定义接口调用。
-
-**方法签名:**
-
-```php
-// 微信公众号
-callApi(string $url, array|string $data = [], string $method = 'GET')
-
-// 微信支付V2
-callApi(string $url, array|string $data = [], string $method = 'POST', bool $isCert = false, string $signType = 'HMAC-SHA256')
-
-// 微信支付V3
-callApi(string $url, array|string $data = '', string $method = 'POST', bool $verify = false)
-
-// 支付宝
-callApi(string $apiMethod, array|string $data = [], string $method = 'GET', bool $verify = false)
-```
-
-**支持的 HTTP 方法:**
-
-- `GET` - 获取资源(默认:微信公众号、支付宝)
-- `POST` - 创建/提交数据(默认:微信支付)
-- `PUT` - 更新资源
-- `DELETE` - 删除资源
-- `PATCH` - 部分更新
-- `HEAD` - 获取响应头
-- `OPTIONS` - 获取支持的方法
-
-##### 微信公众号通用接口
-
-```php
-callApi(
- 'https://api.weixin.qq.com/cgi-bin/user/info?openid=OPENID&lang=zh_CN&ACCESS_TOKEN',
- [], // GET参数(如果URL中已包含参数,这里可以为空)
- 'GET'
-);
-
-// POST请求 - 批量获取用户信息(自动JSON编码)
-$result = $user->callApi(
- 'https://api.weixin.qq.com/cgi-bin/user/info/batchget?ACCESS_TOKEN',
- ['user_list' => [['openid' => 'xxx'], ['openid' => 'yyy']]],
- 'POST'
-);
-
-// PUT请求 - 更新资源
-$result = $user->callApi($url, $data, 'PUT');
-
-// DELETE请求 - 删除资源
-$result = $user->callApi($url, $data, 'DELETE');
-
-// PATCH请求 - 部分更新
-$result = $user->callApi($url, $data, 'PATCH');
-```
-
-**参数说明:**
-
-- `$url` (string) - 完整URL或相对路径(支持 ACCESS_TOKEN 占位符,自动替换)
-- `$data` (array|string) - 请求参数(GET参数或POST数据,支持数组或字符串)
-- `$method` (string) - 请求方法 GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS,默认 GET
-
-**默认行为:**
-
-- ✅ 自动处理 ACCESS_TOKEN(URL中包含 ACCESS_TOKEN 时自动替换)
-- ✅ POST 请求自动转为 JSON(数组数据)
-- ✅ 返回解析后的数组
-
-##### 微信支付V2通用接口
-
-```php
-callApi(
- 'https://api.mch.weixin.qq.com/pay/unifiedorder',
- [
- 'body' => '测试商品',
- 'out_trade_no' => time(),
- 'total_fee' => '1',
- 'openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo',
- 'trade_type' => 'JSAPI',
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'spbill_create_ip' => '127.0.0.1',
- ],
- 'POST'
-);
-
-// POST请求 - 使用MD5签名
-$result = $pay->callApi(
- 'https://api.mch.weixin.qq.com/pay/unifiedorder',
- $data,
- 'POST',
- false, // 不需要证书
- 'MD5' // 签名类型:MD5
-);
-
-// POST请求 - 需要证书(如退款)
-$result = $pay->callApi(
- 'https://api.mch.weixin.qq.com/secapi/pay/refund',
- $data,
- 'POST',
- true, // 需要证书
- 'MD5' // 签名类型
-);
-
-// GET请求 - 查询订单
-$result = $pay->callApi(
- 'https://api.mch.weixin.qq.com/pay/orderquery',
- ['out_trade_no' => '123456'],
- 'GET'
-);
-
-// PUT/DELETE请求
-$result = $pay->callApi($url, $data, 'PUT', false, 'MD5');
-$result = $pay->callApi($url, $data, 'DELETE', false, 'MD5');
-```
-
-**参数说明:**
-
-- `$url` (string) - 完整URL
-- `$data` (array|string) - 请求参数(支持数组或字符串)
-- `$method` (string) - 请求方法 GET|POST|PUT|DELETE|PATCH,默认 POST
-- `$isCert` (bool) - 是否需要证书,默认 false
-- `$signType` (string) - 签名类型 MD5|HMAC-SHA256,默认 HMAC-SHA256
-
-**默认行为:**
-
-- ✅ 自动签名(POST/PUT/PATCH/DELETE 请求)
-- ✅ 返回解析后的数组(XML格式)
-
-##### 微信支付V3通用接口
-
-```php
-callApi(
- '/v3/pay/transactions/jsapi',
- [
- 'appid' => $config['appid'],
- 'mchid' => $config['mch_id'],
- 'description' => '商品描述',
- 'out_trade_no' => (string)time(),
- 'notify_url' => 'https://your-domain.com/notify.php',
- 'payer' => ['openid' => 'o38gpszoJoC9oJYz3UHHf6bEp0Lo'],
- 'amount' => ['total' => 2, 'currency' => 'CNY'],
- ],
- 'POST'
-);
-
-// GET请求 - 查询订单(完整URL或相对路径)
-$result = $payment->callApi(
- '/v3/pay/transactions/out-trade-no/123456?mchid=' . $config['mch_id'],
- '',
- 'GET',
- true // 验证响应签名
-);
-
-// PUT请求 - 更新资源
-$result = $payment->callApi('/v3/some/resource/xxx', $data, 'PUT');
-
-// DELETE请求 - 删除资源
-$result = $payment->callApi('/v3/some/resource/xxx', '', 'DELETE');
-```
-
-**参数说明:**
-
-- `$url` (string) - 完整URL或相对路径(如 `/v3/pay/transactions/jsapi`)
-- `$data` (array|string) - 请求数据(数组会自动转为JSON)
-- `$method` (string) - 请求方法 GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS,默认 POST
-- `$verify` (bool) - 验证响应签名,默认 false
-
-**默认行为:**
-
-- ✅ 数组数据自动转为 JSON
-- ✅ 返回解析后的数组
-
-##### 支付宝通用接口
-
-```php
-callApi(
- 'alipay.trade.query', // API方法名(必填,第一参数)
- ['out_trade_no' => '123456'],
- 'GET',
- false // 验证响应签名,默认false
-);
-
-// POST请求 - 订单退款
-$result = $alipay->callApi(
- 'alipay.trade.refund', // API方法名(第一参数)
- [
- 'out_trade_no' => '123456',
- 'refund_amount' => '10',
- ],
- 'POST',
- false // 不验证响应签名
-);
-
-// PUT/DELETE请求
-$result = $alipay->callApi('alipay.some.method', $data, 'PUT', false);
-```
-
-**参数说明:**
-
-- `$apiMethod` (string) - API方法名(如:`alipay.trade.query`),必填,第一参数
-- `$data` (array|string) - 请求参数(支持数组或字符串)
-- `$method` (string) - 请求方法 GET|POST|PUT|DELETE|PATCH,默认 GET
-- `$verify` (bool) - 验证响应签名,默认 false
-
-**默认行为:**
-
-- ✅ 自动使用 gateway 作为请求URL
-- ✅ 自动签名(默认开启)
-- ✅ 返回解析后的数组
-
-#### 自定义缓存
-
-SDK 支持自定义缓存驱动,可以适配 Redis、Memcached 等缓存系统,特别适用于常驻内存框架(Workerman、Swoole 等)。
-
-```php
- function ($name, $value, $expired = 360) {
- // 自定义缓存设置逻辑
- // $name: 缓存名称
- // $value: 缓存值
- // $expired: 过期时间(秒)
- return Redis::setex($name, $expired, serialize($value));
- },
- 'get' => function ($name) {
- // 自定义缓存获取逻辑
- // $name: 缓存名称
- // 返回: 缓存值或 null
- $data = Redis::get($name);
- return $data ? unserialize($data) : null;
- },
- 'del' => function ($name) {
- // 自定义缓存删除逻辑
- // $name: 缓存名称
- // 返回: boolean
- return Redis::del($name);
- },
- 'put' => function ($name, $content) {
- // 自定义文件缓存逻辑(用于证书等文件)
- // $name: 文件名称
- // $content: 文件内容
- // 返回: 文件路径(必须是可读的文件路径)
- $file = '/path/to/cache/' . $name;
- file_put_contents($file, $content);
- return $file;
- },
-];
-
-// 注意:
-// 1. 未配置自定义缓存时,默认使用文件缓存
-// 2. 文件缓存路径可通过配置中的 'cache_path' 参数设置
-// 3. SDK 会自动清理 CURL 临时缓存文件,无需手动处理
-// 4. 在常驻内存框架中,建议使用 Redis 等外部缓存替代文件缓存
-```
-
-#### 错误处理
-
-```php
-getUserList();
-} catch (\WeChat\Exceptions\InvalidResponseException $e) {
- // 接口调用异常
- echo "接口错误:" . $e->getMessage();
-} catch (\WeChat\Exceptions\LocalCacheException $e) {
- // 缓存异常
- echo "缓存错误:" . $e->getMessage();
-} catch (Exception $e) {
- // 其他异常
- echo "系统错误:" . $e->getMessage();
-}
-```
-
-### 🧩 小程序快速示例
-
-#### 订阅消息发送
-
-```php
-send([
- 'touser' => '用户openid',
- 'template_id' => '模板ID',
- 'page' => 'pages/index?foo=bar',
- 'data' => [
- 'thing1' => ['value' => '订单已支付'],
- 'time2' => ['value' => '2024-01-01 12:00'],
- ],
-]);
-```
-
-#### 内容安全校验
-
-```php
-msgSecCheck('留言内容示例');
-
-// 图片校验(文件流)
-$imgContent = file_get_contents('/path/to/demo.jpg');
-$security->imgSecCheck($imgContent);
-```
-
-## ⚙️ 配置说明
-
-### 基础配置
-
-#### 微信公众号配置
-
-```php
- 'wx60a43dd8161666d4',
- 'appsecret' => 'b4e28746f1bd73b5c6684f5e01883c36',
- 'token' => 'your_wechat_token',
- 'encodingaeskey' => 'your_encodingaeskey',
- 'cache_path' => '/path/to/cache',
-];
-```
-
-#### 微信支付配置
-
-```php
- 'wx60a43dd8161666d4',
- 'mch_id' => '15293xxxxxx',
- 'mch_key' => 'your_merchant_key',
- 'cache_path' => '/path/to/cache',
-];
-
-// 微信支付V3配置(推荐)
-$payV3Config = [
- 'appid' => 'wx60a43dd8161666d4',
- 'mch_id' => '15293xxxxxx',
- 'mch_v3_key' => '98b7fxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
- 'cert_serial' => '49055D67B2XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
- 'cert_public' => '-----BEGIN CERTIFICATE-----...',
- 'cert_private' => '-----BEGIN PRIVATE KEY-----...',
- 'cache_path' => '/path/to/cache',
- 'cert_package' => [
- 'PUB_KEY_ID_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' => '-----BEGIN CERTIFICATE-----...'
- ],
-];
-```
-
-#### 支付宝配置
-
-```php
- '2021000122667306',
- 'private_key' => 'MIIEowIBAAKCAQEAn...',
- 'public_key' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...',
- 'sign_type' => 'RSA2',
- 'notify_url' => 'https://your-domain.com/alipay/notify',
- 'return_url' => 'https://your-domain.com/alipay/return',
- 'charset' => 'utf-8',
- 'debug' => false, // 生产环境设为false
-];
-
-// 支付宝证书模式配置
-$alipayCertConfig = [
- 'appid' => '2021000122667306',
- 'private_key' => 'MIIEowIBAAKCAQEAn...',
- 'app_cert_path' => '/path/to/appPublicCert.crt',
- 'alipay_root_path' => '/path/to/alipayRootCert.crt',
- 'alipay_cert_path' => '/path/to/alipayPublicCert.crt',
- 'sign_type' => 'RSA2',
- 'notify_url' => 'https://your-domain.com/alipay/notify',
- 'return_url' => 'https://your-domain.com/alipay/return',
-];
-```
-
-## ❓ 常见问题
-
-### Q: 如何获取微信支付证书?
-
-A: 登录微信商户平台,在"账户中心" -> "API 安全" -> "API 证书"中下载证书文件,或使用 API 证书下载工具。
-
-### Q: 支付宝沙箱环境如何配置?
-
-A: 设置 `debug => true` 并使用沙箱环境的 `appid` 和密钥即可。
-
-### Q: AccessToken 过期怎么办?
-
-A: SDK 已内置自动刷新机制,无需手动处理。如需自定义,可设置 `GetAccessTokenCallback` 回调函数。
-
-### Q: 如何自定义缓存存储?
-
-A: 配置 `\WeChat\Contracts\Tools::$cache_callable` 数组,实现自定义的缓存逻辑。
-
-### Q: 支持哪些 PHP 版本?
-
-A: 最低支持 PHP 5.4,建议使用 PHP 7.0+ 以获得最佳性能。
-
-### Q: 如何处理支付回调?
-
-A: 使用 `\WeChat\Receive` 类处理微信支付回调,使用 `\AliPay\Web` 的 `notify()` 方法处理支付宝回调。
-
-### Q: 小程序数据解密失败?
-
-A: 确保 `session_key` 有效且未过期,检查 `iv` 和 `encryptedData` 参数是否正确。
-
-### Q: 如何调试接口调用?
-
-A: 开启错误日志,查看具体的错误信息。SDK 会抛出详细的异常信息帮助定位问题。
-
-### Q: 如何在常驻内存框架中使用?
-
-A: SDK 会自动清理 CURL 缓存文件,无需额外配置。在常驻内存环境中,建议通过自定义缓存驱动(`\WeChat\Contracts\Tools::$cache_callable`)使用 Redis 等外部缓存,避免文件缓存带来的问题。
-
-## 📁 文件说明
-
-| 文件名 | 类名 | 描述 | 类型 | 加载方法 |
-|-------------------|---------------------|----------------|-------|---------------------------|
-| **支付宝支付** | | | | |
-| App.php | AliPay\App | 支付宝 App 支付 | 支付宝支付 | \We::AliPayApp() |
-| Bill.php | AliPay\Bill | 支付宝账单下载 | 支付宝支付 | \We::AliPayBill() |
-| Pos.php | AliPay\Pos | 支付宝刷卡支付 | 支付宝支付 | \We::AliPayPos() |
-| Scan.php | AliPay\Scan | 支付宝扫码支付 | 支付宝支付 | \We::AliPayScan() |
-| Transfer.php | AliPay\Transfer | 支付宝转账 | 支付宝支付 | \We::AliPayTransfer() |
-| Wap.php | AliPay\Wap | 支付宝 Wap 支付 | 支付宝支付 | \We::AliPayWap() |
-| Web.php | AliPay\Web | 支付宝 Web 支付 | 支付宝支付 | \We::AliPayWeb() |
-| **微信公众号** | | | | |
-| Card.php | WeChat\Card | 微信卡券接口支持 | 认证服务号 | \We::WeChatCard() |
-| Custom.php | WeChat\Custom | 微信客服消息接口支持 | 认证服务号 | \We::WeChatCustom() |
-| Draft.php | WeChat\Draft | 微信草稿箱 | 认证服务号 | \We::WeChatDraft() |
-| Freepublish.php | WeChat\Freepublish | 微信发布能力 | 认证服务号 | \We::WeChatFreepublish() |
-| Media.php | WeChat\Media | 微信媒体素材接口支持 | 认证服务号 | \We::WeChatMedia() |
-| Menu.php | WeChat\Menu | 微信菜单管理 | 认证服务号 | \We::WeChatMenu() |
-| Oauth.php | WeChat\Oauth | 微信网页授权消息类接口 | 认证服务号 | \We::WeChatOauth() |
-| Pay.php | WeChat\Pay | 微信支付类接口 | 认证服务号 | \We::WeChatPay() |
-| Product.php | WeChat\Product | 微信商店类接口 | 认证服务号 | \We::WeChatProduct() |
-| Qrcode.php | WeChat\Qrcode | 微信二维码接口支持 | 认证服务号 | \We::WeChatQrcode() |
-| Receive.php | WeChat\Receive | 微信推送事件消息处理支持 | 认证服务号 | \We::WeChatReceive() |
-| Scan.php | WeChat\Scan | 微信扫一扫接口支持 | 认证服务号 | \We::WeChatScan() |
-| Script.php | WeChat\Script | 微信前端 JSSDK 支持 | 认证服务号 | \We::WeChatScript() |
-| Shake.php | WeChat\Shake | 微信蓝牙设备揺一揺接口 | 认证服务号 | \We::WeChatShake() |
-| Tags.php | WeChat\Tags | 微信粉丝标签接口支持 | 认证服务号 | \We::WeChatTags() |
-| Template.php | WeChat\Template | 微信模板消息接口支持 | 认证服务号 | \We::WeChatTemplate() |
-| User.php | WeChat\User | 微信粉丝管理接口支持 | 认证服务号 | \We::WeChatUser() |
-| Wifi.php | WeChat\Wifi | 微信门店 WIFI 管理支持 | 认证服务号 | \We::WeChatWifi() |
-| **微信支付** | | | | |
-| Bill.php | WePay\Bill | 微信商户账单及评论 | 微信支付 | \We::WePayBill() |
-| Coupon.php | WePay\Coupon | 微信商户代金券 | 微信支付 | \We::WePayCoupon() |
-| Order.php | WePay\Order | 微信商户订单 | 微信支付 | \We::WePayOrder() |
-| Redpack.php | WePay\Redpack | 微信红包支持 | 微信支付 | \We::WePayRedpack() |
-| Refund.php | WePay\Refund | 微信商户退款 | 微信支付 | \We::WePayRefund() |
-| Transfers.php | WePay\Transfers | 微信商户打款到零钱 | 微信支付 | \We::WePayTransfers() |
-| TransfersBank.php | WePay\TransfersBank | 微信商户打款到银行卡 | 微信支付 | \We::WePayTransfersBank() |
-| **微信小程序** | | | | |
-| Crypt.php | WeMini\Crypt | 微信小程序数据加密处理 | 微信小程序 | \We::WeMiniCrypt() |
-| Delivery.php | WeMini\Delivery | 小程序即时配送 | 微信小程序 | \We::WeMiniDelivery() |
-| Guide.php | WeMini\Guide | 小程序导购助手 | 微信小程序 | \We::WeMiniGuide() |
-| Image.php | WeMini\Image | 小程序图像处理 | 微信小程序 | \We::WeMiniImage() |
-| Live.php | WeMini\Live | 小程序直播接口 | 微信小程序 | \We::WeMiniLive() |
-| Logistics.php | WeMini\Logistics | 小程序物流助手 | 微信小程序 | \We::WeMiniLogistics() |
-| Message.php | WeMini\Message | 小程序动态消息 | 微信小程序 | \We::WeMiniMessage() |
-| Newtmpl.php | WeMini\Newtmpl | 小程序订阅消息 | 微信小程序 | \We::WeMiniNewtmpl() |
-| Ocr.php | WeMini\Ocr | 小程序 ORC 服务 | 微信小程序 | \We::WeMiniOcr() |
-| Operation.php | WeMini\Operation | 小程序运维中心 | 微信小程序 | \We::WeMiniOperation() |
-| Plugs.php | WeMini\Plugs | 微信小程序插件管理 | 微信小程序 | \We::WeMiniPlugs() |
-| Poi.php | WeMini\Poi | 小程序地址管理 | 微信小程序 | \We::WeMiniPoi() |
-| Qrcode.php | WeMini\Qrcode | 微信小程序二维码管理 | 微信小程序 | \We::WeMiniQrcode() |
-| Scheme.php | WeMini\Scheme | 小程序 URL-Scheme | 微信小程序 | \We::WeMiniScheme() |
-| Search.php | WeMini\Search | 小程序搜索 | 微信小程序 | \We::WeMiniSearch() |
-| Security.php | WeMini\Security | 小程序内容安全 | 微信小程序 | \We::WeMiniSecurity() |
-| Shipping.php | WeMini\Shipping | 小程序发货信息 | 微信小程序 | \We::WeMiniShipping() |
-| Soter.php | WeMini\Soter | 小程序生物认证 | 微信小程序 | \We::WeMiniSoter() |
-| Template.php | WeMini\Template | 微信小程序模板消息支持 | 微信小程序 | \We::WeMiniTemplate() |
-| Total.php | WeMini\Total | 微信小程序数据接口 | 微信小程序 | \We::WeMiniTotal() |
-
-## 📚 文档资源
-
-### 官方文档
-
-- **微信公众平台**:https://mp.weixin.qq.com/wiki
-- **微信支付文档**:https://pay.weixin.qq.com/wiki/doc/api/index.html
-- **支付宝开放平台**:https://opendocs.alipay.com/
-
-### 项目资源
-
-- **ThinkAdmin**:https://github.com/zoujingli/ThinkAdmin
-- **在线文档**:https://www.kancloud.cn/zoujingli/wechat-developer
-- **技术交流群**:QQ 群 513350915
-
-### 代码仓库
-
-- **GitHub**:https://github.com/zoujingli/WeChatDeveloper(主仓库)
-- **Gitee**:https://gitee.com/zoujingli/WeChatDeveloper(国内镜像)
-- **GitCode**:https://gitcode.com/ThinkAdmin/WeChatDeveloper(国内镜像)
-
-## 🛡️ 安全说明
-
-本项目经过全面的安全加固,包括:
-
-- 输入验证和 XSS 防护
-- 文件操作安全检查
-- 加密算法安全升级
-- 序列化数据验证
-- 类型安全修复
-
-建议在生产环境中:
-
-- 定期更新到最新版本
-- 配置 HTTPS 传输
-- 设置适当的文件权限
-- 监控异常访问日志
-
-## 📄 版权说明
-
-**WeChatDeveloper** 遵循 **MIT** 开源协议发布,并免费提供使用。
-
-本项目包含的第三方源码和二进制文件的版权信息将另行标注,请在对应文件查看。
-
-版权所有 Copyright © 2014-2025 by ThinkAdmin (https://thinkadmin.top) All rights reserved。
-
-## 💝 赞助支持
-
-如果这个项目对您有帮助,欢迎赞助支持!
-
-
diff --git a/src/Client.php b/src/Client.php
new file mode 100644
index 0000000..091286e
--- /dev/null
+++ b/src/Client.php
@@ -0,0 +1,180 @@
+cacheKeyPrefix = $g;
+ $this->cache = $cache ?? new FileCacheStore(self::defaultCacheStoreDirectory());
+ $this->authorizers = $authorizers;
+ $this->http = $http;
+ }
+
+ /** 默认缓存落盘目录:`sys_get_temp_dir()` + 包级子目录名,供未显式传入 `cache` 时构造 {@see FileCacheStore}。 */
+ public static function defaultCacheStoreDirectory(): string
+ {
+ return rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR . '/') . DIRECTORY_SEPARATOR . self::DEFAULT_CACHE_STORE_DIR_NAME;
+ }
+
+ /**
+ * 按通道标识取实例:`new Client()->get('wechat.platform', new WechatPlatformConfig(...))`
+ */
+ public function get(string $channel, ConfigInterface $config): object
+ {
+ $factory = match ($channel) {
+ 'wechat.platform' => 'wechatPlatform',
+ 'wechat.wxapp' => 'wechatWxapp',
+ 'wechat.service' => 'wechatService',
+ 'wechat.payment' => 'wechatPayment',
+ 'alipay.platform' => 'alipayPlatform',
+ 'alipay.payment' => 'alipayPayment',
+ default => throw new WechatException('不支持的通道标识: ' . $channel),
+ };
+
+ return $this->__call($factory, [$config]);
+ }
+
+ /**
+ * 魔术工厂:`$client->wechatPlatform($config)` 等价于反射 `new WechatPlatformClient(...)`。
+ *
+ * @param array $arguments
+ */
+ public function __call(string $name, array $arguments): object
+ {
+ $config = $arguments[0] ?? null;
+ if (!$config instanceof ConfigInterface) {
+ throw new WechatException('通道工厂第一个参数必须为 ConfigInterface 对象');
+ }
+
+ return match ($name) {
+ 'wechatPlatform' => $this->instantiate(WechatPlatformClient::class, [
+ $this->ensureConfig($config, WechatPlatformConfig::class, 'wechatPlatform'),
+ $this->http,
+ $this->cache,
+ $this->cacheKeyPrefix,
+ ]),
+ 'wechatWxapp' => $this->instantiate(WechatWxappClient::class, [
+ $this->ensureConfig($config, WechatWxappConfig::class, 'wechatWxapp'),
+ $this->http,
+ $this->cache,
+ $this->cacheKeyPrefix,
+ ]),
+ 'wechatService' => $this->instantiate(WechatServiceClient::class, [
+ $this->ensureConfig($config, WechatServiceConfig::class, 'wechatService'),
+ $this->http,
+ $this->cache,
+ $this->authorizers,
+ $this->cacheKeyPrefix,
+ ]),
+ 'wechatPayment' => $this->instantiate(WechatPaymentClient::class, [
+ $this->ensureConfig($config, WechatPaymentConfig::class, 'wechatPayment'),
+ $this->http,
+ ]),
+ 'alipayPlatform' => $this->instantiate(AlipayPlatformClient::class, [
+ $this->ensureConfig($config, AlipayPlatformConfig::class, 'alipayPlatform'),
+ $this->http,
+ ]),
+ 'alipayPayment' => $this->instantiate(AlipayPaymentClient::class, [
+ $this->ensureConfig($config, AlipayPaymentConfig::class, 'alipayPayment'),
+ $this->http,
+ ]),
+ default => throw new WechatException('不支持的通道工厂方法: ' . $name),
+ };
+ }
+
+ /**
+ * @param class-string $class
+ * @param array $args
+ */
+ private function instantiate(string $class, array $args): object
+ {
+ try {
+ return (new ReflectionClass($class))->newInstanceArgs($args);
+ } catch (ReflectionException $e) {
+ throw new WechatException('通道客户端实例化失败: ' . $e->getMessage(), 0, $e);
+ }
+ }
+
+ /**
+ * @template T of object
+ * @param class-string $expected
+ * @return T
+ */
+ private function ensureConfig(ConfigInterface $config, string $expected, string $factory): object
+ {
+ if (!$config instanceof $expected) {
+ throw new WechatException($factory . ' 需要 ' . $this->shortClass($expected));
+ }
+
+ return $config;
+ }
+
+ /** @param class-string $fqcn */
+ private function shortClass(string $fqcn): string
+ {
+ $pos = strrpos($fqcn, '\\');
+
+ return $pos === false ? $fqcn : substr($fqcn, $pos + 1);
+ }
+}
diff --git a/src/Config/AlipayPaymentConfig.php b/src/Config/AlipayPaymentConfig.php
new file mode 100644
index 0000000..2e35016
--- /dev/null
+++ b/src/Config/AlipayPaymentConfig.php
@@ -0,0 +1,9 @@
+validate();
+ }
+
+ public function validate(): void
+ {
+ if (trim($this->appid) === '' || trim($this->privateKey) === '') {
+ throw new WechatException('支付宝 appid 与 private_key 不能为空');
+ }
+ }
+
+ /**
+ * @param array $data
+ */
+ public static function fromArray(array $data): static
+ {
+ return new static(
+ (string)($data['appid'] ?? $data['app_id'] ?? ''),
+ (string)($data['private_key'] ?? $data['merchant_private_key'] ?? ''),
+ (string)($data['alipay_public_key'] ?? ''),
+ (string)($data['gateway'] ?? 'https://openapi.alipay.com/gateway.do'),
+ (string)($data['charset'] ?? 'utf-8'),
+ (string)($data['sign_type'] ?? 'RSA2'),
+ (string)($data['format'] ?? 'JSON'),
+ (string)($data['version'] ?? '1.0'),
+ );
+ }
+}
diff --git a/src/Config/WechatPaymentConfig.php b/src/Config/WechatPaymentConfig.php
new file mode 100644
index 0000000..b6d5d5e
--- /dev/null
+++ b/src/Config/WechatPaymentConfig.php
@@ -0,0 +1,56 @@
+validate();
+ }
+
+ public function validate(): void
+ {
+ foreach ([
+ 'appid' => $this->appid,
+ 'mchId' => $this->mchId,
+ 'apiV3Key' => $this->apiV3Key,
+ 'merchantSerial' => $this->merchantSerial,
+ 'merchantPrivateKey' => $this->merchantPrivateKey,
+ ] as $name => $value) {
+ if (trim($value) === '') {
+ throw new WechatException($name . ' 不能为空');
+ }
+ }
+ }
+
+ /**
+ * @param array $data
+ */
+ public static function fromArray(array $data): static
+ {
+ return new static(
+ (string)($data['appid'] ?? ''),
+ (string)($data['mch_id'] ?? $data['mchid'] ?? ''),
+ (string)($data['api_v3_key'] ?? $data['mch_v3_key'] ?? ''),
+ (string)($data['merchant_serial'] ?? $data['cert_serial'] ?? ''),
+ (string)($data['merchant_private_key'] ?? $data['cert_private'] ?? ''),
+ (string)($data['platform_certificate'] ?? $data['cert_public'] ?? ''),
+ (string)($data['platform_public_key'] ?? ''),
+ (string)($data['platform_serial'] ?? ''),
+ );
+ }
+}
diff --git a/src/Config/WechatPlatformConfig.php b/src/Config/WechatPlatformConfig.php
new file mode 100644
index 0000000..85f9c29
--- /dev/null
+++ b/src/Config/WechatPlatformConfig.php
@@ -0,0 +1,51 @@
+validate();
+ }
+
+ /**
+ * @param array $data
+ */
+ public static function fromArray(array $data): static
+ {
+ return new static(
+ (string)($data['appid'] ?? ''),
+ (string)($data['appsecret'] ?? $data['app_secret'] ?? ''),
+ (string)($data['token'] ?? ''),
+ (string)($data['encodingaeskey'] ?? $data['encoding_aes_key'] ?? ''),
+ (string)($data['storage_scope'] ?? $data['storageScope'] ?? ''),
+ );
+ }
+
+ public function validate(): void
+ {
+ foreach ([
+ 'appid' => $this->appid,
+ 'appSecret' => $this->appSecret,
+ ] as $name => $value) {
+ if (trim($value) === '') {
+ throw new WechatException($name . ' 不能为空');
+ }
+ }
+ }
+}
diff --git a/src/Config/WechatServiceConfig.php b/src/Config/WechatServiceConfig.php
new file mode 100644
index 0000000..601a840
--- /dev/null
+++ b/src/Config/WechatServiceConfig.php
@@ -0,0 +1,50 @@
+validate();
+ }
+
+ public function validate(): void
+ {
+ foreach ([
+ 'componentAppid' => $this->componentAppid,
+ 'componentAppSecret' => $this->componentAppSecret,
+ 'componentToken' => $this->componentToken,
+ 'componentEncodingAesKey' => $this->componentEncodingAesKey,
+ ] as $name => $value) {
+ if (trim($value) === '') {
+ throw new WechatException($name . ' 不能为空');
+ }
+ }
+ }
+
+ /**
+ * @param array $data
+ */
+ public static function fromArray(array $data): static
+ {
+ return new static(
+ (string)($data['component_appid'] ?? ''),
+ (string)($data['component_appsecret'] ?? $data['component_app_secret'] ?? ''),
+ (string)($data['component_token'] ?? ''),
+ (string)($data['component_encodingaeskey'] ?? $data['component_encoding_aes_key'] ?? ''),
+ (string)($data['storage_scope'] ?? $data['storageScope'] ?? ''),
+ );
+ }
+}
diff --git a/src/Config/WechatWxappConfig.php b/src/Config/WechatWxappConfig.php
new file mode 100644
index 0000000..ed8fe7c
--- /dev/null
+++ b/src/Config/WechatWxappConfig.php
@@ -0,0 +1,39 @@
+validate();
+ }
+
+ /**
+ * @param array $data
+ */
+ public static function fromArray(array $data): static
+ {
+ return new static(
+ (string)($data['appid'] ?? ''),
+ (string)($data['appsecret'] ?? $data['app_secret'] ?? ''),
+ (string)($data['storage_scope'] ?? $data['storageScope'] ?? ''),
+ );
+ }
+
+ public function validate(): void
+ {
+ if (trim($this->appid) === '' || trim($this->appSecret) === '') {
+ throw new WechatException('小程序 appid 与 appSecret 不能为空');
+ }
+ }
+}
diff --git a/src/Contract/ConfigInterface.php b/src/Contract/ConfigInterface.php
new file mode 100644
index 0000000..ad3098f
--- /dev/null
+++ b/src/Contract/ConfigInterface.php
@@ -0,0 +1,21 @@
+ $data
+ */
+ public static function fromArray(array $data): static;
+
+ /**
+ * 校验配置字段完整性、密钥格式等通道级约束;失败时抛出 SDK 异常。
+ */
+ public function validate(): void;
+}
diff --git a/src/Contract/StoreCacheInterface.php b/src/Contract/StoreCacheInterface.php
new file mode 100644
index 0000000..bb8cb3b
--- /dev/null
+++ b/src/Contract/StoreCacheInterface.php
@@ -0,0 +1,35 @@
+ $payload
+ */
+ public function saveAuthorizerToken(string $authorizerAppid, array $payload): void;
+}
diff --git a/src/Exception/ApiException.php b/src/Exception/ApiException.php
new file mode 100644
index 0000000..558f4e1
--- /dev/null
+++ b/src/Exception/ApiException.php
@@ -0,0 +1,7 @@
+ $context
+ */
+ public function __construct(
+ string $message,
+ int $code = 0,
+ ?Throwable $previous = null,
+ private readonly array $context = []
+ ) {
+ parent::__construct($message, $code, $previous);
+ }
+
+ /**
+ * @return array
+ */
+ public function context(): array
+ {
+ return $this->context;
+ }
+}
diff --git a/src/Platform/Alipay/PaymentClient.php b/src/Platform/Alipay/PaymentClient.php
new file mode 100644
index 0000000..1f070c9
--- /dev/null
+++ b/src/Platform/Alipay/PaymentClient.php
@@ -0,0 +1,87 @@
+ $bizContent
+ * @param array $extra
+ * @return array
+ */
+ public function refund(array $bizContent, array $extra = []): array
+ {
+ return $this->request('alipay.trade.refund', $bizContent, $extra);
+ }
+
+ /**
+ * @param array $bizContent
+ */
+ public function page(array $bizContent, array $extra = []): string
+ {
+ $params = [
+ 'app_id' => $this->config->appid,
+ 'method' => 'alipay.trade.page.pay',
+ 'format' => $this->config->format,
+ 'charset' => $this->config->charset,
+ 'sign_type' => $this->config->signType,
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'version' => $this->config->version,
+ 'biz_content' => json_encode($bizContent, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}',
+ ];
+ foreach ($extra as $key => $value) {
+ $params[(string)$key] = is_scalar($value) ? (string)$value : json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ }
+ $params['sign'] = $this->sign($params);
+
+ return $this->config->gateway . '?' . http_build_query($params);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function call(string $uriOrPath, array $params = [], string $httpMethod = 'POST', array $options = []): array
+ {
+ $apiMethod = trim($uriOrPath);
+ if ($apiMethod === 'page') {
+ return ['url' => $this->page($params, $options)];
+ }
+ if ($apiMethod === 'refund') {
+ return $this->refund($params, $options);
+ }
+
+ return $this->request($apiMethod, $params, $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function post(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'POST', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function get(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'GET', $options);
+ }
+}
diff --git a/src/Platform/Alipay/PlatformClient.php b/src/Platform/Alipay/PlatformClient.php
new file mode 100644
index 0000000..4ea474c
--- /dev/null
+++ b/src/Platform/Alipay/PlatformClient.php
@@ -0,0 +1,159 @@
+http = $http ?? new GuzzleClient(['timeout' => 20.0]);
+ }
+
+ /** @param array $bizContent @param array $extra @return array */
+ public function request(string $apiMethod, array $bizContent = [], array $extra = []): array
+ {
+ $params = [
+ 'app_id' => $this->config->appid,
+ 'method' => $apiMethod,
+ 'format' => $this->config->format,
+ 'charset' => $this->config->charset,
+ 'sign_type' => $this->config->signType,
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'version' => $this->config->version,
+ 'biz_content' => json_encode($bizContent, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}',
+ ];
+ foreach ($extra as $key => $value) {
+ $params[(string)$key] = is_scalar($value) ? (string)$value : json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
+ }
+ $params['sign'] = $this->sign($params);
+ $response = $this->http->request('POST', $this->config->gateway, [
+ 'form_params' => $params,
+ 'headers' => ['Accept' => 'application/json'],
+ ]);
+ $payload = json_decode((string)$response->getBody(), true);
+ if (!is_array($payload)) {
+ throw new WechatException('支付宝网关响应格式无效');
+ }
+ $node = str_replace('.', '_', $apiMethod) . '_response';
+ $data = is_array($payload[$node] ?? null) ? $payload[$node] : $payload;
+ if (($data['code'] ?? '10000') !== '10000') {
+ throw new WechatException((string)($data['sub_msg'] ?? $data['msg'] ?? '支付宝接口调用失败'));
+ }
+
+ return $data;
+ }
+
+ public function auth(string $redirectUri, string $scope = 'auth_user', string $state = ''): string
+ {
+ return 'https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?' . http_build_query([
+ 'app_id' => $this->config->appid,
+ 'scope' => $scope,
+ 'redirect_uri' => $redirectUri,
+ 'state' => $state,
+ ]);
+ }
+
+ /** @return array */
+ public function decrypt(string $encryptedData, string $sessionKey, string $iv): array
+ {
+ $plain = openssl_decrypt(
+ base64_decode($encryptedData, true) ?: '',
+ 'AES-128-CBC',
+ base64_decode($sessionKey, true) ?: '',
+ OPENSSL_RAW_DATA,
+ base64_decode($iv, true) ?: ''
+ );
+ if (!is_string($plain) || $plain === '') {
+ throw new WechatException('支付宝数据解密失败');
+ }
+ $data = json_decode($plain, true);
+ if (!is_array($data)) {
+ throw new WechatException('支付宝解密结果无效');
+ }
+
+ return $data;
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function call(string $uriOrPath, array $params = [], string $httpMethod = 'POST', array $options = []): array
+ {
+ $apiMethod = trim($uriOrPath);
+ if ($apiMethod === 'auth') {
+ return ['url' => $this->auth(
+ (string)($params['redirect_uri'] ?? ''),
+ (string)($params['scope'] ?? 'auth_user'),
+ (string)($params['state'] ?? ''),
+ )];
+ }
+ if ($apiMethod === 'decrypt') {
+ return $this->decrypt(
+ (string)($params['encrypted_data'] ?? ''),
+ (string)($params['session_key'] ?? ''),
+ (string)($params['iv'] ?? ''),
+ );
+ }
+
+ return $this->request($apiMethod, $params, $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function post(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'POST', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function get(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'GET', $options);
+ }
+
+ /** @param array $params */
+ protected function sign(array $params): string
+ {
+ ksort($params);
+ $pairs = [];
+ foreach ($params as $key => $value) {
+ if ($key === 'sign' || $value === null || $value === '') {
+ continue;
+ }
+ $pairs[] = $key . '=' . $value;
+ }
+ $data = implode('&', $pairs);
+ $privateKey = str_contains($this->config->privateKey, 'BEGIN') ? $this->config->privateKey : "-----BEGIN PRIVATE KEY-----\n" . chunk_split($this->config->privateKey, 64, "\n") . "-----END PRIVATE KEY-----";
+ $resource = openssl_pkey_get_private($privateKey);
+ if ($resource === false) {
+ throw new WechatException('支付宝私钥无效');
+ }
+ $algo = strtoupper($this->config->signType) === 'RSA2' ? OPENSSL_ALGO_SHA256 : OPENSSL_ALGO_SHA1;
+ $ok = openssl_sign($data, $signature, $resource, $algo);
+ if ($ok !== true) {
+ throw new WechatException('支付宝签名失败');
+ }
+
+ return base64_encode($signature);
+ }
+}
diff --git a/src/Platform/Wechat/PaymentClient.php b/src/Platform/Wechat/PaymentClient.php
new file mode 100644
index 0000000..b5df91b
--- /dev/null
+++ b/src/Platform/Wechat/PaymentClient.php
@@ -0,0 +1,142 @@
+http = new JsonClient($http ?? new \GuzzleHttp\Client(['base_uri' => 'https://api.mch.weixin.qq.com/', 'timeout' => 20.0]));
+ }
+
+ /** @param array $payload @return array */
+ public function request(string $method, string $uri, array $payload = [], array $query = []): array
+ {
+ $uri = '/' . ltrim($uri, '/');
+ $body = $payload === [] ? '' : (json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}');
+ $nonce = bin2hex(random_bytes(16));
+ $timestamp = (string)time();
+ $authorization = $this->authorization($method, $uri . ($query === [] ? '' : '?' . http_build_query($query)), $timestamp, $nonce, $body);
+
+ return $this->http->request($method, ltrim($uri, '/'), $query, [
+ 'body' => $body,
+ 'headers' => [
+ 'Accept' => 'application/json',
+ 'Content-Type' => 'application/json',
+ 'Authorization' => $authorization,
+ 'Wechatpay-Serial' => $this->config->merchantSerial,
+ ],
+ ]);
+ }
+
+ /** @param array $payload @return array */
+ public function refund(array $payload): array
+ {
+ return $this->request('POST', 'v3/refund/domestic/refunds', $payload);
+ }
+
+ /**
+ * @param array $headers
+ * @param array $body
+ * @return array
+ */
+ public function decryptNotification(array $headers, array $body): array
+ {
+ $this->assertNotificationSignature($headers, json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}');
+ /** @var array{ciphertext:string,nonce:string,associated_data?:string} $resource */
+ $resource = $body['resource'] ?? [];
+
+ return PayCrypto::decryptResource($this->config->apiV3Key, $resource);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function call(string $uriOrPath, array $params = [], string $httpMethod = 'POST', array $options = []): array
+ {
+ $uri = ltrim($uriOrPath, '/');
+ $method = strtoupper($httpMethod === '' ? 'POST' : $httpMethod);
+ if ($uri === 'refund') {
+ return $this->refund($params);
+ }
+ if ($uri === 'decrypt_notification') {
+ return $this->decryptNotification(
+ is_array($options['headers'] ?? null) ? $options['headers'] : [],
+ is_array($options['body'] ?? null) ? $options['body'] : $params,
+ );
+ }
+
+ return $this->request(
+ $method,
+ $uri,
+ $method === 'GET' ? (is_array($options['payload'] ?? null) ? $options['payload'] : []) : $params,
+ $method === 'GET' ? $params : (is_array($options['query'] ?? null) ? $options['query'] : []),
+ );
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function post(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'POST', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function get(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'GET', $options);
+ }
+
+ private function authorization(string $method, string $uri, string $timestamp, string $nonce, string $body): string
+ {
+ $message = strtoupper($method) . "\n{$uri}\n{$timestamp}\n{$nonce}\n{$body}\n";
+ $signature = Signature::payV3Sign($this->config->merchantPrivateKey, $message);
+ $schema = 'WECHATPAY2-SHA256-RSA2048';
+ $fields = [
+ 'mchid' => $this->config->mchId,
+ 'nonce_str' => $nonce,
+ 'timestamp' => $timestamp,
+ 'serial_no' => $this->config->merchantSerial,
+ 'signature' => $signature,
+ ];
+
+ return $schema . ' ' . implode(',', array_map(static fn (string $key, string $value): string => $key . '="' . $value . '"', array_keys($fields), $fields));
+ }
+
+ private function assertNotificationSignature(array $headers, string $body): void
+ {
+ $timestamp = (string)($headers['Wechatpay-Timestamp'] ?? $headers['wechatpay-timestamp'] ?? '');
+ $nonce = (string)($headers['Wechatpay-Nonce'] ?? $headers['wechatpay-nonce'] ?? '');
+ $signature = (string)($headers['Wechatpay-Signature'] ?? $headers['wechatpay-signature'] ?? '');
+ $message = "{$timestamp}\n{$nonce}\n{$body}\n";
+ $publicKey = $this->config->platformPublicKey !== '' ? $this->config->platformPublicKey : $this->config->platformCertificate;
+ if ($publicKey === '') {
+ throw new SignatureException('微信支付平台公钥或证书不能为空');
+ }
+ if (!Signature::verifyPayV3($publicKey, $message, $signature)) {
+ throw new SignatureException('微信支付回调验签失败');
+ }
+ }
+}
diff --git a/src/Platform/Wechat/PlatformClient.php b/src/Platform/Wechat/PlatformClient.php
new file mode 100644
index 0000000..8b0b230
--- /dev/null
+++ b/src/Platform/Wechat/PlatformClient.php
@@ -0,0 +1,179 @@
+http = new JsonClient($http ?? new \GuzzleHttp\Client(['base_uri' => self::API, 'timeout' => 20.0]));
+ }
+
+ public function accessToken(bool $refresh = false): string
+ {
+ $key = $this->cacheKey(TokenCacheKey::wechatOfficialAccessToken($this->config->appid, $this->config->storageScope));
+ if (!$refresh && is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+
+ return $this->cache->lock('lock:' . $key, 30, function () use ($key, $refresh): string {
+ if (!$refresh && is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+ $data = $this->http->request('GET', 'cgi-bin/token', [
+ 'grant_type' => 'client_credential',
+ 'appid' => $this->config->appid,
+ 'secret' => $this->config->appSecret,
+ ]);
+ $token = (string)($data['access_token'] ?? '');
+ $this->cache->set($key, $token, max(1, (int)($data['expires_in'] ?? 7200) - 300));
+
+ return $token;
+ });
+ }
+
+ /**
+ * @param array $query
+ * @param array $options
+ * @return array
+ */
+ public function request(string $method, string $uri, array $query = [], array $options = [], bool $withToken = true): array
+ {
+ if ($withToken) {
+ $query['access_token'] = $query['access_token'] ?? $this->accessToken();
+ }
+
+ return $this->http->request($method, ltrim($uri, '/'), $query, $options);
+ }
+
+ /** @param array $menu @return array */
+ public function createMenu(array $menu): array
+ {
+ return $this->request('POST', 'cgi-bin/menu/create', options: ['json' => $menu]);
+ }
+
+ /** @return array */
+ public function userList(string $nextOpenid = ''): array
+ {
+ return $this->request('GET', 'cgi-bin/user/get', ['next_openid' => $nextOpenid]);
+ }
+
+ /**
+ * @param array $openids
+ * @return array
+ */
+ public function batchUserInfo(array $openids, string $lang = 'zh_CN'): array
+ {
+ return $this->request('POST', 'cgi-bin/user/info/batchget', options: [
+ 'json' => [
+ 'user_list' => array_map(static fn (string $openid): array => ['openid' => $openid, 'lang' => $lang], $openids),
+ ],
+ ]);
+ }
+
+ public function messageCrypto(): MessageCrypto
+ {
+ return new MessageCrypto($this->config->token, $this->config->encodingAesKey, $this->config->appid);
+ }
+
+ /**
+ * 统一调用入口:除 token 基础接口外,默认按 URI + 参数发起请求。
+ *
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function call(string $uriOrPath, array $params = [], string $httpMethod = 'POST', array $options = []): array
+ {
+ $method = strtoupper($httpMethod === '' ? 'POST' : $httpMethod);
+ $uri = ltrim($uriOrPath, '/');
+ if ($uri === 'decrypt_message') {
+ return $this->messageCrypto()->decryptMessage(
+ (string)($params['body'] ?? ''),
+ (string)($params['msg_signature'] ?? ''),
+ (string)($params['timestamp'] ?? ''),
+ (string)($params['nonce'] ?? ''),
+ );
+ }
+ if ($uri === 'encrypt_message') {
+ return [
+ 'xml' => $this->messageCrypto()->encryptMessage(
+ (string)($params['body'] ?? ''),
+ (string)($params['timestamp'] ?? time()),
+ (string)($params['nonce'] ?? ''),
+ ),
+ ];
+ }
+
+ return $this->request(
+ $method,
+ $uri,
+ $method === 'GET' ? $params : (is_array($options['query'] ?? null) ? $options['query'] : []),
+ $this->buildOptions($method, $params, $options),
+ (bool)($options['with_token'] ?? true),
+ );
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function post(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'POST', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function get(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'GET', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ private function buildOptions(string $method, array $params, array $options): array
+ {
+ if ($method === 'GET' || isset($options['json']) || isset($options['body']) || isset($options['form_params']) || isset($options['multipart'])) {
+ return $options;
+ }
+ $options['json'] = $params;
+
+ return $options;
+ }
+
+ private function cacheKey(string $logicalKey): string
+ {
+ return CacheKey::compose($this->cacheKeyPrefix, self::TOKEN_PLATFORM_CHANNEL, $logicalKey);
+ }
+}
diff --git a/src/Platform/Wechat/ServiceClient.php b/src/Platform/Wechat/ServiceClient.php
new file mode 100644
index 0000000..95276f8
--- /dev/null
+++ b/src/Platform/Wechat/ServiceClient.php
@@ -0,0 +1,249 @@
+http = new JsonClient($http ?? new \GuzzleHttp\Client(['base_uri' => 'https://api.weixin.qq.com/', 'timeout' => 20.0]));
+ $this->authorizers = $authorizers;
+ }
+
+ private readonly ?StoreTokenInterface $authorizers;
+
+ public function componentAccessToken(string $componentVerifyTicket, bool $refresh = false): string
+ {
+ $key = $this->cacheKey(TokenCacheKey::wechatOpenComponentAccessToken($this->config->componentAppid, $this->config->storageScope));
+ if (!$refresh && is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+
+ return $this->cache->lock('lock:' . $key, 30, function () use ($key, $componentVerifyTicket, $refresh): string {
+ if (!$refresh && is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+ $data = $this->http->request('POST', 'cgi-bin/component/api_component_token', options: [
+ 'json' => [
+ 'component_appid' => $this->config->componentAppid,
+ 'component_appsecret' => $this->config->componentAppSecret,
+ 'component_verify_ticket' => $componentVerifyTicket,
+ ],
+ ]);
+ $token = (string)$data['component_access_token'];
+ $this->cache->set($key, $token, max(1, (int)($data['expires_in'] ?? 7200) - 300));
+
+ return $token;
+ });
+ }
+
+ /** @return array */
+ public function request(string $method, string $uri, array $query = [], array $options = []): array
+ {
+ return $this->http->request($method, ltrim($uri, '/'), $query, $options);
+ }
+
+ /** @return array */
+ public function createPreAuthCode(string $componentAccessToken): array
+ {
+ return $this->http->request('POST', 'cgi-bin/component/api_create_preauthcode', ['component_access_token' => $componentAccessToken], [
+ 'json' => ['component_appid' => $this->config->componentAppid],
+ ]);
+ }
+
+ public function authorizationUrl(string $preAuthCode, string $redirectUri, int $authType = 3, string $state = ''): string
+ {
+ return 'https://mp.weixin.qq.com/cgi-bin/componentloginpage?' . http_build_query([
+ 'component_appid' => $this->config->componentAppid,
+ 'pre_auth_code' => $preAuthCode,
+ 'redirect_uri' => $redirectUri,
+ 'auth_type' => $authType,
+ 'biz_appid' => '',
+ 'state' => $state,
+ ]);
+ }
+
+ /** @return array */
+ public function queryAuth(string $componentAccessToken, string $authorizationCode): array
+ {
+ return $this->http->request('POST', 'cgi-bin/component/api_query_auth', ['component_access_token' => $componentAccessToken], [
+ 'json' => [
+ 'component_appid' => $this->config->componentAppid,
+ 'authorization_code' => $authorizationCode,
+ ],
+ ]);
+ }
+
+ /** @return array */
+ public function authorizerInfo(string $componentAccessToken, string $authorizerAppid): array
+ {
+ return $this->http->request('POST', 'cgi-bin/component/api_get_authorizer_info', ['component_access_token' => $componentAccessToken], [
+ 'json' => [
+ 'component_appid' => $this->config->componentAppid,
+ 'authorizer_appid' => $authorizerAppid,
+ ],
+ ]);
+ }
+
+ /** @return array */
+ public function requestAsAuthorizer(string $method, string $uri, string $authorizerAppid, string $componentAccessToken, array $query = [], array $options = []): array
+ {
+ $query['access_token'] = $this->authorizerAccessToken($componentAccessToken, $authorizerAppid);
+
+ return $this->http->request($method, ltrim($uri, '/'), $query, $options);
+ }
+
+ public function messageCrypto(): MessageCrypto
+ {
+ return new MessageCrypto($this->config->componentToken, $this->config->componentEncodingAesKey, $this->config->componentAppid);
+ }
+
+ /**
+ * 统一调用入口:除 token 基础接口外,其他能力默认按 URI + 参数执行。
+ *
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function call(string $uriOrPath, array $params = [], string $httpMethod = 'POST', array $options = []): array
+ {
+ $method = strtoupper($httpMethod === '' ? 'POST' : $httpMethod);
+ $uri = ltrim($uriOrPath, '/');
+ if ($uri === 'decrypt_message') {
+ return $this->messageCrypto()->decryptMessage(
+ (string)($params['body'] ?? ''),
+ (string)($params['msg_signature'] ?? ''),
+ (string)($params['timestamp'] ?? ''),
+ (string)($params['nonce'] ?? ''),
+ );
+ }
+ if ($uri === 'encrypt_message') {
+ return [
+ 'xml' => $this->messageCrypto()->encryptMessage(
+ (string)($params['body'] ?? ''),
+ (string)($params['timestamp'] ?? time()),
+ (string)($params['nonce'] ?? ''),
+ ),
+ ];
+ }
+ if (isset($options['authorizer_appid'], $options['component_access_token'])) {
+ return $this->requestAsAuthorizer(
+ $method,
+ $uri,
+ (string)$options['authorizer_appid'],
+ (string)$options['component_access_token'],
+ is_array($options['query'] ?? null) ? $options['query'] : [],
+ $this->buildOptions($method, $params, $options),
+ );
+ }
+
+ return $this->request(
+ $method,
+ $uri,
+ $method === 'GET' ? $params : (is_array($options['query'] ?? null) ? $options['query'] : []),
+ $this->buildOptions($method, $params, $options),
+ );
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function post(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'POST', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function get(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'GET', $options);
+ }
+
+ private function authorizerAccessToken(string $componentAccessToken, string $authorizerAppid): string
+ {
+ if (!$this->authorizers) {
+ throw new WechatException('未配置授权账号 Token 仓库');
+ }
+ $key = $this->cacheKey(TokenCacheKey::wechatOpenAuthorizerAccessToken(
+ $this->config->componentAppid,
+ $authorizerAppid,
+ $this->config->storageScope,
+ ));
+ if (is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+
+ return $this->cache->lock('lock:' . $key, 30, function () use ($key, $componentAccessToken, $authorizerAppid): string {
+ if (is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+ $data = $this->refreshAuthorizerToken($componentAccessToken, $authorizerAppid, $this->authorizers->refreshToken($authorizerAppid));
+ $this->authorizers->saveAuthorizerToken($authorizerAppid, $data);
+ $token = (string)$data['authorizer_access_token'];
+ $this->cache->set($key, $token, max(1, (int)($data['expires_in'] ?? 7200) - 300));
+
+ return $token;
+ });
+ }
+
+ /** @return array */
+ private function refreshAuthorizerToken(string $componentAccessToken, string $authorizerAppid, string $refreshToken): array
+ {
+ return $this->http->request('POST', 'cgi-bin/component/api_authorizer_token', ['component_access_token' => $componentAccessToken], [
+ 'json' => [
+ 'component_appid' => $this->config->componentAppid,
+ 'authorizer_appid' => $authorizerAppid,
+ 'authorizer_refresh_token' => $refreshToken,
+ ],
+ ]);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ private function buildOptions(string $method, array $params, array $options): array
+ {
+ if ($method === 'GET' || isset($options['json']) || isset($options['body']) || isset($options['form_params']) || isset($options['multipart'])) {
+ return $options;
+ }
+ $options['json'] = $params;
+
+ return $options;
+ }
+
+ private function cacheKey(string $logicalKey): string
+ {
+ return CacheKey::compose($this->cacheKeyPrefix, self::TOKEN_PLATFORM_CHANNEL, $logicalKey);
+ }
+}
diff --git a/src/Platform/Wechat/WxappClient.php b/src/Platform/Wechat/WxappClient.php
new file mode 100644
index 0000000..54d2e12
--- /dev/null
+++ b/src/Platform/Wechat/WxappClient.php
@@ -0,0 +1,123 @@
+http = new JsonClient($http ?? new \GuzzleHttp\Client(['base_uri' => 'https://api.weixin.qq.com/', 'timeout' => 20.0]));
+ }
+
+ public function accessToken(bool $refresh = false): string
+ {
+ $key = $this->cacheKey(TokenCacheKey::wechatMiniAccessToken($this->config->appid, $this->config->storageScope));
+ if (!$refresh && is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+
+ return $this->cache->lock('lock:' . $key, 30, function () use ($key, $refresh): string {
+ if (!$refresh && is_string($token = $this->cache->get($key, '')) && $token !== '') {
+ return $token;
+ }
+ $data = $this->http->request('GET', 'cgi-bin/token', [
+ 'grant_type' => 'client_credential',
+ 'appid' => $this->config->appid,
+ 'secret' => $this->config->appSecret,
+ ]);
+ $token = (string)$data['access_token'];
+ $this->cache->set($key, $token, max(1, (int)($data['expires_in'] ?? 7200) - 300));
+
+ return $token;
+ });
+ }
+
+ /**
+ * @return array
+ */
+ public function request(string $method, string $uri, array $query = [], array $options = [], bool $withToken = true): array
+ {
+ if ($withToken) {
+ $query['access_token'] = $query['access_token'] ?? $this->accessToken();
+ }
+
+ return $this->http->request($method, ltrim($uri, '/'), $query, $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function call(string $uriOrPath, array $params = [], string $httpMethod = 'POST', array $options = []): array
+ {
+ $method = strtoupper($httpMethod === '' ? 'POST' : $httpMethod);
+
+ return $this->request(
+ $method,
+ ltrim($uriOrPath, '/'),
+ $method === 'GET' ? $params : (is_array($options['query'] ?? null) ? $options['query'] : []),
+ $this->buildOptions($method, $params, $options),
+ (bool)($options['with_token'] ?? true),
+ );
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function post(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'POST', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ public function get(string $uriOrPath, array $params = [], array $options = []): array
+ {
+ return $this->call($uriOrPath, $params, 'GET', $options);
+ }
+
+ /**
+ * @param array $params
+ * @param array $options
+ * @return array
+ */
+ private function buildOptions(string $method, array $params, array $options): array
+ {
+ if ($method === 'GET' || isset($options['json']) || isset($options['body']) || isset($options['form_params'])) {
+ return $options;
+ }
+ $options['json'] = $params;
+
+ return $options;
+ }
+
+ private function cacheKey(string $logicalKey): string
+ {
+ return CacheKey::compose($this->cacheKeyPrefix, self::TOKEN_PLATFORM_CHANNEL, $logicalKey);
+ }
+}
diff --git a/src/Support/CacheKey.php b/src/Support/CacheKey.php
new file mode 100644
index 0000000..ec60731
--- /dev/null
+++ b/src/Support/CacheKey.php
@@ -0,0 +1,46 @@
+directory === '') {
+ throw new WechatException('FileCacheStore 目录不能为空');
+ }
+ if (!is_dir($this->directory) && @mkdir($this->directory, 0775, true) !== true) {
+ throw new WechatException('FileCacheStore 无法创建目录: ' . $this->directory);
+ }
+ if (!is_writable($this->directory)) {
+ throw new WechatException('FileCacheStore 目录不可写: ' . $this->directory);
+ }
+ }
+
+ public function get(string $key, mixed $default = null): mixed
+ {
+ $path = $this->pathFor($key);
+ if (!is_file($path)) {
+ return $default;
+ }
+ $handle = @fopen($path, 'rb');
+ if ($handle === false) {
+ return $default;
+ }
+
+ try {
+ if (!flock($handle, LOCK_SH)) {
+ return $default;
+ }
+ $raw = stream_get_contents($handle);
+ flock($handle, LOCK_UN);
+ } finally {
+ fclose($handle);
+ }
+
+ if (!is_string($raw) || $raw === '') {
+ return $default;
+ }
+
+ /** @var array{expires_at?:int,value?:mixed}|null $payload */
+ $payload = json_decode($raw, true);
+ if (!is_array($payload) || !array_key_exists('expires_at', $payload) || !array_key_exists('value', $payload)) {
+ return $default;
+ }
+ if ((int)$payload['expires_at'] < time()) {
+ $this->del($key);
+
+ return $default;
+ }
+
+ return $payload['value'];
+ }
+
+ public function set(string $key, mixed $value, int $ttl): void
+ {
+ $path = $this->pathFor($key);
+ $dir = dirname($path);
+ if (!is_dir($dir) && @mkdir($dir, 0775, true) !== true) {
+ throw new WechatException('FileCacheStore 无法创建子目录: ' . $dir);
+ }
+
+ $body = json_encode(
+ ['expires_at' => time() + max(1, $ttl), 'value' => $value],
+ JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
+ );
+ $tmp = $path . '.' . bin2hex(random_bytes(4)) . '.tmp';
+ if (@file_put_contents($tmp, $body, LOCK_EX) === false) {
+ @unlink($tmp);
+ throw new WechatException('FileCacheStore 写入失败: ' . $tmp);
+ }
+ if (!@rename($tmp, $path)) {
+ @unlink($path);
+ if (!@rename($tmp, $path)) {
+ @unlink($tmp);
+ throw new WechatException('FileCacheStore 提交失败: ' . $path);
+ }
+ }
+ }
+
+ public function del(string $key): void
+ {
+ $path = $this->pathFor($key);
+ if (is_file($path)) {
+ @unlink($path);
+ }
+ }
+
+ public function lock(string $key, int $ttl, callable $callback): mixed
+ {
+ $path = $this->pathFor('lock:' . $key) . '.lock';
+ $dir = dirname($path);
+ if (!is_dir($dir) && @mkdir($dir, 0775, true) !== true) {
+ throw new WechatException('FileCacheStore 无法创建锁目录: ' . $dir);
+ }
+
+ $handle = @fopen($path, 'c');
+ if ($handle === false) {
+ throw new WechatException('FileCacheStore 无法创建锁文件: ' . $path);
+ }
+
+ try {
+ if (!flock($handle, LOCK_EX)) {
+ throw new WechatException('FileCacheStore 获取锁失败: ' . $key);
+ }
+
+ return $callback();
+ } finally {
+ flock($handle, LOCK_UN);
+ fclose($handle);
+ }
+ }
+
+ private function pathFor(string $key): string
+ {
+ $hash = hash('sha256', $key);
+
+ return $this->directory . DIRECTORY_SEPARATOR . substr($hash, 0, 2) . DIRECTORY_SEPARATOR . $hash . '.json';
+ }
+}
diff --git a/src/Support/JsonClient.php b/src/Support/JsonClient.php
new file mode 100644
index 0000000..2b2301c
--- /dev/null
+++ b/src/Support/JsonClient.php
@@ -0,0 +1,52 @@
+ 20.0]),
+ ) {}
+
+ /**
+ * @param array $query
+ * @param array $options
+ * @return array
+ */
+ public function request(string $method, string $uri, array $query = [], array $options = []): array
+ {
+ $options['query'] = array_merge($query, $options['query'] ?? []);
+ $response = $this->send($method, $uri, $options);
+ $body = (string)$response->getBody();
+ $data = $body === '' ? [] : json_decode($body, true);
+ if (!is_array($data)) {
+ throw new ApiException('微信接口响应不是有效 JSON', (int)$response->getStatusCode(), null, ['body' => $body]);
+ }
+ $errcode = (int)($data['errcode'] ?? 0);
+ if ($errcode !== 0) {
+ throw new ApiException((string)($data['errmsg'] ?? '微信接口请求失败'), $errcode, null, $data);
+ }
+
+ return $data;
+ }
+
+ /**
+ * @param array $options
+ */
+ public function send(string $method, string $uri, array $options = []): ResponseInterface
+ {
+ try {
+ return $this->http->request($method, $uri, $options);
+ } catch (GuzzleException $exception) {
+ throw new ApiException($exception->getMessage(), (int)$exception->getCode(), $exception);
+ }
+ }
+}
diff --git a/src/Support/MessageCrypto.php b/src/Support/MessageCrypto.php
new file mode 100644
index 0000000..435ed0c
--- /dev/null
+++ b/src/Support/MessageCrypto.php
@@ -0,0 +1,80 @@
+aesKey = $key;
+ }
+
+ /**
+ * @return array
+ */
+ public function decryptMessage(string $xml, string $msgSignature, string $timestamp, string $nonce): array
+ {
+ $payload = Xml::decode($xml);
+ $encrypt = (string)($payload['Encrypt'] ?? '');
+ if ($encrypt === '') {
+ throw new WechatException('微信加密消息缺少 Encrypt 字段');
+ }
+
+ Signature::assertSha1($msgSignature, [$this->token, $timestamp, $nonce, $encrypt]);
+
+ $plain = openssl_decrypt(base64_decode($encrypt, true) ?: '', 'AES-256-CBC', $this->aesKey, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, substr($this->aesKey, 0, 16));
+ if (!is_string($plain) || $plain === '') {
+ throw new WechatException('微信加密消息解密失败');
+ }
+
+ $plain = $this->removePadding($plain);
+ $length = unpack('N', substr($plain, 16, 4))[1] ?? 0;
+ $message = substr($plain, 20, (int)$length);
+ $appid = substr($plain, 20 + (int)$length);
+ if (!hash_equals($this->appid, $appid)) {
+ throw new SignatureException('微信加密消息 AppID 不匹配');
+ }
+
+ return Xml::decode($message);
+ }
+
+ public function encryptMessage(string $xml, string $timestamp, string $nonce): string
+ {
+ $random = random_bytes(16);
+ $payload = $random . pack('N', strlen($xml)) . $xml . $this->appid;
+ $payload .= str_repeat(chr($pad = 32 - strlen($payload) % 32), $pad);
+ $encrypted = base64_encode(openssl_encrypt($payload, 'AES-256-CBC', $this->aesKey, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, substr($this->aesKey, 0, 16)) ?: '');
+ $signature = Signature::sha1([$this->token, $timestamp, $nonce, $encrypted]);
+
+ return Xml::encode([
+ 'Encrypt' => $encrypted,
+ 'MsgSignature' => $signature,
+ 'TimeStamp' => $timestamp,
+ 'Nonce' => $nonce,
+ ]);
+ }
+
+ private function removePadding(string $data): string
+ {
+ $pad = ord(substr($data, -1));
+ if ($pad < 1 || $pad > 32) {
+ $pad = 0;
+ }
+
+ return substr($data, 0, strlen($data) - $pad);
+ }
+}
diff --git a/src/Support/NullCacheStore.php b/src/Support/NullCacheStore.php
new file mode 100644
index 0000000..7fd5b86
--- /dev/null
+++ b/src/Support/NullCacheStore.php
@@ -0,0 +1,27 @@
+
+ */
+ public static function decryptResource(string $apiV3Key, array $resource): array
+ {
+ $ciphertext = base64_decode($resource['ciphertext'], true);
+ if ($ciphertext === false || strlen($ciphertext) <= 16) {
+ throw new WechatException('微信支付回调密文无效');
+ }
+
+ $tag = substr($ciphertext, -16);
+ $ciphertext = substr($ciphertext, 0, -16);
+ $plain = openssl_decrypt(
+ $ciphertext,
+ 'aes-256-gcm',
+ $apiV3Key,
+ OPENSSL_RAW_DATA,
+ $resource['nonce'],
+ $tag,
+ (string)($resource['associated_data'] ?? '')
+ );
+ if (!is_string($plain) || $plain === '') {
+ throw new WechatException('微信支付回调解密失败');
+ }
+
+ $data = json_decode($plain, true);
+ if (!is_array($data)) {
+ throw new WechatException('微信支付回调明文 JSON 无效');
+ }
+
+ return $data;
+ }
+}
diff --git a/src/Support/PsrSimpleCacheStore.php b/src/Support/PsrSimpleCacheStore.php
new file mode 100644
index 0000000..2308626
--- /dev/null
+++ b/src/Support/PsrSimpleCacheStore.php
@@ -0,0 +1,47 @@
+cache->get($key, $default);
+ }
+
+ public function set(string $key, mixed $value, int $ttl): void
+ {
+ $this->cache->set($key, $value, max(1, $ttl));
+ }
+
+ public function del(string $key): void
+ {
+ $this->cache->delete($key);
+ }
+
+ public function lock(string $key, int $ttl, callable $callback): mixed
+ {
+ if (!is_callable($this->locker)) {
+ throw new WechatException('PsrSimpleCacheStore 未配置锁能力');
+ }
+
+ return ($this->locker)($key, max(1, $ttl), $callback);
+ }
+}
diff --git a/src/Support/Signature.php b/src/Support/Signature.php
new file mode 100644
index 0000000..6291f79
--- /dev/null
+++ b/src/Support/Signature.php
@@ -0,0 +1,56 @@
+ $items
+ */
+ public static function sha1(array $items): string
+ {
+ sort($items, SORT_STRING);
+
+ return sha1(implode('', $items));
+ }
+
+ /**
+ * @param array $items
+ */
+ public static function assertSha1(string $expected, array $items): void
+ {
+ $actual = self::sha1($items);
+ if (!hash_equals($actual, $expected)) {
+ throw new SignatureException('微信回调签名验证失败', 0, null, ['expected' => $expected, 'actual' => $actual]);
+ }
+ }
+
+ public static function payV3Sign(string $privateKey, string $message): string
+ {
+ $key = openssl_pkey_get_private($privateKey);
+ if ($key === false) {
+ throw new SignatureException('微信支付商户私钥无效');
+ }
+ if (!openssl_sign($message, $signature, $key, OPENSSL_ALGO_SHA256)) {
+ throw new SignatureException('微信支付签名生成失败');
+ }
+
+ return base64_encode($signature);
+ }
+
+ public static function verifyPayV3(string $publicKey, string $message, string $signature): bool
+ {
+ $key = openssl_pkey_get_public($publicKey);
+ if ($key === false) {
+ throw new SignatureException('微信支付平台公钥或证书无效');
+ }
+
+ return openssl_verify($message, base64_decode($signature, true) ?: '', $key, OPENSSL_ALGO_SHA256) === 1;
+ }
+}
diff --git a/src/Support/TokenCacheKey.php b/src/Support/TokenCacheKey.php
new file mode 100644
index 0000000..e37f4ef
--- /dev/null
+++ b/src/Support/TokenCacheKey.php
@@ -0,0 +1,57 @@
+
+ */
+ public static function decode(string $xml): array
+ {
+ $xml = trim($xml);
+ if ($xml === '') {
+ return [];
+ }
+
+ $previous = libxml_use_internal_errors(true);
+ $element = simplexml_load_string($xml, SimpleXMLElement::class, LIBXML_NOCDATA);
+ libxml_use_internal_errors($previous);
+ if (!$element instanceof SimpleXMLElement) {
+ throw new WechatException('微信 XML 格式无效');
+ }
+
+ return self::normalize($element);
+ }
+
+ /**
+ * @param array $data
+ */
+ public static function encode(array $data): string
+ {
+ $content = '';
+ foreach ($data as $key => $value) {
+ if (is_array($value)) {
+ $value = json_encode($value, JSON_UNESCAPED_UNICODE) ?: '';
+ }
+ $value = (string)$value;
+ $content .= sprintf('<%1$s>%1$s>', $key, $value);
+ }
+
+ return $content . '';
+ }
+
+ /**
+ * @return array
+ */
+ private static function normalize(SimpleXMLElement $element): array
+ {
+ $result = [];
+ foreach ($element->children() as $key => $value) {
+ $children = $value->children();
+ $result[$key] = $children->count() > 0 ? self::normalize($value) : (string)$value;
+ }
+
+ return $result;
+ }
+}
diff --git a/src/Tests/AccessTokenCacheTest.php b/src/Tests/AccessTokenCacheTest.php
new file mode 100644
index 0000000..9122192
--- /dev/null
+++ b/src/Tests/AccessTokenCacheTest.php
@@ -0,0 +1,130 @@
+set($key, 'cached-token', 3600);
+ $http = new FakeHttpClient(['access_token' => 'remote-token', 'expires_in' => 7200]);
+
+ $token = (new Client(cache: $cache, http: $http))
+ ->wechatPlatform(new WechatPlatformConfig('wx_app', 'secret'))
+ ->accessToken();
+
+ $this->assertSame('cached-token', $token);
+ $this->assertSame(0, $http->requests);
+ $this->assertSame(0, $cache->lockCalls);
+ }
+
+ public function testAccessTokenRefreshUsesLockAndWritesCache(): void
+ {
+ $cache = new ArrayCacheStore();
+ $http = new FakeHttpClient(['access_token' => 'remote-token', 'expires_in' => 7200]);
+ $platform = (new Client(cache: $cache, http: $http))
+ ->wechatPlatform(new WechatPlatformConfig('wx_app', 'secret'));
+
+ $this->assertSame('remote-token', $platform->accessToken());
+ $this->assertSame(1, $http->requests);
+ $this->assertSame(1, $cache->lockCalls);
+ $this->assertSame('remote-token', $platform->accessToken());
+ $this->assertSame(1, $http->requests);
+ }
+}
+
+final class ArrayCacheStore implements StoreCacheInterface
+{
+ /** @var array */
+ private array $values = [];
+
+ public int $lockCalls = 0;
+
+ public function get(string $key, mixed $default = null): mixed
+ {
+ return $this->values[$key] ?? $default;
+ }
+
+ public function set(string $key, mixed $value, int $ttl): void
+ {
+ $this->values[$key] = $value;
+ }
+
+ public function del(string $key): void
+ {
+ unset($this->values[$key]);
+ }
+
+ public function lock(string $key, int $ttl, callable $callback): mixed
+ {
+ ++$this->lockCalls;
+
+ return $callback();
+ }
+}
+
+final class FakeHttpClient implements ClientInterface
+{
+ public int $requests = 0;
+
+ /**
+ * @param array $payload
+ */
+ public function __construct(private readonly array $payload) {}
+
+ public function send(RequestInterface $request, array $options = []): ResponseInterface
+ {
+ return $this->response();
+ }
+
+ public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
+ {
+ return Create::rejectionFor(new \RuntimeException('sendAsync is not used in this test'));
+ }
+
+ public function request(string $method, $uri = '', array $options = []): ResponseInterface
+ {
+ ++$this->requests;
+
+ return $this->response();
+ }
+
+ public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface
+ {
+ return Create::rejectionFor(new \RuntimeException('requestAsync is not used in this test'));
+ }
+
+ public function getConfig(?string $option = null): mixed
+ {
+ return null;
+ }
+
+ private function response(): ResponseInterface
+ {
+ return new Response(200, [], json_encode($this->payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}');
+ }
+}
diff --git a/src/Tests/CacheKeyTest.php b/src/Tests/CacheKeyTest.php
new file mode 100644
index 0000000..19ce736
--- /dev/null
+++ b/src/Tests/CacheKeyTest.php
@@ -0,0 +1,49 @@
+assertSame('myapp:wechat.platform:' . $logical, $full);
+ }
+
+ public function testComposeTrimsColonNoiseOnSegments(): void
+ {
+ $logical = 'wechat:app:z:official:access_token';
+ $this->assertSame('ns:wechat.service:' . $logical, CacheKey::compose('::ns::', ':::wechat.service::', $logical));
+ }
+
+ public function testComposeThrowsWhenPrefixEmpty(): void
+ {
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('通用前缀');
+ CacheKey::compose('', 'wechat.wxapp', 'wechat:app:x:mini:access_token');
+ }
+
+ public function testComposeThrowsWhenChannelEmpty(): void
+ {
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('通道段');
+ CacheKey::compose('app', '', 'wechat:app:x:mini:access_token');
+ }
+
+ public function testComposeThrowsWhenLogicalEmpty(): void
+ {
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('逻辑段');
+ CacheKey::compose('app', 'wechat.platform', ' ');
+ }
+}
diff --git a/src/Tests/CacheStoreTest.php b/src/Tests/CacheStoreTest.php
new file mode 100644
index 0000000..b54973b
--- /dev/null
+++ b/src/Tests/CacheStoreTest.php
@@ -0,0 +1,162 @@
+tempDir();
+ $store = new FileCacheStore($dir);
+
+ $this->assertSame('missing', $store->get('k1', 'missing'));
+ $store->set('k1', 'value', 3600);
+ $this->assertSame('value', $store->get('k1'));
+ $store->del('k1');
+ $this->assertSame('missing', $store->get('k1', 'missing'));
+
+ $store->set('k2', 'expired', -10);
+ sleep(2);
+ $this->assertSame('missing', $store->get('k2', 'missing'));
+
+ $this->removeDir($dir);
+ }
+
+ public function testFileCacheStoreLockExecutesCallback(): void
+ {
+ $dir = $this->tempDir();
+ $store = new FileCacheStore($dir);
+
+ $result = $store->lock('lock:k1', 10, static fn (): string => 'locked');
+
+ $this->assertSame('locked', $result);
+ $this->removeDir($dir);
+ }
+
+ public function testNullCacheStoreLockExecutesCallback(): void
+ {
+ $store = new NullCacheStore();
+
+ $this->assertSame('ok', $store->lock('k', 10, static fn (): string => 'ok'));
+ }
+
+ public function testPsrSimpleCacheStoreThrowsWhenLockerMissing(): void
+ {
+ $store = new PsrSimpleCacheStore(new ArraySimpleCache());
+
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('锁能力');
+
+ $store->lock('k', 10, static fn (): string => 'never');
+ }
+
+ public function testPsrSimpleCacheStoreUsesInjectedLocker(): void
+ {
+ $calls = [];
+ $store = new PsrSimpleCacheStore(new ArraySimpleCache(), static function (string $key, int $ttl, callable $callback) use (&$calls): mixed {
+ $calls[] = [$key, $ttl];
+
+ return $callback();
+ });
+
+ $this->assertSame('ok', $store->lock('k', 10, static fn (): string => 'ok'));
+ $this->assertSame([['k', 10]], $calls);
+ }
+
+ private function tempDir(): string
+ {
+ return sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'wechatdev_cache_' . bin2hex(random_bytes(8));
+ }
+
+ private function removeDir(string $dir): void
+ {
+ if (!is_dir($dir)) {
+ return;
+ }
+ $iterator = new \RecursiveIteratorIterator(
+ new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS),
+ \RecursiveIteratorIterator::CHILD_FIRST,
+ );
+ foreach ($iterator as $file) {
+ $path = $file->getPathname();
+ $file->isDir() ? @rmdir($path) : @unlink($path);
+ }
+ @rmdir($dir);
+ }
+}
+
+final class ArraySimpleCache implements CacheInterface
+{
+ /** @var array */
+ private array $values = [];
+
+ public function get(string $key, mixed $default = null): mixed
+ {
+ return $this->values[$key] ?? $default;
+ }
+
+ public function set(string $key, mixed $value, null|int|DateInterval $ttl = null): bool
+ {
+ $this->values[$key] = $value;
+
+ return true;
+ }
+
+ public function delete(string $key): bool
+ {
+ unset($this->values[$key]);
+
+ return true;
+ }
+
+ public function clear(): bool
+ {
+ $this->values = [];
+
+ return true;
+ }
+
+ public function getMultiple(iterable $keys, mixed $default = null): iterable
+ {
+ foreach ($keys as $key) {
+ yield $key => $this->get((string)$key, $default);
+ }
+ }
+
+ public function setMultiple(iterable $values, null|int|DateInterval $ttl = null): bool
+ {
+ foreach ($values as $key => $value) {
+ $this->set((string)$key, $value, $ttl);
+ }
+
+ return true;
+ }
+
+ public function deleteMultiple(iterable $keys): bool
+ {
+ foreach ($keys as $key) {
+ $this->delete((string)$key);
+ }
+
+ return true;
+ }
+
+ public function has(string $key): bool
+ {
+ return array_key_exists($key, $this->values);
+ }
+}
diff --git a/src/Tests/ClientTest.php b/src/Tests/ClientTest.php
new file mode 100644
index 0000000..f693db7
--- /dev/null
+++ b/src/Tests/ClientTest.php
@@ -0,0 +1,98 @@
+expectException(WechatException::class);
+ $this->expectExceptionMessage('cacheKeyPrefix');
+ new Client(cacheKeyPrefix: ' ');
+ }
+
+ public function testDefaultCacheStoreDirectoryUnderSysTemp(): void
+ {
+ $dir = Client::defaultCacheStoreDirectory();
+ $this->assertStringStartsWith(rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR . '/'), $dir);
+ $this->assertStringEndsWith(Client::DEFAULT_CACHE_STORE_DIR_NAME, $dir);
+ }
+
+ public function testGetThrowsWhenChannelUnsupported(): void
+ {
+ $client = new Client();
+
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('不支持的通道标识');
+ $client->get('unknown.channel', new WechatPlatformConfig('wx_x', 'sec'));
+ }
+
+ public function testGetThrowsWhenConfigMismatch(): void
+ {
+ $client = new Client();
+
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('WechatPlatformConfig');
+ $client->get('wechat.platform', new WechatServiceConfig('app', 'sec', 'token', 'encoding'));
+ }
+
+ public function testWechatPlatformFactoryReturnsTypedClient(): void
+ {
+ $client = new Client();
+ $wechat = $client->wechatPlatform(new WechatPlatformConfig('wx_appid', 'app_secret'));
+
+ $this->assertInstanceOf(WechatPlatformClient::class, $wechat);
+ }
+
+ public function testServiceClientAuthorizationUrlStillAvailable(): void
+ {
+ $client = new Client();
+ $service = $client->wechatService(new WechatServiceConfig(
+ 'wx_component',
+ 'component_secret',
+ 'component_token',
+ 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG'
+ ));
+ $result = $service->authorizationUrl('preauthcode', 'https://example.com/callback', 3, 'STATE_TEST');
+
+ $this->assertStringContainsString('componentloginpage', $result);
+ $this->assertStringContainsString('pre_auth_code=preauthcode', $result);
+ }
+
+ public function testAlipayPlatformCallReturnsAuthorizationUrl(): void
+ {
+ $client = new Client();
+ $alipay = $client->alipayPlatform(new AlipayPlatformConfig('202605010001', str_repeat('a', 64)));
+ $result = $alipay->get('auth', [
+ 'redirect_uri' => 'https://example.com/alipay/callback',
+ 'scope' => 'auth_user',
+ 'state' => 'S2',
+ ]);
+
+ $this->assertArrayHasKey('url', $result);
+ $this->assertStringContainsString('state=S2', (string)$result['url']);
+ }
+
+ public function testGetCanReturnSpecificChannelClient(): void
+ {
+ $client = new Client();
+ $channelClient = $client->get('alipay.platform', new AlipayPlatformConfig('202605010001', str_repeat('a', 64)));
+
+ $this->assertInstanceOf(AlipayPlatformClient::class, $channelClient);
+ $this->assertNotInstanceOf(WechatServiceClient::class, $channelClient);
+ }
+}
diff --git a/src/Tests/ConfigInterfaceTest.php b/src/Tests/ConfigInterfaceTest.php
new file mode 100644
index 0000000..e3d4abc
--- /dev/null
+++ b/src/Tests/ConfigInterfaceTest.php
@@ -0,0 +1,60 @@
+assertInstanceOf(ConfigInterface::class, $config);
+ }
+ }
+
+ public function testConfigValidateRequiredFieldsOnConstruct(): void
+ {
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('不能为空');
+
+ new WechatPlatformConfig('', 'secret');
+ }
+
+ public function testConfigValidateRequiredFieldsFromArray(): void
+ {
+ $this->expectException(WechatException::class);
+ $this->expectExceptionMessage('不能为空');
+
+ WechatPaymentConfig::fromArray(['appid' => 'wx_app']);
+ }
+
+ public function testAlipayPaymentFromArrayReturnsChildClass(): void
+ {
+ $config = AlipayPaymentConfig::fromArray([
+ 'appid' => 'ali_pay',
+ 'private_key' => 'private-key',
+ ]);
+
+ $this->assertInstanceOf(AlipayPaymentConfig::class, $config);
+ }
+}
diff --git a/src/Tests/MessageCryptoTest.php b/src/Tests/MessageCryptoTest.php
new file mode 100644
index 0000000..271ef2f
--- /dev/null
+++ b/src/Tests/MessageCryptoTest.php
@@ -0,0 +1,33 @@
+';
+ $timestamp = '1777600000';
+ $nonce = 'nonce';
+
+ $encrypted = $crypto->encryptMessage($xml, $timestamp, $nonce);
+ preg_match('/<\/Encrypt>/', $encrypted, $matches);
+ $this->assertNotEmpty($matches[1] ?? '');
+ $signature = Signature::sha1(['token', $timestamp, $nonce, $matches[1]]);
+
+ $plain = $crypto->decryptMessage($encrypted, $signature, $timestamp, $nonce);
+
+ $this->assertSame('text', $plain['MsgType']);
+ $this->assertSame('hello', $plain['Content']);
+ }
+}
diff --git a/src/Tests/PayCryptoTest.php b/src/Tests/PayCryptoTest.php
new file mode 100644
index 0000000..0ea344c
--- /dev/null
+++ b/src/Tests/PayCryptoTest.php
@@ -0,0 +1,31 @@
+ base64_encode($cipher . $tag),
+ 'nonce' => $nonce,
+ 'associated_data' => $aad,
+ ]);
+
+ $this->assertSame('T202605010001', $data['out_trade_no']);
+ $this->assertSame('SUCCESS', $data['trade_state']);
+ }
+}
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..40963a2
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,27 @@
+