zoukankan      html  css  js  c++  java
  • PHP实现QQ第三方登录代码

    前言:

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

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

    方法二,三:面向对象

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

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

    前期准备:

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

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

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

    一.进入官网

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

    三.按要求填写资料

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

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

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

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

    最终要求,获得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 >openid,</span><span >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 ComponentQQ_LoginAction();    //引入此类文件即可

    $qq_login->qq_login();     
     

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

    $qc new ComponentQQ_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:WindowsSystem32driversetchost
    2. 添加127.0.0.1    www.test.com
    然后操作就可以了。

  • 相关阅读:
    spring的了解以及简单框架的搭建
    动态代理
    struts2标签(转)
    使用OGNL表达式
    struts2 ValueStack
    struts2框架xml验证
    struts2 validate手动验证
    struts2自定义拦截器
    struts2文件上传
    当findById(Integer id)变成String类型
  • 原文地址:https://www.cnblogs.com/ince/p/11948936.html
Copyright © 2011-2022 走看看