PHP实现QQ快速登录的方法


Posted in PHP onSeptember 28, 2016

前言:

PHP实现QQ快速登录,罗列了三种方法

方法一:面向过程,回调地址和首次触发登录写到了一个方法页面【因为有了if做判断】,

方法二,三:面向对象

1.先调用登录方法,向腾讯发送请求,
2.腾讯携带本网站唯一对应参数OPENID,ACCESSTOKEN,返回到对应回调页面,
3.回调页面接受到腾讯的参数后,通过这个两个参数,再发出对应的请求,如查询用户的数据。
4.腾讯做出对应的操作,如返回这个用户的数据给你

即使你没看懂,也没关系,按照我下面的流程来,保证你可以实现。

前期准备:

使用人家腾讯的功能,总得和人家打招呼吧!

QQ互联首页:http://connect.qq.com/

进入网址后,按如下操作来:

一.进入官网

PHP实现QQ快速登录的方法

二.申请创建【网站】应用

PHP实现QQ快速登录的方法

三.按要求填写资料

注意网站地址:填写你要设置快速登录的网址,eg:http://www.test.com;  

回调地址:填写你发送QQ快速登陆后,腾讯得给你信息,这个信息往此页面接受。eg:http://www.test.com/accept_info.php

【详细的申请填写,请见官方提示,这里不做赘述】

PHP实现QQ快速登录的方法

四.申请成功后,完善信息

PHP实现QQ快速登录的方法

最终要求,获得APP_ID ,APP_KEY

五.代码部分:

在你对应的PHP文件内写入,如下
方法一,面向过程法
使用方法:配置$app_id,$app_secret,$my_url后,其他原封复制即可,$user_data为返回的登录信息
代码:

//应用的APPID 
   $app_id = "你的APPID"; 
   //应用的APPKEY 
   $app_secret = "你的APPKEY"; 
   //【成功授权】后的回调地址,即此地址在腾讯的信息中有储存 
   $my_url = "你的回调网址"; 
 
   //Step1:获取Authorization Code 
   session_start(); 
   $code = $_REQUEST["code"];//存放Authorization Code 
   if(empty($code)) 
   { 
    //state参数用于防止CSRF攻击,成功授权后回调时会原样带回 
    $_SESSION['state'] = md5(uniqid(rand(), TRUE)); 
    //拼接URL 
    $dialog_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=" 
     . $app_id . "&redirect_uri=" . urlencode($my_url) . "&state=" 
     . $_SESSION['state']; 
    echo("<script> top.location.href='" . $dialog_url . "'</script>"); 
   } 
 
   //Step2:通过Authorization Code获取Access Token 
   if($_REQUEST['state'] == $_SESSION['state'] || 1) 
   { 
    //拼接URL 
    $token_url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&" 
     . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url) 
     . "&client_secret=" . $app_secret . "&code=" . $code; 
    $response = file_get_contents($token_url); 
    if (strpos($response, "callback") !== false)//如果登录用户临时改变主意取消了,返回true!==false,否则执行step3 
    { 
     $lpos = strpos($response, "("); 
     $rpos = strrpos($response, ")"); 
     $response = substr($response, $lpos + 1, $rpos - $lpos -1); 
     $msg = json_decode($response); 
     if (isset($msg->error)) 
     { 
      echo "<h3>error:</h3>" . $msg->error; 
      echo "<h3>msg :</h3>" . $msg->error_description; 
      exit; 
     } 
    } 
 
    //Step3:使用Access Token来获取用户的OpenID 
    $params = array(); 
    parse_str($response, $params);//把传回来的数据参数变量化 
    $graph_url = "https://graph.qq.com/oauth2.0/me?access_token=".$params['access_token']; 
    $str = file_get_contents($graph_url); 
    if (strpos($str, "callback") !== false) 
    { 
     $lpos = strpos($str, "("); 
     $rpos = strrpos($str, ")"); 
     $str = substr($str, $lpos + 1, $rpos - $lpos -1); 
    } 
    $user = json_decode($str);//存放返回的数据 client_id ,openid 
    if (isset($user->error)) 
    { 
     echo "<h3>error:</h3>" . $user->error; 
     echo "<h3>msg :</h3>" . $user->error_description; 
     exit; 
    } 
    //echo("Hello " . $user->openid); 
    //echo("Hello " . $params['access_token']); 
 
    //Step4:使用<span style="font-family: Arial, Helvetica, sans-serif;">openid,</span><span style="font-family: Arial, Helvetica, sans-serif;">access_token来获取所接受的用户信息。</span> 
    $user_data_url = "https://graph.qq.com/user/get_user_info?access_token={$params['access_token']}&oauth_consumer_key={$app_id}&openid={$user->openid}&format=json"; 
     
    $user_data = file_get_contents($user_data_url);//此为获取到的user信息 
    } 
    else 
    { 
     echo("The state does not match. You may be a victim of CSRF."); 
    }

