From 045d9556be2fd5e71825ac1f76f9d71dabbfeb1a Mon Sep 17 00:00:00 2001
From: liliuwei <974829947@qq.com>
Date: Sun, 24 Nov 2019 22:49:04 +0800
Subject: [PATCH] init
---
.gitignore | 0
LICENSE | 201 +++++++++++++++++++++++++++++++
README.md | 92 +++++++++++++++
composer.json | 33 ++++++
src/GetInfo.php | 221 ++++++++++++++++++++++++++++++++++
src/Oauth.php | 267 ++++++++++++++++++++++++++++++++++++++++++
src/config/config.php | 67 +++++++++++
src/sdk/Baidu.php | 74 ++++++++++++
src/sdk/Facebook.php | 83 +++++++++++++
src/sdk/Gitee.php | 79 +++++++++++++
src/sdk/Github.php | 73 ++++++++++++
src/sdk/Google.php | 80 +++++++++++++
src/sdk/Oschina.php | 81 +++++++++++++
src/sdk/Qq.php | 111 ++++++++++++++++++
src/sdk/Sina.php | 74 ++++++++++++
src/sdk/Taobao.php | 106 +++++++++++++++++
src/sdk/Weixin.php | 127 ++++++++++++++++++++
17 files changed, 1769 insertions(+)
create mode 100644 .gitignore
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 composer.json
create mode 100644 src/GetInfo.php
create mode 100644 src/Oauth.php
create mode 100644 src/config/config.php
create mode 100644 src/sdk/Baidu.php
create mode 100644 src/sdk/Facebook.php
create mode 100644 src/sdk/Gitee.php
create mode 100644 src/sdk/Github.php
create mode 100644 src/sdk/Google.php
create mode 100644 src/sdk/Oschina.php
create mode 100644 src/sdk/Qq.php
create mode 100644 src/sdk/Sina.php
create mode 100644 src/sdk/Taobao.php
create mode 100644 src/sdk/Weixin.php
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..56bafb7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,92 @@
+## thinkphp-social
+适用于thinkphp5.1 thinkphp6.0的社会化登录扩展
+
+目前已支持:QQ、微信、新浪、百度、Gitee、Github、Oschina、Google、Facebook、淘宝
+
+## 安装(扩展包)
+```php
+composer require liliuwei/thinkphp-social
+```
+
+# 配置Config信息
+```php
+// 安装之后会在config目录里自动生成social.php配置文件
+ [
+ 'app_key' => '*******', //应用注册成功后分配的 APP ID
+ 'app_secret' => '*******', //应用注册成功后分配的KEY
+ 'callback' => 'http://www.youquanya.com/oauth/callback/type/qq', // 应用回调地址
+ ],
+ //微信扫码登录配置
+ 'weixin' => [
+ 'app_key' => '*******', //应用注册成功后分配的 APP ID
+ 'app_secret' => '*******', //应用注册成功后分配的KEY
+ 'callback' => 'http://www.youquanya.com/oauth/callback/type/weixin', // 应用回调地址
+ ],
+];
+
+```
+
+## 用法示例
+````
+QQ登录
+新浪微博登录
+微信登录
+百度登录
+gitee登录
+github登录
+oschaina登录
+google登录
+facebook登录
+淘宝登录
+ ````
+```php
+//设置路由
+Route::get('oauth/callback','index/oauth/callback');
+```
+
+```php
+error('参数错误');
+ }
+ // 获取对象实例
+ $sns = \liliuwei\social\Oauth::getInstance($type);
+ //跳转到授权页面
+ $this->redirect($sns->getRequestCodeURL());
+ }
+
+ //授权回调地址
+ public function callback($type = null, $code = null)
+ {
+ if ($type == null || $code == null) {
+ $this->error('参数错误');
+ }
+ $sns = \liliuwei\social\Oauth::getInstance($type);
+ // 获取TOKEN
+ $token = $sns->getAccessToken($code);
+ //获取当前第三方登录用户信息
+ if (is_array($token)) {
+ $user_info = \liliuwei\social\GetInfo::getInstance($type, $token);
+ dump($user_info);// 获取第三方用户资料
+ $sns->openid();//统一使用$sns->openid()获取openid
+ //$sns->unionid();//QQ和微信、淘宝可以获取unionid
+ dump($sns->openid());
+ echo '登录成功!!';
+ echo '正在持续开发中,敬请期待!!';
+ } else {
+ echo "获取第三方用户的基本信息失败";
+ }
+ }
+}
+```
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..2df64a7
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,33 @@
+{
+ "name": "liliuwei/thinkphp-social",
+ "description": "适用于thinkphp5.1和6.0的社会化登录扩展",
+ "keywords": ["第三方授权登录","QQ登录","微信登录","新浪登录","百度登录","谷歌登录","Google登录","Facebook登录","Gitee登录","Github登录","Oschina登录","淘宝登录","think-social","thinkphp-social","oauth", "thinkphp","thinkphp5.1","thinkphp6.0"],
+ "license": "Apache-2.0",
+ "type": "think-extend",
+ "require": {
+ "php": "^5.6 || ^7.1",
+ "topthink/think-installer": "^2.0",
+ "topthink/framework": "^5.1 || ^6.0"
+ },
+ "authors": [
+ {
+ "name": "liliuwei",
+ "email": "974829947@qq.com"
+ }
+ ],
+ "autoload" : {
+ "psr-4" : {
+ "liliuwei\\social\\" : "src/"
+ }
+ },
+ "extra": {
+ "think-config": {
+ "social": "src/config/config.php"
+ },
+ "think": {
+ "config": {
+ "social": "src/config/config.php"
+ }
+ }
+ }
+}
diff --git a/src/GetInfo.php b/src/GetInfo.php
new file mode 100644
index 0000000..d23ecb4
--- /dev/null
+++ b/src/GetInfo.php
@@ -0,0 +1,221 @@
+call('user/get_user_info');
+ if ($data['ret'] == 0) {
+ $userInfo['type'] = 'qq';
+ $userInfo['name'] = $data['nickname'];
+ $userInfo['nickname'] = $data['nickname'];
+ $userInfo['avatar'] = $data['figureurl_2'];
+ $userInfo['gender'] = $data['gender'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取腾讯QQ用户信息失败:{$data['msg']}");
+ }
+ }
+
+ //微信用户信息
+ public static function weixin($token)
+ {
+ $weixin = Oauth::getInstance('weixin', $token);
+ $data = $weixin->call('sns/userinfo');
+ if (isset($data['errcode'])) {
+ throw new \Exception("获取微信用户信息失败:errcode:{$data['errcode']} errmsg: {$data['errmsg']}");
+ }
+ if ($data['openid']) {
+ $userInfo['type'] = 'weixin';
+ $userInfo['name'] = $data['nickname'];
+ $userInfo['nickname'] = $data['nickname'];
+ $userInfo['avatar'] = $data['headimgurl'];
+ $userInfo['openid'] = $data['openid'];
+ $userInfo['unionid'] = $data['unionid'];
+ $userInfo['province'] = $data['province'];
+ $userInfo['city'] = $data['city'];
+ $userInfo['country'] = $data['country'];
+ $userInfo['sex'] = $data['sex']==1?'男':'女';
+ return $userInfo;
+ } else {
+ throw new \Exception("获取微信用户信息失败");
+ }
+ }
+
+ //新浪微博用户信息
+ public static function sina($token)
+ {
+ $sina = Oauth::getInstance('sina', $token);
+ $data = $sina->call('users/show',"uid={$sina->openid()}");
+ if ($data['id']) {
+ $userInfo['type'] = 'sina';
+ $userInfo['name'] = $data['name'];
+ $userInfo['nickname'] = $data['screen_name'];
+ $userInfo['avatar'] = $data['avatar_large'];
+ $userInfo['openid'] = $data['id'];
+ $userInfo['idstr'] = $data['idstr'];
+ $userInfo['province'] = $data['province'];
+ $userInfo['city'] = $data['city'];
+ $userInfo['location'] = $data['location'];
+ $userInfo['created_at'] = $data['created_at'];
+ $userInfo['gender'] = $data['gender']=='m'?'男':($data['gender']=='f'?'女':'未知');
+ $userInfo['followers_count'] = $data['followers_count'];
+ $userInfo['friends_count'] = $data['friends_count'];
+ $userInfo['statuses_count'] = $data['statuses_count'];
+ $userInfo['favourites_count'] = $data['favourites_count'];
+ $userInfo['description'] = $data['description'];
+ $userInfo['url'] = $data['url'];
+ $userInfo['profile_url'] = $data['profile_url'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取新浪微博用户信息失败:{$data['error']}");
+ }
+ }
+
+ //Baidu用户信息
+ public static function baidu($token)
+ {
+ $baidu = Oauth::getInstance('baidu', $token);
+ $data = $baidu->call('passport/users/getInfo');
+ if (isset($data['userid'])) {
+ $userInfo['type'] = 'baidu';
+ $userInfo['name'] = $data['username'];
+ $userInfo['nickname'] = isset($data['realname'])?$data['realname']:'';
+ $userInfo['avatar'] = 'http://tb.himg.baidu.com/sys/portrait/item/'.$data['portrait'];
+ $userInfo['openid'] = $data['userid'];
+ $userInfo['sex'] = $data['sex']==1?'男':'女';
+ return $userInfo;
+ } else {
+ throw new \Exception("获取Baidu用户信息失败");
+ }
+ }
+
+ //Gitee用户信息
+ public static function gitee($token)
+ {
+ $google = Oauth::getInstance('gitee', $token);
+ $data = $google->call('user');
+ if (isset($data['id'])) {
+ $userInfo['type'] = 'gitee';
+ $userInfo['name'] = $data['name'];
+ $userInfo['nickname'] = $data['login'];
+ $userInfo['avatar'] = $data['avatar_url'];
+ $userInfo['openid'] = $data['id'];
+ $userInfo['html_url'] = $data['html_url'];
+ $userInfo['blog'] = $data['blog'];
+ $userInfo['email'] = $data['email'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取Gitee用户信息失败");
+ }
+ }
+
+ //Github用户信息
+ public static function github($token)
+ {
+ $google = Oauth::getInstance('github', $token);
+ $data = $google->call('user');
+ if (isset($data['id'])) {
+ $userInfo['type'] = 'github';
+ $userInfo['name'] = $data['name'];
+ $userInfo['nickname'] = $data['login'];
+ $userInfo['avatar'] = $data['avatar_url'];
+ $userInfo['openid'] = $data['id'];
+ $userInfo['html_url'] = $data['html_url'];
+ $userInfo['blog'] = $data['blog'];
+ $userInfo['email'] = $data['email'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取Gitee用户信息失败");
+ }
+ }
+
+ //Google用户信息
+ public static function google($token)
+ {
+ $google = Oauth::getInstance('google', $token);
+ $data = $google->call('userinfo');
+ if (isset($data['id'])) {
+ $userInfo['type'] = 'google';
+ $userInfo['name'] = $data['name'];
+ $userInfo['nickname'] = $data['name'];
+ $userInfo['avatar'] = $data['picture'];
+ $userInfo['openid'] = $data['id'];
+ $userInfo['given_name'] = $data['given_name'];
+ $userInfo['family_name'] = $data['family_name'];
+ $userInfo['locale'] = $data['locale'];
+ $userInfo['email'] = $data['email'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取Google用户信息失败");
+ }
+ }
+
+ //Facebook用户信息
+ public static function facebook($token)
+ {
+ $facebook = Oauth::getInstance('facebook', $token);
+ $data = $facebook->call('me', 'fields=name,picture,first_name,last_name,short_name,email');
+ if (isset($data['id'])) {
+ $userInfo['type'] = 'facebook';
+ $userInfo['name'] = $data['name'];
+ $userInfo['nickname'] = $data['name'];
+ $userInfo['avatar'] = $data['picture']['data']['url'];
+ $userInfo['openid'] = $data['id'];
+ $userInfo['first_name'] = $data['first_name'];
+ $userInfo['last_name'] = $data['last_name'];
+ $userInfo['short_name'] = $data['short_name'];
+ $userInfo['email'] = $data['email'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取Facebook用户信息失败");
+ }
+ }
+
+ //Oschina用户信息
+ public static function oschina($token)
+ {
+ $oschina = Oauth::getInstance('oschina', $token);
+ $data = $oschina->call('action/openapi/user');
+ if (isset($data['id'])) {
+ $userInfo['type'] = 'gitee';
+ $userInfo['name'] = $data['name'];
+ $userInfo['nickname'] = $data['name'];
+ $userInfo['avatar'] = $data['avatar'];
+ $userInfo['openid'] = $data['id'];
+ $userInfo['email'] = $data['email'];
+ $userInfo['location'] = $data['location'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取Gitee用户信息失败");
+ }
+ }
+
+ //Taobao用户信息
+ public static function taobao($token)
+ {
+ $data = $token;
+ if (isset($data['taobao_user_id'])) {
+ $userInfo['type'] = 'taobao';
+ $userInfo['name'] = urldecode($data['taobao_user_nick']);
+ $userInfo['nickname'] = urldecode($data['taobao_user_nick']);
+ $userInfo['avatar'] = '';
+ $userInfo['openid'] = $data['taobao_user_id'];
+ $userInfo['taobao_open_uid'] = $data['taobao_open_uid'];
+ return $userInfo;
+ } else {
+ throw new \Exception("获取淘宝用户信息失败");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Oauth.php b/src/Oauth.php
new file mode 100644
index 0000000..380cf56
--- /dev/null
+++ b/src/Oauth.php
@@ -0,0 +1,267 @@
+Type = strtolower($re_str);
+
+ //获取应用配置
+ $config = config("social.{$this->Type}");
+ if (empty($config['app_key']) || empty($config['app_secret'])) {
+ throw new \Exception('请配置您申请的app_key和app_secret');
+ } else {
+ $this->AppKey = $config['app_key'];
+ $this->AppSecret = $config['app_secret'];
+ $this->Token = $token; //设置获取到的TOKEN
+ }
+ }
+
+ /**
+ * 取得Oauth实例
+ * @static
+ * @return mixed 返回Oauth
+ */
+ public static function getInstance($type, $token = null)
+ {
+ $sdk = [
+ 'Qq', 'Weixin', 'Sina', 'Baidu', 'Gitee', 'Github', 'Google', 'Facebook', 'Taobao', 'Oschina'
+ ];
+ $name = ucfirst(strtolower($type));
+ if (in_array($name, $sdk)) {
+ $class = '\\liliuwei\\social\\sdk\\' . $name;
+ return new $class($token);
+ } else {
+ header('content-type:text/html;charset=utf-8');
+ throw new \Exception('暂时还不支持该' . $name . '的扩展');
+ }
+ }
+
+ /**
+ * 初始化配置
+ */
+ protected function config()
+ {
+ $config = config("social.{$this->Type}");
+ if (!empty($config['authorize']))
+ $this->Authorize = $config['authorize'];
+ if (!empty($config['callback']))
+ $this->Callback = $config['callback'];
+ else
+ throw new \Exception('请配置回调页面地址');
+ }
+
+ /**
+ * 请求code
+ */
+ public function getRequestCodeURL()
+ {
+ $this->config();
+ //Oauth 标准参数
+ $params = array(
+ 'client_id' => $this->AppKey,
+ 'redirect_uri' => $this->Callback,
+ 'response_type' => $this->ResponseType,
+ );
+
+ //获取额外参数
+ if ($this->Authorize) {
+ parse_str($this->Authorize, $_param);
+ if (is_array($_param)) {
+ $params = array_merge($params, $_param);
+ } else {
+ throw new \Exception('AUTHORIZE配置不正确!');
+ }
+ }
+ return $this->GetRequestCodeURL . '?' . http_build_query($params);
+ }
+
+ /**
+ * 获取access_token
+ * @param string $code 上一步请求到的code
+ */
+ public function getAccessToken($code, $extend = null)
+ {
+ $this->config();
+ $params = array(
+ 'client_id' => $this->AppKey,
+ 'client_secret' => $this->AppSecret,
+ 'grant_type' => $this->GrantType,
+ 'code' => $code,
+ 'redirect_uri' => $this->Callback,
+ );
+
+ $data = $this->http($this->GetAccessTokenURL, $params, 'POST');
+ $this->Token = $this->parseToken($data, $extend);
+ return $this->Token;
+ }
+
+ /**
+ * 合并默认参数和额外参数
+ * @param array $params 默认参数
+ * @param array/string $param 额外参数
+ * @return array:
+ */
+ protected function param($params, $param)
+ {
+ if (is_string($param))
+ parse_str($param, $param);
+ return array_merge($params, $param);
+ }
+
+ /**
+ * 获取指定API请求的URL
+ * @param string $api API名称
+ * @param string $fix api后缀
+ * @return string 请求的完整URL
+ */
+ protected function url($api = '', $fix = '')
+ {
+ return $this->ApiBase . $api . $fix;
+ }
+
+ /**
+ * 发送HTTP请求方法,目前只支持CURL发送请求
+ * @param string $url 请求URL
+ * @param array $params 请求参数
+ * @param string $method 请求方法GET/POST
+ * @return array $data 响应数据
+ */
+ protected function http($url, $params, $method = 'GET', $header = array(), $multi = false)
+ {
+ $opts = array(
+ CURLOPT_TIMEOUT => 30,
+ CURLOPT_RETURNTRANSFER => 1,
+ CURLOPT_SSL_VERIFYPEER => false,
+ CURLOPT_SSL_VERIFYHOST => false,
+ CURLOPT_HTTPHEADER => $header
+ );
+
+ /* 根据请求类型设置特定参数 */
+ switch (strtoupper($method)) {
+ case 'GET':
+ $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
+ break;
+ case 'POST':
+ //判断是否传输文件
+ $params = $multi ? $params : http_build_query($params);
+ $opts[CURLOPT_URL] = $url;
+ $opts[CURLOPT_POST] = 1;
+ $opts[CURLOPT_POSTFIELDS] = $params;
+ break;
+ default:
+ throw new \Exception('不支持的请求方式!');
+ }
+
+ /* 初始化并执行curl请求 */
+ $ch = curl_init();
+ curl_setopt_array($ch, $opts);
+ $data = curl_exec($ch);
+ $error = curl_error($ch);
+ curl_close($ch);
+ if ($error) throw new \Exception('请求发生错误:' . $error);
+ return $data;
+ }
+
+ /**
+ * 抽象方法,在SNSSDK中实现
+ * 组装接口调用参数 并调用接口
+ */
+ abstract protected function call($api, $param = '', $method = 'GET', $multi = false);
+
+ /**
+ * 抽象方法,在SNSSDK中实现
+ * 解析access_token方法请求后的返回值
+ */
+ abstract protected function parseToken($result, $extend);
+
+ /**
+ * 抽象方法,在SNSSDK中实现
+ * 获取当前授权用户的SNS标识
+ */
+ abstract public function openid();
+}
\ No newline at end of file
diff --git a/src/config/config.php b/src/config/config.php
new file mode 100644
index 0000000..6df26ae
--- /dev/null
+++ b/src/config/config.php
@@ -0,0 +1,67 @@
+ [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //微信扫码登录配置
+ 'weixin' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //新浪登录配置
+ 'sina' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //Baidu登录配置
+ 'baidu' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //Gitee登录配置
+ 'gitee' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //Github登录配置
+ 'github' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //Google登录配置
+ 'google' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //Facebook登录配置
+ 'facebook' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //Oschina登录配置
+ 'oschina' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ],
+ //Taobao登录配置
+ 'taobao' => [
+ 'app_key' => '', //应用注册成功后分配的 APP ID
+ 'app_secret' => '', //应用注册成功后分配的KEY
+ 'callback' => '', // 应用回调地址
+ ]
+];
diff --git a/src/sdk/Baidu.php b/src/sdk/Baidu.php
new file mode 100644
index 0000000..8e9e86a
--- /dev/null
+++ b/src/sdk/Baidu.php
@@ -0,0 +1,74 @@
+ $this->Token['access_token'],
+ );
+ $data = $this->http($this->url($api), $this->param($params, $param), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if ($data['access_token'] && $data['expires_in'] && $data['refresh_token']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取百度ACCESS_TOKEN出错:{$data['error']}");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid()
+ {
+ $data = $this->call('passport/users/getInfo');
+ if (isset($data['userid']))
+ return $data['userid'];
+ else
+ throw new \Exception('没有获取到百度用户ID!');
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Facebook.php b/src/sdk/Facebook.php
new file mode 100644
index 0000000..58dd342
--- /dev/null
+++ b/src/sdk/Facebook.php
@@ -0,0 +1,83 @@
+ $this->Token['access_token']);
+ $data = $this->http($this->url($api), $this->param($params, $param), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ * @param mix $extend
+ * @return array
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if (is_array($data) && $data['access_token'] && $data['expires_in']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else {
+ throw new \Exception("获取 facebook ACCESS_TOKEN出错:未知错误");
+ }
+
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid()
+ {
+ $data = $this->call('me');
+ if (isset($data['id']))
+ return $data['id'];
+ else
+ throw new \Exception('没有获取到 facebook 用户ID!');
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Gitee.php b/src/sdk/Gitee.php
new file mode 100644
index 0000000..5fcd481
--- /dev/null
+++ b/src/sdk/Gitee.php
@@ -0,0 +1,79 @@
+Token['access_token']}");
+ $data = $this->http($this->url($api), $this->param($params, $param), $method, $header);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if ($data['access_token'] && $data['token_type']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取 Gitee ACCESS_TOKEN出错:未知错误");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid()
+ {
+ $data = $this->call('user');
+ if (isset($data['id']))
+ return $data['id'];
+ else
+ throw new \Exception('没有获取到 Gitee 用户ID!');
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Github.php b/src/sdk/Github.php
new file mode 100644
index 0000000..d821e05
--- /dev/null
+++ b/src/sdk/Github.php
@@ -0,0 +1,73 @@
+Token['access_token']}","User-Agent:thinkphp-social");
+ $data = $this->http($this->url($api), $this->param($params, $param), $method, $header);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ parse_str($result, $data);
+ if ($data['access_token'] && $data['token_type']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取 Github ACCESS_TOKEN出错:未知错误");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid()
+ {
+ $data = $this->call('user');
+ if (isset($data['id']))
+ return $data['id'];
+ else
+ throw new \Exception('没有获取到 Github 用户ID!');
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Google.php b/src/sdk/Google.php
new file mode 100644
index 0000000..4502807
--- /dev/null
+++ b/src/sdk/Google.php
@@ -0,0 +1,80 @@
+ $this->Token['access_token'],
+ );
+ $data = $this->http($this->url($api), $this->param($params, $param), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if ($data['access_token'] && $data['expires_in']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取Google ACCESS_TOKEN 出错:{$result}");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid()
+ {
+ $data = $this->call('userinfo');
+ if (isset($data['id']))
+ return $data['id'];
+ else
+ throw new \Exception('没有获取到 Google 用户ID!');
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Oschina.php b/src/sdk/Oschina.php
new file mode 100644
index 0000000..feac8f1
--- /dev/null
+++ b/src/sdk/Oschina.php
@@ -0,0 +1,81 @@
+ $this->Token['access_token'],
+ 'dataType' => 'json'
+ );
+ $data = $this->http($this->url($api), $this->param($params, $param), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if ($data['access_token'] && $data['token_type']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取 Oschina ACCESS_TOKEN出错:未知错误");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid()
+ {
+ $data = $this->call('action/openapi/user');
+ if (isset($data['id']))
+ return $data['id'];
+ else
+ throw new \Exception('没有获取到 Oschina 用户ID!');
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Qq.php b/src/sdk/Qq.php
new file mode 100644
index 0000000..e81f00a
--- /dev/null
+++ b/src/sdk/Qq.php
@@ -0,0 +1,111 @@
+ $this->AppKey,
+ 'access_token' => $this->Token['access_token'],
+ 'openid' => $this->openid(),
+ 'format' => 'json'
+ );
+ $data = $this->http($this->url($api), $this->param($params, $param), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ parse_str($result, $data);
+ if ($data['access_token'] && $data['expires_in']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取腾讯QQ ACCESS_TOKEN 出错:{$result}");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid($unionid=false)
+ {
+ if ($unionid){
+ return $this->unionid();
+ }
+ $data = $this->Token;
+ if ($data['access_token']) {
+ $data = $this->http($this->url('oauth2.0/me'), array('access_token' => $data['access_token']));
+ $data = json_decode(trim(substr($data, 9), " );\n"), true);
+ if (isset($data['openid']))
+ return $data['openid'];
+ else
+ throw new \Exception("获取用户openid出错:{$data['error_description']}");
+ } else {
+ throw new \Exception('没有获取到openid!');
+ }
+ }
+
+ /**
+ * 获取当前授权应用的unionid
+ * @return string
+ */
+ public function unionid()
+ {
+ $data = $this->Token;
+ if ($data['access_token']) {
+ $data = $this->http($this->url('oauth2.0/me'), array('access_token' => $data['access_token'],'unionid'=>1));
+ $data = json_decode(trim(substr($data, 9), " );\n"), true);
+ if (isset($data['unionid']))
+ return $data['unionid'];
+ else
+ throw new \Exception("获取用户unionid出错:{$data['error_description']}");
+ } else {
+ throw new \Exception('没有获取到unionid!');
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Sina.php b/src/sdk/Sina.php
new file mode 100644
index 0000000..d9ea774
--- /dev/null
+++ b/src/sdk/Sina.php
@@ -0,0 +1,74 @@
+ $this->Token['access_token'],
+ );
+ $data = $this->http($this->url($api, '.json'), $this->param($params, $param), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if ($data['access_token'] && $data['expires_in'] && $data['remind_in'] && $data['uid']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取新浪微博ACCESS_TOKEN出错:{$data['error']}");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid()
+ {
+ $data = $this->Token;
+ if (isset($data['uid']))
+ return $data['uid'];
+ else
+ throw new \Exception('没有获取到新浪微博用户ID!');
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Taobao.php b/src/sdk/Taobao.php
new file mode 100644
index 0000000..bb76551
--- /dev/null
+++ b/src/sdk/Taobao.php
@@ -0,0 +1,106 @@
+ $api,
+ 'access_token' => $this->Token['access_token'],
+ 'format' => 'json',
+ 'v' => '2.0',
+ );
+ $paramsAll = $this->param($params, $param);
+ ksort($paramsAll);
+ $str = '';
+ foreach ($paramsAll as $key => $value) {
+ $str .= $key . $value;
+ }
+ $sign = strtoupper(md5($this->AppSecret . $str . $this->AppSecret));
+ $params_sign = array(
+ 'sign' => $sign,
+ );
+ $data = $this->http($this->url(), array_merge($paramsAll, $params_sign), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ * @param string $result 获取access_token的方法的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if ($data['access_token'] && $data['expires_in'] && $data['taobao_user_id']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else {
+ throw new \Exception("获取淘宝网ACCESS_TOKEN出错:{$data['error']}");
+ }
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ * @return string
+ */
+ public function openid($unionid = false)
+ {
+ if ($unionid) {
+ return $this->unionid();
+ }
+ $data = $this->Token;
+ if (isset($data['taobao_user_id'])) {
+ return $data['taobao_user_id'];
+ } else {
+ throw new \Exception('没有获取到淘宝网用户openid!');
+ }
+ }
+
+ /**
+ * 获取当前授权应用的unionid
+ * @return string
+ */
+ public function unionid()
+ {
+ $data = $this->Token;
+ if (isset($data['taobao_open_uid'])) {
+ return $data['taobao_open_uid'];
+ } else {
+ throw new \Exception('没有获取到淘宝网用户unionid!');
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/sdk/Weixin.php b/src/sdk/Weixin.php
new file mode 100644
index 0000000..996923a
--- /dev/null
+++ b/src/sdk/Weixin.php
@@ -0,0 +1,127 @@
+config();
+ $md = md5(rand(10000,99999));
+ $params = array(
+ 'appid' => $this->AppKey,
+ 'redirect_uri' => $this->Callback,
+ 'response_type' => $this->ResponseType,
+ 'scope' => 'snsapi_login',
+ 'state' => $md,
+ );
+ return $this->GetRequestCodeURL . '?' . http_build_query($params) . "#wechat_redirect";
+ }
+
+ /**
+ * 获取access_token
+ * @param string $code 上一步请求到的code
+ */
+ public function getAccessToken($code, $extend = null)
+ {
+ $this->config();
+ $params = array(
+ 'appid' => $this->AppKey,
+ 'secret' => $this->AppSecret,
+ 'grant_type' => $this->GrantType,
+ 'code' => $code,
+ );
+ $data = $this->http($this->GetAccessTokenURL, $params, 'POST');
+ $this->Token = $this->parseToken($data, $extend);
+ return $this->Token;
+ }
+
+ /**
+ * 组装接口调用参数 并调用接口
+ * @param string $api 微信 API
+ * @param string $param 调用API的额外参数
+ * @param string $method HTTP请求方法 默认为GET
+ * @return json
+ */
+ public function call($api, $param = '', $method = 'GET', $multi = false)
+ {
+ /* 微信调用公共参数 */
+ $params = array(
+ 'access_token' => $this->Token['access_token'],
+ 'openid' => $this->openid(),
+ 'lang' => 'zh_CN',
+ );
+ $data = $this->http($this->url($api), $this->param($params, $param), $method);
+ return json_decode($data, true);
+ }
+
+ /**
+ * 解析access_token方法请求后的返回值
+ */
+ protected function parseToken($result, $extend)
+ {
+ $data = json_decode($result, true);
+ if ($data['access_token'] && $data['expires_in']) {
+ $this->Token = $data;
+ $data['openid'] = $this->openid();
+ return $data;
+ } else
+ throw new \Exception("获取微信 ACCESS_TOKEN 出错:{$result}");
+ }
+
+ /**
+ * 获取当前授权应用的openid
+ */
+ public function openid($unionid=false)
+ {
+ if ($unionid){
+ return $this->unionid();
+ }
+ $data = $this->Token;
+ if (isset($data['openid']))
+ return $data['openid'];
+ else
+ exit('没有获取到微信用户openid!');
+ }
+
+ /**
+ * 获取当前授权应用的unionid
+ */
+ public function unionid()
+ {
+ $data = $this->Token;
+ if (isset($data['unionid']))
+ return $data['unionid'];
+ else
+ exit('没有获取到微信用户unionid!');
+ }
+}
\ No newline at end of file