php使用第三方QQ登入

執法丶大隊發表於2020-04-06

前言:

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為返回的登入資訊
 程式碼:
 
[php] view plain copy
  1. //應用的APPID  
  2.            $app_id = "你的APPID";  
  3.            //應用的APPKEY  
  4.            $app_secret = "你的APPKEY";  
  5.            //【成功授權】後的回撥地址,即此地址在騰訊的資訊中有儲存  
  6.            $my_url = "你的回撥網址";  
  7.   
  8.            //Step1:獲取Authorization Code  
  9.            session_start();  
  10.            $code = $_REQUEST["code"];//存放Authorization Code  
  11.            if(empty($code))  
  12.            {  
  13.                //state引數用於防止CSRF攻擊,成功授權後回撥時會原樣帶回  
  14.                $_SESSION['state'] = md5(uniqid(rand(), TRUE));  
  15.                //拼接URL  
  16.                $dialog_url = "https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id="  
  17.                    . $app_id . "&redirect_uri=" . urlencode($my_url) . "&state="  
  18.                    . $_SESSION['state'];  
  19.                echo("<script> top.location.href='" . $dialog_url . "'</script>");  
  20.            }  
  21.   
  22.            //Step2:通過Authorization Code獲取Access Token  
  23.            if($_REQUEST['state'] == $_SESSION['state'] || 1)  
  24.            {  
  25.                //拼接URL  
  26.                $token_url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&"  
  27.                    . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)  
  28.                    . "&client_secret=" . $app_secret . "&code=" . $code;  
  29.                $response = file_get_contents($token_url);  
  30.                if (strpos($response"callback") !== false)//如果登入使用者臨時改變主意取消了,返回true!==false,否則執行step3  
  31.                {  
  32.                    $lpos = strpos($response"(");  
  33.                    $rpos = strrpos($response")");  
  34.                    $response  = substr($response$lpos + 1, $rpos - $lpos -1);  
  35.                    $msg = json_decode($response);  
  36.                    if (isset($msg->error))  
  37.                    {  
  38.                        echo "<h3>error:</h3>" . $msg->error;  
  39.                        echo "<h3>msg  :</h3>" . $msg->error_description;  
  40.                        exit;  
  41.                    }  
  42.                }  
  43.   
  44.                //Step3:使用Access Token來獲取使用者的OpenID  
  45.                $params = array();  
  46.                parse_str($response$params);//把傳回來的資料引數變數化  
  47.                $graph_url = "https://graph.qq.com/oauth2.0/me?access_token=".$params['access_token'];  
  48.                $str  = file_get_contents($graph_url);  
  49.                 if (strpos($str"callback") !== false)  
  50.                 {  
  51.                     $lpos = strpos($str"(");  
  52.                     $rpos = strrpos($str")");  
  53.                     $str  = substr($str$lpos + 1, $rpos - $lpos -1);  
  54.                 }  
  55.                 $user = json_decode($str);//存放返回的資料 client_id  ,openid  
  56.                 if (isset($user->error))  
  57.                 {  
  58.                     echo "<h3>error:</h3>" . $user->error;  
  59.                     echo "<h3>msg  :</h3>" . $user->error_description;  
  60.                     exit;  
  61.                 }  
  62.                 //echo("Hello " . $user->openid);  
  63.                 //echo("Hello " . $params['access_token']);  
  64.   
  65.                //Step4:使用<span style="font-family: Arial, Helvetica, sans-serif;">openid,</span><span style="font-family: Arial, Helvetica, sans-serif;">access_token來獲取所接受的使用者資訊。</span>  
  66.                $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";  
  67.                  
  68.                $user_data = file_get_contents($user_data_url);//此為獲取到的user資訊  
  69.              }  
  70.              else  
  71.              {  
  72.                  echo("The state does not match. You may be a victim of CSRF.");  
  73.              }  





//方法二。物件導向 使用類QQ_LoginAction.class
    使用方法:
        1.在QQ_LoginAction.class中正確配置 APPID,APPKEY CALLBACK(回撥網址)
        2.在呼叫方法中,程式碼:
         
[php] view plain copy
  1. $qq_login = new \Component\QQ_LoginAction();        //引入此類檔案即可  
  2. $qq_login->qq_login();                   //呼叫登入方法,向騰訊發出快速登入請求  


        3.在回撥頁面中,程式碼:
            
