From b0ac3868a8739d124de05180c13eb99fd7aaabbe Mon Sep 17 00:00:00 2001 From: wanghongjun <1445693971@qq,com> Date: Tue, 24 Oct 2023 11:07:07 +0800 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E7=BD=B2=E5=88=B0git?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../overtrue/socialite/.github/FUNDING.yml | 9 + .../vendor/overtrue/socialite/.gitignore | 9 + .../vendor/overtrue/socialite/.php_cs | 28 + .../vendor/overtrue/socialite/.travis.yml | 13 + .../vendor/overtrue/socialite/LICENSE.txt | 21 + .../vendor/overtrue/socialite/README.md | 266 +++++++++ .../vendor/overtrue/socialite/composer.json | 26 + .../vendor/overtrue/socialite/phpunit.xml | 18 + .../overtrue/socialite/src/AccessToken.php | 64 ++ .../socialite/src/AccessTokenInterface.php | 25 + .../src/AuthorizeFailedException.php | 35 ++ .../vendor/overtrue/socialite/src/Config.php | 180 ++++++ .../socialite/src/FactoryInterface.php | 27 + .../overtrue/socialite/src/HasAttributes.php | 135 +++++ .../src/InvalidArgumentException.php | 16 + .../socialite/src/InvalidStateException.php | 16 + .../socialite/src/ProviderInterface.php | 31 + .../src/Providers/AbstractProvider.php | 560 ++++++++++++++++++ .../src/Providers/DouYinProvider.php | 168 ++++++ .../src/Providers/DoubanProvider.php | 88 +++ .../src/Providers/FacebookProvider.php | 167 ++++++ .../src/Providers/GitHubProvider.php | 121 ++++ .../src/Providers/GoogleProvider.php | 118 ++++ .../src/Providers/LinkedinProvider.php | 181 ++++++ .../src/Providers/OutlookProvider.php | 88 +++ .../socialite/src/Providers/QQProvider.php | 206 +++++++ .../src/Providers/TaobaoProvider.php | 242 ++++++++ .../src/Providers/WeChatProvider.php | 234 ++++++++ .../src/Providers/WeWorkProvider.php | 214 +++++++ .../socialite/src/Providers/WeiboProvider.php | 126 ++++ .../socialite/src/SocialiteManager.php | 251 ++++++++ .../vendor/overtrue/socialite/src/User.php | 186 ++++++ .../overtrue/socialite/src/UserInterface.php | 53 ++ .../src/WeChatComponentInterface.php | 32 + .../overtrue/socialite/tests/OAuthTest.php | 161 +++++ .../tests/Providers/WeWorkProviderTest.php | 48 ++ .../overtrue/socialite/tests/UserTest.php | 24 + .../socialite/tests/WechatProviderTest.php | 109 ++++ .../wechat/src/BasicService/Application.php | 39 ++ .../BasicService/ContentSecurity/Client.php | 123 ++++ .../ContentSecurity/ServiceProvider.php | 31 + .../wechat/src/BasicService/Jssdk/Client.php | 207 +++++++ .../BasicService/Jssdk/ServiceProvider.php | 33 ++ .../wechat/src/BasicService/Media/Client.php | 212 +++++++ .../BasicService/Media/ServiceProvider.php | 44 ++ .../wechat/src/BasicService/QrCode/Client.php | 120 ++++ .../BasicService/QrCode/ServiceProvider.php | 31 + .../wechat/src/BasicService/Url/Client.php | 47 ++ .../src/BasicService/Url/ServiceProvider.php | 31 + .../wechat/src/Kernel/AccessToken.php | 282 +++++++++ .../overtrue/wechat/src/Kernel/BaseClient.php | 271 +++++++++ .../wechat/src/Kernel/Clauses/Clause.php | 64 ++ .../overtrue/wechat/src/Kernel/Config.php | 23 + .../Kernel/Contracts/AccessTokenInterface.php | 40 ++ .../wechat/src/Kernel/Contracts/Arrayable.php | 29 + .../Contracts/EventHandlerInterface.php | 25 + .../src/Kernel/Contracts/MediaInterface.php | 25 + .../src/Kernel/Contracts/MessageInterface.php | 35 ++ .../src/Kernel/Decorators/FinallyResult.php | 35 ++ .../src/Kernel/Decorators/TerminateResult.php | 35 ++ .../overtrue/wechat/src/Kernel/Encryptor.php | 219 +++++++ .../Kernel/Events/AccessTokenRefreshed.php | 35 ++ .../Kernel/Events/ApplicationInitialized.php | 35 ++ .../src/Kernel/Events/HttpResponseCreated.php | 35 ++ .../Events/ServerGuardResponseCreated.php | 35 ++ .../Kernel/Exceptions/BadRequestException.php | 21 + .../Kernel/Exceptions/DecryptException.php | 16 + .../src/Kernel/Exceptions/Exception.php | 23 + .../src/Kernel/Exceptions/HttpException.php | 52 ++ .../Exceptions/InvalidArgumentException.php | 21 + .../Exceptions/InvalidConfigException.php | 21 + .../Kernel/Exceptions/RuntimeException.php | 21 + .../Exceptions/UnboundServiceException.php | 21 + .../overtrue/wechat/src/Kernel/Helpers.php | 57 ++ .../wechat/src/Kernel/Http/Response.php | 121 ++++ .../wechat/src/Kernel/Http/StreamResponse.php | 86 +++ .../wechat/src/Kernel/Messages/Article.php | 58 ++ .../wechat/src/Kernel/Messages/Card.php | 52 ++ .../src/Kernel/Messages/DeviceEvent.php | 40 ++ .../wechat/src/Kernel/Messages/DeviceText.php | 50 ++ .../wechat/src/Kernel/Messages/File.php | 25 + .../wechat/src/Kernel/Messages/Image.php | 27 + .../wechat/src/Kernel/Messages/Link.php | 36 ++ .../wechat/src/Kernel/Messages/Location.php | 38 ++ .../wechat/src/Kernel/Messages/Media.php | 70 +++ .../wechat/src/Kernel/Messages/Message.php | 208 +++++++ .../src/Kernel/Messages/MiniProgramPage.php | 31 + .../wechat/src/Kernel/Messages/Music.php | 73 +++ .../wechat/src/Kernel/Messages/News.php | 73 +++ .../wechat/src/Kernel/Messages/NewsItem.php | 57 ++ .../wechat/src/Kernel/Messages/Raw.php | 56 ++ .../wechat/src/Kernel/Messages/ShortVideo.php | 30 + .../wechat/src/Kernel/Messages/TaskCard.php | 44 ++ .../wechat/src/Kernel/Messages/Text.php | 54 ++ .../wechat/src/Kernel/Messages/TextCard.php | 40 ++ .../wechat/src/Kernel/Messages/Transfer.php | 56 ++ .../wechat/src/Kernel/Messages/Video.php | 65 ++ .../wechat/src/Kernel/Messages/Voice.php | 37 ++ .../Providers/ConfigServiceProvider.php | 39 ++ .../EventDispatcherServiceProvider.php | 47 ++ .../Providers/ExtensionServiceProvider.php | 39 ++ .../Providers/HttpClientServiceProvider.php | 39 ++ .../Kernel/Providers/LogServiceProvider.php | 79 +++ .../Providers/RequestServiceProvider.php | 39 ++ .../wechat/src/Kernel/ServerGuard.php | 375 ++++++++++++ .../wechat/src/Kernel/ServiceContainer.php | 167 ++++++ .../wechat/src/Kernel/Support/AES.php | 85 +++ .../wechat/src/Kernel/Support/Arr.php | 466 +++++++++++++++ .../src/Kernel/Support/ArrayAccessible.php | 66 +++ .../wechat/src/Kernel/Support/Collection.php | 421 +++++++++++++ .../wechat/src/Kernel/Support/File.php | 135 +++++ .../wechat/src/Kernel/Support/Helpers.php | 131 ++++ .../wechat/src/Kernel/Support/Str.php | 193 ++++++ .../wechat/src/Kernel/Support/XML.php | 167 ++++++ .../src/Kernel/Traits/HasAttributes.php | 251 ++++++++ .../src/Kernel/Traits/HasHttpRequests.php | 231 ++++++++ .../src/Kernel/Traits/InteractsWithCache.php | 105 ++++ .../wechat/src/Kernel/Traits/Observable.php | 273 +++++++++ .../src/Kernel/Traits/ResponseCastable.php | 93 +++ .../wechat/src/MicroMerchant/Application.php | 171 ++++++ .../wechat/src/MicroMerchant/Base/Client.php | 126 ++++ .../MicroMerchant/Base/ServiceProvider.php | 33 ++ .../src/MicroMerchant/Certficates/Client.php | 93 +++ .../Certficates/ServiceProvider.php | 33 ++ .../src/MicroMerchant/Kernel/BaseClient.php | 256 ++++++++ .../Kernel/Exceptions/EncryptException.php | 23 + .../Exceptions/InvalidExtensionException.php | 23 + .../Exceptions/InvalidSignException.php | 23 + .../src/MicroMerchant/Material/Client.php | 73 +++ .../Material/ServiceProvider.php | 33 ++ .../wechat/src/MicroMerchant/Media/Client.php | 49 ++ .../MicroMerchant/Media/ServiceProvider.php | 44 ++ .../MicroMerchant/MerchantConfig/Client.php | 134 +++++ .../MerchantConfig/ServiceProvider.php | 33 ++ .../src/MicroMerchant/Withdraw/Client.php | 67 +++ .../Withdraw/ServiceProvider.php | 33 ++ 136 files changed, 12805 insertions(+) create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/.github/FUNDING.yml create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/.gitignore create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/.php_cs create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/.travis.yml create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/LICENSE.txt create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/README.md create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/composer.json create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/phpunit.xml create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessToken.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessTokenInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/AuthorizeFailedException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Config.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/FactoryInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/HasAttributes.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidArgumentException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidStateException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/ProviderInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/AbstractProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DouYinProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DoubanProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/FacebookProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GitHubProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GoogleProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/LinkedinProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/OutlookProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/QQProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/TaobaoProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeChatProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeWorkProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeiboProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/SocialiteManager.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/User.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/UserInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/src/WeChatComponentInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/tests/OAuthTest.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/tests/UserTest.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/socialite/tests/WechatProviderTest.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Application.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/AccessToken.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/BaseClient.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Clauses/Clause.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Config.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/AccessTokenInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/Arrayable.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/EventHandlerInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MediaInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MessageInterface.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/FinallyResult.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/TerminateResult.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Encryptor.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/AccessTokenRefreshed.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ApplicationInitialized.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/HttpResponseCreated.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ServerGuardResponseCreated.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/BadRequestException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/DecryptException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/Exception.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/HttpException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidArgumentException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidConfigException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/RuntimeException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/UnboundServiceException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Helpers.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/Response.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/StreamResponse.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Article.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Card.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceEvent.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceText.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/File.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Image.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Link.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Location.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Media.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Message.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/MiniProgramPage.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Music.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/News.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/NewsItem.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Raw.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/ShortVideo.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TaskCard.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Text.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TextCard.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Transfer.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Video.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Voice.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ConfigServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/EventDispatcherServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ExtensionServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/HttpClientServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/LogServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/RequestServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServerGuard.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServiceContainer.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/AES.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Arr.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/ArrayAccessible.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Collection.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/File.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Helpers.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Str.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/XML.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasAttributes.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasHttpRequests.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/InteractsWithCache.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/Observable.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/ResponseCastable.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Application.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/BaseClient.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/EncryptException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidExtensionException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidSignException.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/ServiceProvider.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/Client.php create mode 100644 addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/ServiceProvider.php diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/.github/FUNDING.yml b/addons/weliam_smartcity/vendor/overtrue/socialite/.github/FUNDING.yml new file mode 100644 index 0000000..a3be7fa --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/.github/FUNDING.yml @@ -0,0 +1,9 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: overtrue +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +custom: # Replace with a single custom sponsorship URL diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/.gitignore b/addons/weliam_smartcity/vendor/overtrue/socialite/.gitignore new file mode 100644 index 0000000..d6eb268 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/.gitignore @@ -0,0 +1,9 @@ +/vendor +composer.phar +composer.lock +.DS_Store +/.idea +Thumbs.db +/*.php +sftp-config.json +.php_cs.cache \ No newline at end of file diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/.php_cs b/addons/weliam_smartcity/vendor/overtrue/socialite/.php_cs new file mode 100644 index 0000000..bda3644 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/.php_cs @@ -0,0 +1,28 @@ + + +This source file is subject to the MIT license that is bundled +with this source code in the file LICENSE. +EOF; + +return PhpCsFixer\Config::create() + ->setRiskyAllowed(true) + ->setRules(array( + '@Symfony' => true, + 'header_comment' => array('header' => $header), + 'array_syntax' => array('syntax' => 'short'), + 'ordered_imports' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'php_unit_construct' => true, + 'php_unit_strict' => true, + )) + ->setFinder( + PhpCsFixer\Finder::create() + ->exclude('vendor') + ->in(__DIR__) + ) +; \ No newline at end of file diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/.travis.yml b/addons/weliam_smartcity/vendor/overtrue/socialite/.travis.yml new file mode 100644 index 0000000..39912f9 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/.travis.yml @@ -0,0 +1,13 @@ +language: php + +php: + - 7.0 + - 7.1 + - 7.2 + +sudo: false +dist: trusty + +install: travis_retry composer install --no-interaction --prefer-source + +script: vendor/bin/phpunit --verbose diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/LICENSE.txt b/addons/weliam_smartcity/vendor/overtrue/socialite/LICENSE.txt new file mode 100644 index 0000000..c5fe984 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) overtrue + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/README.md b/addons/weliam_smartcity/vendor/overtrue/socialite/README.md new file mode 100644 index 0000000..ec7ea88 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/README.md @@ -0,0 +1,266 @@ +

Socialite

+

+Build Status +Latest Stable Version +Latest Unstable Version +Build Status +Scrutinizer Code Quality +Code Coverage +Total Downloads +License +

+ + +

Socialite is an OAuth2 Authentication tool. It is inspired by laravel/socialite, You can easily use it in any PHP project.

+ +# Requirement + +``` +PHP >= 7.0 +``` +# Installation + +```shell +$ composer require "overtrue/socialite" -vvv +``` + +# Usage + +For Laravel 5: [overtrue/laravel-socialite](https://github.com/overtrue/laravel-socialite) + +`authorize.php`: + +```php + [ + 'client_id' => 'your-app-id', + 'client_secret' => 'your-app-secret', + 'redirect' => 'http://localhost/socialite/callback.php', + ], +]; + +$socialite = new SocialiteManager($config); + +$response = $socialite->driver('github')->redirect(); + +echo $response;// or $response->send(); +``` + +`callback.php`: + +```php + [ + 'client_id' => 'your-app-id', + 'client_secret' => 'your-app-secret', + 'redirect' => 'http://localhost/socialite/callback.php', + ], +]; + +$socialite = new SocialiteManager($config); + +$user = $socialite->driver('github')->user(); + +$user->getId(); // 1472352 +$user->getNickname(); // "overtrue" +$user->getUsername(); // "overtrue" +$user->getName(); // "安正超" +$user->getEmail(); // "anzhengchao@gmail.com" +$user->getProviderName(); // GitHub +... +``` + +### Configuration + +Now we support the following sites: + +`facebook`, `github`, `google`, `linkedin`, `outlook`, `weibo`, `taobao`, `qq`, `wechat`, `douyin`, and `douban`. + +Each driver uses the same configuration keys: `client_id`, `client_secret`, `redirect`. + +Example: +``` +... + 'weibo' => [ + 'client_id' => 'your-app-id', + 'client_secret' => 'your-app-secret', + 'redirect' => 'http://localhost/socialite/callback.php', + ], +... +``` + +### Scope + +Before redirecting the user, you may also set "scopes" on the request using the scope method. This method will overwrite all existing scopes: + +```php +$response = $socialite->driver('github') + ->scopes(['scope1', 'scope2'])->redirect(); + +``` + +### Redirect URL + +You may also want to dynamicly set `redirect`,you can use the following methods to change the `redirect` URL: + +```php +$socialite->redirect($url); +// or +$socialite->withRedirectUrl($url)->redirect(); +// or +$socialite->setRedirectUrl($url)->redirect(); +``` + +> WeChat scopes: +- `snsapi_base`, `snsapi_userinfo` - Used to Media Platform Authentication. +- `snsapi_login` - Used to web Authentication. + +### Additional parameters + +To include any optional parameters in the request, call the with method with an associative array: + +```php +$response = $socialite->driver('google') + ->with(['hd' => 'example.com'])->redirect(); +``` + +### User interface + +#### Standard user api: + +```php + +$user = $socialite->driver('weibo')->user(); +``` + +```json +{ + "id": 1472352, + "nickname": "overtrue", + "name": "安正超", + "email": "anzhengchao@gmail.com", + "avatar": "https://avatars.githubusercontent.com/u/1472352?v=3", + "original": { + "login": "overtrue", + "id": 1472352, + "avatar_url": "https://avatars.githubusercontent.com/u/1472352?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/overtrue", + "html_url": "https://github.com/overtrue", + ... + }, + "token": { + "access_token": "5b1dc56d64fffbd052359f032716cc4e0a1cb9a0", + "token_type": "bearer", + "scope": "user:email" + } +} +``` + +You can fetch the user attribute as a array keys like these: + +```php +$user['id']; // 1472352 +$user['nickname']; // "overtrue" +$user['name']; // "安正超" +$user['email']; // "anzhengchao@gmail.com" +... +``` + +Or using the method: + +```php +$user->getId(); +$user->getNickname(); +$user->getName(); +$user->getEmail(); +$user->getAvatar(); +$user->getOriginal(); +$user->getToken();// or $user->getAccessToken() +$user->getProviderName(); // GitHub/Google/Facebook... +``` + +#### Get original response from OAuth API + +The `$user->getOriginal()` method will return an array of the API raw response. + +#### Get access token Object + +You can get the access token instance of current session by call `$user->getToken()` or `$user->getAccessToken()` or `$user['token']` . + + +### Get user with access token + +```php +$accessToken = new AccessToken(['access_token' => $accessToken]); +$user = $socialite->user($accessToken); +``` + + +### Custom Session or Request instance. + +You can set the request with your custom `Request` instance which instanceof `Symfony\Component\HttpFoundation\Request` before you call `driver` method. + + +```php + +$request = new Request(); // or use AnotherCustomRequest. + +$socialite = new SocialiteManager($config, $request); +``` + +Or set request to `SocialiteManager` instance: + +```php +$socialite->setRequest($request); +``` + +You can get the request from the `SocialiteManager` instance by `getRequest()`: + +```php +$request = $socialite->getRequest(); +``` + +#### Set custom session manager. + +By default, the `SocialiteManager` uses the `Symfony\Component\HttpFoundation\Session\Session` instance as session manager, you can change it as follows: + +```php +$session = new YourCustomSessionManager(); +$socialite->getRequest()->setSession($session); +``` + +> Your custom session manager must be implement the [`Symfony\Component\HttpFoundation\Session\SessionInterface`](http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/Session/SessionInterface.html). + +Enjoy it! :heart: + +# Reference + +- [Google - OpenID Connect](https://developers.google.com/identity/protocols/OpenIDConnect) +- [Facebook - Graph API](https://developers.facebook.com/docs/graph-api) +- [Linkedin - Authenticating with OAuth 2.0](https://developer.linkedin.com/docs/oauth2) +- [微博 - OAuth 2.0 授权机制说明](http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E) +- [QQ - OAuth 2.0 登录QQ](http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B) +- [微信公众平台 - OAuth文档](http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html) +- [微信开放平台 - 网站应用微信登录开发指南](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN) +- [微信开放平台 - 代公众号发起网页授权](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590&token=&lang=zh_CN) +- [豆瓣 - OAuth 2.0 授权机制说明](http://developers.douban.com/wiki/?title=oauth2) +- [抖音 - 网站应用开发指南](http://open.douyin.com/platform/doc) + +## PHP 扩展包开发 + +> 想知道如何从零开始构建 PHP 扩展包? +> +> 请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— [《PHP 扩展包实战教程 - 从入门到发布》](https://learnku.com/courses/creating-package) + +# License + +MIT diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/composer.json b/addons/weliam_smartcity/vendor/overtrue/socialite/composer.json new file mode 100644 index 0000000..87dec16 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/composer.json @@ -0,0 +1,26 @@ +{ + "name": "overtrue/socialite", + "description": "A collection of OAuth 2 packages that extracts from laravel/socialite.", + "keywords": ["OAuth", "social", "login", "Weibo", "WeChat", "QQ"], + "autoload": { + "psr-4": { + "Overtrue\\Socialite\\": "src/" + } + }, + "require": { + "php": ">=7.0", + "guzzlehttp/guzzle": "~5.0|~6.0", + "symfony/http-foundation": "^2.7|^3.0|^4.0" + }, + "require-dev": { + "mockery/mockery": "~1.2", + "phpunit/phpunit": "~6" + }, + "license": "MIT", + "authors": [ + { + "name": "overtrue", + "email": "anzhengchao@gmail.com" + } + ] +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/phpunit.xml b/addons/weliam_smartcity/vendor/overtrue/socialite/phpunit.xml new file mode 100644 index 0000000..3347b75 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/phpunit.xml @@ -0,0 +1,18 @@ + + + + + ./tests/ + + + diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessToken.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessToken.php new file mode 100644 index 0000000..e089bfa --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessToken.php @@ -0,0 +1,64 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +use ArrayAccess; +use InvalidArgumentException; +use JsonSerializable; + +/** + * Class AccessToken. + */ +class AccessToken implements AccessTokenInterface, ArrayAccess, JsonSerializable +{ + use HasAttributes; + + /** + * AccessToken constructor. + * + * @param array $attributes + */ + public function __construct(array $attributes) + { + if (empty($attributes['access_token'])) { + throw new InvalidArgumentException('The key "access_token" could not be empty.'); + } + + $this->attributes = $attributes; + } + + /** + * Return the access token string. + * + * @return string + */ + public function getToken() + { + return $this->getAttribute('access_token'); + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return strval($this->getAttribute('access_token', '')); + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() + { + return $this->getToken(); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessTokenInterface.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessTokenInterface.php new file mode 100644 index 0000000..f6f54bc --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/AccessTokenInterface.php @@ -0,0 +1,25 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +/** + * Interface AccessTokenInterface. + */ +interface AccessTokenInterface +{ + /** + * Return the access token string. + * + * @return string + */ + public function getToken(); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/AuthorizeFailedException.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/AuthorizeFailedException.php new file mode 100644 index 0000000..cc2b128 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/AuthorizeFailedException.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +class AuthorizeFailedException extends \RuntimeException +{ + /** + * Response body. + * + * @var array + */ + public $body; + + /** + * Constructor. + * + * @param string $message + * @param array $body + */ + public function __construct($message, $body) + { + parent::__construct($message, -1); + + $this->body = $body; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Config.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Config.php new file mode 100644 index 0000000..bbe0862 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Config.php @@ -0,0 +1,180 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +use ArrayAccess; +use InvalidArgumentException; + +/** + * Class Config. + */ +class Config implements ArrayAccess +{ + /** + * @var array + */ + protected $config; + + /** + * Config constructor. + * + * @param array $config + */ + public function __construct(array $config) + { + $this->config = $config; + } + + /** + * Get an item from an array using "dot" notation. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + public function get($key, $default = null) + { + $config = $this->config; + + if (is_null($key)) { + return $config; + } + if (isset($config[$key])) { + return $config[$key]; + } + foreach (explode('.', $key) as $segment) { + if (!is_array($config) || !array_key_exists($segment, $config)) { + return $default; + } + $config = $config[$segment]; + } + + return $config; + } + + /** + * Set an array item to a given value using "dot" notation. + * + * @param string $key + * @param mixed $value + * + * @return array + */ + public function set($key, $value) + { + if (is_null($key)) { + throw new InvalidArgumentException('Invalid config key.'); + } + + $keys = explode('.', $key); + $config = &$this->config; + + while (count($keys) > 1) { + $key = array_shift($keys); + if (!isset($config[$key]) || !is_array($config[$key])) { + $config[$key] = []; + } + $config = &$config[$key]; + } + + $config[array_shift($keys)] = $value; + + return $config; + } + + /** + * Determine if the given configuration value exists. + * + * @param string $key + * + * @return bool + */ + public function has($key) + { + return (bool) $this->get($key); + } + + /** + * Whether a offset exists. + * + * @see http://php.net/manual/en/arrayaccess.offsetexists.php + * + * @param mixed $offset

+ * An offset to check for. + *

+ * + * @return bool true on success or false on failure. + *

+ *

