2019-06-06 15:07:21 +08:00

248 lines
9.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// +----------------------------------------------------------------------
// | framework
// +----------------------------------------------------------------------
// | 版权所有 2014~2018 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
// +----------------------------------------------------------------------
// | 官方网站: http://framework.thinkadmin.top
// +----------------------------------------------------------------------
// | 开源协议 ( https://mit-license.org )
// +----------------------------------------------------------------------
// | github开源项目https://github.com/zoujingli/framework
// +----------------------------------------------------------------------
namespace app\wechat\service;
/**
* 微信处理管理
* Class Wechat
* @package app\wechat\service
*
* ----- WeOpen for Open -----
* @method \WeOpen\Login login() static 第三方微信登录
* @method \WeOpen\Service service() static 第三方服务
*
* ----- WeMini for Open -----
* @method \WeMini\Code WeMiniCode() static 小程序代码管理
* @method \WeMini\User WeMiniUser() static 小程序帐号管理
* @method \WeMini\Basic WeMiniBasic() static 小程序基础信息
* @method \WeMini\Domain WeMiniDomain() static 小程序域名管理
* @method \WeMini\Tester WeMiniTester() static 小程序成员管理
* @method \WeMini\Account WeMiniAccount() static 小程序账号管理
*
* ----- ThinkService -----
* @method mixed wechat() static 第三方微信工具
*/
class Wechat extends \We
{
/**
* 接口类型模式
* @var string
*/
private static $type = 'WeChat';
/**
* 获取微信支付配置
* @param array|null $options
* @return array
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function config($options = null)
{
if (empty($options)) $options = [
// 微信功能必需参数
'appid' => self::getAppid(),
'token' => sysconf('wechat_token'),
'appsecret' => sysconf('wechat_appsecret'),
'encodingaeskey' => sysconf('wechat_encodingaeskey'),
// 微信支付必要参数
'mch_id' => sysconf('wechat_mch_id'),
'mch_key' => sysconf('wechat_mch_key'),
'cache_path' => env('runtime_path') . 'wechat' . DIRECTORY_SEPARATOR,
];
if (sysconf('wechat_mch_ssl_type') === 'p12') {
$options['ssl_p12'] = self::_parseCertPath(sysconf('wechat_mch_ssl_p12'));
} else {
$options['ssl_key'] = self::_parseCertPath(sysconf('wechat_mch_ssl_key'));
$options['ssl_cer'] = self::_parseCertPath(sysconf('wechat_mch_ssl_cer'));
}
return parent::config($options);
}
/**
* 解析证书路径
* @param string $path
* @return mixed
* @throws \think\Exception
*/
private static function _parseCertPath($path)
{
if (preg_match('|^[a-z0-9]{16,16}\/[a-z0-9]{16,16}\.|i', $path)) {
return \library\File::instance('local')->path($path, true);
}
return $path;
}
/**
* 静态魔术加载方法
* @param string $name 静态类名
* @param array $arguments 参数集合
* @return mixed
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function __callStatic($name, $arguments)
{
$config = [];
if (is_array($arguments) && count($arguments) > 0) {
$option = array_shift($arguments);
$config = is_array($option) ? $option : self::config();
}
if (in_array($name, ['wechat'])) {
return self::instance(trim($name, '_'), 'WeChat', $config);
} elseif (substr($name, 0, 6) === 'WeChat') {
return self::instance(substr($name, 6), 'WeChat', $config);
} elseif (substr($name, 0, 6) === 'WeMini') {
return self::instance(substr($name, 6), 'WeMini', $config);
} elseif (substr($name, 0, 5) === 'WePay') {
return self::instance(substr($name, 5), 'WePay', $config);
} elseif (substr($name, 0, 6) === 'AliPay') {
return self::instance(substr($name, 6), 'AliPay', $config);
}
throw new \think\Exception("class {$name} not found");
}
/**
* 接口对象实例化
* @param string $name 接口名称
* @param string $type 接口类型
* @param array $config 微信配置
* @return mixed
* @throws \SoapFault
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function instance($name, $type = 'WeChat', $config = [])
{
if (!in_array($type, ['WeChat', 'WeMini', 'WePay', 'AliPay'])) $type = self::$type;
if (self::getType() === 'api' || in_array($type, ['WePay', 'AliPay'])) {
$class = "\\{$type}\\" . ucfirst(strtolower($name));
if (class_exists($class)) return new $class(empty($config) ? self::config() : $config);
throw new \think\Exception("Class '{$class}' not found");
}
set_time_limit(3600);
list($appid, $appkey) = [sysconf('wechat_thr_appid'), sysconf('wechat_thr_appkey')];
$token = strtolower("{$name}-{$appid}-{$appkey}-{$type}");
if (class_exists('Yar_Client')) {
return new \Yar_Client(config('wechat.service_url') . "/service/api.client/yar/{$token}");
}
if (class_exists('SoapClient')) {
$location = config('wechat.service_url') . "/service/api.client/soap/{$token}";
return new \SoapClient(null, ['uri' => strtolower($name), 'location' => $location]);
}
throw new \think\Exception("Yar or soap extensions are not installed.");
}
/**
* 获取微信网页JSSDK
* @param string $url JS签名地址
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function getWebJssdkSign($url = null)
{
$url = is_null($url) ? request()->url(true) : $url;
if (self::getType() === 'api') {
return self::WeChatScript()->getJsSign($url);
} else {
return self::wechat()->jsSign($url);
}
}
/**
* 初始化进入授权
* @param string $url 授权页面URL地址
* @param integer $isfull 授权公众号模式
* @param boolean $isRedirect 是否进行跳转
* @return array
* @throws \WeChat\Exceptions\InvalidResponseException
* @throws \WeChat\Exceptions\LocalCacheException
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function getWebOauthInfo($url, $isfull = 0, $isRedirect = true)
{
$appid = self::getAppid();
list($openid, $fansinfo) = [session("{$appid}_openid"), session("{$appid}_fansinfo")];
if ((empty($isfull) && !empty($openid)) || (!empty($isfull) && !empty($openid) && !empty($fansinfo))) {
empty($fansinfo) || Fans::set($fansinfo);
return ['openid' => $openid, 'fansinfo' => $fansinfo];
}
if (self::getType() === 'api') {
$wechat = self::WeChatOauth();
if (request()->get('state') !== $appid) {
$snsapi = empty($isfull) ? 'snsapi_base' : 'snsapi_userinfo';
$param = (strpos($url, '?') !== false ? '&' : '?') . 'rcode=' . encode($url);
$OauthUrl = $wechat->getOauthRedirect($url . $param, $appid, $snsapi);
if ($isRedirect) redirect($OauthUrl, [], 301)->send();
exit("window.location.href='{$OauthUrl}'");
}
if (($token = $wechat->getOauthAccessToken()) && isset($token['openid'])) {
session("{$appid}_openid", $openid = $token['openid']);
if (empty($isfull) && request()->get('rcode')) {
redirect(decode(request()->get('rcode')), [], 301)->send();
}
session("{$appid}_fansinfo", $fansinfo = $wechat->getUserInfo($token['access_token'], $openid));
empty($fansinfo) || Fans::set($fansinfo);
}
redirect(decode(request()->get('rcode')), [], 301)->send();
} else {
$result = self::wechat()->oauth(session_id(), $url, $isfull);
session("{$appid}_openid", $openid = $result['openid']);
session("{$appid}_fansinfo", $fansinfo = $result['fans']);
if ((empty($isfull) && !empty($openid)) || (!empty($isfull) && !empty($openid) && !empty($fansinfo))) {
empty($fansinfo) || Fans::set($fansinfo);
return ['openid' => $openid, 'fansinfo' => $fansinfo];
}
if ($isRedirect && !empty($result['url'])) {
redirect($result['url'], [], 301)->send();
}
exit("window.location.href='{$result['url']}'");
}
}
/**
* 获取当前公众号APPID
* @return bool|string
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function getAppid()
{
if (self::getType() === 'api') {
return sysconf('wechat_appid');
} else {
return sysconf('wechat_thr_appid');
}
}
/**
* 获取接口授权模式
* @return string
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function getType()
{
$type = strtolower(sysconf('wechat_type'));
if (in_array($type, ['api', 'thr'])) return $type;
throw new \think\Exception('请在后台配置微信对接授权模式');
}
}