[php] view plain copy
  1. $qc = new \Component\QQ_LoginAction();  
  2. $acs = $qc->qq_callback();<span style="white-space:pre">       //access_token  
  3. $oid=$qc->get_openid();<span style="white-space:pre">          //openid  
  4. $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] view plain copy
  1. <?php  
  2. namespace Component;  
  3.   
  4. session_start();  
  5. define('APPID','XXXX');         //appid  
  6. define('APPKEY','XXXX');        //appkey  
  7. define('CALLBACK','XXXX');      //回撥地址  
  8. define('SCOPE','get_user_info,list_album,add_album,upload_pic,add_topic,add_weibo');      //授權介面列表  
  9. class QQ_LoginAction {  
  10.     const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";  
  11.     const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";  
  12.     const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";  
  13.     private  $APIMap = array(  
  14.         "get_user_info" => array(          //獲取使用者資料  
  15.             "https://graph.qq.com/user/get_user_info",  
  16.             array("format" => "json"),  
  17.         ),  
  18.         "add_t" => array(                //釋出一條普通微博  
  19.             "https://graph.qq.com/t/add_t",  
  20.             array("format" => "json""content","#clientip","#longitude","#latitude","#compatibleflag"),  
  21.             "POST"  
  22.         ),  
  23.         "add_pic_t" => array(             //釋出一條圖片微博  
  24.             "https://graph.qq.com/t/add_pic_t",  
  25.             array("content""pic""format" => "json""#clientip""#longitude""#latitude""#syncflag""#compatiblefalg"),  
  26.             "POST"  
  27.         ),  
  28.         "del_t" => array(                     //刪除一條微博  
  29.             "https://graph.qq.com/t/del_t",  
  30.             array("id""format" => "json"),  
  31.             "POST"  
  32.         ),  
  33.         "get_repost_list" => array(             //獲取單條微博的轉發或點評列表  
  34.             "https://graph.qq.com/t/get_repost_list",  
  35.             array("flag""rootid""pageflag""pagetime""reqnum""twitterid""format" => "json")  
  36.         ),  
  37.         "get_info" => array(                  //獲取當前使用者資料  
  38.             "https://graph.qq.com/user/get_info",  
  39.             array("format" => "json")  
  40.         ),  
  41.         "get_other_info" => array(               //獲取其他使用者資料  
  42.             "https://graph.qq.com/user/get_other_info",  
  43.             array("format" => "json""#name-1""#fopenid-1")  
  44.         ),  
  45.         "get_fanslist" => array(  
  46.             "https://graph.qq.com/relation/get_fanslist",   //我的微博粉絲列表  
  47.             array("format" => "json""reqnum""startindex""#mode""#install""#sex")  
  48.         ),  
  49.         "get_idollist" => array(  
  50.             "https://graph.qq.com/relation/get_idollist",   //我的微博收聽列表  
  51.             array("format" => "json""reqnum""startindex""#mode""#install")  
  52.         ),  
  53.         "add_idol" => array(  
  54.             "https://graph.qq.com/relation/add_idol",     //微博收聽某使用者  
  55.             array("format" => "json""#name-1""#fopenids-1"),  
  56.             "POST"  
  57.         ),  
  58.         "del_idol" => array(          //微博取消收聽某使用者  
  59.             "https://graph.qq.com/relation/del_idol",  
  60.             array("format" => "json""#name-1""#fopenid-1"),  
  61.             "POST"  
  62.         )  
  63.     );  
  64.     private $keysArr;  
  65.     function __construct(){  
  66.         if($_SESSION["openid"]){  
  67.             $this->keysArr = array(  
  68.                 "oauth_consumer_key" => APPID,  
  69.                 "access_token" => $_SESSION['access_token'],  
  70.                 "openid" => $_SESSION["openid"]  
  71.             );  
  72.         }else{  
  73.             $this->keysArr = array(  
  74.                 "oauth_consumer_key" => APPID  
  75.             );  
  76.         }  
  77.     }  
  78.     public function qq_login(){  
  79.         //-------生成唯一隨機串防CSRF攻擊  
  80.         $_SESSION['state'] = md5(uniqid(rand(), TRUE));  
  81.         $keysArr = array(  
  82.             "response_type" => "code",  
  83.             "client_id" => APPID,  
  84.             "redirect_uri" => CALLBACK,  
  85.             "state" => $_SESSION['state'],  
  86.             "scope" => SCOPE  
  87.         );  
  88.         $login_url = self::GET_AUTH_CODE_URL.'?'.http_build_query($keysArr);  
  89.         header("Location:$login_url");  
  90.     }  
  91.     public function qq_callback(){  
  92.         //--------驗證state防止CSRF攻擊  
  93.         if($_GET['state'] != $_SESSION['state']){  
  94.             return false;  
  95.         }  
  96.         //-------請求引數列表  
  97.         $keysArr = array(  
  98.             "grant_type" => "authorization_code",  
  99.             "client_id" => APPID,  
  100.             "redirect_uri" => CALLBACK,  
  101.             "client_secret" => APPKEY,  
  102.             "code" => $_GET['code']  
  103.         );  
  104.         //------構造請求access_token的url  
  105.         $token_url = self::GET_ACCESS_TOKEN_URL.'?'.http_build_query($keysArr);  
  106.         $response = $this->get_contents($token_url);  
  107.         if(strpos($response"callback") !== false){  
  108.             $lpos = strpos($response"(");  
  109.             $rpos = strrpos($response")");  
  110.             $response  = substr($response$lpos + 1, $rpos - $lpos -1);  
  111.             $msg = json_decode($response);  
  112.             if(isset($msg->error)){  
  113.                 $this->showError($msg->error, $msg->error_description);  
  114.             }  
  115.         }  
  116.         $params = array();  
  117.         parse_str($response$params);  
  118.         $_SESSION["access_token"]=$params["access_token"];  
  119.         $this->keysArr['access_token']=$params['access_token'];  
  120.         return $params["access_token"];  
  121.     }  
  122.   
  123.     public function get_contents($url){  
  124.         if (ini_get("allow_url_fopen") == "1") {  
  125.             $response = file_get_contents($url);  
  126.         }else{  
  127.             $ch = curl_init();  
  128.             curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);  
  129.             curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);  
  130.             curl_setopt($ch, CURLOPT_URL, $url);  
  131.             $response =  curl_exec($ch);  
  132.             curl_close($ch);  
  133.         }  
  134.         if(empty($response)){  
  135.             return false;  
  136.         }  
  137.         return $response;  
  138.     }  
  139.     public function get_openid(){  
  140.         //-------請求引數列表  
  141.         $keysArr = array(  
  142.             "access_token" => $_SESSION["access_token"]  
  143.         );  
  144.         $graph_url = self::GET_OPENID_URL.'?'.http_build_query($keysArr);  
  145.         $response = $this->get_contents($graph_url);  
  146.         //--------檢測錯誤是否發生  
  147.         if(strpos($response"callback") !== false){  
  148.             $lpos = strpos($response"(");  
  149.             $rpos = strrpos($response")");  
  150.             $response = substr($response$lpos + 1, $rpos - $lpos -1);  
  151.         }  
  152.         $user = json_decode($response);  
  153.         if(isset($user->error)){  
  154.             $this->showError($user->error, $user->error_description);  
  155.         }  
  156.         //------記錄openid  
  157.         $_SESSION['openid']=$user->openid;  
  158.         $this->keysArr['openid']=$user->openid;  
  159.         return $user->openid;  
  160.     }  
  161.   
  162.     /** 
  163.      * showError 
  164.      * 顯示錯誤資訊 
  165.      * @param int $code    錯誤程式碼 
  166.      * @param string $description 描述資訊(可選) 
  167.      */  
  168.     public function showError($code$description = '$'){  
  169.             echo "<meta charset=\"UTF-8\">";  
  170.             echo "<h3>error:</h3>$code";  
  171.             echo "<h3>msg  :</h3>$description";  
  172.             exit();  
  173.     }  
  174.   
  175.     /** 
  176.      * _call 
  177.      * 魔術方法,做api呼叫轉發 
  178.      * @param string $name    呼叫的方法名稱 
  179.      * @param array $arg      引數列表陣列 
  180.      * @since 5.0 
  181.      * @return array          返加呼叫結果陣列 
  182.      */  
  183.     public function __call($name,$arg){  
  184.         //如果APIMap不存在相應的api  
  185.         if(empty($this->APIMap[$name])){  
  186.             $this->showError("api呼叫名稱錯誤","不存在的API: <span style='color:red;'>$name</span>");  
  187.         }  
  188.         //從APIMap獲取api相應引數  
  189.         $baseUrl = $this->APIMap[$name][0];  
  190.         $argsList = $this->APIMap[$name][1];  
  191.         $method = isset($this->APIMap[$name][2]) ? $this->APIMap[$name][2] : "GET";  
  192.         if(empty($arg)){  
  193.             $arg[0] = null;  
  194.         }  
  195.        $responseArr = json_decode($this->_applyAPI($arg[0], $argsList$baseUrl$method),true);  
  196.         //檢查返回ret判斷api是否成功呼叫  
  197.         if($responseArr['ret'] == 0){  
  198.             return $responseArr;  
  199.         }else{  
  200.             $this->showError($responseArr['ret'], $responseArr['msg']);  
  201.         }  
  202.     }  
  203.   
  204.     //呼叫相應api  
  205.     private function _applyAPI($arr$argsList$baseUrl$method){  
  206.         $pre = "#";  
  207.         $keysArr = $this->keysArr;  
  208.         $optionArgList = array();//一些多項選填引數必選一的情形  
  209.         foreach($argsList as $key => $val){  
  210.             $tmpKey = $key;  
  211.             $tmpVal = $val;  
  212.             if(!is_string($key)){  
  213.                 $tmpKey = $val;  
  214.                 if(strpos($val,$pre) === 0){  
  215.                     $tmpVal = $pre;  
  216.                     $tmpKey = substr($tmpKey,1);  
  217.                     if(preg_match("/-(\d$)/"$tmpKey$res)){  
  218.                         $tmpKey = str_replace($res[0], ""$tmpKey);  
  219.                         $optionArgList[]= $tmpKey;  
  220.                     }  
  221.                 }else{  
  222.                     $tmpVal = null;  
  223.                 }  
  224.             }  
  225.             //-----如果沒有設定相應的引數  
  226.             if(!isset($arr[$tmpKey]) || $arr[$tmpKey] === ""){  
  227.                 if($tmpVal == $pre){  
  228.                     continue;  
  229.                 }else if($tmpVal){//則使用預設的值  
  230.                     $arr[$tmpKey] = $tmpVal;  
  231.                 }else{  
  232.                     $this->showError("api呼叫引數錯誤","未傳入引數$tmpKey");  
  233.                 }  
  234.             }  
  235.             $keysArr[$tmpKey] = $arr[$tmpKey];  
  236.         }  
  237.         //檢查選填引數必填一的情形  
  238.         if(count($optionArgList)!=0){  
  239.             $n = 0;  
  240.             foreach($optionArgList as $val){  
  241.                 if(in_array($valarray_keys($keysArr))){  
  242.                     $n++;  
  243.                 }  
  244.             }  
  245.             if(!$n){  
  246.                 $str = implode(",",$optionArgList);  
  247.                 $this->showError("api呼叫引數錯誤",$str."必填一個");  
  248.             }  
  249.         }  
  250.         if($method == "POST"){  
  251.             $response = $this->post($baseUrl$keysArr, 0);  
  252.         }else if($method == "GET"){  
  253.             $baseUrl=$baseUrl.'?'.http_build_query($keysArr);  
  254.             $response = $this->get_contents($baseUrl);  
  255.         }  
  256.         return $response;  
  257.     }  
  258.   
  259.     public function post($url$keysArr$flag = 0){  
  260.         $ch = curl_init();  
  261.         if(! $flag) curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);  
  262.         curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);  
  263.         curl_setopt($ch, CURLOPT_POST, TRUE);  
  264.         curl_setopt($ch, CURLOPT_POSTFIELDS, $keysArr);  
  265.         curl_setopt($ch, CURLOPT_URL, $url);  
  266.         $ret = curl_exec($ch);  
  267.         curl_close($ch);  
  268.         return $ret;  
  269.     }  
  270. }   

相關文章