+ * The return value will be casted to boolean if non-boolean was returned + * + * @since 5.0.0 + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->config); + } + + /** + * Offset to retrieve. + * + * @see http://php.net/manual/en/arrayaccess.offsetget.php + * + * @param mixed $offset

+ * The offset to retrieve. + *

+ * + * @return mixed Can return all value types + * + * @since 5.0.0 + */ + public function offsetGet($offset) + { + return $this->get($offset); + } + + /** + * Offset to set. + * + * @see http://php.net/manual/en/arrayaccess.offsetset.php + * + * @param mixed $offset

+ * The offset to assign the value to. + *

+ * @param mixed $value

+ * The value to set. + *

+ * + * @since 5.0.0 + */ + public function offsetSet($offset, $value) + { + $this->set($offset, $value); + } + + /** + * Offset to unset. + * + * @see http://php.net/manual/en/arrayaccess.offsetunset.php + * + * @param mixed $offset

+ * The offset to unset. + *

+ * + * @since 5.0.0 + */ + public function offsetUnset($offset) + { + $this->set($offset, null); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/FactoryInterface.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/FactoryInterface.php new file mode 100644 index 0000000..7a4959c --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/FactoryInterface.php @@ -0,0 +1,27 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +/** + * Interface FactoryInterface. + */ +interface FactoryInterface +{ + /** + * Get an OAuth provider implementation. + * + * @param string $driver + * + * @return \Overtrue\Socialite\ProviderInterface + */ + public function driver($driver); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/HasAttributes.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/HasAttributes.php new file mode 100644 index 0000000..eeff890 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/HasAttributes.php @@ -0,0 +1,135 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +/** + * Trait HasAttributes. + */ +trait HasAttributes +{ + /** + * @var array + */ + protected $attributes = []; + + /** + * Return the attributes. + * + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * Return the extra attribute. + * + * @param string $name + * @param string $default + * + * @return mixed + */ + public function getAttribute($name, $default = null) + { + return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; + } + + /** + * Set extra attributes. + * + * @param string $name + * @param mixed $value + * + * @return $this + */ + public function setAttribute($name, $value) + { + $this->attributes[$name] = $value; + + return $this; + } + + /** + * Map the given array onto the user's properties. + * + * @param array $attributes + * + * @return $this + */ + public function merge(array $attributes) + { + $this->attributes = array_merge($this->attributes, $attributes); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->attributes); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + return $this->getAttribute($offset); + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->setAttribute($offset, $value); + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->attributes[$offset]); + } + + /** + * {@inheritdoc} + */ + public function __get($property) + { + return $this->getAttribute($property); + } + + /** + * Return array. + * + * @return array + */ + public function toArray() + { + return $this->getAttributes(); + } + + /** + * Return JSON. + * + * @return string + */ + public function toJSON() + { + return json_encode($this->getAttributes(), JSON_UNESCAPED_UNICODE); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidArgumentException.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidArgumentException.php new file mode 100644 index 0000000..c044e64 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidArgumentException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +class InvalidArgumentException extends \InvalidArgumentException +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidStateException.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidStateException.php new file mode 100644 index 0000000..96ac503 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/InvalidStateException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +class InvalidStateException extends \InvalidArgumentException +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/ProviderInterface.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/ProviderInterface.php new file mode 100644 index 0000000..e78d172 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/ProviderInterface.php @@ -0,0 +1,31 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +interface ProviderInterface +{ + /** + * Redirect the user to the authentication page for the provider. + * + * @return \Symfony\Component\HttpFoundation\RedirectResponse + */ + public function redirect(); + + /** + * Get the User instance for the authenticated user. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return \Overtrue\Socialite\User + */ + public function user(AccessTokenInterface $token = null); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/AbstractProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/AbstractProvider.php new file mode 100644 index 0000000..6b7b886 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/AbstractProvider.php @@ -0,0 +1,560 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use GuzzleHttp\Client; +use GuzzleHttp\ClientInterface; +use Overtrue\Socialite\AccessToken; +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\AuthorizeFailedException; +use Overtrue\Socialite\InvalidStateException; +use Overtrue\Socialite\ProviderInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; + +/** + * Class AbstractProvider. + */ +abstract class AbstractProvider implements ProviderInterface +{ + /** + * Provider name. + * + * @var string + */ + protected $name; + + /** + * The HTTP request instance. + * + * @var \Symfony\Component\HttpFoundation\Request + */ + protected $request; + + /** + * The client ID. + * + * @var string + */ + protected $clientId; + + /** + * The client secret. + * + * @var string + */ + protected $clientSecret; + + /** + * @var \Overtrue\Socialite\AccessTokenInterface + */ + protected $accessToken; + + /** + * The redirect URL. + * + * @var string + */ + protected $redirectUrl; + + /** + * The custom parameters to be sent with the request. + * + * @var array + */ + protected $parameters = []; + + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = []; + + /** + * The separating character for the requested scopes. + * + * @var string + */ + protected $scopeSeparator = ','; + + /** + * The type of the encoding in the query. + * + * @var int Can be either PHP_QUERY_RFC3986 or PHP_QUERY_RFC1738 + */ + protected $encodingType = PHP_QUERY_RFC1738; + + /** + * Indicates if the session state should be utilized. + * + * @var bool + */ + protected $stateless = false; + + /** + * The options for guzzle\client. + * + * @var array + */ + protected static $guzzleOptions = ['http_errors' => false]; + + /** + * Create a new provider instance. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * @param string $clientId + * @param string $clientSecret + * @param string|null $redirectUrl + */ + public function __construct(Request $request, $clientId, $clientSecret, $redirectUrl = null) + { + $this->request = $request; + $this->clientId = $clientId; + $this->clientSecret = $clientSecret; + $this->redirectUrl = $redirectUrl; + } + + /** + * Get the authentication URL for the provider. + * + * @param string $state + * + * @return string + */ + abstract protected function getAuthUrl($state); + + /** + * Get the token URL for the provider. + * + * @return string + */ + abstract protected function getTokenUrl(); + + /** + * Get the raw user for the given access token. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return array + */ + abstract protected function getUserByToken(AccessTokenInterface $token); + + /** + * Map the raw user array to a Socialite User instance. + * + * @param array $user + * + * @return \Overtrue\Socialite\User + */ + abstract protected function mapUserToObject(array $user); + + /** + * Redirect the user of the application to the provider's authentication screen. + * + * @param string $redirectUrl + * + * @return \Symfony\Component\HttpFoundation\RedirectResponse + */ + public function redirect($redirectUrl = null) + { + $state = null; + + if (!is_null($redirectUrl)) { + $this->redirectUrl = $redirectUrl; + } + + if ($this->usesState()) { + $state = $this->makeState(); + } + + return new RedirectResponse($this->getAuthUrl($state)); + } + + /** + * {@inheritdoc} + */ + public function user(AccessTokenInterface $token = null) + { + if (is_null($token) && $this->hasInvalidState()) { + throw new InvalidStateException(); + } + + $token = $token ?: $this->getAccessToken($this->getCode()); + + $user = $this->getUserByToken($token); + + $user = $this->mapUserToObject($user)->merge(['original' => $user]); + + return $user->setToken($token)->setProviderName($this->getName()); + } + + /** + * Set redirect url. + * + * @param string $redirectUrl + * + * @return $this + */ + public function setRedirectUrl($redirectUrl) + { + $this->redirectUrl = $redirectUrl; + + return $this; + } + + /** + * Set redirect url. + * + * @param string $redirectUrl + * + * @return $this + */ + public function withRedirectUrl($redirectUrl) + { + $this->redirectUrl = $redirectUrl; + + return $this; + } + + /** + * Return the redirect url. + * + * @return string + */ + public function getRedirectUrl() + { + return $this->redirectUrl; + } + + /** + * @param \Overtrue\Socialite\AccessTokenInterface $accessToken + * + * @return $this + */ + public function setAccessToken(AccessTokenInterface $accessToken) + { + $this->accessToken = $accessToken; + + return $this; + } + + /** + * Get the access token for the given code. + * + * @param string $code + * + * @return \Overtrue\Socialite\AccessTokenInterface + */ + public function getAccessToken($code) + { + if ($this->accessToken) { + return $this->accessToken; + } + + $postKey = (1 === version_compare(ClientInterface::VERSION, '6')) ? 'form_params' : 'body'; + + $response = $this->getHttpClient()->post($this->getTokenUrl(), [ + 'headers' => ['Accept' => 'application/json'], + $postKey => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()); + } + + /** + * Set the scopes of the requested access. + * + * @param array $scopes + * + * @return $this + */ + public function scopes(array $scopes) + { + $this->scopes = $scopes; + + return $this; + } + + /** + * Set the request instance. + * + * @param Request $request + * + * @return $this + */ + public function setRequest(Request $request) + { + $this->request = $request; + + return $this; + } + + /** + * Get the request instance. + * + * @return \Symfony\Component\HttpFoundation\Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * Indicates that the provider should operate as stateless. + * + * @return $this + */ + public function stateless() + { + $this->stateless = true; + + return $this; + } + + /** + * Set the custom parameters of the request. + * + * @param array $parameters + * + * @return $this + */ + public function with(array $parameters) + { + $this->parameters = $parameters; + + return $this; + } + + /** + * @throws \ReflectionException + * + * @return string + */ + public function getName() + { + if (empty($this->name)) { + $this->name = strstr((new \ReflectionClass(get_class($this)))->getShortName(), 'Provider', true); + } + + return $this->name; + } + + /** + * Get the authentication URL for the provider. + * + * @param string $url + * @param string $state + * + * @return string + */ + protected function buildAuthUrlFromBase($url, $state) + { + return $url.'?'.http_build_query($this->getCodeFields($state), '', '&', $this->encodingType); + } + + /** + * Get the GET parameters for the code request. + * + * @param string|null $state + * + * @return array + */ + protected function getCodeFields($state = null) + { + $fields = array_merge([ + 'client_id' => $this->clientId, + 'redirect_uri' => $this->redirectUrl, + 'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator), + 'response_type' => 'code', + ], $this->parameters); + + if ($this->usesState()) { + $fields['state'] = $state; + } + + return $fields; + } + + /** + * Format the given scopes. + * + * @param array $scopes + * @param string $scopeSeparator + * + * @return string + */ + protected function formatScopes(array $scopes, $scopeSeparator) + { + return implode($scopeSeparator, $scopes); + } + + /** + * Determine if the current request / session has a mismatching "state". + * + * @return bool + */ + protected function hasInvalidState() + { + if ($this->isStateless()) { + return false; + } + + $state = $this->request->getSession()->get('state'); + + return !(strlen($state) > 0 && $this->request->get('state') === $state); + } + + /** + * Get the POST fields for the token request. + * + * @param string $code + * + * @return array + */ + protected function getTokenFields($code) + { + return [ + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'code' => $code, + 'redirect_uri' => $this->redirectUrl, + ]; + } + + /** + * Get the access token from the token response body. + * + * @param \Psr\Http\Message\StreamInterface|array $body + * + * @return \Overtrue\Socialite\AccessTokenInterface + */ + protected function parseAccessToken($body) + { + if (!is_array($body)) { + $body = json_decode($body, true); + } + + if (empty($body['access_token'])) { + throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body); + } + + return new AccessToken($body); + } + + /** + * Get the code from the request. + * + * @return string + */ + protected function getCode() + { + return $this->request->get('code'); + } + + /** + * Get a fresh instance of the Guzzle HTTP client. + * + * @return \GuzzleHttp\Client + */ + protected function getHttpClient() + { + return new Client(self::$guzzleOptions); + } + + /** + * Set options for Guzzle HTTP client. + * + * @param array $config + * + * @return array + */ + public static function setGuzzleOptions($config = []) + { + return self::$guzzleOptions = $config; + } + + /** + * Determine if the provider is operating with state. + * + * @return bool + */ + protected function usesState() + { + return !$this->stateless; + } + + /** + * Determine if the provider is operating as stateless. + * + * @return bool + */ + protected function isStateless() + { + return !$this->request->hasSession() || $this->stateless; + } + + /** + * Return array item by key. + * + * @param array $array + * @param string $key + * @param mixed $default + * + * @return mixed + */ + protected function arrayItem(array $array, $key, $default = null) + { + if (is_null($key)) { + return $array; + } + + if (isset($array[$key])) { + return $array[$key]; + } + + foreach (explode('.', $key) as $segment) { + if (!is_array($array) || !array_key_exists($segment, $array)) { + return $default; + } + + $array = $array[$segment]; + } + + return $array; + } + + /** + * Put state to session storage and return it. + * + * @return string|bool + */ + protected function makeState() + { + if (!$this->request->hasSession()) { + return false; + } + + $state = sha1(uniqid(mt_rand(1, 1000000), true)); + $session = $this->request->getSession(); + + if (is_callable([$session, 'put'])) { + $session->put('state', $state); + } elseif (is_callable([$session, 'set'])) { + $session->set('state', $state); + } else { + return false; + } + + return $state; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DouYinProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DouYinProvider.php new file mode 100644 index 0000000..6e0b108 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DouYinProvider.php @@ -0,0 +1,168 @@ +buildAuthUrlFromBase($this->baseUrl.'/platform/oauth/connect', $state); + } + + /** + * 获取授权码接口参数. + * + * @param string|null $state + * + * @return array + */ + public function getCodeFields($state = null) + { + $fields = [ + 'client_key' => $this->clientId, + 'redirect_uri' => $this->redirectUrl, + 'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator), + 'response_type' => 'code', + ]; + + if ($this->usesState()) { + $fields['state'] = $state; + } + + return $fields; + } + + /** + * 获取access_token地址. + * + * {@inheritdoc} + */ + protected function getTokenUrl() + { + return $this->baseUrl.'/oauth/access_token'; + } + + /** + * 通过code获取access_token. + * + * @param string $code + * + * @return \Overtrue\Socialite\AccessToken + */ + public function getAccessToken($code) + { + $response = $this->getHttpClient()->get($this->getTokenUrl(), [ + 'query' => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()->getContents()); + } + + /** + * 获取access_token接口参数. + * + * @param string $code + * + * @return array + */ + protected function getTokenFields($code) + { + return [ + 'client_key' => $this->clientId, + 'client_secret' => $this->clientSecret, + 'code' => $code, + 'grant_type' => 'authorization_code', + ]; + } + + /** + * 格式化token. + * + * @param \Psr\Http\Message\StreamInterface|array $body + * + * @return \Overtrue\Socialite\AccessTokenInterface + */ + protected function parseAccessToken($body) + { + if (!is_array($body)) { + $body = json_decode($body, true); + } + + if (empty($body['data']['access_token'])) { + throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body); + } + + return new AccessToken($body['data']); + } + + /** + * 通过token 获取用户信息. + * + * @param AccessTokenInterface $token + * + * @return array|mixed + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $userUrl = $this->baseUrl.'/oauth/userinfo/'; + + $response = $this->getHttpClient()->get( + $userUrl, [ + 'query' => [ + 'access_token' => $token->getToken(), + 'open_id' => $token['open_id'], + ], + ] + ); + + return json_decode($response->getBody(), true); + } + + /** + * 格式化用户信息. + * + * @param array $user + * + * @return User + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'open_id'), + 'username' => $this->arrayItem($user, 'nickname'), + 'nickname' => $this->arrayItem($user, 'nickname'), + 'avatar' => $this->arrayItem($user, 'avatar'), + ]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DoubanProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DoubanProvider.php new file mode 100644 index 0000000..f3b5c93 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/DoubanProvider.php @@ -0,0 +1,88 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class DoubanProvider. + * + * @see http://developers.douban.com/wiki/?title=oauth2 [使用 OAuth 2.0 访问豆瓣 API] + */ +class DoubanProvider extends AbstractProvider implements ProviderInterface +{ + /** + * {@inheritdoc}. + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase('https://www.douban.com/service/auth2/auth', $state); + } + + /** + * {@inheritdoc}. + */ + protected function getTokenUrl() + { + return 'https://www.douban.com/service/auth2/token'; + } + + /** + * {@inheritdoc}. + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $response = $this->getHttpClient()->get('https://api.douban.com/v2/user/~me', [ + 'headers' => [ + 'Authorization' => 'Bearer '.$token->getToken(), + ], + ]); + + return json_decode($response->getBody()->getContents(), true); + } + + /** + * {@inheritdoc}. + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'id'), + 'nickname' => $this->arrayItem($user, 'name'), + 'name' => $this->arrayItem($user, 'name'), + 'avatar' => $this->arrayItem($user, 'large_avatar'), + 'email' => null, + ]); + } + + /** + * {@inheritdoc}. + */ + protected function getTokenFields($code) + { + return parent::getTokenFields($code) + ['grant_type' => 'authorization_code']; + } + + /** + * {@inheritdoc}. + */ + public function getAccessToken($code) + { + $response = $this->getHttpClient()->post($this->getTokenUrl(), [ + 'form_params' => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()->getContents()); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/FacebookProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/FacebookProvider.php new file mode 100644 index 0000000..70f7b2e --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/FacebookProvider.php @@ -0,0 +1,167 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class FacebookProvider. + * + * @see https://developers.facebook.com/docs/graph-api [Facebook - Graph API] + */ +class FacebookProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The base Facebook Graph URL. + * + * @var string + */ + protected $graphUrl = 'https://graph.facebook.com'; + + /** + * The Graph API version for the request. + * + * @var string + */ + protected $version = 'v3.3'; + + /** + * The user fields being requested. + * + * @var array + */ + protected $fields = ['first_name', 'last_name', 'email', 'gender', 'verified']; + + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = ['email']; + + /** + * Display the dialog in a popup view. + * + * @var bool + */ + protected $popup = false; + + /** + * {@inheritdoc} + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase('https://www.facebook.com/'.$this->version.'/dialog/oauth', $state); + } + + /** + * {@inheritdoc} + */ + protected function getTokenUrl() + { + return $this->graphUrl.'/oauth/access_token'; + } + + /** + * Get the access token for the given code. + * + * @param string $code + * + * @return \Overtrue\Socialite\AccessToken + */ + public function getAccessToken($code) + { + $response = $this->getHttpClient()->get($this->getTokenUrl(), [ + 'query' => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()); + } + + /** + * {@inheritdoc} + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $appSecretProof = hash_hmac('sha256', $token->getToken(), $this->clientSecret); + + $response = $this->getHttpClient()->get($this->graphUrl.'/'.$this->version.'/me?access_token='.$token.'&appsecret_proof='.$appSecretProof.'&fields='.implode(',', $this->fields), [ + 'headers' => [ + 'Accept' => 'application/json', + ], + ]); + + return json_decode($response->getBody(), true); + } + + /** + * {@inheritdoc} + */ + protected function mapUserToObject(array $user) + { + $avatarUrl = $this->graphUrl.'/'.$this->version.'/'.$user['id'].'/picture'; + + $firstName = $this->arrayItem($user, 'first_name'); + $lastName = $this->arrayItem($user, 'last_name'); + + return new User([ + 'id' => $this->arrayItem($user, 'id'), + 'nickname' => null, + 'name' => $firstName.' '.$lastName, + 'email' => $this->arrayItem($user, 'email'), + 'avatar' => $avatarUrl.'?type=normal', + 'avatar_original' => $avatarUrl.'?width=1920', + ]); + } + + /** + * {@inheritdoc} + */ + protected function getCodeFields($state = null) + { + $fields = parent::getCodeFields($state); + + if ($this->popup) { + $fields['display'] = 'popup'; + } + + return $fields; + } + + /** + * Set the user fields to request from Facebook. + * + * @param array $fields + * + * @return $this + */ + public function fields(array $fields) + { + $this->fields = $fields; + + return $this; + } + + /** + * Set the dialog to be displayed as a popup. + * + * @return $this + */ + public function asPopup() + { + $this->popup = true; + + return $this; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GitHubProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GitHubProvider.php new file mode 100644 index 0000000..410c80f --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GitHubProvider.php @@ -0,0 +1,121 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Exception; +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class GitHubProvider. + */ +class GitHubProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = ['user:email']; + + /** + * {@inheritdoc} + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase('https://github.com/login/oauth/authorize', $state); + } + + /** + * {@inheritdoc} + */ + protected function getTokenUrl() + { + return 'https://github.com/login/oauth/access_token'; + } + + /** + * {@inheritdoc} + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $userUrl = 'https://api.github.com/user?access_token='.$token->getToken(); + + $response = $this->getHttpClient()->get( + $userUrl, $this->getRequestOptions() + ); + + $user = json_decode($response->getBody(), true); + + if (in_array('user:email', $this->scopes)) { + $user['email'] = $this->getEmailByToken($token); + } + + return $user; + } + + /** + * Get the email for the given access token. + * + * @param string $token + * + * @return string|null + */ + protected function getEmailByToken($token) + { + $emailsUrl = 'https://api.github.com/user/emails?access_token='.$token->getToken(); + + try { + $response = $this->getHttpClient()->get( + $emailsUrl, $this->getRequestOptions() + ); + } catch (Exception $e) { + return; + } + + foreach (json_decode($response->getBody(), true) as $email) { + if ($email['primary'] && $email['verified']) { + return $email['email']; + } + } + } + + /** + * {@inheritdoc} + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'id'), + 'username' => $this->arrayItem($user, 'login'), + 'nickname' => $this->arrayItem($user, 'login'), + 'name' => $this->arrayItem($user, 'name'), + 'email' => $this->arrayItem($user, 'email'), + 'avatar' => $this->arrayItem($user, 'avatar_url'), + ]); + } + + /** + * Get the default options for an HTTP request. + * + * @return array + */ + protected function getRequestOptions() + { + return [ + 'headers' => [ + 'Accept' => 'application/vnd.github.v3+json', + ], + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GoogleProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GoogleProvider.php new file mode 100644 index 0000000..e74d830 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/GoogleProvider.php @@ -0,0 +1,118 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use GuzzleHttp\ClientInterface; +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class GoogleProvider. + * + * @see https://developers.google.com/identity/protocols/OpenIDConnect [OpenID Connect] + */ +class GoogleProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The separating character for the requested scopes. + * + * @var string + */ + protected $scopeSeparator = ' '; + + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = [ + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', + ]; + + /** + * {@inheritdoc} + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase('https://accounts.google.com/o/oauth2/v2/auth', $state); + } + + /** + * {@inheritdoc} + */ + protected function getTokenUrl() + { + return 'https://www.googleapis.com/oauth2/v4/token'; + } + + /** + * Get the access token for the given code. + * + * @param string $code + * + * @return string + */ + public function getAccessToken($code) + { + $postKey = (1 === version_compare(ClientInterface::VERSION, '6')) ? 'form_params' : 'body'; + + $response = $this->getHttpClient()->post($this->getTokenUrl(), [ + $postKey => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()); + } + + /** + * Get the POST fields for the token request. + * + * @param string $code + * + * @return array + */ + protected function getTokenFields($code) + { + return parent::getTokenFields($code) + ['grant_type' => 'authorization_code']; + } + + /** + * {@inheritdoc} + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $response = $this->getHttpClient()->get('https://www.googleapis.com/userinfo/v2/me', [ + 'headers' => [ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer '.$token->getToken(), + ], + ]); + + return json_decode($response->getBody(), true); + } + + /** + * {@inheritdoc} + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'id'), + 'username' => $this->arrayItem($user, 'email'), + 'nickname' => $this->arrayItem($user, 'name'), + 'name' => $this->arrayItem($user, 'name'), + 'email' => $this->arrayItem($user, 'email'), + 'avatar' => $this->arrayItem($user, 'picture'), + ]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/LinkedinProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/LinkedinProvider.php new file mode 100644 index 0000000..019167a --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/LinkedinProvider.php @@ -0,0 +1,181 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class LinkedinProvider. + * + * @see https://developer.linkedin.com/docs/oauth2 [Authenticating with OAuth 2.0] + */ +class LinkedinProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = ['r_liteprofile', 'r_emailaddress']; + + /** + * {@inheritdoc} + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization', $state); + } + + /** + * Get the access token for the given code. + * + * @param string $code + * + * @return \Overtrue\Socialite\AccessToken + */ + public function getAccessToken($code) + { + $response = $this->getHttpClient() + ->post($this->getTokenUrl(), ['form_params' => $this->getTokenFields($code)]); + + return $this->parseAccessToken($response->getBody()); + } + + /** + * {@inheritdoc} + */ + protected function getTokenUrl() + { + return 'https://www.linkedin.com/oauth/v2/accessToken'; + } + + /** + * Get the POST fields for the token request. + * + * @param string $code + * + * @return array + */ + protected function getTokenFields($code) + { + return parent::getTokenFields($code) + ['grant_type' => 'authorization_code']; + } + + /** + * {@inheritdoc} + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $basicProfile = $this->getBasicProfile($token); + $emailAddress = $this->getEmailAddress($token); + + return array_merge($basicProfile, $emailAddress); + } + + /** + * Get the basic profile fields for the user. + * + * @param string $token + * + * @return array + */ + protected function getBasicProfile($token) + { + $url = 'https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))'; + + $response = $this->getHttpClient()->get($url, [ + 'headers' => [ + 'Authorization' => 'Bearer '.$token, + 'X-RestLi-Protocol-Version' => '2.0.0', + ], + ]); + + return (array) json_decode($response->getBody(), true); + } + + /** + * Get the email address for the user. + * + * @param string $token + * + * @return array + */ + protected function getEmailAddress($token) + { + $url = 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))'; + + $response = $this->getHttpClient()->get($url, [ + 'headers' => [ + 'Authorization' => 'Bearer '.$token, + 'X-RestLi-Protocol-Version' => '2.0.0', + ], + ]); + + return (array) $this->arrayItem(json_decode($response->getBody(), true), 'elements.0.handle~'); + } + + /** + * {@inheritdoc} + */ + protected function mapUserToObject(array $user) + { + $preferredLocale = $this->arrayItem($user, 'firstName.preferredLocale.language').'_'.$this->arrayItem($user, 'firstName.preferredLocale.country'); + $firstName = $this->arrayItem($user, 'firstName.localized.'.$preferredLocale); + $lastName = $this->arrayItem($user, 'lastName.localized.'.$preferredLocale); + $name = $firstName.' '.$lastName; + + $images = (array) $this->arrayItem($user, 'profilePicture.displayImage~.elements', []); + $avatars = array_filter($images, function ($image) { + return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 100; + }); + $avatar = array_shift($avatars); + $originalAvatars = array_filter($images, function ($image) { + return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 800; + }); + $originalAvatar = array_shift($originalAvatars); + + return new User([ + 'id' => $this->arrayItem($user, 'id'), + 'nickname' => $name, + 'name' => $name, + 'email' => $this->arrayItem($user, 'emailAddress'), + 'avatar' => $avatar ? $this->arrayItem($avatar, 'identifiers.0.identifier') : null, + 'avatar_original' => $originalAvatar ? $this->arrayItem($originalAvatar, 'identifiers.0.identifier') : null, + ]); + } + + /** + * Set the user fields to request from LinkedIn. + * + * @param array $fields + * + * @return $this + */ + public function fields(array $fields) + { + $this->fields = $fields; + + return $this; + } + + /** + * Determine if the provider is operating as stateless. + * + * @return bool + */ + protected function isStateless() + { + return true; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/OutlookProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/OutlookProvider.php new file mode 100644 index 0000000..3a0fb56 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/OutlookProvider.php @@ -0,0 +1,88 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class OutlookProvider. + */ +class OutlookProvider extends AbstractProvider implements ProviderInterface +{ + /** + * {@inheritdoc} + */ + protected $scopes = ['User.Read']; + + /** + * {@inheritdoc} + */ + protected $scopeSeparator = ' '; + + /** + * {@inheritdoc} + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase('https://login.microsoftonline.com/common/oauth2/v2.0/authorize', $state); + } + + /** + * {@inheritdoc} + */ + protected function getTokenUrl() + { + return 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; + } + + /** + * {@inheritdoc} + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $response = $this->getHttpClient()->get( + 'https://graph.microsoft.com/v1.0/me', + ['headers' => [ + 'Accept' => 'application/json', + 'Authorization' => 'Bearer '.$token->getToken(), + ], + ]); + + return json_decode($response->getBody()->getContents(), true); + } + + /** + * {@inheritdoc} + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'id'), + 'nickname' => null, + 'name' => $this->arrayItem($user, 'displayName'), + 'email' => $this->arrayItem($user, 'userPrincipalName'), + 'avatar' => null, + ]); + } + + /** + * {@inheritdoc} + */ + protected function getTokenFields($code) + { + return array_merge(parent::getTokenFields($code), [ + 'grant_type' => 'authorization_code', + ]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/QQProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/QQProvider.php new file mode 100644 index 0000000..921bc20 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/QQProvider.php @@ -0,0 +1,206 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class QQProvider. + * + * @see http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B [QQ - OAuth 2.0 登录QQ] + */ +class QQProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The base url of QQ API. + * + * @var string + */ + protected $baseUrl = 'https://graph.qq.com'; + + /** + * User openid. + * + * @var string + */ + protected $openId; + + /** + * get token(openid) with unionid. + * + * @var bool + */ + protected $withUnionId = false; + + /** + * User unionid. + * + * @var string + */ + protected $unionId; + + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = ['get_user_info']; + + /** + * The uid of user authorized. + * + * @var int + */ + protected $uid; + + /** + * Get the authentication URL for the provider. + * + * @param string $state + * + * @return string + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2.0/authorize', $state); + } + + /** + * Get the token URL for the provider. + * + * @return string + */ + protected function getTokenUrl() + { + return $this->baseUrl.'/oauth2.0/token'; + } + + /** + * Get the Post fields for the token request. + * + * @param string $code + * + * @return array + */ + protected function getTokenFields($code) + { + return parent::getTokenFields($code) + ['grant_type' => 'authorization_code']; + } + + /** + * Get the access token for the given code. + * + * @param string $code + * + * @return \Overtrue\Socialite\AccessToken + */ + public function getAccessToken($code) + { + $response = $this->getHttpClient()->get($this->getTokenUrl(), [ + 'query' => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()->getContents()); + } + + /** + * Get the access token from the token response body. + * + * @param string $body + * + * @return \Overtrue\Socialite\AccessToken + */ + public function parseAccessToken($body) + { + parse_str($body, $token); + + return parent::parseAccessToken($token); + } + + /** + * @return self + */ + public function withUnionId() + { + $this->withUnionId = true; + + return $this; + } + + /** + * Get the raw user for the given access token. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return array + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $url = $this->baseUrl.'/oauth2.0/me?access_token='.$token->getToken(); + $this->withUnionId && $url .= '&unionid=1'; + + $response = $this->getHttpClient()->get($url); + + $me = json_decode($this->removeCallback($response->getBody()->getContents()), true); + $this->openId = $me['openid']; + $this->unionId = isset($me['unionid']) ? $me['unionid'] : ''; + + $queries = [ + 'access_token' => $token->getToken(), + 'openid' => $this->openId, + 'oauth_consumer_key' => $this->clientId, + ]; + + $response = $this->getHttpClient()->get($this->baseUrl.'/user/get_user_info?'.http_build_query($queries)); + + return json_decode($this->removeCallback($response->getBody()->getContents()), true); + } + + /** + * Map the raw user array to a Socialite User instance. + * + * @param array $user + * + * @return \Overtrue\Socialite\User + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->openId, + 'unionid' => $this->unionId, + 'nickname' => $this->arrayItem($user, 'nickname'), + 'name' => $this->arrayItem($user, 'nickname'), + 'email' => $this->arrayItem($user, 'email'), + 'avatar' => $this->arrayItem($user, 'figureurl_qq_2'), + ]); + } + + /** + * Remove the fucking callback parentheses. + * + * @param string $response + * + * @return string + */ + protected function removeCallback($response) + { + if (false !== strpos($response, 'callback')) { + $lpos = strpos($response, '('); + $rpos = strrpos($response, ')'); + $response = substr($response, $lpos + 1, $rpos - $lpos - 1); + } + + return $response; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/TaobaoProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/TaobaoProvider.php new file mode 100644 index 0000000..f7da073 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/TaobaoProvider.php @@ -0,0 +1,242 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class TaobaoProvider. + * + * @author mechono + * + * @see https://open.taobao.com/doc.htm?docId=102635&docType=1&source=search [Taobao - OAuth 2.0 授权登录] + */ +class TaobaoProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The base url of Taobao API. + * + * @var string + */ + protected $baseUrl = 'https://oauth.taobao.com'; + + /** + * Taobao API service URL address. + * + * @var string + */ + protected $gatewayUrl = 'https://eco.taobao.com/router/rest'; + + /** + * The API version for the request. + * + * @var string + */ + protected $version = '2.0'; + + /** + * @var string + */ + protected $format = 'json'; + + /** + * @var string + */ + protected $signMethod = 'md5'; + + /** + * Web 对应 PC 端(淘宝 logo )浏览器页面样式;Tmall 对应天猫的浏览器页面样式;Wap 对应无线端的浏览器页面样式。 + */ + protected $view = 'web'; + + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = ['user_info']; + + /** + * Get the authentication URL for the provider. + * + * @param string $state + * + * @return string + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase($this->baseUrl.'/authorize', $state); + } + + /** + * 获取授权码接口参数. + * + * @param string|null $state + * + * @return array + */ + public function getCodeFields($state = null) + { + $fields = [ + 'client_id' => $this->clientId, + 'redirect_uri' => $this->redirectUrl, + 'view' => $this->view, + 'response_type' => 'code', + ]; + + if ($this->usesState()) { + $fields['state'] = $state; + } + + return $fields; + } + + /** + * Get the token URL for the provider. + * + * @return string + */ + protected function getTokenUrl() + { + return $this->baseUrl.'/token'; + } + + /** + * Get the Post fields for the token request. + * + * @param string $code + * + * @return array + */ + protected function getTokenFields($code) + { + return parent::getTokenFields($code) + ['grant_type' => 'authorization_code', 'view' => $this->view]; + } + + /** + * Get the access token for the given code. + * + * @param string $code + * + * @return \Overtrue\Socialite\AccessToken + */ + public function getAccessToken($code) + { + $response = $this->getHttpClient()->post($this->getTokenUrl(), [ + 'query' => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()->getContents()); + } + + /** + * Get the access token from the token response body. + * + * @param string $body + * + * @return \Overtrue\Socialite\AccessToken + */ + public function parseAccessToken($body) + { + return parent::parseAccessToken($body); + } + + /** + * Get the raw user for the given access token. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return array + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $response = $this->getHttpClient()->post($this->getUserInfoUrl($this->gatewayUrl, $token)); + + return json_decode($response->getBody(), true); + } + + /** + * Map the raw user array to a Socialite User instance. + * + * @param array $user + * + * @return \Overtrue\Socialite\User + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'open_id'), + 'nickname' => $this->arrayItem($user, 'nick'), + 'name' => $this->arrayItem($user, 'nick'), + 'avatar' => $this->arrayItem($user, 'avatar'), + ]); + } + + /** + * @param $params + * + * @return string + */ + protected function generateSign($params) + { + ksort($params); + + $stringToBeSigned = $this->clientSecret; + + foreach ($params as $k => $v) { + if (!is_array($v) && '@' != substr($v, 0, 1)) { + $stringToBeSigned .= "$k$v"; + } + } + + $stringToBeSigned .= $this->clientSecret; + + return strtoupper(md5($stringToBeSigned)); + } + + /** + * @param \Overtrue\Socialite\AccessTokenInterface $token + * @param array $apiFields + * + * @return array + */ + protected function getPublicFields(AccessTokenInterface $token, array $apiFields = []) + { + $fields = [ + 'app_key' => $this->clientId, + 'sign_method' => $this->signMethod, + 'session' => $token->getToken(), + 'timestamp' => date('Y-m-d H:i:s'), + 'v' => $this->version, + 'format' => $this->format, + ]; + + $fields = array_merge($apiFields, $fields); + $fields['sign'] = $this->generateSign($fields); + + return $fields; + } + + /** + * {@inheritdoc}. + */ + protected function getUserInfoUrl($url, AccessTokenInterface $token) + { + $apiFields = ['method' => 'taobao.miniapp.userInfo.get']; + + $query = http_build_query($this->getPublicFields($token, $apiFields), '', '&', $this->encodingType); + + return $url.'?'.$query; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeChatProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeChatProvider.php new file mode 100644 index 0000000..8fb48d3 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeChatProvider.php @@ -0,0 +1,234 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\InvalidArgumentException; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; +use Overtrue\Socialite\WeChatComponentInterface; + +/** + * Class WeChatProvider. + * + * @see http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html [WeChat - 公众平台OAuth文档] + * @see https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN [网站应用微信登录开发指南] + */ +class WeChatProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The base url of WeChat API. + * + * @var string + */ + protected $baseUrl = 'https://api.weixin.qq.com/sns'; + + /** + * {@inheritdoc}. + */ + protected $openId; + + /** + * {@inheritdoc}. + */ + protected $scopes = ['snsapi_login']; + + /** + * Indicates if the session state should be utilized. + * + * @var bool + */ + protected $stateless = true; + + /** + * Return country code instead of country name. + * + * @var bool + */ + protected $withCountryCode = false; + + /** + * @var WeChatComponentInterface + */ + protected $component; + + /** + * Return country code instead of country name. + * + * @return $this + */ + public function withCountryCode() + { + $this->withCountryCode = true; + + return $this; + } + + /** + * WeChat OpenPlatform 3rd component. + * + * @param WeChatComponentInterface $component + * + * @return $this + */ + public function component(WeChatComponentInterface $component) + { + $this->scopes = ['snsapi_base']; + + $this->component = $component; + + return $this; + } + + /** + * {@inheritdoc}. + */ + public function getAccessToken($code) + { + $response = $this->getHttpClient()->get($this->getTokenUrl(), [ + 'headers' => ['Accept' => 'application/json'], + 'query' => $this->getTokenFields($code), + ]); + + return $this->parseAccessToken($response->getBody()); + } + + /** + * {@inheritdoc}. + */ + protected function getAuthUrl($state) + { + $path = 'oauth2/authorize'; + + if (in_array('snsapi_login', $this->scopes)) { + $path = 'qrconnect'; + } + + return $this->buildAuthUrlFromBase("https://open.weixin.qq.com/connect/{$path}", $state); + } + + /** + * {@inheritdoc}. + */ + protected function buildAuthUrlFromBase($url, $state) + { + $query = http_build_query($this->getCodeFields($state), '', '&', $this->encodingType); + + return $url.'?'.$query.'#wechat_redirect'; + } + + /** + * {@inheritdoc}. + */ + protected function getCodeFields($state = null) + { + if ($this->component) { + $this->with(['component_appid' => $this->component->getAppId()]); + } + + return array_merge([ + 'appid' => $this->clientId, + 'redirect_uri' => $this->redirectUrl, + 'response_type' => 'code', + 'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator), + 'state' => $state ?: md5(time()), + 'connect_redirect' => 1, + ], $this->parameters); + } + + /** + * {@inheritdoc}. + */ + protected function getTokenUrl() + { + if ($this->component) { + return $this->baseUrl.'/oauth2/component/access_token'; + } + + return $this->baseUrl.'/oauth2/access_token'; + } + + /** + * {@inheritdoc}. + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $scopes = explode(',', $token->getAttribute('scope', '')); + + if (in_array('snsapi_base', $scopes)) { + return $token->toArray(); + } + + if (empty($token['openid'])) { + throw new InvalidArgumentException('openid of AccessToken is required.'); + } + + $language = $this->withCountryCode ? null : (isset($this->parameters['lang']) ? $this->parameters['lang'] : 'zh_CN'); + + $response = $this->getHttpClient()->get($this->baseUrl.'/userinfo', [ + 'query' => array_filter([ + 'access_token' => $token->getToken(), + 'openid' => $token['openid'], + 'lang' => $language, + ]), + ]); + + return json_decode($response->getBody(), true); + } + + /** + * {@inheritdoc}. + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'openid'), + 'name' => $this->arrayItem($user, 'nickname'), + 'nickname' => $this->arrayItem($user, 'nickname'), + 'avatar' => $this->arrayItem($user, 'headimgurl'), + 'email' => null, + ]); + } + + /** + * {@inheritdoc}. + */ + protected function getTokenFields($code) + { + return array_filter([ + 'appid' => $this->clientId, + 'secret' => $this->clientSecret, + 'component_appid' => $this->component ? $this->component->getAppId() : null, + 'component_access_token' => $this->component ? $this->component->getToken() : null, + 'code' => $code, + 'grant_type' => 'authorization_code', + ]); + } + + /** + * Remove the fucking callback parentheses. + * + * @param mixed $response + * + * @return string + */ + protected function removeCallback($response) + { + if (false !== strpos($response, 'callback')) { + $lpos = strpos($response, '('); + $rpos = strrpos($response, ')'); + $response = substr($response, $lpos + 1, $rpos - $lpos - 1); + } + + return $response; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeWorkProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeWorkProvider.php new file mode 100644 index 0000000..1327e80 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeWorkProvider.php @@ -0,0 +1,214 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class WeWorkProvider. + * + * @author mingyoung + */ +class WeWorkProvider extends AbstractProvider implements ProviderInterface +{ + /** + * @var string + */ + protected $agentId; + + /** + * @var bool + */ + protected $detailed = false; + + /** + * Set agent id. + * + * @param string $agentId + * + * @return $this + */ + public function setAgentId($agentId) + { + $this->agentId = $agentId; + + return $this; + } + + /** + * @param string $agentId + * + * @return $this + */ + public function agent($agentId) + { + return $this->setAgentId($agentId); + } + + /** + * Return user details. + * + * @return $this + */ + public function detailed() + { + $this->detailed = true; + + return $this; + } + + /** + * @param string $state + * + * @return string + */ + protected function getAuthUrl($state) + { + // 网页授权登录 + if (!empty($this->scopes)) { + return $this->getOAuthUrl($state); + } + + // 第三方网页应用登录(扫码登录) + return $this->getQrConnectUrl($state); + } + + /** + * OAuth url. + * + * @param string $state + * + * @return string + */ + protected function getOAuthUrl($state) + { + $queries = [ + 'appid' => $this->clientId, + 'redirect_uri' => $this->redirectUrl, + 'response_type' => 'code', + 'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator), + 'agentid' => $this->agentId, + 'state' => $state, + ]; + + return sprintf('https://open.weixin.qq.com/connect/oauth2/authorize?%s#wechat_redirect', http_build_query($queries)); + } + + /** + * Qr connect url. + * + * @param string $state + * + * @return string + */ + protected function getQrConnectUrl($state) + { + $queries = [ + 'appid' => $this->clientId, + 'agentid' => $this->agentId, + 'redirect_uri' => $this->redirectUrl, + 'state' => $state, + ]; + + return 'https://open.work.weixin.qq.com/wwopen/sso/qrConnect?'.http_build_query($queries); + } + + protected function getTokenUrl() + { + return null; + } + + /** + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return mixed + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $userInfo = $this->getUserInfo($token); + + if ($this->detailed && isset($userInfo['user_ticket'])) { + return $this->getUserDetail($token, $userInfo['user_ticket']); + } + + $this->detailed = false; + + return $userInfo; + } + + /** + * Get user base info. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return mixed + */ + protected function getUserInfo(AccessTokenInterface $token) + { + $response = $this->getHttpClient()->get('https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo', [ + 'query' => array_filter([ + 'access_token' => $token->getToken(), + 'code' => $this->getCode(), + ]), + ]); + + return json_decode($response->getBody(), true); + } + + /** + * Get user detail info. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * @param $ticket + * + * @return mixed + */ + protected function getUserDetail(AccessTokenInterface $token, $ticket) + { + $response = $this->getHttpClient()->post('https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail', [ + 'query' => [ + 'access_token' => $token->getToken(), + ], + 'json' => [ + 'user_ticket' => $ticket, + ], + ]); + + return json_decode($response->getBody(), true); + } + + /** + * @param array $user + * + * @return \Overtrue\Socialite\User + */ + protected function mapUserToObject(array $user) + { + if ($this->detailed) { + return new User([ + 'id' => $this->arrayItem($user, 'userid'), + 'name' => $this->arrayItem($user, 'name'), + 'avatar' => $this->arrayItem($user, 'avatar'), + 'email' => $this->arrayItem($user, 'email'), + ]); + } + + return new User(array_filter([ + 'id' => $this->arrayItem($user, 'UserId') ?: $this->arrayItem($user, 'OpenId'), + 'userId' => $this->arrayItem($user, 'UserId'), + 'openid' => $this->arrayItem($user, 'OpenId'), + 'deviceId' => $this->arrayItem($user, 'DeviceId'), + ])); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeiboProvider.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeiboProvider.php new file mode 100644 index 0000000..47ec56d --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/Providers/WeiboProvider.php @@ -0,0 +1,126 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite\Providers; + +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\ProviderInterface; +use Overtrue\Socialite\User; + +/** + * Class WeiboProvider. + * + * @see http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E [OAuth 2.0 授权机制说明] + */ +class WeiboProvider extends AbstractProvider implements ProviderInterface +{ + /** + * The base url of Weibo API. + * + * @var string + */ + protected $baseUrl = 'https://api.weibo.com'; + + /** + * The API version for the request. + * + * @var string + */ + protected $version = '2'; + + /** + * The scopes being requested. + * + * @var array + */ + protected $scopes = ['email']; + + /** + * The uid of user authorized. + * + * @var int + */ + protected $uid; + + /** + * Get the authentication URL for the provider. + * + * @param string $state + * + * @return string + */ + protected function getAuthUrl($state) + { + return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2/authorize', $state); + } + + /** + * Get the token URL for the provider. + * + * @return string + */ + protected function getTokenUrl() + { + return $this->baseUrl.'/'.$this->version.'/oauth2/access_token'; + } + + /** + * Get the Post fields for the token request. + * + * @param string $code + * + * @return array + */ + protected function getTokenFields($code) + { + return parent::getTokenFields($code) + ['grant_type' => 'authorization_code']; + } + + /** + * Get the raw user for the given access token. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return array + */ + protected function getUserByToken(AccessTokenInterface $token) + { + $response = $this->getHttpClient()->get($this->baseUrl.'/'.$this->version.'/users/show.json', [ + 'query' => [ + 'uid' => $token['uid'], + 'access_token' => $token->getToken(), + ], + 'headers' => [ + 'Accept' => 'application/json', + ], + ]); + + return json_decode($response->getBody(), true); + } + + /** + * Map the raw user array to a Socialite User instance. + * + * @param array $user + * + * @return \Overtrue\Socialite\User + */ + protected function mapUserToObject(array $user) + { + return new User([ + 'id' => $this->arrayItem($user, 'id'), + 'nickname' => $this->arrayItem($user, 'screen_name'), + 'name' => $this->arrayItem($user, 'name'), + 'email' => $this->arrayItem($user, 'email'), + 'avatar' => $this->arrayItem($user, 'avatar_large'), + ]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/SocialiteManager.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/SocialiteManager.php new file mode 100644 index 0000000..8e99cf0 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/SocialiteManager.php @@ -0,0 +1,251 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +use Closure; +use InvalidArgumentException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Session\Session; + +/** + * Class SocialiteManager. + */ +class SocialiteManager implements FactoryInterface +{ + /** + * The configuration. + * + * @var \Overtrue\Socialite\Config + */ + protected $config; + + /** + * The request instance. + * + * @var Request + */ + protected $request; + + /** + * The registered custom driver creators. + * + * @var array + */ + protected $customCreators = []; + + /** + * The initial drivers. + * + * @var array + */ + protected $initialDrivers = [ + 'facebook' => 'Facebook', + 'github' => 'GitHub', + 'google' => 'Google', + 'linkedin' => 'Linkedin', + 'weibo' => 'Weibo', + 'qq' => 'QQ', + 'wechat' => 'WeChat', + 'douban' => 'Douban', + 'wework' => 'WeWork', + 'outlook' => 'Outlook', + 'douyin' => 'DouYin', + 'taobao' => 'Taobao', + ]; + + /** + * The array of created "drivers". + * + * @var ProviderInterface[] + */ + protected $drivers = []; + + /** + * SocialiteManager constructor. + * + * @param array $config + * @param Request|null $request + */ + public function __construct(array $config, Request $request = null) + { + $this->config = new Config($config); + + if ($this->config->has('guzzle')) { + Providers\AbstractProvider::setGuzzleOptions($this->config->get('guzzle')); + } + + if ($request) { + $this->setRequest($request); + } + } + + /** + * Set config instance. + * + * @param \Overtrue\Socialite\Config $config + * + * @return $this + */ + public function config(Config $config) + { + $this->config = $config; + + return $this; + } + + /** + * Get a driver instance. + * + * @param string $driver + * + * @return ProviderInterface + */ + public function driver($driver) + { + if (!isset($this->drivers[$driver])) { + $this->drivers[$driver] = $this->createDriver($driver); + } + + return $this->drivers[$driver]; + } + + /** + * @param \Symfony\Component\HttpFoundation\Request $request + * + * @return $this + */ + public function setRequest(Request $request) + { + $this->request = $request; + + return $this; + } + + /** + * @return \Symfony\Component\HttpFoundation\Request + */ + public function getRequest() + { + return $this->request ?: $this->createDefaultRequest(); + } + + /** + * Create a new driver instance. + * + * @param string $driver + * + * @throws \InvalidArgumentException + * + * @return ProviderInterface + */ + protected function createDriver($driver) + { + if (isset($this->initialDrivers[$driver])) { + $provider = $this->initialDrivers[$driver]; + $provider = __NAMESPACE__.'\\Providers\\'.$provider.'Provider'; + + return $this->buildProvider($provider, $this->formatConfig($this->config->get($driver))); + } + + if (isset($this->customCreators[$driver])) { + return $this->callCustomCreator($driver); + } + + throw new InvalidArgumentException("Driver [$driver] not supported."); + } + + /** + * Call a custom driver creator. + * + * @param string $driver + * + * @return ProviderInterface + */ + protected function callCustomCreator($driver) + { + return $this->customCreators[$driver]($this->config); + } + + /** + * Create default request instance. + * + * @return Request + */ + protected function createDefaultRequest() + { + $request = Request::createFromGlobals(); + $session = new Session(); + + $request->setSession($session); + + return $request; + } + + /** + * Register a custom driver creator Closure. + * + * @param string $driver + * @param \Closure $callback + * + * @return $this + */ + public function extend($driver, Closure $callback) + { + $this->customCreators[$driver] = $callback; + + return $this; + } + + /** + * Get all of the created "drivers". + * + * @return ProviderInterface[] + */ + public function getDrivers() + { + return $this->drivers; + } + + /** + * Build an OAuth 2 provider instance. + * + * @param string $provider + * @param array $config + * + * @return ProviderInterface + */ + public function buildProvider($provider, $config) + { + return new $provider( + $this->getRequest(), + $config['client_id'], + $config['client_secret'], + $config['redirect'] + ); + } + + /** + * Format the server configuration. + * + * @param array $config + * + * @return array + */ + public function formatConfig(array $config) + { + return array_merge([ + 'identifier' => $config['client_id'], + 'secret' => $config['client_secret'], + 'callback_uri' => $config['redirect'], + ], $config); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/User.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/User.php new file mode 100644 index 0000000..82827dd --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/User.php @@ -0,0 +1,186 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +use ArrayAccess; +use JsonSerializable; + +/** + * Class User. + */ +class User implements ArrayAccess, UserInterface, JsonSerializable, \Serializable +{ + use HasAttributes; + + /** + * User constructor. + * + * @param array $attributes + */ + public function __construct(array $attributes) + { + $this->attributes = $attributes; + } + + /** + * Get the unique identifier for the user. + * + * @return string + */ + public function getId() + { + return $this->getAttribute('id'); + } + + /** + * Get the username for the user. + * + * @return string + */ + public function getUsername() + { + return $this->getAttribute('username', $this->getId()); + } + + /** + * Get the nickname / username for the user. + * + * @return string + */ + public function getNickname() + { + return $this->getAttribute('nickname'); + } + + /** + * Get the full name of the user. + * + * @return string + */ + public function getName() + { + return $this->getAttribute('name'); + } + + /** + * Get the e-mail address of the user. + * + * @return string + */ + public function getEmail() + { + return $this->getAttribute('email'); + } + + /** + * Get the avatar / image URL for the user. + * + * @return string + */ + public function getAvatar() + { + return $this->getAttribute('avatar'); + } + + /** + * Set the token on the user. + * + * @param \Overtrue\Socialite\AccessTokenInterface $token + * + * @return $this + */ + public function setToken(AccessTokenInterface $token) + { + $this->setAttribute('token', $token->getToken()); + + return $this; + } + + /** + * @param string $provider + * + * @return $this + */ + public function setProviderName($provider) + { + $this->setAttribute('provider', $provider); + + return $this; + } + + /** + * @return string + */ + public function getProviderName() + { + return $this->getAttribute('provider'); + } + + /** + * Get the authorized token. + * + * @return \Overtrue\Socialite\AccessToken + */ + public function getToken() + { + return new AccessToken(['access_token' => $this->getAttribute('token')]); + } + + /** + * Alias of getToken(). + * + * @return \Overtrue\Socialite\AccessToken + */ + public function getAccessToken() + { + return $this->getToken(); + } + + /** + * Get the original attributes. + * + * @return array + */ + public function getOriginal() + { + return $this->getAttribute('original'); + } + + /** + * {@inheritdoc} + */ + public function jsonSerialize() + { + return $this->attributes; + } + + public function serialize() + { + return serialize($this->attributes); + } + + /** + * Constructs the object. + * + * @see https://php.net/manual/en/serializable.unserialize.php + * + * @param string $serialized

+ * The string representation of the object. + *

+ * + * @since 5.1.0 + */ + public function unserialize($serialized) + { + $this->attributes = \unserialize($serialized) ?? []; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/UserInterface.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/UserInterface.php new file mode 100644 index 0000000..1403339 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/UserInterface.php @@ -0,0 +1,53 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +/** + * Interface UserInterface. + */ +interface UserInterface +{ + /** + * Get the unique identifier for the user. + * + * @return string + */ + public function getId(); + + /** + * Get the nickname / username for the user. + * + * @return string + */ + public function getNickname(); + + /** + * Get the full name of the user. + * + * @return string + */ + public function getName(); + + /** + * Get the e-mail address of the user. + * + * @return string + */ + public function getEmail(); + + /** + * Get the avatar / image URL for the user. + * + * @return string + */ + public function getAvatar(); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/src/WeChatComponentInterface.php b/addons/weliam_smartcity/vendor/overtrue/socialite/src/WeChatComponentInterface.php new file mode 100644 index 0000000..1754521 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/src/WeChatComponentInterface.php @@ -0,0 +1,32 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace Overtrue\Socialite; + +/** + * Interface WeChatComponentInterface. + */ +interface WeChatComponentInterface +{ + /** + * Return the open-platform component app id. + * + * @return string + */ + public function getAppId(); + + /** + * Return the open-platform component access token string. + * + * @return string + */ + public function getToken(); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/tests/OAuthTest.php b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/OAuthTest.php new file mode 100644 index 0000000..c637606 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/OAuthTest.php @@ -0,0 +1,161 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +use Mockery as m; +use Overtrue\Socialite\AccessTokenInterface; +use Overtrue\Socialite\Providers\AbstractProvider; +use Overtrue\Socialite\User; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; + +class OAuthTest extends TestCase +{ + public function tearDown() + { + m::close(); + } + + public function testRedirectGeneratesTheProperSymfonyRedirectResponse() + { + $request = Request::create('foo'); + $request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface')); + $session->shouldReceive('put')->once(); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect'); + $response = $provider->redirect(); + + $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response); + $this->assertSame('http://auth.url', $response->getTargetUrl()); + } + + public function testRedirectUrl() + { + $request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']); + $request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface')); + + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret'); + $this->assertNull($provider->getRedirectUrl()); + + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect_uri'); + $this->assertSame('redirect_uri', $provider->getRedirectUrl()); + $provider->setRedirectUrl('overtrue.me'); + $this->assertSame('overtrue.me', $provider->getRedirectUrl()); + + $provider->withRedirectUrl('http://overtrue.me'); + $this->assertSame('http://overtrue.me', $provider->getRedirectUrl()); + } + + public function testUserReturnsAUserInstanceForTheAuthenticatedRequest() + { + $request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']); + $request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface')); + + $session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40)); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect_uri'); + $provider->http = m::mock('StdClass'); + $provider->http->shouldReceive('post')->once()->with('http://token.url', [ + 'headers' => ['Accept' => 'application/json'], 'form_params' => ['client_id' => 'client_id', 'client_secret' => 'client_secret', 'code' => 'code', 'redirect_uri' => 'redirect_uri'], + ])->andReturn($response = m::mock('StdClass')); + $response->shouldReceive('getBody')->once()->andReturn('{"access_token":"access_token"}'); + $user = $provider->user(); + + $this->assertInstanceOf('Overtrue\Socialite\User', $user); + $this->assertSame('foo', $user->getId()); + } + + /** + * @expectedException \Overtrue\Socialite\InvalidStateException + */ + public function testExceptionIsThrownIfStateIsInvalid() + { + $request = Request::create('foo', 'GET', ['state' => str_repeat('B', 40), 'code' => 'code']); + $request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface')); + $session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40)); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect'); + $user = $provider->user(); + } + + /** + * @expectedException \Overtrue\Socialite\AuthorizeFailedException + * @expectedExceptionMessage Authorize Failed: {"error":"scope is invalid"} + */ + public function testExceptionisThrownIfAuthorizeFailed() + { + $request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']); + $request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface')); + $session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40)); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect_uri'); + $provider->http = m::mock('StdClass'); + $provider->http->shouldReceive('post')->once()->with('http://token.url', [ + 'headers' => ['Accept' => 'application/json'], 'form_params' => ['client_id' => 'client_id', 'client_secret' => 'client_secret', 'code' => 'code', 'redirect_uri' => 'redirect_uri'], + ])->andReturn($response = m::mock('StdClass')); + $response->shouldReceive('getBody')->once()->andReturn('{"error":"scope is invalid"}'); + $user = $provider->user(); + } + + /** + * @expectedException \Overtrue\Socialite\InvalidStateException + */ + public function testExceptionIsThrownIfStateIsNotSet() + { + $request = Request::create('foo', 'GET', ['state' => 'state', 'code' => 'code']); + $request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface')); + $session->shouldReceive('get')->once()->with('state'); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect'); + $user = $provider->user(); + } + + public function testDriverName() + { + $request = Request::create('foo', 'GET', ['state' => 'state', 'code' => 'code']); + $provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect'); + + $this->assertSame('OAuthTwoTest', $provider->getName()); + } +} + +class OAuthTwoTestProviderStub extends AbstractProvider +{ + public $http; + + protected function getAuthUrl($state) + { + return 'http://auth.url'; + } + + protected function getTokenUrl() + { + return 'http://token.url'; + } + + protected function getUserByToken(AccessTokenInterface $token) + { + return ['id' => 'foo']; + } + + protected function mapUserToObject(array $user) + { + return new User(['id' => $user['id']]); + } + + /** + * Get a fresh instance of the Guzzle HTTP client. + * + * @return \GuzzleHttp\Client + */ + protected function getHttpClient() + { + if ($this->http) { + return $this->http; + } + + return $this->http = m::mock('StdClass'); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php new file mode 100644 index 0000000..88377a7 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php @@ -0,0 +1,48 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +use Overtrue\Socialite\Providers\WeWorkProvider; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; + +class WeWorkProviderTest extends TestCase +{ + public function testQrConnect() + { + $response = (new WeWorkProvider(Request::create('foo'), 'ww100000a5f2191', 'client_secret', 'http://www.oa.com')) + ->setAgentId('1000000') + ->stateless() + ->redirect(); + + $this->assertSame('https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=ww100000a5f2191&agentid=1000000&redirect_uri=http%3A%2F%2Fwww.oa.com', $response->getTargetUrl()); + } + + public function testOAuthWithAgentId() + { + $response = (new WeWorkProvider(Request::create('foo'), 'CORPID', 'client_secret', 'REDIRECT_URI')) + ->scopes(['snsapi_base']) + ->setAgentId('1000000') + ->stateless() + ->redirect(); + + $this->assertSame('https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&agentid=1000000#wechat_redirect', $response->getTargetUrl()); + } + + public function testOAuthWithoutAgentId() + { + $response = (new WeWorkProvider(Request::create('foo'), 'CORPID', 'client_secret', 'REDIRECT_URI')) + ->scopes(['snsapi_base']) + ->stateless() + ->redirect(); + + $this->assertSame('https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base#wechat_redirect', $response->getTargetUrl()); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/tests/UserTest.php b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/UserTest.php new file mode 100644 index 0000000..dd42010 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/UserTest.php @@ -0,0 +1,24 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +use Overtrue\Socialite\AccessToken; +use Overtrue\Socialite\User; +use PHPUnit\Framework\TestCase; + +class UserTest extends TestCase +{ + public function testJsonserialize() + { + $this->assertSame('[]', json_encode(new User([]))); + + $this->assertSame('{"token":"mock-token"}', json_encode(new User(['token' => new AccessToken(['access_token' => 'mock-token'])]))); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/socialite/tests/WechatProviderTest.php b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/WechatProviderTest.php new file mode 100644 index 0000000..7576b02 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/socialite/tests/WechatProviderTest.php @@ -0,0 +1,109 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +use Overtrue\Socialite\Providers\WeChatProvider as RealWeChatProvider; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; + +class WechatProviderTest extends TestCase +{ + public function testWeChatProviderHasCorrectlyRedirectResponse() + { + $response = (new WeChatProvider(Request::create('foo'), 'client_id', 'client_secret', 'http://localhost/socialite/callback.php'))->redirect(); + + $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response); + $this->assertStringStartsWith('https://open.weixin.qq.com/connect/qrconnect', $response->getTargetUrl()); + $this->assertRegExp('/redirect_uri=http%3A%2F%2Flocalhost%2Fsocialite%2Fcallback.php/', $response->getTargetUrl()); + } + + public function testWeChatProviderTokenUrlAndRequestFields() + { + $provider = new WeChatProvider(Request::create('foo'), 'client_id', 'client_secret', 'http://localhost/socialite/callback.php'); + + $this->assertSame('https://api.weixin.qq.com/sns/oauth2/access_token', $provider->tokenUrl()); + $this->assertSame([ + 'appid' => 'client_id', + 'secret' => 'client_secret', + 'code' => 'iloveyou', + 'grant_type' => 'authorization_code', + ], $provider->tokenFields('iloveyou')); + + $this->assertSame([ + 'appid' => 'client_id', + 'redirect_uri' => 'http://localhost/socialite/callback.php', + 'response_type' => 'code', + 'scope' => 'snsapi_login', + 'state' => 'wechat-state', + 'connect_redirect' => 1, + ], $provider->codeFields('wechat-state')); + } + + public function testOpenPlatformComponent() + { + $provider = new WeChatProvider(Request::create('foo'), 'client_id', null, 'redirect-url'); + $provider->component(new WeChatComponent()); + $this->assertSame([ + 'appid' => 'client_id', + 'redirect_uri' => 'redirect-url', + 'response_type' => 'code', + 'scope' => 'snsapi_base', + 'state' => 'state', + 'connect_redirect' => 1, + 'component_appid' => 'component-app-id', + ], $provider->codeFields('state')); + + $this->assertSame([ + 'appid' => 'client_id', + 'component_appid' => 'component-app-id', + 'component_access_token' => 'token', + 'code' => 'simcode', + 'grant_type' => 'authorization_code', + ], $provider->tokenFields('simcode')); + + $this->assertSame('https://api.weixin.qq.com/sns/oauth2/component/access_token', $provider->tokenUrl()); + } +} + +trait ProviderTrait +{ + public function tokenUrl() + { + return $this->getTokenUrl(); + } + + public function tokenFields($code) + { + return $this->getTokenFields($code); + } + + public function codeFields($state = null) + { + return $this->getCodeFields($state); + } +} + +class WeChatProvider extends RealWeChatProvider +{ + use ProviderTrait; +} + +class WeChatComponent implements \Overtrue\Socialite\WeChatComponentInterface +{ + public function getAppId() + { + return 'component-app-id'; + } + + public function getToken() + { + return 'token'; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Application.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Application.php new file mode 100644 index 0000000..e4b1e8a --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Application.php @@ -0,0 +1,39 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService; + +use EasyWeChat\Kernel\ServiceContainer; + +/** + * Class Application. + * + * @author overtrue + * + * @property \EasyWeChat\BasicService\Jssdk\Client $jssdk + * @property \EasyWeChat\BasicService\Media\Client $media + * @property \EasyWeChat\BasicService\QrCode\Client $qrcode + * @property \EasyWeChat\BasicService\Url\Client $url + * @property \EasyWeChat\BasicService\ContentSecurity\Client $content_security + */ +class Application extends ServiceContainer +{ + /** + * @var array + */ + protected $providers = [ + Jssdk\ServiceProvider::class, + QrCode\ServiceProvider::class, + Media\ServiceProvider::class, + Url\ServiceProvider::class, + ContentSecurity\ServiceProvider::class, + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php new file mode 100644 index 0000000..7bc11bd --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php @@ -0,0 +1,123 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\ContentSecurity; + +use EasyWeChat\Kernel\BaseClient; +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; + +/** + * Class Client. + * + * @author tianyong90 <412039588@qq.com> + */ +class Client extends BaseClient +{ + /** + * @var string + */ + protected $baseUri = 'https://api.weixin.qq.com/wxa/'; + + /** + * Text content security check. + * + * @param string $text + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function checkText(string $text) + { + $params = [ + 'content' => $text, + ]; + + return $this->httpPostJson('msg_sec_check', $params); + } + + /** + * Image security check. + * + * @param string $path + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function checkImage(string $path) + { + return $this->httpUpload('img_sec_check', ['media' => $path]); + } + + /** + * Media security check. + * + * @param string $mediaUrl + * @param int $mediaType + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function checkMediaAsync(string $mediaUrl, int $mediaType) + { + /* + * 1:音频;2:图片 + */ + $mediaTypes = [1, 2]; + + if (!in_array($mediaType, $mediaTypes, true)) { + throw new InvalidArgumentException('media type must be 1 or 2'); + } + + $params = [ + 'media_url' => $mediaUrl, + 'media_type' => $mediaType, + ]; + + return $this->httpPostJson('media_check_async', $params); + } + + /** + * Image security check async. + * + * @param string $mediaUrl + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function checkImageAsync(string $mediaUrl) + { + return $this->checkMediaAsync($mediaUrl, 2); + } + + /** + * Audio security check async. + * + * @param string $mediaUrl + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function checkAudioAsync(string $mediaUrl) + { + return $this->checkMediaAsync($mediaUrl, 1); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php new file mode 100644 index 0000000..3645de9 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php @@ -0,0 +1,31 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\ContentSecurity; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['content_security'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/Client.php new file mode 100644 index 0000000..33367fc --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/Client.php @@ -0,0 +1,207 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\Jssdk; + +use EasyWeChat\Kernel\BaseClient; +use EasyWeChat\Kernel\Exceptions\RuntimeException; +use EasyWeChat\Kernel\Support; +use EasyWeChat\Kernel\Traits\InteractsWithCache; + +/** + * Class Client. + * + * @author overtrue + */ +class Client extends BaseClient +{ + use InteractsWithCache; + + /** + * @var string + */ + protected $ticketEndpoint = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket'; + + /** + * Current URI. + * + * @var string + */ + protected $url; + + /** + * Get config json for jsapi. + * + * @param array $jsApiList + * @param bool $debug + * @param bool $beta + * @param bool $json + * + * @return array|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function buildConfig(array $jsApiList, bool $debug = false, bool $beta = false, bool $json = true) + { + $config = array_merge(compact('debug', 'beta', 'jsApiList'), $this->configSignature()); + + return $json ? json_encode($config) : $config; + } + + /** + * Return jsapi config as a PHP array. + * + * @param array $apis + * @param bool $debug + * @param bool $beta + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function getConfigArray(array $apis, bool $debug = false, bool $beta = false) + { + return $this->buildConfig($apis, $debug, $beta, false); + } + + /** + * Get js ticket. + * + * @param bool $refresh + * @param string $type + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function getTicket(bool $refresh = false, string $type = 'jsapi'): array + { + $cacheKey = sprintf('easywechat.basic_service.jssdk.ticket.%s.%s', $type, $this->getAppId()); + + if (!$refresh && $this->getCache()->has($cacheKey)) { + return $this->getCache()->get($cacheKey); + } + + /** @var array $result */ + $result = $this->castResponseToType( + $this->requestRaw($this->ticketEndpoint, 'GET', ['query' => ['type' => $type]]), + 'array' + ); + + $this->getCache()->set($cacheKey, $result, $result['expires_in'] - 500); + + if (!$this->getCache()->has($cacheKey)) { + throw new RuntimeException('Failed to cache jssdk ticket.'); + } + + return $result; + } + + /** + * Build signature. + * + * @param string|null $url + * @param string|null $nonce + * @param int|null $timestamp + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + protected function configSignature(string $url = null, string $nonce = null, $timestamp = null): array + { + $url = $url ?: $this->getUrl(); + $nonce = $nonce ?: Support\Str::quickRandom(10); + $timestamp = $timestamp ?: time(); + + return [ + 'appId' => $this->getAppId(), + 'nonceStr' => $nonce, + 'timestamp' => $timestamp, + 'url' => $url, + 'signature' => $this->getTicketSignature($this->getTicket()['ticket'], $nonce, $timestamp, $url), + ]; + } + + /** + * Sign the params. + * + * @param string $ticket + * @param string $nonce + * @param int $timestamp + * @param string $url + * + * @return string + */ + public function getTicketSignature($ticket, $nonce, $timestamp, $url): string + { + return sha1(sprintf('jsapi_ticket=%s&noncestr=%s×tamp=%s&url=%s', $ticket, $nonce, $timestamp, $url)); + } + + /** + * @return string + */ + public function dictionaryOrderSignature() + { + $params = func_get_args(); + + sort($params, SORT_STRING); + + return sha1(implode('', $params)); + } + + /** + * Set current url. + * + * @param string $url + * + * @return $this + */ + public function setUrl(string $url) + { + $this->url = $url; + + return $this; + } + + /** + * Get current url. + * + * @return string + */ + public function getUrl(): string + { + if ($this->url) { + return $this->url; + } + + return Support\current_url(); + } + + /** + * @return string + */ + protected function getAppId() + { + return $this->app['config']->get('app_id'); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/ServiceProvider.php new file mode 100644 index 0000000..5581a1e --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Jssdk/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\Jssdk; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['jssdk'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/Client.php new file mode 100644 index 0000000..13f1afa --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/Client.php @@ -0,0 +1,212 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\Media; + +use EasyWeChat\Kernel\BaseClient; +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\Http\StreamResponse; + +/** + * Class Client. + * + * @author overtrue + */ +class Client extends BaseClient +{ + /** + * @var string + */ + protected $baseUri = 'https://api.weixin.qq.com/cgi-bin/'; + + /** + * Allow media type. + * + * @var array + */ + protected $allowTypes = ['image', 'voice', 'video', 'thumb']; + + /** + * Upload image. + * + * @param string $path + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function uploadImage($path) + { + return $this->upload('image', $path); + } + + /** + * Upload video. + * + * @param string $path + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function uploadVideo($path) + { + return $this->upload('video', $path); + } + + /** + * @param string $path + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function uploadVoice($path) + { + return $this->upload('voice', $path); + } + + /** + * @param string $path + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function uploadThumb($path) + { + return $this->upload('thumb', $path); + } + + /** + * Upload temporary material. + * + * @param string $type + * @param string $path + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function upload(string $type, string $path) + { + if (!file_exists($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf("File does not exist, or the file is unreadable: '%s'", $path)); + } + + if (!in_array($type, $this->allowTypes, true)) { + throw new InvalidArgumentException(sprintf("Unsupported media type: '%s'", $type)); + } + + return $this->httpUpload('media/upload', ['media' => $path], ['type' => $type]); + } + + /** + * @param string $path + * @param string $title + * @param string $description + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function uploadVideoForBroadcasting(string $path, string $title, string $description) + { + $response = $this->uploadVideo($path); + /** @var array $arrayResponse */ + $arrayResponse = $this->detectAndCastResponseToType($response, 'array'); + + if (!empty($arrayResponse['media_id'])) { + return $this->createVideoForBroadcasting($arrayResponse['media_id'], $title, $description); + } + + return $response; + } + + /** + * @param string $mediaId + * @param string $title + * @param string $description + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function createVideoForBroadcasting(string $mediaId, string $title, string $description) + { + return $this->httpPostJson('media/uploadvideo', [ + 'media_id' => $mediaId, + 'title' => $title, + 'description' => $description, + ]); + } + + /** + * Fetch item from WeChat server. + * + * @param string $mediaId + * + * @return \EasyWeChat\Kernel\Http\StreamResponse|\Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function get(string $mediaId) + { + $response = $this->requestRaw('media/get', 'GET', [ + 'query' => [ + 'media_id' => $mediaId, + ], + ]); + + if (false !== stripos($response->getHeaderLine('Content-disposition'), 'attachment')) { + return StreamResponse::buildFromPsrResponse($response); + } + + return $this->castResponseToType($response, $this->app['config']->get('response_type')); + } + + /** + * @param string $mediaId + * + * @return array|\EasyWeChat\Kernel\Http\Response|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getJssdkMedia(string $mediaId) + { + $response = $this->requestRaw('media/get/jssdk', 'GET', [ + 'query' => [ + 'media_id' => $mediaId, + ], + ]); + + if (false !== stripos($response->getHeaderLine('Content-disposition'), 'attachment')) { + return StreamResponse::buildFromPsrResponse($response); + } + + return $this->castResponseToType($response, $this->app['config']->get('response_type')); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/ServiceProvider.php new file mode 100644 index 0000000..45de142 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Media/ServiceProvider.php @@ -0,0 +1,44 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * ServiceProvider.php. + * + * This file is part of the wechat. + * + * (c) overtrue + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\Media; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['media'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/Client.php new file mode 100644 index 0000000..ac606a3 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/Client.php @@ -0,0 +1,120 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\QrCode; + +use EasyWeChat\Kernel\BaseClient; + +/** + * Class Client. + * + * @author overtrue + */ +class Client extends BaseClient +{ + /** + * @var string + */ + protected $baseUri = 'https://api.weixin.qq.com/cgi-bin/'; + + const DAY = 86400; + const SCENE_MAX_VALUE = 100000; + const SCENE_QR_CARD = 'QR_CARD'; + const SCENE_QR_TEMPORARY = 'QR_SCENE'; + const SCENE_QR_TEMPORARY_STR = 'QR_STR_SCENE'; + const SCENE_QR_FOREVER = 'QR_LIMIT_SCENE'; + const SCENE_QR_FOREVER_STR = 'QR_LIMIT_STR_SCENE'; + + /** + * Create forever QR code. + * + * @param string|int $sceneValue + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + */ + public function forever($sceneValue) + { + if (is_int($sceneValue) && $sceneValue > 0 && $sceneValue < self::SCENE_MAX_VALUE) { + $type = self::SCENE_QR_FOREVER; + $sceneKey = 'scene_id'; + } else { + $type = self::SCENE_QR_FOREVER_STR; + $sceneKey = 'scene_str'; + } + $scene = [$sceneKey => $sceneValue]; + + return $this->create($type, $scene, false); + } + + /** + * Create temporary QR code. + * + * @param string|int $sceneValue + * @param int|null $expireSeconds + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + */ + public function temporary($sceneValue, $expireSeconds = null) + { + if (is_int($sceneValue) && $sceneValue > 0) { + $type = self::SCENE_QR_TEMPORARY; + $sceneKey = 'scene_id'; + } else { + $type = self::SCENE_QR_TEMPORARY_STR; + $sceneKey = 'scene_str'; + } + $scene = [$sceneKey => $sceneValue]; + + return $this->create($type, $scene, true, $expireSeconds); + } + + /** + * Return url for ticket. + * Detail: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433542 . + * + * @param string $ticket + * + * @return string + */ + public function url($ticket) + { + return sprintf('https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s', urlencode($ticket)); + } + + /** + * Create a QrCode. + * + * @param string $actionName + * @param array $actionInfo + * @param bool $temporary + * @param int $expireSeconds + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + protected function create($actionName, $actionInfo, $temporary = true, $expireSeconds = null) + { + null !== $expireSeconds || $expireSeconds = 7 * self::DAY; + + $params = [ + 'action_name' => $actionName, + 'action_info' => ['scene' => $actionInfo], + ]; + + if ($temporary) { + $params['expire_seconds'] = min($expireSeconds, 30 * self::DAY); + } + + return $this->httpPostJson('qrcode/create', $params); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/ServiceProvider.php new file mode 100644 index 0000000..1638c66 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/QrCode/ServiceProvider.php @@ -0,0 +1,31 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\QrCode; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['qrcode'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/Client.php new file mode 100644 index 0000000..19a5fb1 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/Client.php @@ -0,0 +1,47 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\Url; + +use EasyWeChat\Kernel\BaseClient; + +/** + * Class Client. + * + * @author overtrue + */ +class Client extends BaseClient +{ + /** + * @var string + */ + protected $baseUri = 'https://api.weixin.qq.com/'; + + /** + * Shorten the url. + * + * @param string $url + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function shorten(string $url) + { + $params = [ + 'action' => 'long2short', + 'long_url' => $url, + ]; + + return $this->httpPostJson('cgi-bin/shorturl', $params); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/ServiceProvider.php new file mode 100644 index 0000000..6740bb8 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/BasicService/Url/ServiceProvider.php @@ -0,0 +1,31 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\BasicService\Url; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['url'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/AccessToken.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/AccessToken.php new file mode 100644 index 0000000..77f23c0 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/AccessToken.php @@ -0,0 +1,282 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel; + +use EasyWeChat\Kernel\Contracts\AccessTokenInterface; +use EasyWeChat\Kernel\Exceptions\HttpException; +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\Exceptions\RuntimeException; +use EasyWeChat\Kernel\Traits\HasHttpRequests; +use EasyWeChat\Kernel\Traits\InteractsWithCache; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; + +/** + * Class AccessToken. + * + * @author overtrue + */ +abstract class AccessToken implements AccessTokenInterface +{ + use HasHttpRequests; + use InteractsWithCache; + + /** + * @var \EasyWeChat\Kernel\ServiceContainer + */ + protected $app; + + /** + * @var string + */ + protected $requestMethod = 'GET'; + + /** + * @var string + */ + protected $endpointToGetToken; + + /** + * @var string + */ + protected $queryName; + + /** + * @var array + */ + protected $token; + + /** + * @var int + */ + protected $safeSeconds = 500; + + /** + * @var string + */ + protected $tokenKey = 'access_token'; + + /** + * @var string + */ + protected $cachePrefix = 'easywechat.kernel.access_token.'; + + /** + * AccessToken constructor. + * + * @param \EasyWeChat\Kernel\ServiceContainer $app + */ + public function __construct(ServiceContainer $app) + { + $this->app = $app; + } + + /** + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\HttpException + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function getRefreshedToken(): array + { + return $this->getToken(true); + } + + /** + * @param bool $refresh + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\HttpException + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function getToken(bool $refresh = false): array + { + $cacheKey = $this->getCacheKey(); + $cache = $this->getCache(); + + if (!$refresh && $cache->has($cacheKey)) { + return $cache->get($cacheKey); + } + + /** @var array $token */ + $token = $this->requestToken($this->getCredentials(), true); + + $this->setToken($token[$this->tokenKey], $token['expires_in'] ?? 7200); + + $this->app->events->dispatch(new Events\AccessTokenRefreshed($this)); + + return $token; + } + + /** + * @param string $token + * @param int $lifetime + * + * @return \EasyWeChat\Kernel\Contracts\AccessTokenInterface + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function setToken(string $token, int $lifetime = 7200): AccessTokenInterface + { + $this->getCache()->set($this->getCacheKey(), [ + $this->tokenKey => $token, + 'expires_in' => $lifetime, + ], $lifetime - $this->safeSeconds); + + if (!$this->getCache()->has($this->getCacheKey())) { + throw new RuntimeException('Failed to cache access token.'); + } + + return $this; + } + + /** + * @return \EasyWeChat\Kernel\Contracts\AccessTokenInterface + * + * @throws \EasyWeChat\Kernel\Exceptions\HttpException + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function refresh(): AccessTokenInterface + { + $this->getToken(true); + + return $this; + } + + /** + * @param array $credentials + * @param bool $toArray + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\HttpException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function requestToken(array $credentials, $toArray = false) + { + $response = $this->sendRequest($credentials); + $result = json_decode($response->getBody()->getContents(), true); + $formatted = $this->castResponseToType($response, $this->app['config']->get('response_type')); + + if (empty($result[$this->tokenKey])) { + throw new HttpException('Request access_token fail: '.json_encode($result, JSON_UNESCAPED_UNICODE), $response, $formatted); + } + + return $toArray ? $result : $formatted; + } + + /** + * @param \Psr\Http\Message\RequestInterface $request + * @param array $requestOptions + * + * @return \Psr\Http\Message\RequestInterface + * + * @throws \EasyWeChat\Kernel\Exceptions\HttpException + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function applyToRequest(RequestInterface $request, array $requestOptions = []): RequestInterface + { + parse_str($request->getUri()->getQuery(), $query); + + $query = http_build_query(array_merge($this->getQuery(), $query)); + + return $request->withUri($request->getUri()->withQuery($query)); + } + + /** + * Send http request. + * + * @param array $credentials + * + * @return ResponseInterface + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + protected function sendRequest(array $credentials): ResponseInterface + { + $options = [ + ('GET' === $this->requestMethod) ? 'query' : 'json' => $credentials, + ]; + + return $this->setHttpClient($this->app['http_client'])->request($this->getEndpoint(), $this->requestMethod, $options); + } + + /** + * @return string + */ + protected function getCacheKey() + { + return $this->cachePrefix.md5(json_encode($this->getCredentials())); + } + + /** + * The request query will be used to add to the request. + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\HttpException + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + protected function getQuery(): array + { + return [$this->queryName ?? $this->tokenKey => $this->getToken()[$this->tokenKey]]; + } + + /** + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function getEndpoint(): string + { + if (empty($this->endpointToGetToken)) { + throw new InvalidArgumentException('No endpoint for access token request.'); + } + + return $this->endpointToGetToken; + } + + /** + * @return string + */ + public function getTokenKey() + { + return $this->tokenKey; + } + + /** + * Credential for get token. + * + * @return array + */ + abstract protected function getCredentials(): array; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/BaseClient.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/BaseClient.php new file mode 100644 index 0000000..75e79e8 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/BaseClient.php @@ -0,0 +1,271 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel; + +use EasyWeChat\Kernel\Contracts\AccessTokenInterface; +use EasyWeChat\Kernel\Http\Response; +use EasyWeChat\Kernel\Traits\HasHttpRequests; +use GuzzleHttp\MessageFormatter; +use GuzzleHttp\Middleware; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Log\LogLevel; + +/** + * Class BaseClient. + * + * @author overtrue + */ +class BaseClient +{ + use HasHttpRequests { request as performRequest; } + + /** + * @var \EasyWeChat\Kernel\ServiceContainer + */ + protected $app; + + /** + * @var \EasyWeChat\Kernel\Contracts\AccessTokenInterface + */ + protected $accessToken; + + /** + * @var string + */ + protected $baseUri; + + /** + * BaseClient constructor. + * + * @param \EasyWeChat\Kernel\ServiceContainer $app + * @param \EasyWeChat\Kernel\Contracts\AccessTokenInterface|null $accessToken + */ + public function __construct(ServiceContainer $app, AccessTokenInterface $accessToken = null) + { + $this->app = $app; + $this->accessToken = $accessToken ?? $this->app['access_token']; + } + + /** + * GET request. + * + * @param string $url + * @param array $query + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function httpGet(string $url, array $query = []) + { + return $this->request($url, 'GET', ['query' => $query]); + } + + /** + * POST request. + * + * @param string $url + * @param array $data + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function httpPost(string $url, array $data = []) + { + return $this->request($url, 'POST', ['form_params' => $data]); + } + + /** + * JSON request. + * + * @param string $url + * @param array $data + * @param array $query + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function httpPostJson(string $url, array $data = [], array $query = []) + { + return $this->request($url, 'POST', ['query' => $query, 'json' => $data]); + } + + /** + * Upload file. + * + * @param string $url + * @param array $files + * @param array $form + * @param array $query + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function httpUpload(string $url, array $files = [], array $form = [], array $query = []) + { + $multipart = []; + + foreach ($files as $name => $path) { + $multipart[] = [ + 'name' => $name, + 'contents' => fopen($path, 'r'), + ]; + } + + foreach ($form as $name => $contents) { + $multipart[] = compact('name', 'contents'); + } + + return $this->request($url, 'POST', ['query' => $query, 'multipart' => $multipart, 'connect_timeout' => 30, 'timeout' => 30, 'read_timeout' => 30]); + } + + /** + * @return AccessTokenInterface + */ + public function getAccessToken(): AccessTokenInterface + { + return $this->accessToken; + } + + /** + * @param \EasyWeChat\Kernel\Contracts\AccessTokenInterface $accessToken + * + * @return $this + */ + public function setAccessToken(AccessTokenInterface $accessToken) + { + $this->accessToken = $accessToken; + + return $this; + } + + /** + * @param string $url + * @param string $method + * @param array $options + * @param bool $returnRaw + * + * @return \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function request(string $url, string $method = 'GET', array $options = [], $returnRaw = false) + { + if (empty($this->middlewares)) { + $this->registerHttpMiddlewares(); + } + + $response = $this->performRequest($url, $method, $options); + + $this->app->events->dispatch(new Events\HttpResponseCreated($response)); + + return $returnRaw ? $response : $this->castResponseToType($response, $this->app->config->get('response_type')); + } + + /** + * @param string $url + * @param string $method + * @param array $options + * + * @return \EasyWeChat\Kernel\Http\Response + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function requestRaw(string $url, string $method = 'GET', array $options = []) + { + return Response::buildFromPsrResponse($this->request($url, $method, $options, true)); + } + + /** + * Register Guzzle middlewares. + */ + protected function registerHttpMiddlewares() + { + // retry + $this->pushMiddleware($this->retryMiddleware(), 'retry'); + // access token + $this->pushMiddleware($this->accessTokenMiddleware(), 'access_token'); + // log + $this->pushMiddleware($this->logMiddleware(), 'log'); + } + + /** + * Attache access token to request query. + * + * @return \Closure + */ + protected function accessTokenMiddleware() + { + return function (callable $handler) { + return function (RequestInterface $request, array $options) use ($handler) { + if ($this->accessToken) { + $request = $this->accessToken->applyToRequest($request, $options); + } + + return $handler($request, $options); + }; + }; + } + + /** + * Log the request. + * + * @return \Closure + */ + protected function logMiddleware() + { + $formatter = new MessageFormatter($this->app['config']['http.log_template'] ?? MessageFormatter::DEBUG); + + return Middleware::log($this->app['logger'], $formatter, LogLevel::DEBUG); + } + + /** + * Return retry middleware. + * + * @return \Closure + */ + protected function retryMiddleware() + { + return Middleware::retry(function ( + $retries, + RequestInterface $request, + ResponseInterface $response = null + ) { + // Limit the number of retries to 2 + if ($retries < $this->app->config->get('http.max_retries', 1) && $response && $body = $response->getBody()) { + // Retry on server errors + $response = json_decode($body, true); + + if (!empty($response['errcode']) && in_array(abs($response['errcode']), [40001, 40014, 42001], true)) { + $this->accessToken->refresh(); + $this->app['logger']->debug('Retrying with refreshed access token.'); + + return true; + } + } + + return false; + }, function () { + return abs($this->app->config->get('http.retry_delay', 500)); + }); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Clauses/Clause.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Clauses/Clause.php new file mode 100644 index 0000000..49bbb22 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Clauses/Clause.php @@ -0,0 +1,64 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Clauses; + +/** + * Class Clause. + * + * @author mingyoung + */ +class Clause +{ + /** + * @var array + */ + protected $clauses = [ + 'where' => [], + ]; + + /** + * @param mixed ...$args + * + * @return $this + */ + public function where(...$args) + { + array_push($this->clauses['where'], $args); + + return $this; + } + + /** + * @param mixed $payload + * + * @return bool + */ + public function intercepted($payload) + { + return (bool) $this->interceptWhereClause($payload); + } + + /** + * @param mixed $payload + * + * @return bool + */ + protected function interceptWhereClause($payload) + { + foreach ($this->clauses['where'] as $item) { + list($key, $value) = $item; + if (isset($payload[$key]) && $payload[$key] !== $value) { + return true; + } + } + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Config.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Config.php new file mode 100644 index 0000000..081f6fd --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Config.php @@ -0,0 +1,23 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel; + +use EasyWeChat\Kernel\Support\Collection; + +/** + * Class Config. + * + * @author overtrue + */ +class Config extends Collection +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/AccessTokenInterface.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/AccessTokenInterface.php new file mode 100644 index 0000000..56f4a4d --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/AccessTokenInterface.php @@ -0,0 +1,40 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Contracts; + +use Psr\Http\Message\RequestInterface; + +/** + * Interface AuthorizerAccessToken. + * + * @author overtrue + */ +interface AccessTokenInterface +{ + /** + * @return array + */ + public function getToken(): array; + + /** + * @return \EasyWeChat\Kernel\Contracts\AccessTokenInterface + */ + public function refresh(): self; + + /** + * @param \Psr\Http\Message\RequestInterface $request + * @param array $requestOptions + * + * @return \Psr\Http\Message\RequestInterface + */ + public function applyToRequest(RequestInterface $request, array $requestOptions = []): RequestInterface; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/Arrayable.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/Arrayable.php new file mode 100644 index 0000000..d947f8f --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/Arrayable.php @@ -0,0 +1,29 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Contracts; + +use ArrayAccess; + +/** + * Interface Arrayable. + * + * @author overtrue + */ +interface Arrayable extends ArrayAccess +{ + /** + * Get the instance as an array. + * + * @return array + */ + public function toArray(); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/EventHandlerInterface.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/EventHandlerInterface.php new file mode 100644 index 0000000..c9d116c --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/EventHandlerInterface.php @@ -0,0 +1,25 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Contracts; + +/** + * Interface EventHandlerInterface. + * + * @author mingyoung + */ +interface EventHandlerInterface +{ + /** + * @param mixed $payload + */ + public function handle($payload = null); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MediaInterface.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MediaInterface.php new file mode 100644 index 0000000..63768cf --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MediaInterface.php @@ -0,0 +1,25 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Contracts; + +/** + * Interface MediaInterface. + * + * @author overtrue + */ +interface MediaInterface extends MessageInterface +{ + /** + * @return string + */ + public function getMediaId(): string; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MessageInterface.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MessageInterface.php new file mode 100644 index 0000000..29ddb57 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Contracts/MessageInterface.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Contracts; + +/** + * Interface MessageInterface. + * + * @author overtrue + */ +interface MessageInterface +{ + /** + * @return string + */ + public function getType(): string; + + /** + * @return array + */ + public function transformForJsonRequest(): array; + + /** + * @return string + */ + public function transformToXml(): string; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/FinallyResult.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/FinallyResult.php new file mode 100644 index 0000000..e698bbf --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/FinallyResult.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Decorators; + +/** + * Class FinallyResult. + * + * @author overtrue + */ +class FinallyResult +{ + /** + * @var mixed + */ + public $content; + + /** + * FinallyResult constructor. + * + * @param mixed $content + */ + public function __construct($content) + { + $this->content = $content; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/TerminateResult.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/TerminateResult.php new file mode 100644 index 0000000..cf1042d --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Decorators/TerminateResult.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Decorators; + +/** + * Class TerminateResult. + * + * @author overtrue + */ +class TerminateResult +{ + /** + * @var mixed + */ + public $content; + + /** + * FinallyResult constructor. + * + * @param mixed $content + */ + public function __construct($content) + { + $this->content = $content; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Encryptor.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Encryptor.php new file mode 100644 index 0000000..150ad21 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Encryptor.php @@ -0,0 +1,219 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel; + +use EasyWeChat\Kernel\Exceptions\RuntimeException; +use EasyWeChat\Kernel\Support\AES; +use function EasyWeChat\Kernel\Support\str_random; +use EasyWeChat\Kernel\Support\XML; +use Throwable; + +/** + * Class Encryptor. + * + * @author overtrue + */ +class Encryptor +{ + const ERROR_INVALID_SIGNATURE = -40001; // Signature verification failed + const ERROR_PARSE_XML = -40002; // Parse XML failed + const ERROR_CALC_SIGNATURE = -40003; // Calculating the signature failed + const ERROR_INVALID_AES_KEY = -40004; // Invalid AESKey + const ERROR_INVALID_APP_ID = -40005; // Check AppID failed + const ERROR_ENCRYPT_AES = -40006; // AES EncryptionInterface failed + const ERROR_DECRYPT_AES = -40007; // AES decryption failed + const ERROR_INVALID_XML = -40008; // Invalid XML + const ERROR_BASE64_ENCODE = -40009; // Base64 encoding failed + const ERROR_BASE64_DECODE = -40010; // Base64 decoding failed + const ERROR_XML_BUILD = -40011; // XML build failed + const ILLEGAL_BUFFER = -41003; // Illegal buffer + + /** + * App id. + * + * @var string + */ + protected $appId; + + /** + * App token. + * + * @var string + */ + protected $token; + + /** + * @var string + */ + protected $aesKey; + + /** + * Block size. + * + * @var int + */ + protected $blockSize = 32; + + /** + * Constructor. + * + * @param string $appId + * @param string|null $token + * @param string|null $aesKey + */ + public function __construct(string $appId, string $token = null, string $aesKey = null) + { + $this->appId = $appId; + $this->token = $token; + $this->aesKey = base64_decode($aesKey.'=', true); + } + + /** + * Get the app token. + * + * @return string + */ + public function getToken(): string + { + return $this->token; + } + + /** + * Encrypt the message and return XML. + * + * @param string $xml + * @param string $nonce + * @param int $timestamp + * + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function encrypt($xml, $nonce = null, $timestamp = null): string + { + try { + $xml = $this->pkcs7Pad(str_random(16).pack('N', strlen($xml)).$xml.$this->appId, $this->blockSize); + + $encrypted = base64_encode(AES::encrypt( + $xml, + $this->aesKey, + substr($this->aesKey, 0, 16), + OPENSSL_NO_PADDING + )); + // @codeCoverageIgnoreStart + } catch (Throwable $e) { + throw new RuntimeException($e->getMessage(), self::ERROR_ENCRYPT_AES); + } + // @codeCoverageIgnoreEnd + + !is_null($nonce) || $nonce = substr($this->appId, 0, 10); + !is_null($timestamp) || $timestamp = time(); + + $response = [ + 'Encrypt' => $encrypted, + 'MsgSignature' => $this->signature($this->token, $timestamp, $nonce, $encrypted), + 'TimeStamp' => $timestamp, + 'Nonce' => $nonce, + ]; + + //生成响应xml + return XML::build($response); + } + + /** + * Decrypt message. + * + * @param string $content + * @param string $msgSignature + * @param string $nonce + * @param string $timestamp + * + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function decrypt($content, $msgSignature, $nonce, $timestamp): string + { + $signature = $this->signature($this->token, $timestamp, $nonce, $content); + + if ($signature !== $msgSignature) { + throw new RuntimeException('Invalid Signature.', self::ERROR_INVALID_SIGNATURE); + } + + $decrypted = AES::decrypt( + base64_decode($content, true), + $this->aesKey, + substr($this->aesKey, 0, 16), + OPENSSL_NO_PADDING + ); + $result = $this->pkcs7Unpad($decrypted); + $content = substr($result, 16, strlen($result)); + $contentLen = unpack('N', substr($content, 0, 4))[1]; + + if (trim(substr($content, $contentLen + 4)) !== $this->appId) { + throw new RuntimeException('Invalid appId.', self::ERROR_INVALID_APP_ID); + } + + return substr($content, 4, $contentLen); + } + + /** + * Get SHA1. + * + * @return string + */ + public function signature(): string + { + $array = func_get_args(); + sort($array, SORT_STRING); + + return sha1(implode($array)); + } + + /** + * PKCS#7 pad. + * + * @param string $text + * @param int $blockSize + * + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function pkcs7Pad(string $text, int $blockSize): string + { + if ($blockSize > 256) { + throw new RuntimeException('$blockSize may not be more than 256'); + } + $padding = $blockSize - (strlen($text) % $blockSize); + $pattern = chr($padding); + + return $text.str_repeat($pattern, $padding); + } + + /** + * PKCS#7 unpad. + * + * @param string $text + * + * @return string + */ + public function pkcs7Unpad(string $text): string + { + $pad = ord(substr($text, -1)); + if ($pad < 1 || $pad > $this->blockSize) { + $pad = 0; + } + + return substr($text, 0, (strlen($text) - $pad)); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/AccessTokenRefreshed.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/AccessTokenRefreshed.php new file mode 100644 index 0000000..a829901 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/AccessTokenRefreshed.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Events; + +use EasyWeChat\Kernel\AccessToken; + +/** + * Class AccessTokenRefreshed. + * + * @author mingyoung + */ +class AccessTokenRefreshed +{ + /** + * @var \EasyWeChat\Kernel\AccessToken + */ + public $accessToken; + + /** + * @param \EasyWeChat\Kernel\AccessToken $accessToken + */ + public function __construct(AccessToken $accessToken) + { + $this->accessToken = $accessToken; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ApplicationInitialized.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ApplicationInitialized.php new file mode 100644 index 0000000..89d67fe --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ApplicationInitialized.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Events; + +use EasyWeChat\Kernel\ServiceContainer; + +/** + * Class ApplicationInitialized. + * + * @author mingyoung + */ +class ApplicationInitialized +{ + /** + * @var \EasyWeChat\Kernel\ServiceContainer + */ + public $app; + + /** + * @param \EasyWeChat\Kernel\ServiceContainer $app + */ + public function __construct(ServiceContainer $app) + { + $this->app = $app; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/HttpResponseCreated.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/HttpResponseCreated.php new file mode 100644 index 0000000..2257260 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/HttpResponseCreated.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Events; + +use Psr\Http\Message\ResponseInterface; + +/** + * Class HttpResponseCreated. + * + * @author mingyoung + */ +class HttpResponseCreated +{ + /** + * @var \Psr\Http\Message\ResponseInterface + */ + public $response; + + /** + * @param \Psr\Http\Message\ResponseInterface $response + */ + public function __construct(ResponseInterface $response) + { + $this->response = $response; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ServerGuardResponseCreated.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ServerGuardResponseCreated.php new file mode 100644 index 0000000..3ab9925 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Events/ServerGuardResponseCreated.php @@ -0,0 +1,35 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Events; + +use Symfony\Component\HttpFoundation\Response; + +/** + * Class ServerGuardResponseCreated. + * + * @author mingyoung + */ +class ServerGuardResponseCreated +{ + /** + * @var \Symfony\Component\HttpFoundation\Response + */ + public $response; + + /** + * @param \Symfony\Component\HttpFoundation\Response $response + */ + public function __construct(Response $response) + { + $this->response = $response; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/BadRequestException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/BadRequestException.php new file mode 100644 index 0000000..a0b4f91 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/BadRequestException.php @@ -0,0 +1,21 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +/** + * Class BadRequestException. + * + * @author overtrue + */ +class BadRequestException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/DecryptException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/DecryptException.php new file mode 100644 index 0000000..f29acca --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/DecryptException.php @@ -0,0 +1,16 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +class DecryptException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/Exception.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/Exception.php new file mode 100644 index 0000000..9eba298 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/Exception.php @@ -0,0 +1,23 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +use Exception as BaseException; + +/** + * Class Exception. + * + * @author overtrue + */ +class Exception extends BaseException +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/HttpException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/HttpException.php new file mode 100644 index 0000000..8ab130d --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/HttpException.php @@ -0,0 +1,52 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +use Psr\Http\Message\ResponseInterface; + +/** + * Class HttpException. + * + * @author overtrue + */ +class HttpException extends Exception +{ + /** + * @var \Psr\Http\Message\ResponseInterface|null + */ + public $response; + + /** + * @var \Psr\Http\Message\ResponseInterface|\EasyWeChat\Kernel\Support\Collection|array|object|string|null + */ + public $formattedResponse; + + /** + * HttpException constructor. + * + * @param string $message + * @param \Psr\Http\Message\ResponseInterface|null $response + * @param null $formattedResponse + * @param int|null $code + */ + public function __construct($message, ResponseInterface $response = null, $formattedResponse = null, $code = null) + { + parent::__construct($message, $code); + + $this->response = $response; + $this->formattedResponse = $formattedResponse; + + if ($response) { + $response->getBody()->rewind(); + } + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidArgumentException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidArgumentException.php new file mode 100644 index 0000000..386a144 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +/** + * Class InvalidArgumentException. + * + * @author overtrue + */ +class InvalidArgumentException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidConfigException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidConfigException.php new file mode 100644 index 0000000..1e4ae2a --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidConfigException.php @@ -0,0 +1,21 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +/** + * Class InvalidConfigException. + * + * @author overtrue + */ +class InvalidConfigException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/RuntimeException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/RuntimeException.php new file mode 100644 index 0000000..25f2f5b --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/RuntimeException.php @@ -0,0 +1,21 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +/** + * Class RuntimeException. + * + * @author overtrue + */ +class RuntimeException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/UnboundServiceException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/UnboundServiceException.php new file mode 100644 index 0000000..78ea85c --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Exceptions/UnboundServiceException.php @@ -0,0 +1,21 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Exceptions; + +/** + * Class InvalidConfigException. + * + * @author overtrue + */ +class UnboundServiceException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Helpers.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Helpers.php new file mode 100644 index 0000000..3ea48a4 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Helpers.php @@ -0,0 +1,57 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel; + +use EasyWeChat\Kernel\Contracts\Arrayable; +use EasyWeChat\Kernel\Exceptions\RuntimeException; +use EasyWeChat\Kernel\Support\Arr; +use EasyWeChat\Kernel\Support\Collection; + +function data_get($data, $key, $default = null) +{ + switch (true) { + case is_array($data): + return Arr::get($data, $key, $default); + case $data instanceof Collection: + return $data->get($key, $default); + case $data instanceof Arrayable: + return Arr::get($data->toArray(), $key, $default); + case $data instanceof \ArrayIterator: + return $data->getArrayCopy()[$key] ?? $default; + case $data instanceof \ArrayAccess: + return $data[$key] ?? $default; + case $data instanceof \IteratorAggregate && $data->getIterator() instanceof \ArrayIterator: + return $data->getIterator()->getArrayCopy()[$key] ?? $default; + case is_object($data): + return $data->{$key} ?? $default; + default: + throw new RuntimeException(sprintf('Can\'t access data with key "%s"', $key)); + } +} + +function data_to_array($data) +{ + switch (true) { + case is_array($data): + return $data; + case $data instanceof Collection: + return $data->all(); + case $data instanceof Arrayable: + return $data->toArray(); + case $data instanceof \IteratorAggregate && $data->getIterator() instanceof \ArrayIterator: + return $data->getIterator()->getArrayCopy(); + case $data instanceof \ArrayIterator: + return $data->getArrayCopy(); + default: + throw new RuntimeException(sprintf('Can\'t transform data to array')); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/Response.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/Response.php new file mode 100644 index 0000000..adcd416 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/Response.php @@ -0,0 +1,121 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Http; + +use EasyWeChat\Kernel\Support\Collection; +use EasyWeChat\Kernel\Support\XML; +use GuzzleHttp\Psr7\Response as GuzzleResponse; +use Psr\Http\Message\ResponseInterface; + +/** + * Class Response. + * + * @author overtrue + */ +class Response extends GuzzleResponse +{ + /** + * @return string + */ + public function getBodyContents() + { + $this->getBody()->rewind(); + $contents = $this->getBody()->getContents(); + $this->getBody()->rewind(); + + return $contents; + } + + /** + * @param \Psr\Http\Message\ResponseInterface $response + * + * @return \EasyWeChat\Kernel\Http\Response + */ + public static function buildFromPsrResponse(ResponseInterface $response) + { + return new static( + $response->getStatusCode(), + $response->getHeaders(), + $response->getBody(), + $response->getProtocolVersion(), + $response->getReasonPhrase() + ); + } + + /** + * Build to json. + * + * @return string + */ + public function toJson() + { + return json_encode($this->toArray()); + } + + /** + * Build to array. + * + * @return array + */ + public function toArray() + { + $content = $this->removeControlCharacters($this->getBodyContents()); + + if (false !== stripos($this->getHeaderLine('Content-Type'), 'xml') || 0 === stripos($content, 'toArray()); + } + + /** + * @return object + */ + public function toObject() + { + return json_decode($this->toJson()); + } + + /** + * @return bool|string + */ + public function __toString() + { + return $this->getBodyContents(); + } + + /** + * @param string $content + * + * @return string + */ + protected function removeControlCharacters(string $content) + { + return \preg_replace('/[\x00-\x1F\x80-\x9F]/u', '', $content); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/StreamResponse.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/StreamResponse.php new file mode 100644 index 0000000..104e8c3 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Http/StreamResponse.php @@ -0,0 +1,86 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Http; + +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\Exceptions\RuntimeException; +use EasyWeChat\Kernel\Support\File; + +/** + * Class StreamResponse. + * + * @author overtrue + */ +class StreamResponse extends Response +{ + /** + * @param string $directory + * @param string $filename + * @param bool $appendSuffix + * + * @return bool|int + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function save(string $directory, string $filename = '', bool $appendSuffix = true) + { + $this->getBody()->rewind(); + + $directory = rtrim($directory, '/'); + + if (!is_dir($directory)) { + mkdir($directory, 0755, true); // @codeCoverageIgnore + } + + if (!is_writable($directory)) { + throw new InvalidArgumentException(sprintf("'%s' is not writable.", $directory)); + } + + $contents = $this->getBody()->getContents(); + + if (empty($contents) || '{' === $contents[0]) { + throw new RuntimeException('Invalid media response content.'); + } + + if (empty($filename)) { + if (preg_match('/filename="(?.*?)"/', $this->getHeaderLine('Content-Disposition'), $match)) { + $filename = $match['filename']; + } else { + $filename = md5($contents); + } + } + + if ($appendSuffix && empty(pathinfo($filename, PATHINFO_EXTENSION))) { + $filename .= File::getStreamExt($contents); + } + + file_put_contents($directory.'/'.$filename, $contents); + + return $filename; + } + + /** + * @param string $directory + * @param string $filename + * @param bool $appendSuffix + * + * @return bool|int + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public function saveAs(string $directory, string $filename, bool $appendSuffix = true) + { + return $this->save($directory, $filename, $appendSuffix); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Article.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Article.php new file mode 100644 index 0000000..4792a1f --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Article.php @@ -0,0 +1,58 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Article. + */ +class Article extends Message +{ + /** + * @var string + */ + protected $type = 'mpnews'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'thumb_media_id', + 'author', + 'title', + 'content', + 'digest', + 'source_url', + 'show_cover', + ]; + + /** + * Aliases of attribute. + * + * @var array + */ + protected $jsonAliases = [ + 'content_source_url' => 'source_url', + 'show_cover_pic' => 'show_cover', + ]; + + /** + * @var array + */ + protected $required = [ + 'thumb_media_id', + 'title', + 'content', + 'show_cover', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Card.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Card.php new file mode 100644 index 0000000..0e21231 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Card.php @@ -0,0 +1,52 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * Card.php. + * + * @author overtrue + * @copyright 2015 overtrue + * + * @see https://github.com/overtrue + * @see http://overtrue.me + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Card. + */ +class Card extends Message +{ + /** + * Message type. + * + * @var string + */ + protected $type = 'wxcard'; + + /** + * Properties. + * + * @var array + */ + protected $properties = ['card_id']; + + /** + * Media constructor. + * + * @param string $cardId + */ + public function __construct(string $cardId) + { + parent::__construct(['card_id' => $cardId]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceEvent.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceEvent.php new file mode 100644 index 0000000..ae57910 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceEvent.php @@ -0,0 +1,40 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class DeviceEvent. + * + * @property string $media_id + */ +class DeviceEvent extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'device_event'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'device_type', + 'device_id', + 'content', + 'session_id', + 'open_id', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceText.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceText.php new file mode 100644 index 0000000..87e627a --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/DeviceText.php @@ -0,0 +1,50 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class DeviceText. + * + * @property string $content + */ +class DeviceText extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'device_text'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'device_type', + 'device_id', + 'content', + 'session_id', + 'open_id', + ]; + + public function toXmlArray() + { + return [ + 'DeviceType' => $this->get('device_type'), + 'DeviceID' => $this->get('device_id'), + 'SessionID' => $this->get('session_id'), + 'Content' => base64_encode($this->get('content')), + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/File.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/File.php new file mode 100644 index 0000000..a14c42f --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/File.php @@ -0,0 +1,25 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Image. + * + * @property string $media_id + */ +class File extends Media +{ + /** + * @var string + */ + protected $type = 'file'; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Image.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Image.php new file mode 100644 index 0000000..982033b --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Image.php @@ -0,0 +1,27 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Image. + * + * @property string $media_id + */ +class Image extends Media +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'image'; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Link.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Link.php new file mode 100644 index 0000000..9c126b5 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Link.php @@ -0,0 +1,36 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Link. + */ +class Link extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'link'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'title', + 'description', + 'url', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Location.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Location.php new file mode 100644 index 0000000..f10351b --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Location.php @@ -0,0 +1,38 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Location. + */ +class Location extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'location'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'latitude', + 'longitude', + 'scale', + 'label', + 'precision', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Media.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Media.php new file mode 100644 index 0000000..d8706fe --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Media.php @@ -0,0 +1,70 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +use EasyWeChat\Kernel\Contracts\MediaInterface; +use EasyWeChat\Kernel\Support\Str; + +/** + * Class Media. + */ +class Media extends Message implements MediaInterface +{ + /** + * Properties. + * + * @var array + */ + protected $properties = ['media_id']; + + /** + * @var array + */ + protected $required = [ + 'media_id', + ]; + + /** + * MaterialClient constructor. + * + * @param string $mediaId + * @param string $type + * @param array $attributes + */ + public function __construct(string $mediaId, $type = null, array $attributes = []) + { + parent::__construct(array_merge(['media_id' => $mediaId], $attributes)); + + !empty($type) && $this->setType($type); + } + + /** + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function getMediaId(): string + { + $this->checkRequiredAttributes(); + + return $this->get('media_id'); + } + + public function toXmlArray() + { + return [ + Str::studly($this->getType()) => [ + 'MediaId' => $this->get('media_id'), + ], + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Message.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Message.php new file mode 100644 index 0000000..0c22aac --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Message.php @@ -0,0 +1,208 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +use EasyWeChat\Kernel\Contracts\MessageInterface; +use EasyWeChat\Kernel\Support\XML; +use EasyWeChat\Kernel\Traits\HasAttributes; +use Mockery\Exception\BadMethodCallException; + +/** + * Class Messages. + */ +abstract class Message implements MessageInterface +{ + use HasAttributes; + + const TEXT = 2; + const IMAGE = 4; + const VOICE = 8; + const VIDEO = 16; + const SHORT_VIDEO = 32; + const LOCATION = 64; + const LINK = 128; + const DEVICE_EVENT = 256; + const DEVICE_TEXT = 512; + const FILE = 1024; + const TEXT_CARD = 2048; + const TRANSFER = 4096; + const EVENT = 1048576; + const MINIPROGRAM_PAGE = 2097152; + const ALL = self::TEXT | self::IMAGE | self::VOICE | self::VIDEO | self::SHORT_VIDEO | self::LOCATION | self::LINK + | self::DEVICE_EVENT | self::DEVICE_TEXT | self::FILE | self::TEXT_CARD | self::TRANSFER | self::EVENT | self::MINIPROGRAM_PAGE; + + /** + * @var string + */ + protected $type; + + /** + * @var int + */ + protected $id; + + /** + * @var string + */ + protected $to; + + /** + * @var string + */ + protected $from; + + /** + * @var array + */ + protected $properties = []; + + /** + * @var array + */ + protected $jsonAliases = []; + + /** + * Message constructor. + * + * @param array $attributes + */ + public function __construct(array $attributes = []) + { + $this->setAttributes($attributes); + } + + /** + * Return type name message. + * + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @param string $type + */ + public function setType(string $type) + { + $this->type = $type; + } + + /** + * Magic getter. + * + * @param string $property + * + * @return mixed + */ + public function __get($property) + { + if (property_exists($this, $property)) { + return $this->$property; + } + + return $this->getAttribute($property); + } + + /** + * Magic setter. + * + * @param string $property + * @param mixed $value + * + * @return Message + */ + public function __set($property, $value) + { + if (property_exists($this, $property)) { + $this->$property = $value; + } else { + $this->setAttribute($property, $value); + } + + return $this; + } + + /** + * @param array $appends + * + * @return array + */ + public function transformForJsonRequestWithoutType(array $appends = []) + { + return $this->transformForJsonRequest($appends, false); + } + + /** + * @param array $appends + * @param bool $withType + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function transformForJsonRequest(array $appends = [], $withType = true): array + { + if (!$withType) { + return $this->propertiesToArray([], $this->jsonAliases); + } + $messageType = $this->getType(); + $data = array_merge(['msgtype' => $messageType], $appends); + + $data[$messageType] = array_merge($data[$messageType] ?? [], $this->propertiesToArray([], $this->jsonAliases)); + + return $data; + } + + /** + * @param array $appends + * @param bool $returnAsArray + * + * @return string + */ + public function transformToXml(array $appends = [], bool $returnAsArray = false): string + { + $data = array_merge(['MsgType' => $this->getType()], $this->toXmlArray(), $appends); + + return $returnAsArray ? $data : XML::build($data); + } + + /** + * @param array $data + * @param array $aliases + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + protected function propertiesToArray(array $data, array $aliases = []): array + { + $this->checkRequiredAttributes(); + + foreach ($this->attributes as $property => $value) { + if (is_null($value) && !$this->isRequired($property)) { + continue; + } + $alias = array_search($property, $aliases, true); + + $data[$alias ?: $property] = $this->get($property); + } + + return $data; + } + + public function toXmlArray() + { + throw new BadMethodCallException(sprintf('Class "%s" cannot support transform to XML message.', __CLASS__)); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/MiniProgramPage.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/MiniProgramPage.php new file mode 100644 index 0000000..e4973b1 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/MiniProgramPage.php @@ -0,0 +1,31 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class MiniProgramPage. + */ +class MiniProgramPage extends Message +{ + protected $type = 'miniprogrampage'; + + protected $properties = [ + 'title', + 'appid', + 'pagepath', + 'thumb_media_id', + ]; + + protected $required = [ + 'thumb_media_id', 'appid', 'pagepath', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Music.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Music.php new file mode 100644 index 0000000..85feb76 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Music.php @@ -0,0 +1,73 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Music. + * + * @property string $url + * @property string $hq_url + * @property string $title + * @property string $description + * @property string $thumb_media_id + * @property string $format + */ +class Music extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'music'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'title', + 'description', + 'url', + 'hq_url', + 'thumb_media_id', + 'format', + ]; + + /** + * Aliases of attribute. + * + * @var array + */ + protected $jsonAliases = [ + 'musicurl' => 'url', + 'hqmusicurl' => 'hq_url', + ]; + + public function toXmlArray() + { + $music = [ + 'Music' => [ + 'Title' => $this->get('title'), + 'Description' => $this->get('description'), + 'MusicUrl' => $this->get('url'), + 'HQMusicUrl' => $this->get('hq_url'), + ], + ]; + if ($thumbMediaId = $this->get('thumb_media_id')) { + $music['Music']['ThumbMediaId'] = $thumbMediaId; + } + + return $music; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/News.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/News.php new file mode 100644 index 0000000..2ad46e8 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/News.php @@ -0,0 +1,73 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class News. + * + * @author overtrue + */ +class News extends Message +{ + /** + * @var string + */ + protected $type = 'news'; + + /** + * @var array + */ + protected $properties = [ + 'items', + ]; + + /** + * News constructor. + * + * @param array $items + */ + public function __construct(array $items = []) + { + parent::__construct(compact('items')); + } + + /** + * @param array $data + * @param array $aliases + * + * @return array + */ + public function propertiesToArray(array $data, array $aliases = []): array + { + return ['articles' => array_map(function ($item) { + if ($item instanceof NewsItem) { + return $item->toJsonArray(); + } + }, $this->get('items'))]; + } + + public function toXmlArray() + { + $items = []; + + foreach ($this->get('items') as $item) { + if ($item instanceof NewsItem) { + $items[] = $item->toXmlArray(); + } + } + + return [ + 'ArticleCount' => count($items), + 'Articles' => $items, + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/NewsItem.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/NewsItem.php new file mode 100644 index 0000000..50bf336 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/NewsItem.php @@ -0,0 +1,57 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class NewsItem. + */ +class NewsItem extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'news'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'title', + 'description', + 'url', + 'image', + ]; + + public function toJsonArray() + { + return [ + 'title' => $this->get('title'), + 'description' => $this->get('description'), + 'url' => $this->get('url'), + 'picurl' => $this->get('image'), + ]; + } + + public function toXmlArray() + { + return [ + 'Title' => $this->get('title'), + 'Description' => $this->get('description'), + 'Url' => $this->get('url'), + 'PicUrl' => $this->get('image'), + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Raw.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Raw.php new file mode 100644 index 0000000..53f2a78 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Raw.php @@ -0,0 +1,56 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Raw. + */ +class Raw extends Message +{ + /** + * @var string + */ + protected $type = 'raw'; + + /** + * Properties. + * + * @var array + */ + protected $properties = ['content']; + + /** + * Constructor. + * + * @param string $content + */ + public function __construct(string $content) + { + parent::__construct(['content' => strval($content)]); + } + + /** + * @param array $appends + * @param bool $withType + * + * @return array + */ + public function transformForJsonRequest(array $appends = [], $withType = true): array + { + return json_decode($this->content, true) ?? []; + } + + public function __toString() + { + return $this->get('content') ?? ''; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/ShortVideo.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/ShortVideo.php new file mode 100644 index 0000000..1dc1db9 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/ShortVideo.php @@ -0,0 +1,30 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class ShortVideo. + * + * @property string $title + * @property string $media_id + * @property string $description + * @property string $thumb_media_id + */ +class ShortVideo extends Video +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'shortvideo'; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TaskCard.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TaskCard.php new file mode 100644 index 0000000..d02c411 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TaskCard.php @@ -0,0 +1,44 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class TaskCard. + * + * @property string $title + * @property string $description + * @property string $url + * @property string $task_id + * @property array $btn + */ +class TaskCard extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'taskcard'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'title', + 'description', + 'url', + 'task_id', + 'btn', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Text.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Text.php new file mode 100644 index 0000000..e355743 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Text.php @@ -0,0 +1,54 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Text. + * + * @property string $content + */ +class Text extends Message +{ + /** + * Message type. + * + * @var string + */ + protected $type = 'text'; + + /** + * Properties. + * + * @var array + */ + protected $properties = ['content']; + + /** + * Text constructor. + * + * @param string $content + */ + public function __construct(string $content) + { + parent::__construct(compact('content')); + } + + /** + * @return array + */ + public function toXmlArray() + { + return [ + 'Content' => $this->get('content'), + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TextCard.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TextCard.php new file mode 100644 index 0000000..edfb7c5 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/TextCard.php @@ -0,0 +1,40 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Text. + * + * @property string $title + * @property string $description + * @property string $url + */ +class TextCard extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'textcard'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'title', + 'description', + 'url', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Transfer.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Transfer.php new file mode 100644 index 0000000..ff27d1a --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Transfer.php @@ -0,0 +1,56 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Transfer. + * + * @property string $to + * @property string $account + */ +class Transfer extends Message +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'transfer_customer_service'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'account', + ]; + + /** + * Transfer constructor. + * + * @param string|null $account + */ + public function __construct(string $account = null) + { + parent::__construct(compact('account')); + } + + public function toXmlArray() + { + return empty($this->get('account')) ? [] : [ + 'TransInfo' => [ + 'KfAccount' => $this->get('account'), + ], + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Video.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Video.php new file mode 100644 index 0000000..90f72a0 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Video.php @@ -0,0 +1,65 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Video. + * + * @property string $video + * @property string $title + * @property string $media_id + * @property string $description + * @property string $thumb_media_id + */ +class Video extends Media +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'video'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'title', + 'description', + 'media_id', + 'thumb_media_id', + ]; + + /** + * Video constructor. + * + * @param string $mediaId + * @param array $attributes + */ + public function __construct(string $mediaId, array $attributes = []) + { + parent::__construct($mediaId, 'video', $attributes); + } + + public function toXmlArray() + { + return [ + 'Video' => [ + 'MediaId' => $this->get('media_id'), + 'Title' => $this->get('title'), + 'Description' => $this->get('description'), + ], + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Voice.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Voice.php new file mode 100644 index 0000000..ff723ea --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Messages/Voice.php @@ -0,0 +1,37 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Messages; + +/** + * Class Voice. + * + * @property string $media_id + */ +class Voice extends Media +{ + /** + * Messages type. + * + * @var string + */ + protected $type = 'voice'; + + /** + * Properties. + * + * @var array + */ + protected $properties = [ + 'media_id', + 'recognition', + ]; +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ConfigServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ConfigServiceProvider.php new file mode 100644 index 0000000..b33f4a1 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ConfigServiceProvider.php @@ -0,0 +1,39 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Providers; + +use EasyWeChat\Kernel\Config; +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ConfigServiceProvider. + * + * @author overtrue + */ +class ConfigServiceProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * This method should only be used to configure services and parameters. + * It should not get services. + * + * @param Container $pimple A container instance + */ + public function register(Container $pimple) + { + $pimple['config'] = function ($app) { + return new Config($app->getConfig()); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/EventDispatcherServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/EventDispatcherServiceProvider.php new file mode 100644 index 0000000..9095cef --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/EventDispatcherServiceProvider.php @@ -0,0 +1,47 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Providers; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; + +/** + * Class EventDispatcherServiceProvider. + * + * @author mingyoung + */ +class EventDispatcherServiceProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * This method should only be used to configure services and parameters. + * It should not get services. + * + * @param Container $pimple A container instance + */ + public function register(Container $pimple) + { + $pimple['events'] = function ($app) { + $dispatcher = new EventDispatcher(); + + foreach ($app->config->get('events.listen', []) as $event => $listeners) { + foreach ($listeners as $listener) { + $dispatcher->addListener($event, $listener); + } + } + + return $dispatcher; + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ExtensionServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ExtensionServiceProvider.php new file mode 100644 index 0000000..23af832 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/ExtensionServiceProvider.php @@ -0,0 +1,39 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Providers; + +use EasyWeChatComposer\Extension; +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ExtensionServiceProvider. + * + * @author overtrue + */ +class ExtensionServiceProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * This method should only be used to configure services and parameters. + * It should not get services. + * + * @param Container $pimple A container instance + */ + public function register(Container $pimple) + { + $pimple['extension'] = function ($app) { + return new Extension($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/HttpClientServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/HttpClientServiceProvider.php new file mode 100644 index 0000000..aca7fa9 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/HttpClientServiceProvider.php @@ -0,0 +1,39 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Providers; + +use GuzzleHttp\Client; +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class HttpClientServiceProvider. + * + * @author overtrue + */ +class HttpClientServiceProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * This method should only be used to configure services and parameters. + * It should not get services. + * + * @param Container $pimple A container instance + */ + public function register(Container $pimple) + { + $pimple['http_client'] = function ($app) { + return new Client($app['config']->get('http', [])); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/LogServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/LogServiceProvider.php new file mode 100644 index 0000000..83498ac --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/LogServiceProvider.php @@ -0,0 +1,79 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Providers; + +use EasyWeChat\Kernel\Log\LogManager; +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class LoggingServiceProvider. + * + * @author overtrue + */ +class LogServiceProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * This method should only be used to configure services and parameters. + * It should not get services. + * + * @param Container $pimple A container instance + */ + public function register(Container $pimple) + { + $pimple['logger'] = $pimple['log'] = function ($app) { + $config = $this->formatLogConfig($app); + + if (!empty($config)) { + $app->rebind('config', $app['config']->merge($config)); + } + + return new LogManager($app); + }; + } + + public function formatLogConfig($app) + { + if (!empty($app['config']->get('log.channels'))) { + return $app['config']->get('log'); + } + + if (empty($app['config']->get('log'))) { + return [ + 'log' => [ + 'default' => 'errorlog', + 'channels' => [ + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], + ], + ], + ]; + } + + return [ + 'log' => [ + 'default' => 'single', + 'channels' => [ + 'single' => [ + 'driver' => 'single', + 'path' => $app['config']->get('log.file') ?: \sys_get_temp_dir().'/logs/easywechat.log', + 'level' => $app['config']->get('log.level', 'debug'), + ], + ], + ], + ]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/RequestServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/RequestServiceProvider.php new file mode 100644 index 0000000..a0b111d --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Providers/RequestServiceProvider.php @@ -0,0 +1,39 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Providers; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; +use Symfony\Component\HttpFoundation\Request; + +/** + * Class RequestServiceProvider. + * + * @author overtrue + */ +class RequestServiceProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * This method should only be used to configure services and parameters. + * It should not get services. + * + * @param Container $pimple A container instance + */ + public function register(Container $pimple) + { + $pimple['request'] = function () { + return Request::createFromGlobals(); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServerGuard.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServerGuard.php new file mode 100644 index 0000000..c135e12 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServerGuard.php @@ -0,0 +1,375 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel; + +use EasyWeChat\Kernel\Contracts\MessageInterface; +use EasyWeChat\Kernel\Exceptions\BadRequestException; +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\Messages\Message; +use EasyWeChat\Kernel\Messages\News; +use EasyWeChat\Kernel\Messages\NewsItem; +use EasyWeChat\Kernel\Messages\Raw as RawMessage; +use EasyWeChat\Kernel\Messages\Text; +use EasyWeChat\Kernel\Support\XML; +use EasyWeChat\Kernel\Traits\Observable; +use EasyWeChat\Kernel\Traits\ResponseCastable; +use Symfony\Component\HttpFoundation\Response; + +/** + * Class ServerGuard. + * + * 1. url 里的 signature 只是将 token+nonce+timestamp 得到的签名,只是用于验证当前请求的,在公众号环境下一直有 + * 2. 企业号消息发送时是没有的,因为固定为完全模式,所以 url 里不会存在 signature, 只有 msg_signature 用于解密消息的 + * + * @author overtrue + */ +class ServerGuard +{ + use Observable; + use ResponseCastable; + + /** + * @var bool + */ + protected $alwaysValidate = false; + + /** + * Empty string. + */ + const SUCCESS_EMPTY_RESPONSE = 'success'; + + /** + * @var array + */ + const MESSAGE_TYPE_MAPPING = [ + 'text' => Message::TEXT, + 'image' => Message::IMAGE, + 'voice' => Message::VOICE, + 'video' => Message::VIDEO, + 'shortvideo' => Message::SHORT_VIDEO, + 'location' => Message::LOCATION, + 'link' => Message::LINK, + 'device_event' => Message::DEVICE_EVENT, + 'device_text' => Message::DEVICE_TEXT, + 'event' => Message::EVENT, + 'file' => Message::FILE, + 'miniprogrampage' => Message::MINIPROGRAM_PAGE, + ]; + + /** + * @var \EasyWeChat\Kernel\ServiceContainer + */ + protected $app; + + /** + * Constructor. + * + * @codeCoverageIgnore + * + * @param \EasyWeChat\Kernel\ServiceContainer $app + */ + public function __construct(ServiceContainer $app) + { + $this->app = $app; + + foreach ($this->app->extension->observers() as $observer) { + call_user_func_array([$this, 'push'], $observer); + } + } + + /** + * Handle and return response. + * + * @return Response + * + * @throws BadRequestException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + public function serve(): Response + { + $this->app['logger']->debug('Request received:', [ + 'method' => $this->app['request']->getMethod(), + 'uri' => $this->app['request']->getUri(), + 'content-type' => $this->app['request']->getContentType(), + 'content' => $this->app['request']->getContent(), + ]); + + $response = $this->validate()->resolve(); + + $this->app['logger']->debug('Server response created:', ['content' => $response->getContent()]); + + return $response; + } + + /** + * @return $this + * + * @throws \EasyWeChat\Kernel\Exceptions\BadRequestException + */ + public function validate() + { + if (!$this->alwaysValidate && !$this->isSafeMode()) { + return $this; + } + + if ($this->app['request']->get('signature') !== $this->signature([ + $this->getToken(), + $this->app['request']->get('timestamp'), + $this->app['request']->get('nonce'), + ])) { + throw new BadRequestException('Invalid request signature.', 400); + } + + return $this; + } + + /** + * Force validate request. + * + * @return $this + */ + public function forceValidate() + { + $this->alwaysValidate = true; + + return $this; + } + + /** + * Get request message. + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|string + * + * @throws BadRequestException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + public function getMessage() + { + $message = $this->parseMessage($this->app['request']->getContent(false)); + + if (!is_array($message) || empty($message)) { + throw new BadRequestException('No message received.'); + } + + if ($this->isSafeMode() && !empty($message['Encrypt'])) { + $message = $this->decryptMessage($message); + + // Handle JSON format. + $dataSet = json_decode($message, true); + + if ($dataSet && (JSON_ERROR_NONE === json_last_error())) { + return $dataSet; + } + + $message = XML::parse($message); + } + + return $this->detectAndCastResponseToType($message, $this->app->config->get('response_type')); + } + + /** + * Resolve server request and return the response. + * + * @return \Symfony\Component\HttpFoundation\Response + * + * @throws \EasyWeChat\Kernel\Exceptions\BadRequestException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + protected function resolve(): Response + { + $result = $this->handleRequest(); + + if ($this->shouldReturnRawResponse()) { + $response = new Response($result['response']); + } else { + $response = new Response( + $this->buildResponse($result['to'], $result['from'], $result['response']), + 200, + ['Content-Type' => 'application/xml'] + ); + } + + $this->app->events->dispatch(new Events\ServerGuardResponseCreated($response)); + + return $response; + } + + /** + * @return string|null + */ + protected function getToken() + { + return $this->app['config']['token']; + } + + /** + * @param string $to + * @param string $from + * @param \EasyWeChat\Kernel\Contracts\MessageInterface|string|int $message + * + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function buildResponse(string $to, string $from, $message) + { + if (empty($message) || self::SUCCESS_EMPTY_RESPONSE === $message) { + return self::SUCCESS_EMPTY_RESPONSE; + } + + if ($message instanceof RawMessage) { + return $message->get('content', self::SUCCESS_EMPTY_RESPONSE); + } + + if (is_string($message) || is_numeric($message)) { + $message = new Text((string) $message); + } + + if (is_array($message) && reset($message) instanceof NewsItem) { + $message = new News($message); + } + + if (!($message instanceof Message)) { + throw new InvalidArgumentException(sprintf('Invalid Messages type "%s".', gettype($message))); + } + + return $this->buildReply($to, $from, $message); + } + + /** + * Handle request. + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\BadRequestException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + protected function handleRequest(): array + { + $castedMessage = $this->getMessage(); + + $messageArray = $this->detectAndCastResponseToType($castedMessage, 'array'); + + $response = $this->dispatch(self::MESSAGE_TYPE_MAPPING[$messageArray['MsgType'] ?? $messageArray['msg_type'] ?? 'text'], $castedMessage); + + return [ + 'to' => $messageArray['FromUserName'] ?? '', + 'from' => $messageArray['ToUserName'] ?? '', + 'response' => $response, + ]; + } + + /** + * Build reply XML. + * + * @param string $to + * @param string $from + * @param \EasyWeChat\Kernel\Contracts\MessageInterface $message + * + * @return string + */ + protected function buildReply(string $to, string $from, MessageInterface $message): string + { + $prepends = [ + 'ToUserName' => $to, + 'FromUserName' => $from, + 'CreateTime' => time(), + 'MsgType' => $message->getType(), + ]; + + $response = $message->transformToXml($prepends); + + if ($this->isSafeMode()) { + $this->app['logger']->debug('Messages safe mode is enabled.'); + $response = $this->app['encryptor']->encrypt($response); + } + + return $response; + } + + /** + * @param array $params + * + * @return string + */ + protected function signature(array $params) + { + sort($params, SORT_STRING); + + return sha1(implode($params)); + } + + /** + * Parse message array from raw php input. + * + * @param string $content + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\BadRequestException + */ + protected function parseMessage($content) + { + try { + if (0 === stripos($content, '<')) { + $content = XML::parse($content); + } else { + // Handle JSON format. + $dataSet = json_decode($content, true); + if ($dataSet && (JSON_ERROR_NONE === json_last_error())) { + $content = $dataSet; + } + } + + return (array) $content; + } catch (\Exception $e) { + throw new BadRequestException(sprintf('Invalid message content:(%s) %s', $e->getCode(), $e->getMessage()), $e->getCode()); + } + } + + /** + * Check the request message safe mode. + * + * @return bool + */ + protected function isSafeMode(): bool + { + return $this->app['request']->get('signature') && 'aes' === $this->app['request']->get('encrypt_type'); + } + + /** + * @return bool + */ + protected function shouldReturnRawResponse(): bool + { + return false; + } + + /** + * @param array $message + * + * @return mixed + */ + protected function decryptMessage(array $message) + { + return $message = $this->app['encryptor']->decrypt( + $message['Encrypt'], + $this->app['request']->get('msg_signature'), + $this->app['request']->get('nonce'), + $this->app['request']->get('timestamp') + ); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServiceContainer.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServiceContainer.php new file mode 100644 index 0000000..af1f35b --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/ServiceContainer.php @@ -0,0 +1,167 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel; + +use EasyWeChat\Kernel\Providers\ConfigServiceProvider; +use EasyWeChat\Kernel\Providers\EventDispatcherServiceProvider; +use EasyWeChat\Kernel\Providers\ExtensionServiceProvider; +use EasyWeChat\Kernel\Providers\HttpClientServiceProvider; +use EasyWeChat\Kernel\Providers\LogServiceProvider; +use EasyWeChat\Kernel\Providers\RequestServiceProvider; +use EasyWeChatComposer\Traits\WithAggregator; +use Pimple\Container; + +/** + * Class ServiceContainer. + * + * @author overtrue + * + * @property \EasyWeChat\Kernel\Config $config + * @property \Symfony\Component\HttpFoundation\Request $request + * @property \GuzzleHttp\Client $http_client + * @property \Monolog\Logger $logger + * @property \Symfony\Component\EventDispatcher\EventDispatcher $events + */ +class ServiceContainer extends Container +{ + use WithAggregator; + + /** + * @var string + */ + protected $id; + + /** + * @var array + */ + protected $providers = []; + + /** + * @var array + */ + protected $defaultConfig = []; + + /** + * @var array + */ + protected $userConfig = []; + + /** + * Constructor. + * + * @param array $config + * @param array $prepends + * @param string|null $id + */ + public function __construct(array $config = [], array $prepends = [], string $id = null) + { + $this->registerProviders($this->getProviders()); + + parent::__construct($prepends); + + $this->userConfig = $config; + + $this->id = $id; + + $this->aggregate(); + + $this->events->dispatch(new Events\ApplicationInitialized($this)); + } + + /** + * @return string + */ + public function getId() + { + return $this->id ?? $this->id = md5(json_encode($this->userConfig)); + } + + /** + * @return array + */ + public function getConfig() + { + $base = [ + // http://docs.guzzlephp.org/en/stable/request-options.html + 'http' => [ + 'timeout' => 30.0, + 'base_uri' => 'https://api.weixin.qq.com/', + ], + ]; + + return array_replace_recursive($base, $this->defaultConfig, $this->userConfig); + } + + /** + * Return all providers. + * + * @return array + */ + public function getProviders() + { + return array_merge([ + ConfigServiceProvider::class, + LogServiceProvider::class, + RequestServiceProvider::class, + HttpClientServiceProvider::class, + ExtensionServiceProvider::class, + EventDispatcherServiceProvider::class, + ], $this->providers); + } + + /** + * @param string $id + * @param mixed $value + */ + public function rebind($id, $value) + { + $this->offsetUnset($id); + $this->offsetSet($id, $value); + } + + /** + * Magic get access. + * + * @param string $id + * + * @return mixed + */ + public function __get($id) + { + if ($this->shouldDelegate($id)) { + return $this->delegateTo($id); + } + + return $this->offsetGet($id); + } + + /** + * Magic set access. + * + * @param string $id + * @param mixed $value + */ + public function __set($id, $value) + { + $this->offsetSet($id, $value); + } + + /** + * @param array $providers + */ + public function registerProviders(array $providers) + { + foreach ($providers as $provider) { + parent::register(new $provider()); + } + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/AES.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/AES.php new file mode 100644 index 0000000..73b1b24 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/AES.php @@ -0,0 +1,85 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +/** + * Class AES. + * + * @author overtrue + */ +class AES +{ + /** + * @param string $text + * @param string $key + * @param string $iv + * @param int $option + * + * @return string + */ + public static function encrypt(string $text, string $key, string $iv, int $option = OPENSSL_RAW_DATA): string + { + self::validateKey($key); + self::validateIv($iv); + + return openssl_encrypt($text, self::getMode($key), $key, $option, $iv); + } + + /** + * @param string $cipherText + * @param string $key + * @param string $iv + * @param int $option + * @param string|null $method + * + * @return string + */ + public static function decrypt(string $cipherText, string $key, string $iv, int $option = OPENSSL_RAW_DATA, $method = null): string + { + self::validateKey($key); + self::validateIv($iv); + + return openssl_decrypt($cipherText, $method ?: self::getMode($key), $key, $option, $iv); + } + + /** + * @param string $key + * + * @return string + */ + public static function getMode($key) + { + return 'aes-'.(8 * strlen($key)).'-cbc'; + } + + /** + * @param string $key + */ + public static function validateKey(string $key) + { + if (!in_array(strlen($key), [16, 24, 32], true)) { + throw new \InvalidArgumentException(sprintf('Key length must be 16, 24, or 32 bytes; got key len (%s).', strlen($key))); + } + } + + /** + * @param string $iv + * + * @throws \InvalidArgumentException + */ + public static function validateIv(string $iv) + { + if (!empty($iv) && 16 !== strlen($iv)) { + throw new \InvalidArgumentException('IV length must be 16 bytes.'); + } + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Arr.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Arr.php new file mode 100644 index 0000000..ac34038 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Arr.php @@ -0,0 +1,466 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +/** + * Array helper from Illuminate\Support\Arr. + */ +class Arr +{ + /** + * Add an element to an array using "dot" notation if it doesn't exist. + * + * @param array $array + * @param string $key + * @param mixed $value + * + * @return array + */ + public static function add(array $array, $key, $value) + { + if (is_null(static::get($array, $key))) { + static::set($array, $key, $value); + } + + return $array; + } + + /** + * Cross join the given arrays, returning all possible permutations. + * + * @param array ...$arrays + * + * @return array + */ + public static function crossJoin(...$arrays) + { + $results = [[]]; + + foreach ($arrays as $index => $array) { + $append = []; + + foreach ($results as $product) { + foreach ($array as $item) { + $product[$index] = $item; + + $append[] = $product; + } + } + + $results = $append; + } + + return $results; + } + + /** + * Divide an array into two arrays. One with keys and the other with values. + * + * @param array $array + * + * @return array + */ + public static function divide(array $array) + { + return [array_keys($array), array_values($array)]; + } + + /** + * Flatten a multi-dimensional associative array with dots. + * + * @param array $array + * @param string $prepend + * + * @return array + */ + public static function dot(array $array, $prepend = '') + { + $results = []; + + foreach ($array as $key => $value) { + if (is_array($value) && !empty($value)) { + $results = array_merge($results, static::dot($value, $prepend.$key.'.')); + } else { + $results[$prepend.$key] = $value; + } + } + + return $results; + } + + /** + * Get all of the given array except for a specified array of items. + * + * @param array $array + * @param array|string $keys + * + * @return array + */ + public static function except(array $array, $keys) + { + static::forget($array, $keys); + + return $array; + } + + /** + * Determine if the given key exists in the provided array. + * + * @param array $array + * @param string|int $key + * + * @return bool + */ + public static function exists(array $array, $key) + { + return array_key_exists($key, $array); + } + + /** + * Return the first element in an array passing a given truth test. + * + * @param array $array + * @param callable|null $callback + * @param mixed $default + * + * @return mixed + */ + public static function first(array $array, callable $callback = null, $default = null) + { + if (is_null($callback)) { + if (empty($array)) { + return $default; + } + + foreach ($array as $item) { + return $item; + } + } + + foreach ($array as $key => $value) { + if (call_user_func($callback, $value, $key)) { + return $value; + } + } + + return $default; + } + + /** + * Return the last element in an array passing a given truth test. + * + * @param array $array + * @param callable|null $callback + * @param mixed $default + * + * @return mixed + */ + public static function last(array $array, callable $callback = null, $default = null) + { + if (is_null($callback)) { + return empty($array) ? $default : end($array); + } + + return static::first(array_reverse($array, true), $callback, $default); + } + + /** + * Flatten a multi-dimensional array into a single level. + * + * @param array $array + * @param int $depth + * + * @return array + */ + public static function flatten(array $array, $depth = INF) + { + return array_reduce($array, function ($result, $item) use ($depth) { + $item = $item instanceof Collection ? $item->all() : $item; + + if (!is_array($item)) { + return array_merge($result, [$item]); + } elseif (1 === $depth) { + return array_merge($result, array_values($item)); + } + + return array_merge($result, static::flatten($item, $depth - 1)); + }, []); + } + + /** + * Remove one or many array items from a given array using "dot" notation. + * + * @param array $array + * @param array|string $keys + */ + public static function forget(array &$array, $keys) + { + $original = &$array; + + $keys = (array) $keys; + + if (0 === count($keys)) { + return; + } + + foreach ($keys as $key) { + // if the exact key exists in the top-level, remove it + if (static::exists($array, $key)) { + unset($array[$key]); + + continue; + } + + $parts = explode('.', $key); + + // clean up before each pass + $array = &$original; + + while (count($parts) > 1) { + $part = array_shift($parts); + + if (isset($array[$part]) && is_array($array[$part])) { + $array = &$array[$part]; + } else { + continue 2; + } + } + + unset($array[array_shift($parts)]); + } + } + + /** + * Get an item from an array using "dot" notation. + * + * @param array $array + * @param string $key + * @param mixed $default + * + * @return mixed + */ + public static function get(array $array, $key, $default = null) + { + if (is_null($key)) { + return $array; + } + + if (static::exists($array, $key)) { + return $array[$key]; + } + + foreach (explode('.', $key) as $segment) { + if (static::exists($array, $segment)) { + $array = $array[$segment]; + } else { + return $default; + } + } + + return $array; + } + + /** + * Check if an item or items exist in an array using "dot" notation. + * + * @param array $array + * @param string|array $keys + * + * @return bool + */ + public static function has(array $array, $keys) + { + if (is_null($keys)) { + return false; + } + + $keys = (array) $keys; + + if (empty($array)) { + return false; + } + + if ($keys === []) { + return false; + } + + foreach ($keys as $key) { + $subKeyArray = $array; + + if (static::exists($array, $key)) { + continue; + } + + foreach (explode('.', $key) as $segment) { + if (static::exists($subKeyArray, $segment)) { + $subKeyArray = $subKeyArray[$segment]; + } else { + return false; + } + } + } + + return true; + } + + /** + * Determines if an array is associative. + * + * An array is "associative" if it doesn't have sequential numerical keys beginning with zero. + * + * @param array $array + * + * @return bool + */ + public static function isAssoc(array $array) + { + $keys = array_keys($array); + + return array_keys($keys) !== $keys; + } + + /** + * Get a subset of the items from the given array. + * + * @param array $array + * @param array|string $keys + * + * @return array + */ + public static function only(array $array, $keys) + { + return array_intersect_key($array, array_flip((array) $keys)); + } + + /** + * Push an item onto the beginning of an array. + * + * @param array $array + * @param mixed $value + * @param mixed $key + * + * @return array + */ + public static function prepend(array $array, $value, $key = null) + { + if (is_null($key)) { + array_unshift($array, $value); + } else { + $array = [$key => $value] + $array; + } + + return $array; + } + + /** + * Get a value from the array, and remove it. + * + * @param array $array + * @param string $key + * @param mixed $default + * + * @return mixed + */ + public static function pull(array &$array, $key, $default = null) + { + $value = static::get($array, $key, $default); + + static::forget($array, $key); + + return $value; + } + + /** + * Get a 1 value from an array. + * + * @param array $array + * @param int|null $amount + * + * @return mixed + * + * @throws \InvalidArgumentException + */ + public static function random(array $array, int $amount = null) + { + if (is_null($amount)) { + return $array[array_rand($array)]; + } + + $keys = array_rand($array, $amount); + + $results = []; + + foreach ((array) $keys as $key) { + $results[] = $array[$key]; + } + + return $results; + } + + /** + * Set an array item to a given value using "dot" notation. + * + * If no key is given to the method, the entire array will be replaced. + * + * @param array $array + * @param string $key + * @param mixed $value + * + * @return array + */ + public static function set(array &$array, string $key, $value) + { + $keys = explode('.', $key); + + while (count($keys) > 1) { + $key = array_shift($keys); + + // If the key doesn't exist at this depth, we will just create an empty array + // to hold the next value, allowing us to create the arrays to hold final + // values at the correct depth. Then we'll keep digging into the array. + if (!isset($array[$key]) || !is_array($array[$key])) { + $array[$key] = []; + } + + $array = &$array[$key]; + } + + $array[array_shift($keys)] = $value; + + return $array; + } + + /** + * Filter the array using the given callback. + * + * @param array $array + * @param callable $callback + * + * @return array + */ + public static function where(array $array, callable $callback) + { + return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH); + } + + /** + * If the given value is not an array, wrap it in one. + * + * @param mixed $value + * + * @return array + */ + public static function wrap($value) + { + return !is_array($value) ? [$value] : $value; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/ArrayAccessible.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/ArrayAccessible.php new file mode 100644 index 0000000..72e0b04 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/ArrayAccessible.php @@ -0,0 +1,66 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +use ArrayAccess; +use ArrayIterator; +use EasyWeChat\Kernel\Contracts\Arrayable; +use IteratorAggregate; + +/** + * Class ArrayAccessible. + * + * @author overtrue + */ +class ArrayAccessible implements ArrayAccess, IteratorAggregate, Arrayable +{ + private $array; + + public function __construct(array $array = []) + { + $this->array = $array; + } + + public function offsetExists($offset) + { + return array_key_exists($offset, $this->array); + } + + public function offsetGet($offset) + { + return $this->array[$offset]; + } + + public function offsetSet($offset, $value) + { + if (null === $offset) { + $this->array[] = $value; + } else { + $this->array[$offset] = $value; + } + } + + public function offsetUnset($offset) + { + unset($this->array[$offset]); + } + + public function getIterator() + { + return new ArrayIterator($this->array); + } + + public function toArray() + { + return $this->array; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Collection.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Collection.php new file mode 100644 index 0000000..adf24ea --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Collection.php @@ -0,0 +1,421 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +use ArrayAccess; +use ArrayIterator; +use Countable; +use EasyWeChat\Kernel\Contracts\Arrayable; +use IteratorAggregate; +use JsonSerializable; +use Serializable; + +/** + * Class Collection. + */ +class Collection implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Serializable, Arrayable +{ + /** + * The collection data. + * + * @var array + */ + protected $items = []; + + /** + * set data. + * + * @param array $items + */ + public function __construct(array $items = []) + { + foreach ($items as $key => $value) { + $this->set($key, $value); + } + } + + /** + * Return all items. + * + * @return array + */ + public function all() + { + return $this->items; + } + + /** + * Return specific items. + * + * @param array $keys + * + * @return \EasyWeChat\Kernel\Support\Collection + */ + public function only(array $keys) + { + $return = []; + + foreach ($keys as $key) { + $value = $this->get($key); + + if (!is_null($value)) { + $return[$key] = $value; + } + } + + return new static($return); + } + + /** + * Get all items except for those with the specified keys. + * + * @param mixed $keys + * + * @return static + */ + public function except($keys) + { + $keys = is_array($keys) ? $keys : func_get_args(); + + return new static(Arr::except($this->items, $keys)); + } + + /** + * Merge data. + * + * @param Collection|array $items + * + * @return \EasyWeChat\Kernel\Support\Collection + */ + public function merge($items) + { + $clone = new static($this->all()); + + foreach ($items as $key => $value) { + $clone->set($key, $value); + } + + return $clone; + } + + /** + * To determine Whether the specified element exists. + * + * @param string $key + * + * @return bool + */ + public function has($key) + { + return !is_null(Arr::get($this->items, $key)); + } + + /** + * Retrieve the first item. + * + * @return mixed + */ + public function first() + { + return reset($this->items); + } + + /** + * Retrieve the last item. + * + * @return bool + */ + public function last() + { + $end = end($this->items); + + reset($this->items); + + return $end; + } + + /** + * add the item value. + * + * @param string $key + * @param mixed $value + */ + public function add($key, $value) + { + Arr::set($this->items, $key, $value); + } + + /** + * Set the item value. + * + * @param string $key + * @param mixed $value + */ + public function set($key, $value) + { + Arr::set($this->items, $key, $value); + } + + /** + * Retrieve item from Collection. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + public function get($key, $default = null) + { + return Arr::get($this->items, $key, $default); + } + + /** + * Remove item form Collection. + * + * @param string $key + */ + public function forget($key) + { + Arr::forget($this->items, $key); + } + + /** + * Build to array. + * + * @return array + */ + public function toArray() + { + return $this->all(); + } + + /** + * Build to json. + * + * @param int $option + * + * @return string + */ + public function toJson($option = JSON_UNESCAPED_UNICODE) + { + return json_encode($this->all(), $option); + } + + /** + * To string. + * + * @return string + */ + public function __toString() + { + return $this->toJson(); + } + + /** + * (PHP 5 >= 5.4.0)
+ * Specify data which should be serialized to JSON. + * + * @see http://php.net/manual/en/jsonserializable.jsonserialize.php + * + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource + */ + public function jsonSerialize() + { + return $this->items; + } + + /** + * (PHP 5 >= 5.1.0)
+ * String representation of object. + * + * @see http://php.net/manual/en/serializable.serialize.php + * + * @return string the string representation of the object or null + */ + public function serialize() + { + return serialize($this->items); + } + + /** + * (PHP 5 >= 5.0.0)
+ * Retrieve an external iterator. + * + * @see http://php.net/manual/en/iteratoraggregate.getiterator.php + * + * @return \ArrayIterator An instance of an object implementing Iterator or + * Traversable + */ + public function getIterator() + { + return new ArrayIterator($this->items); + } + + /** + * (PHP 5 >= 5.1.0)
+ * Count elements of an object. + * + * @see http://php.net/manual/en/countable.count.php + * + * @return int the custom count as an integer. + *

+ *

+ * The return value is cast to an integer + */ + public function count() + { + return count($this->items); + } + + /** + * (PHP 5 >= 5.1.0)
+ * Constructs the object. + * + * @see http://php.net/manual/en/serializable.unserialize.php + * + * @param string $serialized

+ * The string representation of the object. + *

+ * + * @return mixed|void + */ + public function unserialize($serialized) + { + return $this->items = unserialize($serialized); + } + + /** + * Get a data by key. + * + * @param string $key + * + * @return mixed + */ + public function __get($key) + { + return $this->get($key); + } + + /** + * Assigns a value to the specified data. + * + * @param string $key + * @param mixed $value + */ + public function __set($key, $value) + { + $this->set($key, $value); + } + + /** + * Whether or not an data exists by key. + * + * @param string $key + * + * @return bool + */ + public function __isset($key) + { + return $this->has($key); + } + + /** + * Unset an data by key. + * + * @param string $key + */ + public function __unset($key) + { + $this->forget($key); + } + + /** + * var_export. + * + * @return array + */ + public function __set_state() + { + return $this->all(); + } + + /** + * (PHP 5 >= 5.0.0)
+ * Whether a offset exists. + * + * @see http://php.net/manual/en/arrayaccess.offsetexists.php + * + * @param mixed $offset

+ * An offset to check for. + *

+ * + * @return bool true on success or false on failure. + * The return value will be casted to boolean if non-boolean was returned + */ + public function offsetExists($offset) + { + return $this->has($offset); + } + + /** + * (PHP 5 >= 5.0.0)
+ * Offset to unset. + * + * @see http://php.net/manual/en/arrayaccess.offsetunset.php + * + * @param mixed $offset

+ * The offset to unset. + *

+ */ + public function offsetUnset($offset) + { + if ($this->offsetExists($offset)) { + $this->forget($offset); + } + } + + /** + * (PHP 5 >= 5.0.0)
+ * Offset to retrieve. + * + * @see http://php.net/manual/en/arrayaccess.offsetget.php + * + * @param mixed $offset

+ * The offset to retrieve. + *

+ * + * @return mixed Can return all value types + */ + public function offsetGet($offset) + { + return $this->offsetExists($offset) ? $this->get($offset) : null; + } + + /** + * (PHP 5 >= 5.0.0)
+ * Offset to set. + * + * @see http://php.net/manual/en/arrayaccess.offsetset.php + * + * @param mixed $offset

+ * The offset to assign the value to. + *

+ * @param mixed $value

+ * The value to set. + *

+ */ + public function offsetSet($offset, $value) + { + $this->set($offset, $value); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/File.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/File.php new file mode 100644 index 0000000..b51b41d --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/File.php @@ -0,0 +1,135 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +use finfo; + +/** + * Class File. + */ +class File +{ + /** + * MIME mapping. + * + * @var array + */ + protected static $extensionMap = [ + 'audio/wav' => '.wav', + 'audio/x-ms-wma' => '.wma', + 'video/x-ms-wmv' => '.wmv', + 'video/mp4' => '.mp4', + 'audio/mpeg' => '.mp3', + 'audio/amr' => '.amr', + 'application/vnd.rn-realmedia' => '.rm', + 'audio/mid' => '.mid', + 'image/bmp' => '.bmp', + 'image/gif' => '.gif', + 'image/png' => '.png', + 'image/tiff' => '.tiff', + 'image/jpeg' => '.jpg', + 'application/pdf' => '.pdf', + + // 列举更多的文件 mime, 企业号是支持的,公众平台这边之后万一也更新了呢 + 'application/msword' => '.doc', + + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => '.docx', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => '.dotx', + 'application/vnd.ms-word.document.macroEnabled.12' => '.docm', + 'application/vnd.ms-word.template.macroEnabled.12' => '.dotm', + + 'application/vnd.ms-excel' => '.xls', + + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => '.xlsx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => '.xltx', + 'application/vnd.ms-excel.sheet.macroEnabled.12' => '.xlsm', + 'application/vnd.ms-excel.template.macroEnabled.12' => '.xltm', + 'application/vnd.ms-excel.addin.macroEnabled.12' => '.xlam', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' => '.xlsb', + + 'application/vnd.ms-powerpoint' => '.ppt', + + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => '.pptx', + 'application/vnd.openxmlformats-officedocument.presentationml.template' => '.potx', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => '.ppsx', + 'application/vnd.ms-powerpoint.addin.macroEnabled.12' => '.ppam', + ]; + + /** + * File header signatures. + * + * @var array + */ + protected static $signatures = [ + 'ffd8ff' => '.jpg', + '424d' => '.bmp', + '47494638' => '.gif', + '2f55736572732f6f7665' => '.png', + '89504e47' => '.png', + '494433' => '.mp3', + 'fffb' => '.mp3', + 'fff3' => '.mp3', + '3026b2758e66cf11' => '.wma', + '52494646' => '.wav', + '57415645' => '.wav', + '41564920' => '.avi', + '000001ba' => '.mpg', + '000001b3' => '.mpg', + '2321414d52' => '.amr', + '25504446' => '.pdf', + ]; + + /** + * Return steam extension. + * + * @param string $stream + * + * @return string|false + */ + public static function getStreamExt($stream) + { + $ext = self::getExtBySignature($stream); + + try { + if (empty($ext) && is_readable($stream)) { + $stream = file_get_contents($stream); + } + } catch (\Exception $e) { + } + + $fileInfo = new finfo(FILEINFO_MIME); + + $mime = strstr($fileInfo->buffer($stream), ';', true); + + return isset(self::$extensionMap[$mime]) ? self::$extensionMap[$mime] : $ext; + } + + /** + * Get file extension by file header signature. + * + * @param string $stream + * + * @return string + */ + public static function getExtBySignature($stream) + { + $prefix = strval(bin2hex(mb_strcut($stream, 0, 10))); + + foreach (self::$signatures as $signature => $extension) { + if (0 === strpos($prefix, strval($signature))) { + return $extension; + } + } + + return ''; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Helpers.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Helpers.php new file mode 100644 index 0000000..08d4092 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Helpers.php @@ -0,0 +1,131 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +/* + * helpers. + * + * @author overtrue + */ + +/** + * Generate a signature. + * + * @param array $attributes + * @param string $key + * @param string $encryptMethod + * + * @return string + */ +function generate_sign(array $attributes, $key, $encryptMethod = 'md5') +{ + ksort($attributes); + + $attributes['key'] = $key; + + return strtoupper(call_user_func_array($encryptMethod, [urldecode(http_build_query($attributes))])); +} + +/** + * @param string $signType + * @param string $secretKey + * + * @return \Closure|string + */ +function get_encrypt_method(string $signType, string $secretKey = '') +{ + if ('HMAC-SHA256' === $signType) { + return function ($str) use ($secretKey) { + return hash_hmac('sha256', $str, $secretKey); + }; + } + + return 'md5'; +} + +/** + * Get client ip. + * + * @return string + */ +function get_client_ip() +{ + if (!empty($_SERVER['REMOTE_ADDR'])) { + $ip = $_SERVER['REMOTE_ADDR']; + } else { + // for php-cli(phpunit etc.) + $ip = defined('PHPUNIT_RUNNING') ? '127.0.0.1' : gethostbyname(gethostname()); + } + + return filter_var($ip, FILTER_VALIDATE_IP) ?: '127.0.0.1'; +} + +/** + * Get current server ip. + * + * @return string + */ +function get_server_ip() +{ + if (!empty($_SERVER['SERVER_ADDR'])) { + $ip = $_SERVER['SERVER_ADDR']; + } elseif (!empty($_SERVER['SERVER_NAME'])) { + $ip = gethostbyname($_SERVER['SERVER_NAME']); + } else { + // for php-cli(phpunit etc.) + $ip = defined('PHPUNIT_RUNNING') ? '127.0.0.1' : gethostbyname(gethostname()); + } + + return filter_var($ip, FILTER_VALIDATE_IP) ?: '127.0.0.1'; +} + +/** + * Return current url. + * + * @return string + */ +function current_url() +{ + $protocol = 'http://'; + + if ((!empty($_SERVER['HTTPS']) && 'off' !== $_SERVER['HTTPS']) || ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? 'http') === 'https') { + $protocol = 'https://'; + } + + return $protocol.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; +} + +/** + * Return random string. + * + * @param string $length + * + * @return string + */ +function str_random($length) +{ + return Str::random($length); +} + +/** + * @param string $content + * @param string $publicKey + * + * @return string + */ +function rsa_public_encrypt($content, $publicKey) +{ + $encrypted = ''; + openssl_public_encrypt($content, $encrypted, openssl_pkey_get_public($publicKey), OPENSSL_PKCS1_OAEP_PADDING); + + return base64_encode($encrypted); +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Str.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Str.php new file mode 100644 index 0000000..3a51968 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/Str.php @@ -0,0 +1,193 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +use EasyWeChat\Kernel\Exceptions\RuntimeException; + +/** + * Class Str. + */ +class Str +{ + /** + * The cache of snake-cased words. + * + * @var array + */ + protected static $snakeCache = []; + + /** + * The cache of camel-cased words. + * + * @var array + */ + protected static $camelCache = []; + + /** + * The cache of studly-cased words. + * + * @var array + */ + protected static $studlyCache = []; + + /** + * Convert a value to camel case. + * + * @param string $value + * + * @return string + */ + public static function camel($value) + { + if (isset(static::$camelCache[$value])) { + return static::$camelCache[$value]; + } + + return static::$camelCache[$value] = lcfirst(static::studly($value)); + } + + /** + * Generate a more truly "random" alpha-numeric string. + * + * @param int $length + * + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException + */ + public static function random($length = 16) + { + $string = ''; + + while (($len = strlen($string)) < $length) { + $size = $length - $len; + + $bytes = static::randomBytes($size); + + $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size); + } + + return $string; + } + + /** + * Generate a more truly "random" bytes. + * + * @param int $length + * + * @return string + * + * @throws RuntimeException + * + * @codeCoverageIgnore + * + * @throws \Exception + */ + public static function randomBytes($length = 16) + { + if (function_exists('random_bytes')) { + $bytes = random_bytes($length); + } elseif (function_exists('openssl_random_pseudo_bytes')) { + $bytes = openssl_random_pseudo_bytes($length, $strong); + if (false === $bytes || false === $strong) { + throw new RuntimeException('Unable to generate random string.'); + } + } else { + throw new RuntimeException('OpenSSL extension is required for PHP 5 users.'); + } + + return $bytes; + } + + /** + * Generate a "random" alpha-numeric string. + * + * Should not be considered sufficient for cryptography, etc. + * + * @param int $length + * + * @return string + */ + public static function quickRandom($length = 16) + { + $pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + return substr(str_shuffle(str_repeat($pool, $length)), 0, $length); + } + + /** + * Convert the given string to upper-case. + * + * @param string $value + * + * @return string + */ + public static function upper($value) + { + return mb_strtoupper($value); + } + + /** + * Convert the given string to title case. + * + * @param string $value + * + * @return string + */ + public static function title($value) + { + return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8'); + } + + /** + * Convert a string to snake case. + * + * @param string $value + * @param string $delimiter + * + * @return string + */ + public static function snake($value, $delimiter = '_') + { + $key = $value.$delimiter; + + if (isset(static::$snakeCache[$key])) { + return static::$snakeCache[$key]; + } + + if (!ctype_lower($value)) { + $value = strtolower(preg_replace('/(.)(?=[A-Z])/', '$1'.$delimiter, $value)); + } + + return static::$snakeCache[$key] = trim($value, '_'); + } + + /** + * Convert a value to studly caps case. + * + * @param string $value + * + * @return string + */ + public static function studly($value) + { + $key = $value; + + if (isset(static::$studlyCache[$key])) { + return static::$studlyCache[$key]; + } + + $value = ucwords(str_replace(['-', '_'], ' ', $value)); + + return static::$studlyCache[$key] = str_replace(' ', '', $value); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/XML.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/XML.php new file mode 100644 index 0000000..93026e6 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Support/XML.php @@ -0,0 +1,167 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Support; + +use SimpleXMLElement; + +/** + * Class XML. + */ +class XML +{ + /** + * XML to array. + * + * @param string $xml XML string + * + * @return array + */ + public static function parse($xml) + { + $backup = libxml_disable_entity_loader(true); + + $result = self::normalize(simplexml_load_string(self::sanitize($xml), 'SimpleXMLElement', LIBXML_COMPACT | LIBXML_NOCDATA | LIBXML_NOBLANKS)); + + libxml_disable_entity_loader($backup); + + return $result; + } + + /** + * XML encode. + * + * @param mixed $data + * @param string $root + * @param string $item + * @param string $attr + * @param string $id + * + * @return string + */ + public static function build( + $data, + $root = 'xml', + $item = 'item', + $attr = '', + $id = 'id' + ) { + if (is_array($attr)) { + $_attr = []; + + foreach ($attr as $key => $value) { + $_attr[] = "{$key}=\"{$value}\""; + } + + $attr = implode(' ', $_attr); + } + + $attr = trim($attr); + $attr = empty($attr) ? '' : " {$attr}"; + $xml = "<{$root}{$attr}>"; + $xml .= self::data2Xml($data, $item, $id); + $xml .= ""; + + return $xml; + } + + /** + * Build CDATA. + * + * @param string $string + * + * @return string + */ + public static function cdata($string) + { + return sprintf('', $string); + } + + /** + * Object to array. + * + * + * @param SimpleXMLElement $obj + * + * @return array + */ + protected static function normalize($obj) + { + $result = null; + + if (is_object($obj)) { + $obj = (array) $obj; + } + + if (is_array($obj)) { + foreach ($obj as $key => $value) { + $res = self::normalize($value); + if (('@attributes' === $key) && ($key)) { + $result = $res; // @codeCoverageIgnore + } else { + $result[$key] = $res; + } + } + } else { + $result = $obj; + } + + return $result; + } + + /** + * Array to XML. + * + * @param array $data + * @param string $item + * @param string $id + * + * @return string + */ + protected static function data2Xml($data, $item = 'item', $id = 'id') + { + $xml = $attr = ''; + + foreach ($data as $key => $val) { + if (is_numeric($key)) { + $id && $attr = " {$id}=\"{$key}\""; + $key = $item; + } + + $xml .= "<{$key}{$attr}>"; + + if ((is_array($val) || is_object($val))) { + $xml .= self::data2Xml((array) $val, $item, $id); + } else { + $xml .= is_numeric($val) ? $val : self::cdata($val); + } + + $xml .= ""; + } + + return $xml; + } + + /** + * Delete invalid characters in XML. + * + * @see https://www.w3.org/TR/2008/REC-xml-20081126/#charsets - XML charset range + * @see http://php.net/manual/en/regexp.reference.escape.php - escape in UTF-8 mode + * + * @param string $xml + * + * @return string + */ + public static function sanitize($xml) + { + return preg_replace('/[^\x{9}\x{A}\x{D}\x{20}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]+/u', '', $xml); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasAttributes.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasAttributes.php new file mode 100644 index 0000000..238d9e2 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasAttributes.php @@ -0,0 +1,251 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Traits; + +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\Support\Arr; +use EasyWeChat\Kernel\Support\Str; + +/** + * Trait Attributes. + */ +trait HasAttributes +{ + /** + * @var array + */ + protected $attributes = []; + + /** + * @var bool + */ + protected $snakeable = true; + + /** + * Set Attributes. + * + * @param array $attributes + * + * @return $this + */ + public function setAttributes(array $attributes = []) + { + $this->attributes = $attributes; + + return $this; + } + + /** + * Set attribute. + * + * @param string $attribute + * @param string $value + * + * @return $this + */ + public function setAttribute($attribute, $value) + { + Arr::set($this->attributes, $attribute, $value); + + return $this; + } + + /** + * Get attribute. + * + * @param string $attribute + * @param mixed $default + * + * @return mixed + */ + public function getAttribute($attribute, $default = null) + { + return Arr::get($this->attributes, $attribute, $default); + } + + /** + * @param string $attribute + * + * @return bool + */ + public function isRequired($attribute) + { + return in_array($attribute, $this->getRequired(), true); + } + + /** + * @return array|mixed + */ + public function getRequired() + { + return property_exists($this, 'required') ? $this->required : []; + } + + /** + * Set attribute. + * + * @param string $attribute + * @param mixed $value + * + * @return $this + */ + public function with($attribute, $value) + { + $this->snakeable && $attribute = Str::snake($attribute); + + $this->setAttribute($attribute, $value); + + return $this; + } + + /** + * Override parent set() method. + * + * @param string $attribute + * @param mixed $value + * + * @return $this + */ + public function set($attribute, $value) + { + $this->setAttribute($attribute, $value); + + return $this; + } + + /** + * Override parent get() method. + * + * @param string $attribute + * @param mixed $default + * + * @return mixed + */ + public function get($attribute, $default = null) + { + return $this->getAttribute($attribute, $default); + } + + /** + * @param string $key + * + * @return bool + */ + public function has(string $key) + { + return Arr::has($this->attributes, $key); + } + + /** + * @param array $attributes + * + * @return $this + */ + public function merge(array $attributes) + { + $this->attributes = array_merge($this->attributes, $attributes); + + return $this; + } + + /** + * @param array|string $keys + * + * @return array + */ + public function only($keys) + { + return Arr::only($this->attributes, $keys); + } + + /** + * Return all items. + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function all() + { + $this->checkRequiredAttributes(); + + return $this->attributes; + } + + /** + * Magic call. + * + * @param string $method + * @param array $args + * + * @return $this + */ + public function __call($method, $args) + { + if (0 === stripos($method, 'with')) { + return $this->with(substr($method, 4), array_shift($args)); + } + + throw new \BadMethodCallException(sprintf('Method "%s" does not exists.', $method)); + } + + /** + * Magic get. + * + * @param string $property + * + * @return mixed + */ + public function __get($property) + { + return $this->get($property); + } + + /** + * Magic set. + * + * @param string $property + * @param mixed $value + * + * @return $this + */ + public function __set($property, $value) + { + return $this->with($property, $value); + } + + /** + * Whether or not an data exists by key. + * + * @param string $key + * + * @return bool + */ + public function __isset($key) + { + return isset($this->attributes[$key]); + } + + /** + * Check required attributes. + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + protected function checkRequiredAttributes() + { + foreach ($this->getRequired() as $attribute) { + if (is_null($this->get($attribute))) { + throw new InvalidArgumentException(sprintf('"%s" cannot be empty.', $attribute)); + } + } + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasHttpRequests.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasHttpRequests.php new file mode 100644 index 0000000..9bf0a02 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/HasHttpRequests.php @@ -0,0 +1,231 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Traits; + +use GuzzleHttp\Client; +use GuzzleHttp\ClientInterface; +use GuzzleHttp\HandlerStack; +use Psr\Http\Message\ResponseInterface; + +/** + * Trait HasHttpRequests. + * + * @author overtrue + */ +trait HasHttpRequests +{ + use ResponseCastable; + + /** + * @var \GuzzleHttp\ClientInterface + */ + protected $httpClient; + + /** + * @var array + */ + protected $middlewares = []; + + /** + * @var \GuzzleHttp\HandlerStack + */ + protected $handlerStack; + + /** + * @var array + */ + protected static $defaults = [ + 'curl' => [ + CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, + ], + ]; + + /** + * Set guzzle default settings. + * + * @param array $defaults + */ + public static function setDefaultOptions($defaults = []) + { + self::$defaults = $defaults; + } + + /** + * Return current guzzle default settings. + * + * @return array + */ + public static function getDefaultOptions(): array + { + return self::$defaults; + } + + /** + * Set GuzzleHttp\Client. + * + * @param \GuzzleHttp\ClientInterface $httpClient + * + * @return $this + */ + public function setHttpClient(ClientInterface $httpClient) + { + $this->httpClient = $httpClient; + + return $this; + } + + /** + * Return GuzzleHttp\ClientInterface instance. + * + * @return ClientInterface + */ + public function getHttpClient(): ClientInterface + { + if (!($this->httpClient instanceof ClientInterface)) { + if (property_exists($this, 'app') && $this->app['http_client']) { + $this->httpClient = $this->app['http_client']; + } else { + $this->httpClient = new Client(['handler' => HandlerStack::create($this->getGuzzleHandler())]); + } + } + + return $this->httpClient; + } + + /** + * Add a middleware. + * + * @param callable $middleware + * @param string $name + * + * @return $this + */ + public function pushMiddleware(callable $middleware, string $name = null) + { + if (!is_null($name)) { + $this->middlewares[$name] = $middleware; + } else { + array_push($this->middlewares, $middleware); + } + + return $this; + } + + /** + * Return all middlewares. + * + * @return array + */ + public function getMiddlewares(): array + { + return $this->middlewares; + } + + /** + * Make a request. + * + * @param string $url + * @param string $method + * @param array $options + * + * @return \Psr\Http\Message\ResponseInterface + * + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function request($url, $method = 'GET', $options = []): ResponseInterface + { + $method = strtoupper($method); + + $options = array_merge(self::$defaults, $options, ['handler' => $this->getHandlerStack()]); + + $options = $this->fixJsonIssue($options); + + if (property_exists($this, 'baseUri') && !is_null($this->baseUri)) { + $options['base_uri'] = $this->baseUri; + } + + $response = $this->getHttpClient()->request($method, $url, $options); + $response->getBody()->rewind(); + + return $response; + } + + /** + * @param \GuzzleHttp\HandlerStack $handlerStack + * + * @return $this + */ + public function setHandlerStack(HandlerStack $handlerStack) + { + $this->handlerStack = $handlerStack; + + return $this; + } + + /** + * Build a handler stack. + * + * @return \GuzzleHttp\HandlerStack + */ + public function getHandlerStack(): HandlerStack + { + if ($this->handlerStack) { + return $this->handlerStack; + } + + $this->handlerStack = HandlerStack::create($this->getGuzzleHandler()); + + foreach ($this->middlewares as $name => $middleware) { + $this->handlerStack->push($middleware, $name); + } + + return $this->handlerStack; + } + + /** + * @param array $options + * + * @return array + */ + protected function fixJsonIssue(array $options): array + { + if (isset($options['json']) && is_array($options['json'])) { + $options['headers'] = array_merge($options['headers'] ?? [], ['Content-Type' => 'application/json']); + + if (empty($options['json'])) { + $options['body'] = \GuzzleHttp\json_encode($options['json'], JSON_FORCE_OBJECT); + } else { + $options['body'] = \GuzzleHttp\json_encode($options['json'], JSON_UNESCAPED_UNICODE); + } + + unset($options['json']); + } + + return $options; + } + + /** + * Get guzzle handler. + * + * @return callable + */ + protected function getGuzzleHandler() + { + if (property_exists($this, 'app') && isset($this->app['guzzle_handler'])) { + return is_string($handler = $this->app->raw('guzzle_handler')) + ? new $handler() + : $handler; + } + + return \GuzzleHttp\choose_handler(); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/InteractsWithCache.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/InteractsWithCache.php new file mode 100644 index 0000000..fc5182c --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/InteractsWithCache.php @@ -0,0 +1,105 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Traits; + +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\ServiceContainer; +use Psr\Cache\CacheItemPoolInterface; +use Psr\SimpleCache\CacheInterface as SimpleCacheInterface; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\Psr16Cache; +use Symfony\Component\Cache\Simple\FilesystemCache; + +/** + * Trait InteractsWithCache. + * + * @author overtrue + */ +trait InteractsWithCache +{ + /** + * @var \Psr\SimpleCache\CacheInterface + */ + protected $cache; + + /** + * Get cache instance. + * + * @return \Psr\SimpleCache\CacheInterface + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function getCache() + { + if ($this->cache) { + return $this->cache; + } + + if (property_exists($this, 'app') && $this->app instanceof ServiceContainer && isset($this->app['cache'])) { + $this->setCache($this->app['cache']); + + // Fix PHPStan error + assert($this->cache instanceof \Psr\SimpleCache\CacheInterface); + + return $this->cache; + } + + return $this->cache = $this->createDefaultCache(); + } + + /** + * Set cache instance. + * + * @param \Psr\SimpleCache\CacheInterface|\Psr\Cache\CacheItemPoolInterface $cache + * + * @return $this + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function setCache($cache) + { + if (empty(\array_intersect([SimpleCacheInterface::class, CacheItemPoolInterface::class], \class_implements($cache)))) { + throw new InvalidArgumentException(\sprintf('The cache instance must implements %s or %s interface.', SimpleCacheInterface::class, CacheItemPoolInterface::class)); + } + + if ($cache instanceof CacheItemPoolInterface) { + if (!$this->isSymfony43()) { + throw new InvalidArgumentException(sprintf('The cache instance must implements %s', SimpleCacheInterface::class)); + } + $cache = new Psr16Cache($cache); + } + + $this->cache = $cache; + + return $this; + } + + /** + * @return \Psr\SimpleCache\CacheInterface + */ + protected function createDefaultCache() + { + if ($this->isSymfony43()) { + return new Psr16Cache(new FilesystemAdapter('easywechat', 1500)); + } + + return new FilesystemCache(); + } + + /** + * @return bool + */ + protected function isSymfony43(): bool + { + return \class_exists('Symfony\Component\Cache\Psr16Cache'); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/Observable.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/Observable.php new file mode 100644 index 0000000..7db03f5 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/Observable.php @@ -0,0 +1,273 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Traits; + +use EasyWeChat\Kernel\Clauses\Clause; +use EasyWeChat\Kernel\Contracts\EventHandlerInterface; +use EasyWeChat\Kernel\Decorators\FinallyResult; +use EasyWeChat\Kernel\Decorators\TerminateResult; +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\ServiceContainer; + +/** + * Trait Observable. + * + * @author overtrue + */ +trait Observable +{ + /** + * @var array + */ + protected $handlers = []; + + /** + * @var array + */ + protected $clauses = []; + + /** + * @param \Closure|EventHandlerInterface|callable|string $handler + * @param \Closure|EventHandlerInterface|callable|string $condition + * + * @return \EasyWeChat\Kernel\Clauses\Clause + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \ReflectionException + */ + public function push($handler, $condition = '*') + { + list($handler, $condition) = $this->resolveHandlerAndCondition($handler, $condition); + + if (!isset($this->handlers[$condition])) { + $this->handlers[$condition] = []; + } + + array_push($this->handlers[$condition], $handler); + + return $this->newClause($handler); + } + + /** + * @param \Closure|EventHandlerInterface|string $handler + * @param \Closure|EventHandlerInterface|string $condition + * + * @return \EasyWeChat\Kernel\Clauses\Clause + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \ReflectionException + */ + public function unshift($handler, $condition = '*') + { + list($handler, $condition) = $this->resolveHandlerAndCondition($handler, $condition); + + if (!isset($this->handlers[$condition])) { + $this->handlers[$condition] = []; + } + + array_unshift($this->handlers[$condition], $handler); + + return $this->newClause($handler); + } + + /** + * @param string $condition + * @param \Closure|EventHandlerInterface|string $handler + * + * @return \EasyWeChat\Kernel\Clauses\Clause + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \ReflectionException + */ + public function observe($condition, $handler) + { + return $this->push($handler, $condition); + } + + /** + * @param string $condition + * @param \Closure|EventHandlerInterface|string $handler + * + * @return \EasyWeChat\Kernel\Clauses\Clause + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \ReflectionException + */ + public function on($condition, $handler) + { + return $this->push($handler, $condition); + } + + /** + * @param string|int $event + * @param mixed ...$payload + * + * @return mixed|null + */ + public function dispatch($event, $payload) + { + return $this->notify($event, $payload); + } + + /** + * @param string|int $event + * @param mixed ...$payload + * + * @return mixed|null + */ + public function notify($event, $payload) + { + $result = null; + + foreach ($this->handlers as $condition => $handlers) { + if ('*' === $condition || ($condition & $event) === $event) { + foreach ($handlers as $handler) { + if ($clause = $this->clauses[$this->getHandlerHash($handler)] ?? null) { + if ($clause->intercepted($payload)) { + continue; + } + } + + $response = $this->callHandler($handler, $payload); + + switch (true) { + case $response instanceof TerminateResult: + return $response->content; + case true === $response: + continue 2; + case false === $response: + break 2; + case !empty($response) && !($result instanceof FinallyResult): + $result = $response; + } + } + } + } + + return $result instanceof FinallyResult ? $result->content : $result; + } + + /** + * @return array + */ + public function getHandlers() + { + return $this->handlers; + } + + /** + * @param mixed $handler + * + * @return \EasyWeChat\Kernel\Clauses\Clause + */ + protected function newClause($handler): Clause + { + return $this->clauses[$this->getHandlerHash($handler)] = new Clause(); + } + + /** + * @param mixed $handler + * + * @return string + */ + protected function getHandlerHash($handler) + { + if (is_string($handler)) { + return $handler; + } + + if (is_array($handler)) { + return is_string($handler[0]) + ? $handler[0].'::'.$handler[1] + : get_class($handler[0]).$handler[1]; + } + + return spl_object_hash($handler); + } + + /** + * @param callable $handler + * @param mixed $payload + * + * @return mixed + */ + protected function callHandler(callable $handler, $payload) + { + try { + return call_user_func_array($handler, [$payload]); + } catch (\Exception $e) { + if (property_exists($this, 'app') && $this->app instanceof ServiceContainer) { + $this->app['logger']->error($e->getCode().': '.$e->getMessage(), [ + 'code' => $e->getCode(), + 'message' => $e->getMessage(), + 'file' => $e->getFile(), + 'line' => $e->getLine(), + ]); + } + } + } + + /** + * @param mixed $handler + * + * @return \Closure + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \ReflectionException + */ + protected function makeClosure($handler) + { + if (is_callable($handler)) { + return $handler; + } + + if (is_string($handler) && '*' !== $handler) { + if (!class_exists($handler)) { + throw new InvalidArgumentException(sprintf('Class "%s" not exists.', $handler)); + } + + if (!in_array(EventHandlerInterface::class, (new \ReflectionClass($handler))->getInterfaceNames(), true)) { + throw new InvalidArgumentException(sprintf('Class "%s" not an instance of "%s".', $handler, EventHandlerInterface::class)); + } + + return function ($payload) use ($handler) { + return (new $handler($this->app ?? null))->handle($payload); + }; + } + + if ($handler instanceof EventHandlerInterface) { + return function () use ($handler) { + return $handler->handle(...func_get_args()); + }; + } + + throw new InvalidArgumentException('No valid handler is found in arguments.'); + } + + /** + * @param mixed $handler + * @param mixed $condition + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \ReflectionException + */ + protected function resolveHandlerAndCondition($handler, $condition): array + { + if (is_int($handler) || (is_string($handler) && !class_exists($handler))) { + list($handler, $condition) = [$condition, $handler]; + } + + return [$this->makeClosure($handler), $condition]; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/ResponseCastable.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/ResponseCastable.php new file mode 100644 index 0000000..5492bd4 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/Kernel/Traits/ResponseCastable.php @@ -0,0 +1,93 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\Kernel\Traits; + +use EasyWeChat\Kernel\Contracts\Arrayable; +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\Exceptions\InvalidConfigException; +use EasyWeChat\Kernel\Http\Response; +use EasyWeChat\Kernel\Support\Collection; +use Psr\Http\Message\ResponseInterface; + +/** + * Trait ResponseCastable. + * + * @author overtrue + */ +trait ResponseCastable +{ + /** + * @param \Psr\Http\Message\ResponseInterface $response + * @param string|null $type + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + protected function castResponseToType(ResponseInterface $response, $type = null) + { + $response = Response::buildFromPsrResponse($response); + $response->getBody()->rewind(); + + switch ($type ?? 'array') { + case 'collection': + return $response->toCollection(); + case 'array': + return $response->toArray(); + case 'object': + return $response->toObject(); + case 'raw': + return $response; + default: + if (!is_subclass_of($type, Arrayable::class)) { + throw new InvalidConfigException(sprintf('Config key "response_type" classname must be an instanceof %s', Arrayable::class)); + } + + return new $type($response); + } + } + + /** + * @param mixed $response + * @param string|null $type + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + protected function detectAndCastResponseToType($response, $type = null) + { + switch (true) { + case $response instanceof ResponseInterface: + $response = Response::buildFromPsrResponse($response); + + break; + case $response instanceof Arrayable: + $response = new Response(200, [], json_encode($response->toArray())); + + break; + case ($response instanceof Collection) || is_array($response) || is_object($response): + $response = new Response(200, [], json_encode($response)); + + break; + case is_scalar($response): + $response = new Response(200, [], (string) $response); + + break; + default: + throw new InvalidArgumentException(sprintf('Unsupported response type "%s"', gettype($response))); + } + + return $this->castResponseToType($response, $type); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Application.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Application.php new file mode 100644 index 0000000..9bf8196 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Application.php @@ -0,0 +1,171 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant; + +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\ServiceContainer; +use EasyWeChat\Kernel\Support; +use EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidSignException; + +/** + * Class Application. + * + * @author liuml + * + * @property \EasyWeChat\MicroMerchant\Certficates\Client $certficates + * @property \EasyWeChat\MicroMerchant\Material\Client $material + * @property \EasyWeChat\MicroMerchant\MerchantConfig\Client $merchantConfig + * @property \EasyWeChat\MicroMerchant\Withdraw\Client $withdraw + * @property \EasyWeChat\MicroMerchant\Media\Client $media + * + * @method mixed submitApplication(array $params) + * @method mixed getStatus(string $applymentId, string $businessCode = '') + * @method mixed upgrade(array $params) + * @method mixed getUpgradeStatus(string $subMchId = '') + */ +class Application extends ServiceContainer +{ + /** + * @var array + */ + protected $providers = [ + // Base services + Base\ServiceProvider::class, + Certficates\ServiceProvider::class, + MerchantConfig\ServiceProvider::class, + Material\ServiceProvider::class, + Withdraw\ServiceProvider::class, + Media\ServiceProvider::class, + ]; + + /** + * @var array + */ + protected $defaultConfig = [ + 'http' => [ + 'base_uri' => 'https://api.mch.weixin.qq.com/', + ], + 'log' => [ + 'default' => 'dev', // 默认使用的 channel,生产环境可以改为下面的 prod + 'channels' => [ + // 测试环境 + 'dev' => [ + 'driver' => 'single', + 'path' => '/tmp/easywechat.log', + 'level' => 'debug', + ], + // 生产环境 + 'prod' => [ + 'driver' => 'daily', + 'path' => '/tmp/easywechat.log', + 'level' => 'info', + ], + ], + ], + ]; + + /** + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + public function getKey() + { + $key = $this['config']->key; + + if (empty($key)) { + throw new InvalidArgumentException('config key connot be empty.'); + } + + if (32 !== strlen($key)) { + throw new InvalidArgumentException(sprintf("'%s' should be 32 chars length.", $key)); + } + + return $key; + } + + /** + * set sub-mch-id and appid. + * + * @param string $subMchId Identification Number of Small and Micro Businessmen Reported by Service Providers + * @param string $appId Public Account ID of Service Provider + * + * @return $this + */ + public function setSubMchId(string $subMchId, string $appId = '') + { + $this['config']->set('sub_mch_id', $subMchId); + $this['config']->set('appid', $appId); + + return $this; + } + + /** + * setCertificate. + * + * @param string $certificate + * @param string $serialNo + * + * @return $this + */ + public function setCertificate(string $certificate, string $serialNo) + { + $this['config']->set('certificate', $certificate); + $this['config']->set('serial_no', $serialNo); + + return $this; + } + + /** + * Returning true indicates that the verification is successful, + * returning false indicates that the signature field does not exist or is empty, + * and if the signature verification is wrong, the InvalidSignException will be thrown directly. + * + * @param array $data + * + * @return bool + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidSignException + */ + public function verifySignature(array $data) + { + if (!isset($data['sign']) || empty($data['sign'])) { + return false; + } + + $sign = $data['sign']; + unset($data['sign']); + + $signType = strlen($sign) > 32 ? 'HMAC-SHA256' : 'MD5'; + $secretKey = $this->getKey(); + + $encryptMethod = Support\get_encrypt_method($signType, $secretKey); + + if (Support\generate_sign($data, $secretKey, $encryptMethod) === $sign) { + return true; + } + + throw new InvalidSignException('return value signature verification error'); + } + + /** + * @param string $name + * @param array $arguments + * + * @return mixed + */ + public function __call($name, $arguments) + { + return call_user_func_array([$this['base'], $name], $arguments); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/Client.php new file mode 100644 index 0000000..ba92756 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/Client.php @@ -0,0 +1,126 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Base; + +use EasyWeChat\MicroMerchant\Kernel\BaseClient; + +/** + * Class Client. + * + * @author liuml + * @DateTime 2019-05-30 14:19 + */ +class Client extends BaseClient +{ + /** + * apply to settle in to become a small micro merchant. + * + * @param array $params + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\EncryptException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function submitApplication(array $params) + { + $params = $this->processParams(array_merge($params, [ + 'version' => '3.0', + 'cert_sn' => '', + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + ])); + + return $this->safeRequest('applyment/micro/submit', $params); + } + + /** + * query application status. + * + * @param string $applymentId + * @param string $businessCode + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getStatus(string $applymentId, string $businessCode = '') + { + if (!empty($applymentId)) { + $params = [ + 'applyment_id' => $applymentId, + ]; + } else { + $params = [ + 'business_code' => $businessCode, + ]; + } + + $params = array_merge($params, [ + 'version' => '1.0', + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + ]); + + return $this->safeRequest('applyment/micro/getstate', $params); + } + + /** + * merchant upgrade api. + * + * @param array $params + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\EncryptException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function upgrade(array $params) + { + $params['sub_mch_id'] = $params['sub_mch_id'] ?? $this->app['config']->sub_mch_id; + $params = $this->processParams(array_merge($params, [ + 'version' => '1.0', + 'cert_sn' => '', + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + ])); + + return $this->safeRequest('applyment/micro/submitupgrade', $params); + } + + /** + * get upgrade status. + * + * @param string $subMchId + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getUpgradeStatus(string $subMchId = '') + { + return $this->safeRequest('applyment/micro/getupgradestate', [ + 'version' => '1.0', + 'sign_type' => 'HMAC-SHA256', + 'sub_mch_id' => $subMchId ?: $this->app['config']->sub_mch_id, + 'nonce_str' => uniqid('micro'), + ]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/ServiceProvider.php new file mode 100644 index 0000000..db2f056 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Base/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Base; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['base'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/Client.php new file mode 100644 index 0000000..9731703 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/Client.php @@ -0,0 +1,93 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Certficates; + +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\MicroMerchant\Kernel\BaseClient; +use EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidExtensionException; + +/** + * Class Client. + * + * @author liuml + * @DateTime 2019-05-30 14:19 + */ +class Client extends BaseClient +{ + /** + * get certficates. + * + * @param bool $returnRaw + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidExtensionException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function get(bool $returnRaw = false) + { + $params = [ + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + ]; + + if (true === $returnRaw) { + return $this->requestRaw('risk/getcertficates', $params); + } + /** @var array $response */ + $response = $this->requestArray('risk/getcertficates', $params); + + if ('SUCCESS' !== $response['return_code']) { + throw new InvalidArgumentException(sprintf('Failed to get certificate. return_code_msg: "%s" .', $response['return_code'].'('.$response['return_msg'].')')); + } + if ('SUCCESS' !== $response['result_code']) { + throw new InvalidArgumentException(sprintf('Failed to get certificate. result_err_code_des: "%s" .', $response['result_code'].'('.$response['err_code'].'['.$response['err_code_des'].'])')); + } + $certificates = \GuzzleHttp\json_decode($response['certificates'], true)['data'][0]; + $ciphertext = $this->decrypt($certificates['encrypt_certificate']); + unset($certificates['encrypt_certificate']); + $certificates['certificates'] = $ciphertext; + + return $certificates; + } + + /** + * decrypt ciphertext. + * + * @param array $encryptCertificate + * + * @return string + * + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidExtensionException + */ + public function decrypt(array $encryptCertificate) + { + if (false === extension_loaded('sodium')) { + throw new InvalidExtensionException('sodium extension is not installed,Reference link https://php.net/manual/zh/book.sodium.php'); + } + + if (false === sodium_crypto_aead_aes256gcm_is_available()) { + throw new InvalidExtensionException('aes256gcm is not currently supported'); + } + + // sodium_crypto_aead_aes256gcm_decrypt function needs to open libsodium extension. + // https://www.php.net/manual/zh/function.sodium-crypto-aead-aes256gcm-decrypt.php + return sodium_crypto_aead_aes256gcm_decrypt( + base64_decode($encryptCertificate['ciphertext'], true), + $encryptCertificate['associated_data'], + $encryptCertificate['nonce'], + $this->app['config']->apiv3_key + ); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/ServiceProvider.php new file mode 100644 index 0000000..2e88b7e --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Certficates/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Certficates; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['certficates'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/BaseClient.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/BaseClient.php new file mode 100644 index 0000000..d91b467 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/BaseClient.php @@ -0,0 +1,256 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Kernel; + +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\Kernel\Support; +use EasyWeChat\MicroMerchant\Application; +use EasyWeChat\MicroMerchant\Kernel\Exceptions\EncryptException; +use EasyWeChat\Payment\Kernel\BaseClient as PaymentBaseClient; + +/** + * Class BaseClient. + * + * @author liuml + * @DateTime 2019-07-10 12:06 + */ +class BaseClient extends PaymentBaseClient +{ + /** + * @var string + */ + protected $certificates; + + /** + * BaseClient constructor. + * + * @param \EasyWeChat\MicroMerchant\Application $app + */ + public function __construct(Application $app) + { + $this->app = $app; + + $this->setHttpClient($this->app['http_client']); + } + + /** + * Extra request params. + * + * @return array + */ + protected function prepends() + { + return []; + } + + /** + * httpUpload. + * + * @param string $url + * @param array $files + * @param array $form + * @param array $query + * @param bool $returnResponse + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidSignException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function httpUpload(string $url, array $files = [], array $form = [], array $query = [], $returnResponse = false) + { + $multipart = []; + + foreach ($files as $name => $path) { + $multipart[] = [ + 'name' => $name, + 'contents' => fopen($path, 'r'), + ]; + } + + $base = [ + 'mch_id' => $this->app['config']['mch_id'], + ]; + + $form = array_merge($base, $form); + + $form['sign'] = $this->getSign($form); + + foreach ($form as $name => $contents) { + $multipart[] = compact('name', 'contents'); + } + + $options = [ + 'query' => $query, + 'multipart' => $multipart, + 'connect_timeout' => 30, + 'timeout' => 30, + 'read_timeout' => 30, + 'cert' => $this->app['config']->get('cert_path'), + 'ssl_key' => $this->app['config']->get('key_path'), + ]; + + $this->pushMiddleware($this->logMiddleware(), 'log'); + + $response = $this->performRequest($url, 'POST', $options); + + $result = $returnResponse ? $response : $this->castResponseToType($response, $this->app->config->get('response_type')); + // auto verify signature + if ($returnResponse || 'array' !== ($this->app->config->get('response_type') ?? 'array')) { + $this->app->verifySignature($this->castResponseToType($response, 'array')); + } else { + $this->app->verifySignature($result); + } + + return $result; + } + + /** + * request. + * + * @param string $endpoint + * @param array $params + * @param string $method + * @param array $options + * @param bool $returnResponse + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidSignException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + protected function request(string $endpoint, array $params = [], $method = 'post', array $options = [], $returnResponse = false) + { + $base = [ + 'mch_id' => $this->app['config']['mch_id'], + ]; + + $params = array_merge($base, $this->prepends(), $params); + $params['sign'] = $this->getSign($params); + $options = array_merge([ + 'body' => Support\XML::build($params), + ], $options); + + $this->pushMiddleware($this->logMiddleware(), 'log'); + $response = $this->performRequest($endpoint, $method, $options); + $result = $returnResponse ? $response : $this->castResponseToType($response, $this->app->config->get('response_type')); + // auto verify signature + if ($returnResponse || 'array' !== ($this->app->config->get('response_type') ?? 'array')) { + $this->app->verifySignature($this->castResponseToType($response, 'array')); + } else { + $this->app->verifySignature($result); + } + + return $result; + } + + /** + * processing parameters contain fields that require sensitive information encryption. + * + * @param array $params + * + * @return array + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\EncryptException + */ + protected function processParams(array $params) + { + $serial_no = $this->app['config']->get('serial_no'); + if (null === $serial_no) { + throw new InvalidArgumentException('config serial_no connot be empty.'); + } + + $params['cert_sn'] = $serial_no; + $sensitive_fields = $this->getSensitiveFieldsName(); + foreach ($params as $k => $v) { + if (in_array($k, $sensitive_fields, true)) { + $params[$k] = $this->encryptSensitiveInformation($v); + } + } + + return $params; + } + + /** + * To id card, mobile phone number and other fields sensitive information encryption. + * + * @param string $string + * + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\EncryptException + */ + protected function encryptSensitiveInformation(string $string) + { + $certificates = $this->app['config']->get('certificate'); + if (null === $certificates) { + throw new InvalidArgumentException('config certificate connot be empty.'); + } + + $encrypted = ''; + $publicKeyResource = openssl_get_publickey($certificates); + $f = openssl_public_encrypt($string, $encrypted, $publicKeyResource); + openssl_free_key($publicKeyResource); + if ($f) { + return base64_encode($encrypted); + } + + throw new EncryptException('Encryption of sensitive information failed'); + } + + /** + * get sensitive fields name. + * + * @return array + */ + protected function getSensitiveFieldsName() + { + return [ + 'id_card_name', + 'id_card_number', + 'account_name', + 'account_number', + 'contact', + 'contact_phone', + 'contact_email', + 'legal_person', + 'mobile_phone', + 'email', + ]; + } + + /** + * getSign. + * + * @param array $params + * + * @return string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + */ + protected function getSign(array $params) + { + $params = array_filter($params); + + $key = $this->app->getKey(); + + $encryptMethod = Support\get_encrypt_method(Support\Arr::get($params, 'sign_type', 'MD5'), $key); + + return Support\generate_sign($params, $key, $encryptMethod); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/EncryptException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/EncryptException.php new file mode 100644 index 0000000..dd874ae --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/EncryptException.php @@ -0,0 +1,23 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Kernel\Exceptions; + +use EasyWeChat\Kernel\Exceptions\Exception; + +/** + * Class EncryptException. + * + * @author liuml + */ +class EncryptException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidExtensionException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidExtensionException.php new file mode 100644 index 0000000..41e21cf --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidExtensionException.php @@ -0,0 +1,23 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Kernel\Exceptions; + +use EasyWeChat\Kernel\Exceptions\Exception; + +/** + * Class InvalidExtensionException. + * + * @author liuml + */ +class InvalidExtensionException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidSignException.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidSignException.php new file mode 100644 index 0000000..d09d92b --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidSignException.php @@ -0,0 +1,23 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Kernel\Exceptions; + +use EasyWeChat\Kernel\Exceptions\Exception; + +/** + * Class InvalidSignException. + * + * @author liuml + */ +class InvalidSignException extends Exception +{ +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/Client.php new file mode 100644 index 0000000..ee1038a --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/Client.php @@ -0,0 +1,73 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Material; + +use EasyWeChat\MicroMerchant\Kernel\BaseClient; + +/** + * Class Client. + * + * @author liuml + * @DateTime 2019-05-30 14:19 + */ +class Client extends BaseClient +{ + /** + * update settlement card. + * + * @param array $params + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\EncryptException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function setSettlementCard(array $params) + { + $params['sub_mch_id'] = $params['sub_mch_id'] ?? $this->app['config']->sub_mch_id; + $params = $this->processParams(array_merge($params, [ + 'version' => '1.0', + 'cert_sn' => '', + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + ])); + + return $this->safeRequest('applyment/micro/modifyarchives', $params); + } + + /** + * update contact info. + * + * @param array $params + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\EncryptException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function updateContact(array $params) + { + $params['sub_mch_id'] = $params['sub_mch_id'] ?? $this->app['config']->sub_mch_id; + $params = $this->processParams(array_merge($params, [ + 'version' => '1.0', + 'cert_sn' => '', + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + ])); + + return $this->safeRequest('applyment/micro/modifycontactinfo', $params); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/ServiceProvider.php new file mode 100644 index 0000000..dec5af7 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Material/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Material; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['material'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/Client.php new file mode 100644 index 0000000..fde755b --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/Client.php @@ -0,0 +1,49 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Media; + +use EasyWeChat\Kernel\Exceptions\InvalidArgumentException; +use EasyWeChat\MicroMerchant\Kernel\BaseClient; + +/** + * Class Client. + * + * @author liuml + * @DateTime 2019-06-10 14:50 + */ +class Client extends BaseClient +{ + /** + * Upload material. + * + * @param string $path + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \EasyWeChat\MicroMerchant\Kernel\Exceptions\InvalidSignException + */ + public function upload(string $path) + { + if (!file_exists($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf("File does not exist, or the file is unreadable: '%s'", $path)); + } + + $form = [ + 'media_hash' => strtolower(md5_file($path)), + 'sign_type' => 'HMAC-SHA256', + ]; + + return $this->httpUpload('secapi/mch/uploadmedia', ['media' => $path], $form); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/ServiceProvider.php new file mode 100644 index 0000000..9d46a84 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Media/ServiceProvider.php @@ -0,0 +1,44 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +/** + * ServiceProvider.php. + * + * This file is part of the wechat. + * + * (c) overtrue + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Media; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['media'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/Client.php new file mode 100644 index 0000000..c8573af --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/Client.php @@ -0,0 +1,134 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\MerchantConfig; + +use EasyWeChat\MicroMerchant\Kernel\BaseClient; + +/** + * Class Client. + * + * @author liuml + * @DateTime 2019-05-30 14:19 + */ +class Client extends BaseClient +{ + /** + * Service providers configure recommendation functions for small and micro businesses. + * + * @param string $subAppId + * @param string $subscribeAppId + * @param string $receiptAppId + * @param string $subMchId + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function setFollowConfig(string $subAppId, string $subscribeAppId, string $receiptAppId = '', string $subMchId = '') + { + $params = [ + 'sub_appid' => $subAppId, + 'sub_mch_id' => $subMchId ?: $this->app['config']->sub_mch_id, + ]; + + if (!empty($subscribeAppId)) { + $params['subscribe_appid'] = $subscribeAppId; + } else { + $params['receipt_appid'] = $receiptAppId; + } + + return $this->safeRequest('secapi/mkt/addrecommendconf', array_merge($params, [ + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + ])); + } + + /** + * Configure the new payment directory. + * + * @param string $jsapiPath + * @param string $appId + * @param string $subMchId + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + public function addPath(string $jsapiPath, string $appId = '', string $subMchId = '') + { + return $this->addConfig([ + 'appid' => $appId ?: $this->app['config']->appid, + 'sub_mch_id' => $subMchId ?: $this->app['config']->sub_mch_id, + 'jsapi_path' => $jsapiPath, + ]); + } + + /** + * bind appid. + * + * @param string $subAppId + * @param string $appId + * @param string $subMchId + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + */ + public function bindAppId(string $subAppId, string $appId = '', string $subMchId = '') + { + return $this->addConfig([ + 'appid' => $appId ?: $this->app['config']->appid, + 'sub_mch_id' => $subMchId ?: $this->app['config']->sub_mch_id, + 'sub_appid' => $subAppId, + ]); + } + + /** + * add sub dev config. + * + * @param array $params + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + private function addConfig(array $params) + { + return $this->safeRequest('secapi/mch/addsubdevconfig', $params); + } + + /** + * query Sub Dev Config. + * + * @param string $subMchId + * @param string $appId + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function getConfig(string $subMchId = '', string $appId = '') + { + return $this->safeRequest('secapi/mch/querysubdevconfig', [ + 'sub_mch_id' => $subMchId ?: $this->app['config']->sub_mch_id, + 'appid' => $appId ?: $this->app['config']->appid, + ]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/ServiceProvider.php new file mode 100644 index 0000000..5b78710 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\MerchantConfig; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['merchantConfig'] = function ($app) { + return new Client($app); + }; + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/Client.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/Client.php new file mode 100644 index 0000000..c96c363 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/Client.php @@ -0,0 +1,67 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Withdraw; + +use EasyWeChat\MicroMerchant\Kernel\BaseClient; + +/** + * Class Client. + * + * @author liuml + * @DateTime 2019-05-30 14:19 + */ +class Client extends BaseClient +{ + /** + * Query withdrawal status. + * + * @param string $date + * @param string $subMchId + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function queryWithdrawalStatus($date, $subMchId = '') + { + return $this->safeRequest('fund/queryautowithdrawbydate', [ + 'date' => $date, + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + 'sub_mch_id' => $subMchId ?: $this->app['config']->sub_mch_id, + ]); + } + + /** + * Re-initiation of withdrawal. + * + * @param string $date + * @param string $subMchId + * + * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string + * + * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException + * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException + * @throws \GuzzleHttp\Exception\GuzzleException + */ + public function requestWithdraw($date, $subMchId = '') + { + return $this->safeRequest('fund/reautowithdrawbydate', [ + 'date' => $date, + 'sign_type' => 'HMAC-SHA256', + 'nonce_str' => uniqid('micro'), + 'sub_mch_id' => $subMchId ?: $this->app['config']->sub_mch_id, + ]); + } +} diff --git a/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/ServiceProvider.php b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/ServiceProvider.php new file mode 100644 index 0000000..b9c0141 --- /dev/null +++ b/addons/weliam_smartcity/vendor/overtrue/wechat/src/MicroMerchant/Withdraw/ServiceProvider.php @@ -0,0 +1,33 @@ + + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace EasyWeChat\MicroMerchant\Withdraw; + +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ServiceProvider. + * + * @author overtrue + */ +class ServiceProvider implements ServiceProviderInterface +{ + /** + * {@inheritdoc}. + */ + public function register(Container $app) + { + $app['withdraw'] = function ($app) { + return new Client($app); + }; + } +}