方法二,面向对象 使用类QQ_LoginAction.class
使用方法:
1.在QQ_LoginAction.class中正确配置 APPID,APPKEY CALLBACK(回调网址)
2.在调用方法中,代码:

$qq_login = new \Component\QQ_LoginAction();    //引入此类文件即可 
$qq_login->qq_login();          //调用登录方法,向腾讯发出快速登录请求

3.在回调页面中,代码:

$qc = new \Component\QQ_LoginAction(); 
$acs = $qc->qq_callback();<span style="white-space:pre">    //access_token 
$oid=$qc->get_openid();<span style="white-space:pre">     //openid 
$user_data = $qc->get_user_info();<span style="white-space:pre">  //get_user_info()为获得该用户的信息,其他操作方法见API文档

4.$user_data即为返回的用户数据。
5.QQ_LoginAction.class.php 文件代码:【用的ThinkPHP3.2】

<?php 
namespace Component; 
 
session_start(); 
define('APPID','XXXX');   //appid 
define('APPKEY','XXXX');  //appkey 
define('CALLBACK','XXXX');  //回调地址 
define('SCOPE','get_user_info,list_album,add_album,upload_pic,add_topic,add_weibo');  //授权接口列表 
class QQ_LoginAction { 
 const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize"; 
 const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token"; 
 const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me"; 
 private $APIMap = array( 
  "get_user_info" => array(   //获取用户资料 
   "https://graph.qq.com/user/get_user_info", 
   array("format" => "json"), 
  ), 
  "add_t" => array(    //发布一条普通微博 
   "https://graph.qq.com/t/add_t", 
   array("format" => "json", "content","#clientip","#longitude","#latitude","#compatibleflag"), 
   "POST" 
  ), 
  "add_pic_t" => array(    //发布一条图片微博 
   "https://graph.qq.com/t/add_pic_t", 
   array("content", "pic", "format" => "json", "#clientip", "#longitude", "#latitude", "#syncflag", "#compatiblefalg"), 
   "POST" 
  ), 
  "del_t" => array(      //删除一条微博 
   "https://graph.qq.com/t/del_t", 
   array("id", "format" => "json"), 
   "POST" 
  ), 
  "get_repost_list" => array(    //获取单条微博的转发或点评列表 
   "https://graph.qq.com/t/get_repost_list", 
   array("flag", "rootid", "pageflag", "pagetime", "reqnum", "twitterid", "format" => "json") 
  ), 
  "get_info" => array(     //获取当前用户资料 
   "https://graph.qq.com/user/get_info", 
   array("format" => "json") 
  ), 
  "get_other_info" => array(    //获取其他用户资料 
   "https://graph.qq.com/user/get_other_info", 
   array("format" => "json", "#name-1", "#fopenid-1") 
  ), 
  "get_fanslist" => array( 
   "https://graph.qq.com/relation/get_fanslist", //我的微博粉丝列表 
   array("format" => "json", "reqnum", "startindex", "#mode", "#install", "#sex") 
  ), 
  "get_idollist" => array( 
   "https://graph.qq.com/relation/get_idollist", //我的微博收听列表 
   array("format" => "json", "reqnum", "startindex", "#mode", "#install") 
  ), 
  "add_idol" => array( 
   "https://graph.qq.com/relation/add_idol",  //微博收听某用户 
   array("format" => "json", "#name-1", "#fopenids-1"), 
   "POST" 
  ), 
  "del_idol" => array(   //微博取消收听某用户 
   "https://graph.qq.com/relation/del_idol", 
   array("format" => "json", "#name-1", "#fopenid-1"), 
   "POST" 
  ) 
 ); 
 private $keysArr; 
 function __construct(){ 
  if($_SESSION["openid"]){ 
   $this->keysArr = array( 
    "oauth_consumer_key" => APPID, 
    "access_token" => $_SESSION['access_token'], 
    "openid" => $_SESSION["openid"] 
   ); 
  }else{ 
   $this->keysArr = array( 
    "oauth_consumer_key" => APPID 
   ); 
  } 
 } 
 public function qq_login(){ 
  //-------生成唯一随机串防CSRF攻击 
  $_SESSION['state'] = md5(uniqid(rand(), TRUE)); 
  $keysArr = array( 
   "response_type" => "code", 
   "client_id" => APPID, 
   "redirect_uri" => CALLBACK, 
   "state" => $_SESSION['state'], 
   "scope" => SCOPE 
  ); 
  $login_url = self::GET_AUTH_CODE_URL.'?'.http_build_query($keysArr); 
  header("Location:$login_url"); 
 } 
 public function qq_callback(){ 
  //--------验证state防止CSRF攻击 
  if($_GET['state'] != $_SESSION['state']){ 
   return false; 
  } 
  //-------请求参数列表 
  $keysArr = array( 
   "grant_type" => "authorization_code", 
   "client_id" => APPID, 
   "redirect_uri" => CALLBACK, 
   "client_secret" => APPKEY, 
   "code" => $_GET['code'] 
  ); 
  //------构造请求access_token的url 
  $token_url = self::GET_ACCESS_TOKEN_URL.'?'.http_build_query($keysArr); 
  $response = $this->get_contents($token_url); 
  if(strpos($response, "callback") !== false){ 
   $lpos = strpos($response, "("); 
   $rpos = strrpos($response, ")"); 
   $response = substr($response, $lpos + 1, $rpos - $lpos -1); 
   $msg = json_decode($response); 
   if(isset($msg->error)){ 
    $this->showError($msg->error, $msg->error_description); 
   } 
  } 
  $params = array(); 
  parse_str($response, $params); 
  $_SESSION["access_token"]=$params["access_token"]; 
  $this->keysArr['access_token']=$params['access_token']; 
  return $params["access_token"]; 
 } 
 
