添加网站文件
This commit is contained in:
39
vendor/overtrue/wechat/src/BasicService/Application.php
vendored
Normal file
39
vendor/overtrue/wechat/src/BasicService/Application.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*
|
||||
* @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,
|
||||
];
|
||||
}
|
||||
112
vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php
vendored
Normal file
112
vendor/overtrue/wechat/src/BasicService/ContentSecurity/Client.php
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
31
vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php
vendored
Normal file
31
vendor/overtrue/wechat/src/BasicService/ContentSecurity/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
198
vendor/overtrue/wechat/src/BasicService/Jssdk/Client.php
vendored
Normal file
198
vendor/overtrue/wechat/src/BasicService/Jssdk/Client.php
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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
|
||||
* @param array $openTagList
|
||||
* @param string $url
|
||||
*
|
||||
* @return array|string
|
||||
*
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
|
||||
* @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, array $openTagList = [], string $url = null)
|
||||
{
|
||||
$config = array_merge(compact('debug', 'beta', 'jsApiList', 'openTagList'), $this->configSignature($url));
|
||||
|
||||
return $json ? json_encode($config) : $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return jsapi config as a PHP array.
|
||||
*
|
||||
* @param array $apis
|
||||
* @param bool $debug
|
||||
* @param bool $beta
|
||||
* @param array $openTagList
|
||||
* @param string $url
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
|
||||
* @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, array $openTagList = [], string $url = null)
|
||||
{
|
||||
return $this->buildConfig($apis, $debug, $beta, false, $openTagList, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get js ticket.
|
||||
*
|
||||
* @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<string, mixed> $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 int|null $timestamp
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUrl(string $url)
|
||||
{
|
||||
$this->url = $url;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current url.
|
||||
*/
|
||||
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');
|
||||
}
|
||||
}
|
||||
33
vendor/overtrue/wechat/src/BasicService/Jssdk/ServiceProvider.php
vendored
Normal file
33
vendor/overtrue/wechat/src/BasicService/Jssdk/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['jssdk'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
197
vendor/overtrue/wechat/src/BasicService/Media/Client.php
vendored
Normal file
197
vendor/overtrue/wechat/src/BasicService/Media/Client.php
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* @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'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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'));
|
||||
}
|
||||
}
|
||||
44
vendor/overtrue/wechat/src/BasicService/Media/ServiceProvider.php
vendored
Normal file
44
vendor/overtrue/wechat/src/BasicService/Media/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['media'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
120
vendor/overtrue/wechat/src/BasicService/QrCode/Client.php
vendored
Normal file
120
vendor/overtrue/wechat/src/BasicService/QrCode/Client.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUri = 'https://api.weixin.qq.com/cgi-bin/';
|
||||
|
||||
public const DAY = 86400;
|
||||
public const SCENE_MAX_VALUE = 100000;
|
||||
public const SCENE_QR_CARD = 'QR_CARD';
|
||||
public const SCENE_QR_TEMPORARY = 'QR_SCENE';
|
||||
public const SCENE_QR_TEMPORARY_STR = 'QR_STR_SCENE';
|
||||
public const SCENE_QR_FOREVER = 'QR_LIMIT_SCENE';
|
||||
public 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);
|
||||
}
|
||||
}
|
||||
31
vendor/overtrue/wechat/src/BasicService/QrCode/ServiceProvider.php
vendored
Normal file
31
vendor/overtrue/wechat/src/BasicService/QrCode/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
45
vendor/overtrue/wechat/src/BasicService/Url/Client.php
vendored
Normal file
45
vendor/overtrue/wechat/src/BasicService/Url/Client.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUri = 'https://api.weixin.qq.com/';
|
||||
|
||||
/**
|
||||
* Shorten the 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);
|
||||
}
|
||||
}
|
||||
31
vendor/overtrue/wechat/src/BasicService/Url/ServiceProvider.php
vendored
Normal file
31
vendor/overtrue/wechat/src/BasicService/Url/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
53
vendor/overtrue/wechat/src/Factory.php
vendored
Normal file
53
vendor/overtrue/wechat/src/Factory.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace EasyWeChat;
|
||||
|
||||
/**
|
||||
* Class Factory.
|
||||
*
|
||||
* @method static \EasyWeChat\Payment\Application payment(array $config)
|
||||
* @method static \EasyWeChat\MiniProgram\Application miniProgram(array $config)
|
||||
* @method static \EasyWeChat\OpenPlatform\Application openPlatform(array $config)
|
||||
* @method static \EasyWeChat\OfficialAccount\Application officialAccount(array $config)
|
||||
* @method static \EasyWeChat\BasicService\Application basicService(array $config)
|
||||
* @method static \EasyWeChat\Work\Application work(array $config)
|
||||
* @method static \EasyWeChat\OpenWork\Application openWork(array $config)
|
||||
* @method static \EasyWeChat\MicroMerchant\Application microMerchant(array $config)
|
||||
*/
|
||||
class Factory
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return \EasyWeChat\Kernel\ServiceContainer
|
||||
*/
|
||||
public static function make($name, array $config)
|
||||
{
|
||||
$namespace = Kernel\Support\Str::studly($name);
|
||||
$application = "\\EasyWeChat\\{$namespace}\\Application";
|
||||
|
||||
return new $application($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically pass methods to the application.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function __callStatic($name, $arguments)
|
||||
{
|
||||
return self::make($name, ...$arguments);
|
||||
}
|
||||
}
|
||||
248
vendor/overtrue/wechat/src/Kernel/AccessToken.php
vendored
Normal file
248
vendor/overtrue/wechat/src/Kernel/AccessToken.php
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) && $result = $cache->get($cacheKey)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
if (!$this->getCache()->has($this->getCacheKey())) {
|
||||
throw new RuntimeException('Failed to cache access token.');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
abstract protected function getCredentials(): array;
|
||||
}
|
||||
243
vendor/overtrue/wechat/src/Kernel/BaseClient.php
vendored
Normal file
243
vendor/overtrue/wechat/src/Kernel/BaseClient.php
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public function __construct(ServiceContainer $app, AccessTokenInterface $accessToken = null)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->accessToken = $accessToken ?? $this->app['access_token'];
|
||||
}
|
||||
|
||||
/**
|
||||
* GET request.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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]);
|
||||
}
|
||||
|
||||
public function getAccessToken(): AccessTokenInterface
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setAccessToken(AccessTokenInterface $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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));
|
||||
});
|
||||
}
|
||||
}
|
||||
64
vendor/overtrue/wechat/src/Kernel/Clauses/Clause.php
vendored
Normal file
64
vendor/overtrue/wechat/src/Kernel/Clauses/Clause.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
vendor/overtrue/wechat/src/Kernel/Config.php
vendored
Normal file
23
vendor/overtrue/wechat/src/Kernel/Config.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class Config extends Collection
|
||||
{
|
||||
}
|
||||
31
vendor/overtrue/wechat/src/Kernel/Contracts/AccessTokenInterface.php
vendored
Normal file
31
vendor/overtrue/wechat/src/Kernel/Contracts/AccessTokenInterface.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
interface AccessTokenInterface
|
||||
{
|
||||
public function getToken(): array;
|
||||
|
||||
/**
|
||||
* @return \EasyWeChat\Kernel\Contracts\AccessTokenInterface
|
||||
*/
|
||||
public function refresh(): self;
|
||||
|
||||
public function applyToRequest(RequestInterface $request, array $requestOptions = []): RequestInterface;
|
||||
}
|
||||
29
vendor/overtrue/wechat/src/Kernel/Contracts/Arrayable.php
vendored
Normal file
29
vendor/overtrue/wechat/src/Kernel/Contracts/Arrayable.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
interface Arrayable extends ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Get the instance as an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
}
|
||||
25
vendor/overtrue/wechat/src/Kernel/Contracts/EventHandlerInterface.php
vendored
Normal file
25
vendor/overtrue/wechat/src/Kernel/Contracts/EventHandlerInterface.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
interface EventHandlerInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $payload
|
||||
*/
|
||||
public function handle($payload = null);
|
||||
}
|
||||
22
vendor/overtrue/wechat/src/Kernel/Contracts/MediaInterface.php
vendored
Normal file
22
vendor/overtrue/wechat/src/Kernel/Contracts/MediaInterface.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
interface MediaInterface extends MessageInterface
|
||||
{
|
||||
public function getMediaId(): string;
|
||||
}
|
||||
26
vendor/overtrue/wechat/src/Kernel/Contracts/MessageInterface.php
vendored
Normal file
26
vendor/overtrue/wechat/src/Kernel/Contracts/MessageInterface.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
interface MessageInterface
|
||||
{
|
||||
public function getType(): string;
|
||||
|
||||
public function transformForJsonRequest(): array;
|
||||
|
||||
public function transformToXml(): string;
|
||||
}
|
||||
35
vendor/overtrue/wechat/src/Kernel/Decorators/FinallyResult.php
vendored
Normal file
35
vendor/overtrue/wechat/src/Kernel/Decorators/FinallyResult.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class FinallyResult
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* FinallyResult constructor.
|
||||
*
|
||||
* @param mixed $content
|
||||
*/
|
||||
public function __construct($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
}
|
||||
35
vendor/overtrue/wechat/src/Kernel/Decorators/TerminateResult.php
vendored
Normal file
35
vendor/overtrue/wechat/src/Kernel/Decorators/TerminateResult.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class TerminateResult
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* FinallyResult constructor.
|
||||
*
|
||||
* @param mixed $content
|
||||
*/
|
||||
public function __construct($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
}
|
||||
198
vendor/overtrue/wechat/src/Kernel/Encryptor.php
vendored
Normal file
198
vendor/overtrue/wechat/src/Kernel/Encryptor.php
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 EasyWeChat\Kernel\Support\XML;
|
||||
use Throwable;
|
||||
use function EasyWeChat\Kernel\Support\str_random;
|
||||
|
||||
/**
|
||||
* Class Encryptor.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
*/
|
||||
class Encryptor
|
||||
{
|
||||
public const ERROR_INVALID_SIGNATURE = -40001; // Signature verification failed
|
||||
public const ERROR_PARSE_XML = -40002; // Parse XML failed
|
||||
public const ERROR_CALC_SIGNATURE = -40003; // Calculating the signature failed
|
||||
public const ERROR_INVALID_AES_KEY = -40004; // Invalid AESKey
|
||||
public const ERROR_INVALID_APP_ID = -40005; // Check AppID failed
|
||||
public const ERROR_ENCRYPT_AES = -40006; // AES EncryptionInterface failed
|
||||
public const ERROR_DECRYPT_AES = -40007; // AES decryption failed
|
||||
public const ERROR_INVALID_XML = -40008; // Invalid XML
|
||||
public const ERROR_BASE64_ENCODE = -40009; // Base64 encoding failed
|
||||
public const ERROR_BASE64_DECODE = -40010; // Base64 decoding failed
|
||||
public const ERROR_XML_BUILD = -40011; // XML build failed
|
||||
public 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public function getToken(): string
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the message and return XML.
|
||||
*
|
||||
* @param string $xml
|
||||
* @param string $nonce
|
||||
* @param int $timestamp
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public function signature(): string
|
||||
{
|
||||
$array = func_get_args();
|
||||
sort($array, SORT_STRING);
|
||||
|
||||
return sha1(implode($array));
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#7 pad.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
32
vendor/overtrue/wechat/src/Kernel/Events/AccessTokenRefreshed.php
vendored
Normal file
32
vendor/overtrue/wechat/src/Kernel/Events/AccessTokenRefreshed.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
class AccessTokenRefreshed
|
||||
{
|
||||
/**
|
||||
* @var \EasyWeChat\Kernel\AccessToken
|
||||
*/
|
||||
public $accessToken;
|
||||
|
||||
public function __construct(AccessToken $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
}
|
||||
}
|
||||
32
vendor/overtrue/wechat/src/Kernel/Events/ApplicationInitialized.php
vendored
Normal file
32
vendor/overtrue/wechat/src/Kernel/Events/ApplicationInitialized.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
class ApplicationInitialized
|
||||
{
|
||||
/**
|
||||
* @var \EasyWeChat\Kernel\ServiceContainer
|
||||
*/
|
||||
public $app;
|
||||
|
||||
public function __construct(ServiceContainer $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
}
|
||||
32
vendor/overtrue/wechat/src/Kernel/Events/HttpResponseCreated.php
vendored
Normal file
32
vendor/overtrue/wechat/src/Kernel/Events/HttpResponseCreated.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
class HttpResponseCreated
|
||||
{
|
||||
/**
|
||||
* @var \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public $response;
|
||||
|
||||
public function __construct(ResponseInterface $response)
|
||||
{
|
||||
$this->response = $response;
|
||||
}
|
||||
}
|
||||
32
vendor/overtrue/wechat/src/Kernel/Events/ServerGuardResponseCreated.php
vendored
Normal file
32
vendor/overtrue/wechat/src/Kernel/Events/ServerGuardResponseCreated.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
class ServerGuardResponseCreated
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public $response;
|
||||
|
||||
public function __construct(Response $response)
|
||||
{
|
||||
$this->response = $response;
|
||||
}
|
||||
}
|
||||
21
vendor/overtrue/wechat/src/Kernel/Exceptions/BadRequestException.php
vendored
Normal file
21
vendor/overtrue/wechat/src/Kernel/Exceptions/BadRequestException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class BadRequestException extends Exception
|
||||
{
|
||||
}
|
||||
16
vendor/overtrue/wechat/src/Kernel/Exceptions/DecryptException.php
vendored
Normal file
16
vendor/overtrue/wechat/src/Kernel/Exceptions/DecryptException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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
|
||||
{
|
||||
}
|
||||
23
vendor/overtrue/wechat/src/Kernel/Exceptions/Exception.php
vendored
Normal file
23
vendor/overtrue/wechat/src/Kernel/Exceptions/Exception.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class Exception extends BaseException
|
||||
{
|
||||
}
|
||||
51
vendor/overtrue/wechat/src/Kernel/Exceptions/HttpException.php
vendored
Normal file
51
vendor/overtrue/wechat/src/Kernel/Exceptions/HttpException.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidArgumentException.php
vendored
Normal file
21
vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidArgumentException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class InvalidArgumentException extends Exception
|
||||
{
|
||||
}
|
||||
21
vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidConfigException.php
vendored
Normal file
21
vendor/overtrue/wechat/src/Kernel/Exceptions/InvalidConfigException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class InvalidConfigException extends Exception
|
||||
{
|
||||
}
|
||||
21
vendor/overtrue/wechat/src/Kernel/Exceptions/RuntimeException.php
vendored
Normal file
21
vendor/overtrue/wechat/src/Kernel/Exceptions/RuntimeException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class RuntimeException extends Exception
|
||||
{
|
||||
}
|
||||
21
vendor/overtrue/wechat/src/Kernel/Exceptions/UnboundServiceException.php
vendored
Normal file
21
vendor/overtrue/wechat/src/Kernel/Exceptions/UnboundServiceException.php
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class UnboundServiceException extends Exception
|
||||
{
|
||||
}
|
||||
57
vendor/overtrue/wechat/src/Kernel/Helpers.php
vendored
Normal file
57
vendor/overtrue/wechat/src/Kernel/Helpers.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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'));
|
||||
}
|
||||
}
|
||||
117
vendor/overtrue/wechat/src/Kernel/Http/Response.php
vendored
Normal file
117
vendor/overtrue/wechat/src/Kernel/Http/Response.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class Response extends GuzzleResponse
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBodyContents()
|
||||
{
|
||||
$this->getBody()->rewind();
|
||||
$contents = $this->getBody()->getContents();
|
||||
$this->getBody()->rewind();
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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, '<xml')) {
|
||||
return XML::parse($content);
|
||||
}
|
||||
|
||||
$array = json_decode($content, true, 512, JSON_BIGINT_AS_STRING);
|
||||
|
||||
if (JSON_ERROR_NONE === json_last_error()) {
|
||||
return (array) $array;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get collection data.
|
||||
*
|
||||
* @return \EasyWeChat\Kernel\Support\Collection
|
||||
*/
|
||||
public function toCollection()
|
||||
{
|
||||
return new Collection($this->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object
|
||||
*/
|
||||
public function toObject()
|
||||
{
|
||||
return json_decode($this->toJson());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getBodyContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function removeControlCharacters(string $content)
|
||||
{
|
||||
return \preg_replace('/[\x00-\x1F\x80-\x9F]/u', '', $content);
|
||||
}
|
||||
}
|
||||
78
vendor/overtrue/wechat/src/Kernel/Http/StreamResponse.php
vendored
Normal file
78
vendor/overtrue/wechat/src/Kernel/Http/StreamResponse.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class StreamResponse extends Response
|
||||
{
|
||||
/**
|
||||
* @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="(?<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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
580
vendor/overtrue/wechat/src/Kernel/Log/LogManager.php
vendored
Normal file
580
vendor/overtrue/wechat/src/Kernel/Log/LogManager.php
vendored
Normal file
@@ -0,0 +1,580 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace EasyWeChat\Kernel\Log;
|
||||
|
||||
use EasyWeChat\Kernel\ServiceContainer;
|
||||
use InvalidArgumentException;
|
||||
use Monolog\Formatter\LineFormatter;
|
||||
use Monolog\Handler\ErrorLogHandler;
|
||||
use Monolog\Handler\FormattableHandlerInterface;
|
||||
use Monolog\Handler\HandlerInterface;
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\RotatingFileHandler;
|
||||
use Monolog\Handler\SlackWebhookHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogHandler;
|
||||
use Monolog\Handler\WhatFailureGroupHandler;
|
||||
use Monolog\Logger as Monolog;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class LogManager.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
*/
|
||||
class LogManager implements LoggerInterface
|
||||
{
|
||||
/**
|
||||
* @var \EasyWeChat\Kernel\ServiceContainer
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* The array of resolved channels.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $channels = [];
|
||||
|
||||
/**
|
||||
* The registered custom driver creators.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $customCreators = [];
|
||||
|
||||
/**
|
||||
* The Log levels.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $levels = [
|
||||
'debug' => Monolog::DEBUG,
|
||||
'info' => Monolog::INFO,
|
||||
'notice' => Monolog::NOTICE,
|
||||
'warning' => Monolog::WARNING,
|
||||
'error' => Monolog::ERROR,
|
||||
'critical' => Monolog::CRITICAL,
|
||||
'alert' => Monolog::ALERT,
|
||||
'emergency' => Monolog::EMERGENCY,
|
||||
];
|
||||
|
||||
/**
|
||||
* LogManager constructor.
|
||||
*/
|
||||
public function __construct(ServiceContainer $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new, on-demand aggregate logger instance.
|
||||
*
|
||||
* @param array $channels
|
||||
* @param string|null $channel
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function stack(array $channels, $channel = null)
|
||||
{
|
||||
return $this->createStackDriver(compact('channels', 'channel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log channel instance.
|
||||
*
|
||||
* @param string|null $channel
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function channel($channel = null)
|
||||
{
|
||||
return $this->driver($channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a log driver instance.
|
||||
*
|
||||
* @param string|null $driver
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function driver($driver = null)
|
||||
{
|
||||
return $this->get($driver ?? $this->getDefaultDriver());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the log from the local cache.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function get($name)
|
||||
{
|
||||
try {
|
||||
return $this->channels[$name] ?? ($this->channels[$name] = $this->resolve($name));
|
||||
} catch (\Throwable $e) {
|
||||
$logger = $this->createEmergencyLogger();
|
||||
|
||||
$logger->emergency('Unable to create configured logger. Using emergency logger.', [
|
||||
'exception' => $e,
|
||||
]);
|
||||
|
||||
return $logger;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the given log instance by name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function resolve($name)
|
||||
{
|
||||
$config = $this->app['config']->get(\sprintf('log.channels.%s', $name));
|
||||
|
||||
if (is_null($config)) {
|
||||
throw new InvalidArgumentException(\sprintf('Log [%s] is not defined.', $name));
|
||||
}
|
||||
|
||||
if (isset($this->customCreators[$config['driver']])) {
|
||||
return $this->callCustomCreator($config);
|
||||
}
|
||||
|
||||
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
|
||||
|
||||
if (method_exists($this, $driverMethod)) {
|
||||
return $this->{$driverMethod}($config);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(\sprintf('Driver [%s] is not supported.', $config['driver']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a custom driver creator.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function callCustomCreator(array $config)
|
||||
{
|
||||
return $this->customCreators[$config['driver']]($this->app, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an emergency log handler to avoid white screens of death.
|
||||
*
|
||||
* @return \Monolog\Logger
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function createEmergencyLogger()
|
||||
{
|
||||
return new Monolog('EasyWeChat', $this->prepareHandlers([new StreamHandler(
|
||||
\sys_get_temp_dir().'/easywechat/easywechat.log',
|
||||
$this->level(['level' => 'debug'])
|
||||
)]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an aggregate log driver instance.
|
||||
*
|
||||
* @return \Monolog\Logger
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function createStackDriver(array $config)
|
||||
{
|
||||
$handlers = [];
|
||||
|
||||
foreach ($config['channels'] ?? [] as $channel) {
|
||||
$handlers = \array_merge($handlers, $this->channel($channel)->getHandlers());
|
||||
}
|
||||
|
||||
if ($config['ignore_exceptions'] ?? false) {
|
||||
$handlers = [new WhatFailureGroupHandler($handlers)];
|
||||
}
|
||||
|
||||
return new Monolog($this->parseChannel($config), $handlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the single file log driver.
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function createSingleDriver(array $config)
|
||||
{
|
||||
return new Monolog($this->parseChannel($config), [
|
||||
$this->prepareHandler(new StreamHandler(
|
||||
$config['path'],
|
||||
$this->level($config),
|
||||
$config['bubble'] ?? true,
|
||||
$config['permission'] ?? null,
|
||||
$config['locking'] ?? false
|
||||
), $config),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the daily file log driver.
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected function createDailyDriver(array $config)
|
||||
{
|
||||
return new Monolog($this->parseChannel($config), [
|
||||
$this->prepareHandler(new RotatingFileHandler(
|
||||
$config['path'],
|
||||
$config['days'] ?? 7,
|
||||
$this->level($config),
|
||||
$config['bubble'] ?? true,
|
||||
$config['permission'] ?? null,
|
||||
$config['locking'] ?? false
|
||||
), $config),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the Slack log driver.
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected function createSlackDriver(array $config)
|
||||
{
|
||||
return new Monolog($this->parseChannel($config), [
|
||||
$this->prepareHandler(new SlackWebhookHandler(
|
||||
$config['url'],
|
||||
$config['channel'] ?? null,
|
||||
$config['username'] ?? 'EasyWeChat',
|
||||
$config['attachment'] ?? true,
|
||||
$config['emoji'] ?? ':boom:',
|
||||
$config['short'] ?? false,
|
||||
$config['context'] ?? true,
|
||||
$this->level($config),
|
||||
$config['bubble'] ?? true,
|
||||
$config['exclude_fields'] ?? []
|
||||
), $config),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the syslog log driver.
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected function createSyslogDriver(array $config)
|
||||
{
|
||||
return new Monolog($this->parseChannel($config), [
|
||||
$this->prepareHandler(new SyslogHandler(
|
||||
'EasyWeChat',
|
||||
$config['facility'] ?? LOG_USER,
|
||||
$this->level($config)
|
||||
), $config),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the "error log" log driver.
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected function createErrorlogDriver(array $config)
|
||||
{
|
||||
return new Monolog($this->parseChannel($config), [
|
||||
$this->prepareHandler(
|
||||
new ErrorLogHandler(
|
||||
$config['type'] ?? ErrorLogHandler::OPERATING_SYSTEM,
|
||||
$this->level($config)
|
||||
)
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function createNullDriver()
|
||||
{
|
||||
return new Monolog('EasyWeChat', [new NullHandler()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the handlers for usage by Monolog.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareHandlers(array $handlers)
|
||||
{
|
||||
foreach ($handlers as $key => $handler) {
|
||||
$handlers[$key] = $this->prepareHandler($handler);
|
||||
}
|
||||
|
||||
return $handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the handler for usage by Monolog.
|
||||
*
|
||||
* @return \Monolog\Handler\HandlerInterface
|
||||
*/
|
||||
protected function prepareHandler(HandlerInterface $handler, array $config = [])
|
||||
{
|
||||
if (!isset($config['formatter'])) {
|
||||
if ($handler instanceof FormattableHandlerInterface) {
|
||||
$handler->setFormatter($this->formatter());
|
||||
}
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Monolog formatter instance.
|
||||
*
|
||||
* @return \Monolog\Formatter\FormatterInterface
|
||||
*/
|
||||
protected function formatter()
|
||||
{
|
||||
$formatter = new LineFormatter(null, null, true, true);
|
||||
$formatter->includeStacktraces();
|
||||
|
||||
return $formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the log channel from the given configuration.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function parseChannel(array $config)
|
||||
{
|
||||
return $config['name'] ?? 'EasyWeChat';
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string level into a Monolog constant.
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
protected function level(array $config)
|
||||
{
|
||||
$level = $config['level'] ?? 'debug';
|
||||
|
||||
if (isset($this->levels[$level])) {
|
||||
return $this->levels[$level];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Invalid log level.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default log driver name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDefaultDriver()
|
||||
{
|
||||
return $this->app['config']['log.default'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default log driver name.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setDefaultDriver($name)
|
||||
{
|
||||
$this->app['config']['log.default'] = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom driver creator Closure.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function extend($driver, \Closure $callback)
|
||||
{
|
||||
$this->customCreators[$driver] = $callback->bindTo($this, $this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* System is unusable.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function emergency($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->emergency($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action must be taken immediately.
|
||||
*
|
||||
* Example: Entire website down, database unavailable, etc. This should
|
||||
* trigger the SMS alerts and wake you up.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function alert($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->alert($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Critical conditions.
|
||||
*
|
||||
* Example: Application component unavailable, unexpected exception.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function critical($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->critical($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runtime errors that do not require immediate action but should typically
|
||||
* be logged and monitored.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function error($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->error($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exceptional occurrences that are not errors.
|
||||
*
|
||||
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
||||
* that are not necessarily wrong.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function warning($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->warning($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normal but significant events.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function notice($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->notice($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interesting events.
|
||||
*
|
||||
* Example: User logs in, SQL logs.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function info($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->info($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detailed debug information.
|
||||
*
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function debug($message, array $context = [])
|
||||
{
|
||||
return $this->driver()->debug($message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs with an arbitrary level.
|
||||
*
|
||||
* @param mixed $level
|
||||
* @param string $message
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function log($level, $message, array $context = [])
|
||||
{
|
||||
return $this->driver()->log($level, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically call the default driver instance.
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
return $this->driver()->$method(...$parameters);
|
||||
}
|
||||
}
|
||||
58
vendor/overtrue/wechat/src/Kernel/Messages/Article.php
vendored
Normal file
58
vendor/overtrue/wechat/src/Kernel/Messages/Article.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
50
vendor/overtrue/wechat/src/Kernel/Messages/Card.php
vendored
Normal file
50
vendor/overtrue/wechat/src/Kernel/Messages/Card.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Card.php.
|
||||
*
|
||||
* @author overtrue <i@overtrue.me>
|
||||
* @copyright 2015 overtrue <i@overtrue.me>
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public function __construct(string $cardId)
|
||||
{
|
||||
parent::__construct(['card_id' => $cardId]);
|
||||
}
|
||||
}
|
||||
40
vendor/overtrue/wechat/src/Kernel/Messages/DeviceEvent.php
vendored
Normal file
40
vendor/overtrue/wechat/src/Kernel/Messages/DeviceEvent.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
50
vendor/overtrue/wechat/src/Kernel/Messages/DeviceText.php
vendored
Normal file
50
vendor/overtrue/wechat/src/Kernel/Messages/DeviceText.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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')),
|
||||
];
|
||||
}
|
||||
}
|
||||
25
vendor/overtrue/wechat/src/Kernel/Messages/File.php
vendored
Normal file
25
vendor/overtrue/wechat/src/Kernel/Messages/File.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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';
|
||||
}
|
||||
27
vendor/overtrue/wechat/src/Kernel/Messages/Image.php
vendored
Normal file
27
vendor/overtrue/wechat/src/Kernel/Messages/Image.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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';
|
||||
}
|
||||
36
vendor/overtrue/wechat/src/Kernel/Messages/Link.php
vendored
Normal file
36
vendor/overtrue/wechat/src/Kernel/Messages/Link.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
38
vendor/overtrue/wechat/src/Kernel/Messages/Location.php
vendored
Normal file
38
vendor/overtrue/wechat/src/Kernel/Messages/Location.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
66
vendor/overtrue/wechat/src/Kernel/Messages/Media.php
vendored
Normal file
66
vendor/overtrue/wechat/src/Kernel/Messages/Media.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 $type
|
||||
*/
|
||||
public function __construct(string $mediaId, $type = null, array $attributes = [])
|
||||
{
|
||||
parent::__construct(array_merge(['media_id' => $mediaId], $attributes));
|
||||
|
||||
!empty($type) && $this->setType($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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'),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
187
vendor/overtrue/wechat/src/Kernel/Messages/Message.php
vendored
Normal file
187
vendor/overtrue/wechat/src/Kernel/Messages/Message.php
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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\Exceptions\RuntimeException;
|
||||
use EasyWeChat\Kernel\Support\XML;
|
||||
use EasyWeChat\Kernel\Traits\HasAttributes;
|
||||
|
||||
/**
|
||||
* Class Messages.
|
||||
*/
|
||||
abstract class Message implements MessageInterface
|
||||
{
|
||||
use HasAttributes;
|
||||
|
||||
public const TEXT = 2;
|
||||
public const IMAGE = 4;
|
||||
public const VOICE = 8;
|
||||
public const VIDEO = 16;
|
||||
public const SHORT_VIDEO = 32;
|
||||
public const LOCATION = 64;
|
||||
public const LINK = 128;
|
||||
public const DEVICE_EVENT = 256;
|
||||
public const DEVICE_TEXT = 512;
|
||||
public const FILE = 1024;
|
||||
public const TEXT_CARD = 2048;
|
||||
public const TRANSFER = 4096;
|
||||
public const EVENT = 1048576;
|
||||
public const MINIPROGRAM_PAGE = 2097152;
|
||||
public const MINIPROGRAM_NOTICE = 4194304;
|
||||
public 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 | self::MINIPROGRAM_NOTICE;
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
$this->setAttributes($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return type name message.
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function transformForJsonRequestWithoutType(array $appends = [])
|
||||
{
|
||||
return $this->transformForJsonRequest($appends, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $withType
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
public function transformToXml(array $appends = [], bool $returnAsArray = false): string
|
||||
{
|
||||
$data = array_merge(['MsgType' => $this->getType()], $this->toXmlArray(), $appends);
|
||||
|
||||
return $returnAsArray ? $data : XML::build($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 RuntimeException(sprintf('Class "%s" cannot support transform to XML message.', __CLASS__));
|
||||
}
|
||||
}
|
||||
31
vendor/overtrue/wechat/src/Kernel/Messages/MiniProgramPage.php
vendored
Normal file
31
vendor/overtrue/wechat/src/Kernel/Messages/MiniProgramPage.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
22
vendor/overtrue/wechat/src/Kernel/Messages/MiniprogramNotice.php
vendored
Normal file
22
vendor/overtrue/wechat/src/Kernel/Messages/MiniprogramNotice.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 MiniprogramNotice extends Message
|
||||
{
|
||||
protected $type = 'miniprogram_notice';
|
||||
|
||||
protected $properties = [
|
||||
'appid',
|
||||
'title',
|
||||
];
|
||||
}
|
||||
73
vendor/overtrue/wechat/src/Kernel/Messages/Music.php
vendored
Normal file
73
vendor/overtrue/wechat/src/Kernel/Messages/Music.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
65
vendor/overtrue/wechat/src/Kernel/Messages/News.php
vendored
Normal file
65
vendor/overtrue/wechat/src/Kernel/Messages/News.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class News extends Message
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'news';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = [
|
||||
'items',
|
||||
];
|
||||
|
||||
/**
|
||||
* News constructor.
|
||||
*/
|
||||
public function __construct(array $items = [])
|
||||
{
|
||||
parent::__construct(compact('items'));
|
||||
}
|
||||
|
||||
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,
|
||||
];
|
||||
}
|
||||
}
|
||||
57
vendor/overtrue/wechat/src/Kernel/Messages/NewsItem.php
vendored
Normal file
57
vendor/overtrue/wechat/src/Kernel/Messages/NewsItem.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
51
vendor/overtrue/wechat/src/Kernel/Messages/Raw.php
vendored
Normal file
51
vendor/overtrue/wechat/src/Kernel/Messages/Raw.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public function __construct(string $content)
|
||||
{
|
||||
parent::__construct(['content' => strval($content)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $withType
|
||||
*/
|
||||
public function transformForJsonRequest(array $appends = [], $withType = true): array
|
||||
{
|
||||
return json_decode($this->content, true) ?? [];
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->get('content') ?? '';
|
||||
}
|
||||
}
|
||||
30
vendor/overtrue/wechat/src/Kernel/Messages/ShortVideo.php
vendored
Normal file
30
vendor/overtrue/wechat/src/Kernel/Messages/ShortVideo.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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';
|
||||
}
|
||||
44
vendor/overtrue/wechat/src/Kernel/Messages/TaskCard.php
vendored
Normal file
44
vendor/overtrue/wechat/src/Kernel/Messages/TaskCard.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
52
vendor/overtrue/wechat/src/Kernel/Messages/Text.php
vendored
Normal file
52
vendor/overtrue/wechat/src/Kernel/Messages/Text.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public function __construct(string $content)
|
||||
{
|
||||
parent::__construct(compact('content'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toXmlArray()
|
||||
{
|
||||
return [
|
||||
'Content' => $this->get('content'),
|
||||
];
|
||||
}
|
||||
}
|
||||
40
vendor/overtrue/wechat/src/Kernel/Messages/TextCard.php
vendored
Normal file
40
vendor/overtrue/wechat/src/Kernel/Messages/TextCard.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
54
vendor/overtrue/wechat/src/Kernel/Messages/Transfer.php
vendored
Normal file
54
vendor/overtrue/wechat/src/Kernel/Messages/Transfer.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
public function __construct(string $account = null)
|
||||
{
|
||||
parent::__construct(compact('account'));
|
||||
}
|
||||
|
||||
public function toXmlArray()
|
||||
{
|
||||
return empty($this->get('account')) ? [] : [
|
||||
'TransInfo' => [
|
||||
'KfAccount' => $this->get('account'),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
62
vendor/overtrue/wechat/src/Kernel/Messages/Video.php
vendored
Normal file
62
vendor/overtrue/wechat/src/Kernel/Messages/Video.php
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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'),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
37
vendor/overtrue/wechat/src/Kernel/Messages/Voice.php
vendored
Normal file
37
vendor/overtrue/wechat/src/Kernel/Messages/Voice.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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',
|
||||
];
|
||||
}
|
||||
39
vendor/overtrue/wechat/src/Kernel/Providers/ConfigServiceProvider.php
vendored
Normal file
39
vendor/overtrue/wechat/src/Kernel/Providers/ConfigServiceProvider.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
!isset($pimple['config']) && $pimple['config'] = function ($app) {
|
||||
return new Config($app->getConfig());
|
||||
};
|
||||
}
|
||||
}
|
||||
47
vendor/overtrue/wechat/src/Kernel/Providers/EventDispatcherServiceProvider.php
vendored
Normal file
47
vendor/overtrue/wechat/src/Kernel/Providers/EventDispatcherServiceProvider.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
!isset($pimple['events']) && $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;
|
||||
};
|
||||
}
|
||||
}
|
||||
39
vendor/overtrue/wechat/src/Kernel/Providers/ExtensionServiceProvider.php
vendored
Normal file
39
vendor/overtrue/wechat/src/Kernel/Providers/ExtensionServiceProvider.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
!isset($pimple['extension']) && $pimple['extension'] = function ($app) {
|
||||
return new Extension($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
39
vendor/overtrue/wechat/src/Kernel/Providers/HttpClientServiceProvider.php
vendored
Normal file
39
vendor/overtrue/wechat/src/Kernel/Providers/HttpClientServiceProvider.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
!isset($pimple['http_client']) && $pimple['http_client'] = function ($app) {
|
||||
return new Client($app['config']->get('http', []));
|
||||
};
|
||||
}
|
||||
}
|
||||
80
vendor/overtrue/wechat/src/Kernel/Providers/LogServiceProvider.php
vendored
Normal file
80
vendor/overtrue/wechat/src/Kernel/Providers/LogServiceProvider.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
!isset($pimple['log']) && $pimple['log'] = function ($app) {
|
||||
$config = $this->formatLogConfig($app);
|
||||
|
||||
if (!empty($config)) {
|
||||
$app->rebind('config', $app['config']->merge($config));
|
||||
}
|
||||
|
||||
return new LogManager($app);
|
||||
};
|
||||
|
||||
!isset($pimple['logger']) && $pimple['logger'] = $pimple['log'];
|
||||
}
|
||||
|
||||
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' => 'null',
|
||||
'channels' => [
|
||||
'null' => [
|
||||
'driver' => 'null',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
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'),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
39
vendor/overtrue/wechat/src/Kernel/Providers/RequestServiceProvider.php
vendored
Normal file
39
vendor/overtrue/wechat/src/Kernel/Providers/RequestServiceProvider.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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)
|
||||
{
|
||||
!isset($pimple['request']) && $pimple['request'] = function () {
|
||||
return Request::createFromGlobals();
|
||||
};
|
||||
}
|
||||
}
|
||||
352
vendor/overtrue/wechat/src/Kernel/ServerGuard.php
vendored
Normal file
352
vendor/overtrue/wechat/src/Kernel/ServerGuard.php
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServerGuard
|
||||
{
|
||||
use Observable;
|
||||
use ResponseCastable;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $alwaysValidate = false;
|
||||
|
||||
/**
|
||||
* Empty string.
|
||||
*/
|
||||
public const SUCCESS_EMPTY_RESPONSE = 'success';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public 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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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 \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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
protected function isSafeMode(): bool
|
||||
{
|
||||
return $this->app['request']->get('signature') && 'aes' === $this->app['request']->get('encrypt_type');
|
||||
}
|
||||
|
||||
protected function shouldReturnRawResponse(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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')
|
||||
);
|
||||
}
|
||||
}
|
||||
160
vendor/overtrue/wechat/src/Kernel/ServiceContainer.php
vendored
Normal file
160
vendor/overtrue/wechat/src/Kernel/ServiceContainer.php
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public function __construct(array $config = [], array $prepends = [], string $id = null)
|
||||
{
|
||||
$this->userConfig = $config;
|
||||
|
||||
parent::__construct($prepends);
|
||||
|
||||
$this->id = $id;
|
||||
|
||||
$this->registerProviders($this->getProviders());
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
public function registerProviders(array $providers)
|
||||
{
|
||||
foreach ($providers as $provider) {
|
||||
parent::register(new $provider());
|
||||
}
|
||||
}
|
||||
}
|
||||
66
vendor/overtrue/wechat/src/Kernel/Support/AES.php
vendored
Normal file
66
vendor/overtrue/wechat/src/Kernel/Support/AES.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class AES
|
||||
{
|
||||
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|null $method
|
||||
*/
|
||||
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';
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function validateIv(string $iv)
|
||||
{
|
||||
if (!empty($iv) && 16 !== strlen($iv)) {
|
||||
throw new \InvalidArgumentException('IV length must be 16 bytes.');
|
||||
}
|
||||
}
|
||||
}
|
||||
439
vendor/overtrue/wechat/src/Kernel/Support/Arr.php
vendored
Normal file
439
vendor/overtrue/wechat/src/Kernel/Support/Arr.php
vendored
Normal file
@@ -0,0 +1,439 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 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.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function divide(array $array)
|
||||
{
|
||||
return [array_keys($array), array_values($array)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten a multi-dimensional associative array with dots.
|
||||
*
|
||||
* @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|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 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 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 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 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|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 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 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.
|
||||
*
|
||||
* @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|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 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 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.
|
||||
*
|
||||
* @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 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.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
66
vendor/overtrue/wechat/src/Kernel/Support/ArrayAccessible.php
vendored
Normal file
66
vendor/overtrue/wechat/src/Kernel/Support/ArrayAccessible.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
417
vendor/overtrue/wechat/src/Kernel/Support/Collection.php
vendored
Normal file
417
vendor/overtrue/wechat/src/Kernel/Support/Collection.php
vendored
Normal file
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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)<br/>
|
||||
* 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 <b>json_encode</b>,
|
||||
* which is a value of any type other than a resource
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.1.0)<br/>
|
||||
* 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)<br/>
|
||||
* Retrieve an external iterator.
|
||||
*
|
||||
* @see http://php.net/manual/en/iteratoraggregate.getiterator.php
|
||||
*
|
||||
* @return \ArrayIterator An instance of an object implementing <b>Iterator</b> or
|
||||
* <b>Traversable</b>
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new ArrayIterator($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.1.0)<br/>
|
||||
* Count elements of an object.
|
||||
*
|
||||
* @see http://php.net/manual/en/countable.count.php
|
||||
*
|
||||
* @return int the custom count as an integer.
|
||||
* </p>
|
||||
* <p>
|
||||
* The return value is cast to an integer
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.1.0)<br/>
|
||||
* Constructs the object.
|
||||
*
|
||||
* @see http://php.net/manual/en/serializable.unserialize.php
|
||||
*
|
||||
* @param string $serialized <p>
|
||||
* The string representation of the object.
|
||||
* </p>
|
||||
*
|
||||
* @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 static function __set_state(array $properties)
|
||||
{
|
||||
return (new static($properties))->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Whether a offset exists.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetexists.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* An offset to check for.
|
||||
* </p>
|
||||
*
|
||||
* @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)<br/>
|
||||
* Offset to unset.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetunset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to unset.
|
||||
* </p>
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if ($this->offsetExists($offset)) {
|
||||
$this->forget($offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Offset to retrieve.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetget.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to retrieve.
|
||||
* </p>
|
||||
*
|
||||
* @return mixed Can return all value types
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->offsetExists($offset) ? $this->get($offset) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Offset to set.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to assign the value to.
|
||||
* </p>
|
||||
* @param mixed $value <p>
|
||||
* The value to set.
|
||||
* </p>
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->set($offset, $value);
|
||||
}
|
||||
}
|
||||
135
vendor/overtrue/wechat/src/Kernel/Support/File.php
vendored
Normal file
135
vendor/overtrue/wechat/src/Kernel/Support/File.php
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 '';
|
||||
}
|
||||
}
|
||||
127
vendor/overtrue/wechat/src/Kernel/Support/Helpers.php
vendored
Normal file
127
vendor/overtrue/wechat/src/Kernel/Support/Helpers.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generate a signature.
|
||||
*
|
||||
* @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))]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
193
vendor/overtrue/wechat/src/Kernel/Support/Str.php
vendored
Normal file
193
vendor/overtrue/wechat/src/Kernel/Support/Str.php
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
166
vendor/overtrue/wechat/src/Kernel/Support/XML.php
vendored
Normal file
166
vendor/overtrue/wechat/src/Kernel/Support/XML.php
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 .= "</{$root}>";
|
||||
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build CDATA.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function cdata($string)
|
||||
{
|
||||
return sprintf('<![CDATA[%s]]>', $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 .= "</{$key}>";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
245
vendor/overtrue/wechat/src/Kernel/Traits/HasAttributes.php
vendored
Normal file
245
vendor/overtrue/wechat/src/Kernel/Traits/HasAttributes.php
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $key)
|
||||
{
|
||||
return Arr::has($this->attributes, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
211
vendor/overtrue/wechat/src/Kernel/Traits/HasHttpRequests.php
vendored
Normal file
211
vendor/overtrue/wechat/src/Kernel/Traits/HasHttpRequests.php
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public static function getDefaultOptions(): array
|
||||
{
|
||||
return self::$defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set GuzzleHttp\Client.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHttpClient(ClientInterface $httpClient)
|
||||
{
|
||||
$this->httpClient = $httpClient;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return GuzzleHttp\ClientInterface instance.
|
||||
*/
|
||||
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 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.
|
||||
*/
|
||||
public function getMiddlewares(): array
|
||||
{
|
||||
return $this->middlewares;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a request.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param array $options
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setHandlerStack(HandlerStack $handlerStack)
|
||||
{
|
||||
$this->handlerStack = $handlerStack;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a handler stack.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
102
vendor/overtrue/wechat/src/Kernel/Traits/InteractsWithCache.php
vendored
Normal file
102
vendor/overtrue/wechat/src/Kernel/Traits/InteractsWithCache.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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->isSymfony43OrHigher()) {
|
||||
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->isSymfony43OrHigher()) {
|
||||
return new Psr16Cache(new FilesystemAdapter('easywechat', 1500));
|
||||
}
|
||||
|
||||
return new FilesystemCache();
|
||||
}
|
||||
|
||||
protected function isSymfony43OrHigher(): bool
|
||||
{
|
||||
return \class_exists('Symfony\Component\Cache\Psr16Cache');
|
||||
}
|
||||
}
|
||||
278
vendor/overtrue/wechat/src/Kernel/Traits/Observable.php
vendored
Normal file
278
vendor/overtrue/wechat/src/Kernel/Traits/Observable.php
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setHandlers(array $handlers = [])
|
||||
{
|
||||
$this->handlers = $handlers;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
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 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
|
||||
*
|
||||
* @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];
|
||||
}
|
||||
}
|
||||
92
vendor/overtrue/wechat/src/Kernel/Traits/ResponseCastable.php
vendored
Normal file
92
vendor/overtrue/wechat/src/Kernel/Traits/ResponseCastable.php
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
trait ResponseCastable
|
||||
{
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
168
vendor/overtrue/wechat/src/MicroMerchant/Application.php
vendored
Normal file
168
vendor/overtrue/wechat/src/MicroMerchant/Application.php
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@gmail.com>
|
||||
*
|
||||
* @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);
|
||||
if ($appId) {
|
||||
$this['config']->set('appid', $appId);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* setCertificate.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
117
vendor/overtrue/wechat/src/MicroMerchant/Base/Client.php
vendored
Normal file
117
vendor/overtrue/wechat/src/MicroMerchant/Base/Client.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
* @DateTime 2019-05-30 14:19
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* apply to settle in to become a small micro merchant.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
33
vendor/overtrue/wechat/src/MicroMerchant/Base/ServiceProvider.php
vendored
Normal file
33
vendor/overtrue/wechat/src/MicroMerchant/Base/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['base'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
89
vendor/overtrue/wechat/src/MicroMerchant/Certficates/Client.php
vendored
Normal file
89
vendor/overtrue/wechat/src/MicroMerchant/Certficates/Client.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
* @DateTime 2019-05-30 14:19
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* get certficates.
|
||||
*
|
||||
* @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_desc: "%s" .', $response['result_code'].'('.$response['err_code'].'['.$response['err_code_desc'].'])'));
|
||||
}
|
||||
$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.
|
||||
*
|
||||
* @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
|
||||
);
|
||||
}
|
||||
}
|
||||
33
vendor/overtrue/wechat/src/MicroMerchant/Certficates/ServiceProvider.php
vendored
Normal file
33
vendor/overtrue/wechat/src/MicroMerchant/Certficates/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['certficates'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
241
vendor/overtrue/wechat/src/MicroMerchant/Kernel/BaseClient.php
vendored
Normal file
241
vendor/overtrue/wechat/src/MicroMerchant/Kernel/BaseClient.php
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
* @DateTime 2019-07-10 12:06
|
||||
*/
|
||||
class BaseClient extends PaymentBaseClient
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $certificates;
|
||||
|
||||
/**
|
||||
* BaseClient constructor.
|
||||
*/
|
||||
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 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 $method
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
23
vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/EncryptException.php
vendored
Normal file
23
vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/EncryptException.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
*/
|
||||
class EncryptException extends Exception
|
||||
{
|
||||
}
|
||||
23
vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidExtensionException.php
vendored
Normal file
23
vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidExtensionException.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
*/
|
||||
class InvalidExtensionException extends Exception
|
||||
{
|
||||
}
|
||||
23
vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidSignException.php
vendored
Normal file
23
vendor/overtrue/wechat/src/MicroMerchant/Kernel/Exceptions/InvalidSignException.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
*/
|
||||
class InvalidSignException extends Exception
|
||||
{
|
||||
}
|
||||
69
vendor/overtrue/wechat/src/MicroMerchant/Material/Client.php
vendored
Normal file
69
vendor/overtrue/wechat/src/MicroMerchant/Material/Client.php
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
* @DateTime 2019-05-30 14:19
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* update settlement card.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
33
vendor/overtrue/wechat/src/MicroMerchant/Material/ServiceProvider.php
vendored
Normal file
33
vendor/overtrue/wechat/src/MicroMerchant/Material/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['material'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
47
vendor/overtrue/wechat/src/MicroMerchant/Media/Client.php
vendored
Normal file
47
vendor/overtrue/wechat/src/MicroMerchant/Media/Client.php
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
* @DateTime 2019-06-10 14:50
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* Upload material.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
44
vendor/overtrue/wechat/src/MicroMerchant/Media/ServiceProvider.php
vendored
Normal file
44
vendor/overtrue/wechat/src/MicroMerchant/Media/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['media'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
116
vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/Client.php
vendored
Normal file
116
vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/Client.php
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
* @DateTime 2019-05-30 14:19
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* Service providers configure recommendation functions for small and micro businesses.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
33
vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/ServiceProvider.php
vendored
Normal file
33
vendor/overtrue/wechat/src/MicroMerchant/MerchantConfig/ServiceProvider.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <i@overtrue.me>
|
||||
*/
|
||||
class ServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['merchantConfig'] = function ($app) {
|
||||
return new Client($app);
|
||||
};
|
||||
}
|
||||
}
|
||||
67
vendor/overtrue/wechat/src/MicroMerchant/Withdraw/Client.php
vendored
Normal file
67
vendor/overtrue/wechat/src/MicroMerchant/Withdraw/Client.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/wechat.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* 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 <liumenglei0211@163.com>
|
||||
* @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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user