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