 public function get_contents($url){ 
  if (ini_get("allow_url_fopen") == "1") { 
   $response = file_get_contents($url); 
  }else{ 
   $ch = curl_init(); 
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 
   curl_setopt($ch, CURLOPT_URL, $url); 
   $response = curl_exec($ch); 
   curl_close($ch); 
  } 
  if(empty($response)){ 
   return false; 
  } 
  return $response; 
 } 
 public function get_openid(){ 
  //-------请求参数列表 
  $keysArr = array( 
   "access_token" => $_SESSION["access_token"] 
  ); 
  $graph_url = self::GET_OPENID_URL.'?'.http_build_query($keysArr); 
  $response = $this->get_contents($graph_url); 
  //--------检测错误是否发生 
  if(strpos($response, "callback") !== false){ 
   $lpos = strpos($response, "("); 
   $rpos = strrpos($response, ")"); 
   $response = substr($response, $lpos + 1, $rpos - $lpos -1); 
  } 
  $user = json_decode($response); 
  if(isset($user->error)){ 
   $this->showError($user->error, $user->error_description); 
  } 
  //------记录openid 
  $_SESSION['openid']=$user->openid; 
  $this->keysArr['openid']=$user->openid; 
  return $user->openid; 
 } 
 
 /** 
  * showError 
  * 显示错误信息 
  * @param int $code 错误代码 
  * @param string $description 描述信息(可选) 
  */ 
 public function showError($code, $description = '$'){ 
   echo "<meta charset=\"UTF-8\">"; 
   echo "<h3>error:</h3>$code"; 
   echo "<h3>msg :</h3>$description"; 
   exit(); 
 } 
 
