qq.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <?php
  2. namespace app\components\OpenAuth\core;
  3. use app\common\helpers\Session;
  4. use \Exception;
  5. use Yii;
  6. require_once 'qqclient.php';
  7. class QQ extends QQOAuth {
  8. function __construct($access_token = NULL, $refresh_token = NULL) {
  9. parent::__construct($access_token, $refresh_token);
  10. }
  11. function verify() {
  12. if (isset($_SESSION['qq_token']) && $_SESSION['qq_token'] && isset($_SESSION['qq_token']['uid'])) {
  13. return true;
  14. } else {
  15. return false;
  16. }
  17. }
  18. }
  19. class QQOAuth {
  20. public $client_id;
  21. public $client_secret;
  22. public $access_token;
  23. public $refresh_token;
  24. public $http_code;
  25. public $url;
  26. public $host = "https://graph.qq.com/";
  27. public $timeout = 30;
  28. public $connecttimeout = 30;
  29. public $ssl_verifypeer = FALSE;
  30. public $format = 'json';
  31. public $decode_json = TRUE;
  32. public $http_info;
  33. public $useragent = 'QQ OAuth2.0';
  34. public $debug = FALSE;
  35. public static $boundary = '';
  36. function accessTokenURL() {
  37. return 'https://graph.qq.com/oauth2.0/token';
  38. }
  39. function authorizeURL() {
  40. return 'https://graph.qq.com/oauth2.0/authorize';
  41. }
  42. function openidURL() {
  43. return "https://graph.qq.com/oauth2.0/me";
  44. }
  45. function __construct($access_token = NULL, $refresh_token = NULL) {
  46. $this->client_id = QQ_APPID;
  47. $this->client_secret = QQ_APPKEY;
  48. $this->access_token = $access_token;
  49. $this->refresh_token = $refresh_token;
  50. }
  51. function getAuthorizeURL($url, $response_type = 'code', $state = NULL, $scope = NULL) {
  52. $params = array();
  53. $params['client_id'] = $this->client_id;
  54. $params['redirect_uri'] = $url;
  55. $params['response_type'] = $response_type;
  56. $params['state'] = $state;
  57. $params['scope'] = $scope;
  58. return $this->authorizeURL() . "?" . http_build_query($params);
  59. }
  60. function getAccessToken($type = 'code', $keys = array()) {
  61. $params = array();
  62. $params['client_id'] = $this->client_id;
  63. $params['client_secret'] = $this->client_secret;
  64. if ($type === 'token') {
  65. $params['grant_type'] = 'refresh_token';
  66. $params['refresh_token'] = $keys['refresh_token'];
  67. } elseif ($type === 'code') {
  68. $params['grant_type'] = 'authorization_code';
  69. $params['code'] = $keys['code'];
  70. $params['redirect_uri'] = $keys['redirect_uri'];
  71. } elseif ($type === 'password') {
  72. $params['grant_type'] = 'password';
  73. $params['username'] = $keys['username'];
  74. $params['password'] = $keys['password'];
  75. } else {
  76. throw new Exception("wrong auth type");
  77. }
  78. $response = $this->oAuthRequest($this->accessTokenURL(), 'POST', $params);
  79. $response = $this->filterResponse($response);
  80. parse_str($response, $token);
  81. if (is_array($token)) {
  82. $this->access_token = $token['access_token'];
  83. $this->refresh_token = isset($token['refresh_token']) ? $token['refresh_token'] : '';
  84. } else {
  85. throw new Exception("读取access_token错误:{$token['error']}");
  86. }
  87. return $token;
  88. }
  89. function getOpenID() {
  90. $params = array();
  91. $params['access_token'] = $this->access_token;
  92. $response = $this->oAuthRequest($this->openidURL(), 'POST', $params);
  93. $response = $this->filterResponse($response);
  94. $result = json_decode($response, true);
  95. if (!is_array($result)) {
  96. throw new Exception("读取OPENID错误");
  97. }
  98. return $result['openid'];
  99. }
  100. function filterResponse($response) {
  101. if (strpos($response, "callback") !== false) {
  102. $lpos = strpos($response, "(");
  103. $rpos = strrpos($response, ")");
  104. $response = substr($response, $lpos + 1, $rpos - $lpos - 1);
  105. $msg = json_decode($response);
  106. if (isset($msg->error)) {
  107. throw new \Exception("发生一个已知的错误:{$msg->error}");
  108. }
  109. }
  110. return $response;
  111. }
  112. /**
  113. * 从数组中读取access_token和refresh_token
  114. * 常用于从Session或Cookie中读取token,或通过Session/Cookie中是否存有token判断登录状态。
  115. *
  116. * @param array $arr 存有access_token和secret_token的数组
  117. * @return array 成功返回array('access_token'=>'value', 'refresh_token'=>'value'); 失败返回false
  118. */
  119. function getTokenFromArray($arr) {
  120. if (isset($arr['access_token']) && $arr['access_token']) {
  121. $token = array();
  122. $this->access_token = $token['access_token'] = $arr['access_token'];
  123. if (isset($arr['refresh_token']) && $arr['refresh_token']) {
  124. $this->refresh_token = $token['refresh_token'] = $arr['refresh_token'];
  125. }
  126. return $token;
  127. } else {
  128. return false;
  129. }
  130. }
  131. /**
  132. * GET wrappwer for oAuthRequest.
  133. *
  134. * @return mixed
  135. */
  136. function get($url, $parameters = array()) {
  137. $response = $this->oAuthRequest($url, 'GET', $parameters);
  138. if ($this->format === 'json' && $this->decode_json) {
  139. return json_decode($response, true);
  140. }
  141. return $response;
  142. }
  143. /**
  144. * POST wreapper for oAuthRequest.
  145. *
  146. * @return mixed
  147. */
  148. function post($url, $parameters = array(), $multi = false) {
  149. $response = $this->oAuthRequest($url, 'POST', $parameters, $multi);
  150. if ($this->format === 'json' && $this->decode_json) {
  151. return json_decode($response, true);
  152. }
  153. return $response;
  154. }
  155. /**
  156. * DELTE wrapper for oAuthReqeust.
  157. *
  158. * @return mixed
  159. */
  160. function delete($url, $parameters = array()) {
  161. $response = $this->oAuthRequest($url, 'DELETE', $parameters);
  162. if ($this->format === 'json' && $this->decode_json) {
  163. return json_decode($response, true);
  164. }
  165. return $response;
  166. }
  167. /**
  168. * Format and sign an OAuth / API request
  169. *
  170. * @return string
  171. * @ignore
  172. */
  173. function oAuthRequest($url, $method, $parameters, $multi = false) {
  174. if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
  175. $url = "{$this->host}{$url}.{$this->format}";
  176. }
  177. switch ($method) {
  178. case 'GET':
  179. $url = $url . '?' . http_build_query($parameters);
  180. return $this->http($url, 'GET');
  181. default:
  182. $headers = array();
  183. if (!$multi && (is_array($parameters) || is_object($parameters))) {
  184. $body = http_build_query($parameters);
  185. } else {
  186. $body = self::build_http_query_multi($parameters);
  187. $headers[] = "Content-Type: multipart/form-data; boundary=" . self::$boundary;
  188. }
  189. return $this->http($url, $method, $body, $headers);
  190. }
  191. }
  192. /**
  193. * Make an HTTP request
  194. *
  195. * @return string API results
  196. * @ignore
  197. */
  198. function http($url, $method, $postfields = NULL, $headers = array()) {
  199. $this->http_info = array();
  200. $ci = curl_init();
  201. /* Curl settings */
  202. curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  203. curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
  204. curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
  205. curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
  206. curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
  207. curl_setopt($ci, CURLOPT_ENCODING, "");
  208. curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
  209. //curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, 1);
  210. curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
  211. curl_setopt($ci, CURLOPT_HEADER, FALSE);
  212. switch ($method) {
  213. case 'POST':
  214. curl_setopt($ci, CURLOPT_POST, TRUE);
  215. if (!empty($postfields)) {
  216. curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
  217. $this->postdata = $postfields;
  218. }
  219. break;
  220. case 'DELETE':
  221. curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
  222. if (!empty($postfields)) {
  223. $url = "{$url}?{$postfields}";
  224. }
  225. }
  226. if (isset($this->access_token) && $this->access_token)
  227. $headers[] = "Authorization: OAuth2 " . $this->access_token;
  228. if (!empty($this->remote_ip)) {
  229. if (defined('SAE_ACCESSKEY')) {
  230. $headers[] = "SaeRemoteIP: " . $this->remote_ip;
  231. } else {
  232. $headers[] = "API-RemoteIP: " . $this->remote_ip;
  233. }
  234. } else {
  235. if (!defined('SAE_ACCESSKEY')) {
  236. $headers[] = "API-RemoteIP: " . $_SERVER['REMOTE_ADDR'];
  237. }
  238. }
  239. curl_setopt($ci, CURLOPT_URL, $url);
  240. curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
  241. curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE);
  242. $response = curl_exec($ci);
  243. $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
  244. $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
  245. $this->url = $url;
  246. if ($this->debug) {
  247. echo "=====post data======\r\n";
  248. var_dump($postfields);
  249. echo "=====headers======\r\n";
  250. print_r($headers);
  251. echo '=====request info=====' . "\r\n";
  252. print_r(curl_getinfo($ci));
  253. echo '=====response=====' . "\r\n";
  254. print_r($response);
  255. }
  256. curl_close($ci);
  257. return $response;
  258. }
  259. /**
  260. * 开启调试信息
  261. *
  262. * 开启调试信息后,SDK会将每次请求微博API所发送的POST Data、Headers以及请求信息、返回内容输出出来。
  263. *
  264. * @access public
  265. * @param bool $enable 是否开启调试信息
  266. * @return void
  267. */
  268. function set_debug($enable) {
  269. $this->debug = $enable;
  270. }
  271. /**
  272. * Get the header info to store.
  273. *
  274. * @return int
  275. * @ignore
  276. */
  277. function getHeader($ch, $header) {
  278. $i = strpos($header, ':');
  279. if (!empty($i)) {
  280. $key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
  281. $value = trim(substr($header, $i + 2));
  282. $this->http_header[$key] = $value;
  283. }
  284. return strlen($header);
  285. }
  286. /**
  287. * @ignore
  288. */
  289. public static function build_http_query_multi($params) {
  290. if (!$params)
  291. return '';
  292. uksort($params, 'strcmp');
  293. $pairs = array();
  294. self::$boundary = $boundary = uniqid('------------------');
  295. $MPboundary = '--' . $boundary;
  296. $endMPboundary = $MPboundary . '--';
  297. $multipartbody = '';
  298. foreach ($params as $parameter => $value) {
  299. if (in_array($parameter, array('pic', 'image')) && $value{0} == '@') {
  300. $url = ltrim($value, '@');
  301. $content = file_get_contents($url);
  302. $array = explode('?', basename($url));
  303. $filename = $array[0];
  304. $multipartbody .= $MPboundary . "\r\n";
  305. $multipartbody .= 'Content-Disposition: form-data; name="' . $parameter . '"; filename="' . $filename . '"' . "\r\n";
  306. $multipartbody .= "Content-Type: image/unknown\r\n\r\n";
  307. $multipartbody .= $content . "\r\n";
  308. } else {
  309. $multipartbody .= $MPboundary . "\r\n";
  310. $multipartbody .= 'content-disposition: form-data; name="' . $parameter . "\"\r\n\r\n";
  311. $multipartbody .= $value . "\r\n";
  312. }
  313. }
  314. $multipartbody .= $endMPboundary;
  315. return $multipartbody;
  316. }
  317. }