 /** 
  * _call 
  * 魔术方法,做api调用转发 
  * @param string $name 调用的方法名称 
  * @param array $arg  参数列表数组 
  * @since 5.0 
  * @return array   返加调用结果数组 
  */ 
 public function __call($name,$arg){ 
  //如果APIMap不存在相应的api 
  if(empty($this->APIMap[$name])){ 
   $this->showError("api调用名称错误","不存在的API: <span style='color:red;'>$name</span>"); 
  } 
  //从APIMap获取api相应参数 
  $baseUrl = $this->APIMap[$name][0]; 
  $argsList = $this->APIMap[$name][1]; 
  $method = isset($this->APIMap[$name][2]) ? $this->APIMap[$name][2] : "GET"; 
  if(empty($arg)){ 
   $arg[0] = null; 
  } 
  $responseArr = json_decode($this->_applyAPI($arg[0], $argsList, $baseUrl, $method),true); 
  //检查返回ret判断api是否成功调用 
  if($responseArr['ret'] == 0){ 
   return $responseArr; 
  }else{ 
   $this->showError($responseArr['ret'], $responseArr['msg']); 
  } 
 } 
 
 //调用相应api 
 private function _applyAPI($arr, $argsList, $baseUrl, $method){ 
  $pre = "#"; 
  $keysArr = $this->keysArr; 
  $optionArgList = array();//一些多项选填参数必选一的情形 
  foreach($argsList as $key => $val){ 
   $tmpKey = $key; 
   $tmpVal = $val; 
   if(!is_string($key)){ 
    $tmpKey = $val; 
    if(strpos($val,$pre) === 0){ 
     $tmpVal = $pre; 
     $tmpKey = substr($tmpKey,1); 
     if(preg_match("/-(\d$)/", $tmpKey, $res)){ 
      $tmpKey = str_replace($res[0], "", $tmpKey); 
      $optionArgList[]= $tmpKey; 
     } 
    }else{ 
     $tmpVal = null; 
    } 
   } 
   //-----如果没有设置相应的参数 
   if(!isset($arr[$tmpKey]) || $arr[$tmpKey] === ""){ 
    if($tmpVal == $pre){ 
     continue; 
    }else if($tmpVal){//则使用默认的值 
     $arr[$tmpKey] = $tmpVal; 
    }else{ 
     $this->showError("api调用参数错误","未传入参数$tmpKey"); 
    } 
   } 
   $keysArr[$tmpKey] = $arr[$tmpKey]; 
  } 
  //检查选填参数必填一的情形 
  if(count($optionArgList)!=0){ 
   $n = 0; 
   foreach($optionArgList as $val){ 
    if(in_array($val, array_keys($keysArr))){ 
     $n++; 
    } 
   } 
   if(!$n){ 
    $str = implode(",",$optionArgList); 
    $this->showError("api调用参数错误",$str."必填一个"); 
   } 
  } 
  if($method == "POST"){ 
   $response = $this->post($baseUrl, $keysArr, 0); 
  }else if($method == "GET"){ 
   $baseUrl=$baseUrl.'?'.http_build_query($keysArr); 
   $response = $this->get_contents($baseUrl); 
  } 
  return $response; 
 } 
 
 public function post($url, $keysArr, $flag = 0){ 
  $ch = curl_init(); 
  if(! $flag) curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 
  curl_setopt($ch, CURLOPT_POST, TRUE); 
  curl_setopt($ch, CURLOPT_POSTFIELDS, $keysArr); 
  curl_setopt($ch, CURLOPT_URL, $url); 
  $ret = curl_exec($ch); 
  curl_close($ch); 
  return $ret; 
 } 
}

方法三,面向对象 使用腾讯给的SDK
使用方法:腾讯SDK,API写的很详细,不做赘述
地址:http://wiki.connect.qq.com/%E7%BD%91%E7%AB%99%E6%8E%A5%E5%85%A5%E6%A6%82%E8%BF%B0

这样就实现了QQ快捷登录,其实很简单的,大家可以试一试。
还有什么不清楚的,可以看看官方介绍,更详细,

Tips:如何在本地测试QQ快速登录
方法:修改HOST配置文件
1. 打开C:\Windows\System32\drivers\etc\host
2. 添加127.0.0.1    www.test.com
然后操作就可以了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP 已经成熟
Dec 04 PHP
php access 数据连接与读取保存编辑数据的实现代码
May 12 PHP
PHP运行环境配置与开发环境的配置(图文教程)
Jun 04 PHP
探讨PHP函数ip2long转换IP时数值太大产生负数的解决方法
Jun 06 PHP
smarty模板引擎基础知识入门
Mar 30 PHP
php计算整个目录大小的方法
Jun 19 PHP
PHP查看当前变量类型的方法
Jul 31 PHP
使用PHPMailer发送邮件实例
Feb 15 PHP
PHP提取字符串中的手机号正则表达式怎么写
Jul 17 PHP
Windows平台实现PHP连接SQL Server2008的方法
Jul 26 PHP
ThinkPHP框架中使用Memcached缓存数据的方法
Mar 31 PHP
提高Laravel应用性能方法详解
Jun 24 PHP
PHP自定义错误用法示例
Sep 28 #PHP
PHP构造函数与析构函数用法示例
Sep 28 #PHP
PHP设计模式之工厂模式与单例模式
Sep 28 #PHP
PHP类相关知识点实例总结
Sep 28 #PHP
PHP 闭包详解及实例代码
Sep 28 #PHP
php类的自动加载操作实例详解
Sep 28 #PHP
PHP对象克隆clone用法示例
Sep 28 #PHP
You might like
Discuz板块横排显示图片的实现方法
2007/05/28 PHP
PHP中数组合并的两种方法及区别介绍
2012/09/14 PHP
codeigniter使用技巧批量插入数据实例方法分享
2013/12/31 PHP
PHP基于imap获取邮件实例
2014/11/11 PHP
php实现生成code128条形码的方法详解
2017/07/19 PHP
PHP memcache在微信公众平台的应用方法示例
2017/09/13 PHP
javascript 继承实现方法
2009/08/26 Javascript
javascript 图片上一张下一张链接效果代码
2010/03/12 Javascript
jquery中的 $(&quot;#jb51&quot;)与document.getElementById(&quot;jb51&quot;) 的区别
2011/07/26 Javascript
js中top/parent/frame概述及案例应用
2013/02/06 Javascript
Extjs单独定义各组件的实例代码
2013/06/25 Javascript
jQuery获取对象简单实现方法小结
2014/10/30 Javascript
jQuery学习笔记之jQuery中的$
2015/01/19 Javascript
JavaScript中的Number数字类型学习笔记
2016/05/26 Javascript
探索Javascript中this的奥秘
2016/12/11 Javascript
对比分析Django的Q查询及AngularJS的Datatables分页插件
2017/02/07 Javascript
JS传参及动态修改页面布局
2017/04/13 Javascript
vue Render中slots的使用的实例代码
2017/07/19 Javascript
JS实现的点击按钮图片上下滚动效果示例
2019/01/28 Javascript
基于Cesium绘制抛物弧线
2020/11/18 Javascript
[03:09]DOTA2亚洲邀请赛 LGD战队出场宣传片
2015/02/07 DOTA
Python用Bottle轻量级框架进行Web开发
2016/06/08 Python
Python socket网络编程TCP/IP服务器与客户端通信
2017/01/05 Python
Python2.7基于淘宝接口获取IP地址所在地理位置的方法【测试可用】
2017/06/07 Python
Flask框架Jinjia模板常用语法总结
2018/07/19 Python
Scrapy框架使用的基本知识
2018/10/21 Python
在macOS上搭建python环境的实现方法
2019/08/13 Python
Django实现将一个字典传到前端显示出来
2020/04/03 Python
html5 音乐播放器 audio 标签使用概述
2013/07/15 HTML / CSS
世界上最大的糖果店:Dylan’s Candy Bar
2017/11/07 全球购物
家得宝墨西哥官网:The Home Depot墨西哥
2019/11/18 全球购物
家具商场的活动方案
2014/08/16 职场文书
个人自查自纠材料
2014/10/14 职场文书
宣传部部长竞选稿
2015/11/21 职场文书
nginx配置proxy_pass中url末尾带/与不带/的区别详解
2021/03/31 Servers
详解Redis实现限流的三种方式
2021/04/27 Redis