2014年3月22日 星期六

yii framework - 如何使用Facebook登入(Facebook PHP SDK)


本篇是使用Facebook API PHP SDK, 如果是要用JavaScript SDK的人可以直接搜尋"JavaScript SDK facebook"就有非常多資訊了! 或是參考這篇:facebook程式設計-JavaScript SDK


許多開發者都會經歷一個階段, 就是讓使用者可以用FB登入->註冊
到底在yii framework要如何實現呢? 在這Joker就分享一下自己的開發過程及心得:

首先我先講一下, 網路上很多都使用JavaScript SDK, 這讓我很困惑. 困惑的點是我到底該使用哪個呢? PHP or JavaScript SDK?

其實兩邊的寫法都不難, 只是一個寫在客戶端、一個是在伺服端罷了!
後來我想到有關於資訊安全上的問題, 所以試著去找一下, 有沒有相關的資料來印證我對於JavaScript安全性的顧慮, 後來我找到這篇, 大家可以看一下:網站利用 Facebook 帳號登入 (使用 OAuth)



其實我甚至有到一些網站去看他們是如何用JavaScript來實作登入機制, 如果是比較大的網站, 其實他們會盡可能的把code隱藏起來 (不過畢竟是前端語言, 只要用點心還是可以找到的), 可見他們也有多少顧慮到資安的問題.

不過如果是這樣的話, 為什麼還是有很多網站會選擇使用JavaScript來開發呢? 其實原因不外乎幾種:

1. 跨平台
2. 減少server負擔
3. 比較好寫?

不過針對上面幾點來看, 我的現況是:

1. 我的網站是架設在Linux, 所以用PHP很OK
2. 這我沒有實測, 不過我覺得不會差太多吧? (因為JavaScript也要利用AJAX傳到後端來跟自己的資料庫做search, 如果要結合會員制的話)
3. 我比較會PHP


個人後來的理解是:
以Yii framework來說, 流程是:先Controller然後在render到View (參考下圖), 所以如果是這樣的話, 我想既然會先到伺服端, 何不直接使用PHP SDK, 這樣就可以在Controller判斷是否登入FB, 然後render到不同頁面 (or帶不同的值), 似乎更符合yii 的架構.



好了! 題外話就到這, 我們來實作吧!

1. 到官網的擴充功能區下載這個: facebook-opengraph

2. 全部解壓縮後 (資料夾名為yii-facebook-opengraph)將裡面的facebook-channel.php放到建立的專案根目錄下 (就是放在有protected資料夾的那一層) PS: 後來發現這是用JavaScropt SDK開發才需要

3. 將yii-facebook-opengraph資料夾整個複製到protected/extensions裡面 (README.markdown是說明檔, 其實裡面說得很清楚, 哈哈~)

到這裡前置作業已經完成了!

4. 在protected/config/main.php新增下面code

    'components'=>array(
      'facebook'=>array(
        'class' => 'ext.yii-facebook-opengraph.SFacebook',
        'appId'=>'YOUR_FACEBOOK_APP_ID', // needed for JS SDK, Social Plugins and PHP SDK
        'secret'=>'YOUR_FACEBOOK_APP_SECRET', // needed for the PHP SDK
        //'fileUpload'=>false, // needed to support API POST requests which send files
        //'trustForwarded'=>false, // trust HTTP_X_FORWARDED_* headers ?
        //'locale'=>'en_US', // override locale setting (defaults to en_US)
        //'jsSdk'=>true, // don't include JS SDK
        //'async'=>true, // load JS SDK asynchronously
        //'jsCallback'=>false, // declare if you are going to be inserting any JS callbacks to the async JS SDK loader
        //'status'=>true, // JS SDK - check login status
        //'cookie'=>true, // JS SDK - enable cookies to allow the server to access the session
        //'oauth'=>true,  // JS SDK - enable OAuth 2.0
        //'xfbml'=>true,  // JS SDK - parse XFBML / html5 Social Plugins
        //'frictionlessRequests'=>true, // JS SDK - enable frictionless requests for request dialogs
        //'html5'=>true,  // use html5 Social Plugins instead of XFBML
        //'ogTags'=>array(  // set default OG tags
            //'og:title'=>'MY_WEBSITE_NAME',
            //'og:description'=>'MY_WEBSITE_DESCRIPTION',
            //'og:image'=>'URL_TO_WEBSITE_LOGO',
        //),
      ),
    ),

如果是要使用PHP SDK, 而且只要做登入、登出, 會員認證的話只要用紅字的部分就可以了! PS:'locale'=>'en_US' 我有改成 'locale'=>'zh_TW', 但是不改的話並不影響我們的應用!

5. 先參考官方的範例 (使用API來獲取用戶個人資料), 重要部分已翻譯
<?php
  // Remember to copy files from the SDK's src/ directory to a
  // directory in your application on the server, such as php-sdk/
  require_once('php-sdk/facebook.php');

  $config = array(
    'appId' => 'YOUR_APP_ID',
    'secret' => 'YOUR_APP_SECRET',
    'allowSignedRequest' => false // optional but should be set to false for non-canvas apps
  );

  $facebook = new Facebook($config);
  $user_id = $facebook->getUser();
?>
<html>
  <head></head>
  <body>

  <?php
    if($user_id) {

      // 如果我們得到用戶FB的id, 有可能是用戶已登入, 如果不是
      // 如果不是, 我們會得到一個異常, 下面是我們的處理
      try {

        $user_profile = $facebook->api('/me','GET');
        echo "Name: " . $user_profile['name'];

      } catch(FacebookApiException $e) {
        // 如果用戶已登出, 即使access token失效仍然可以得到用戶id,
        // 這時候我們會得到一個異常, 並請用戶再次登入
        $login_url = $facebook->getLoginUrl(); 
        echo 'Please <a href="' . $login_url . '">login.</a>';
        error_log($e->getType());
        error_log($e->getMessage());
      }   
    } else {

      // 沒有用戶的話, 給他一個登入的連結
      $login_url = $facebook->getLoginUrl();
      echo 'Please <a href="' . $login_url . '">login.</a>';

    }

  ?>

  </body>
</html>
官方的範例其實非常清楚, 運作也沒有問題 (廢話..), 但是在我們這個yii framework的擴展裡, 寫法要改一下:

1.  以下的code整段刪掉! 因為我們的前置作業已經完成這部分了! ^^

require_once('php-sdk/facebook.php');

  $config = array(
    'appId' => 'YOUR_APP_ID',
    'secret' => 'YOUR_APP_SECRET',
    'allowSignedRequest' => false // optional but should be set to false for non-canvas apps
  );

  $facebook = new Facebook($config);

2. $facebook->getUser(); 改成 Yii::app()->facebook->getUser();

3. $facebook->api('/me','GET'); 改成 Yii::app()->facebook->api('/me');

4. $facebook->getLoginUrl(); 改成 Yii::app()->facebook->getLoginUrl();

這樣這個官方範例就可以在yii上運作了!

至於登出的寫法就是:
官方說明 (getLogoutUrl) , 一樣改成yii的寫法就是

$params = array( 'next' => '登出後要轉到的網址' );
$logout_url = Yii::app()->facebook->getLogoutUrl($params);


小提醒:

getLoginUrl 跟 getLogoutUrl 產生的是一個網址, 直接設成超連結就可以用了! 但是我為了方便重複使用, 將登出寫成一個action, 這樣的話就必須透過轉址, 轉到產生的網址裡, 分享給大家:

public function actionLogout()
{
$params = array( 'next' => '登出後要轉到的網址' );
$logout_url = Yii::app()->facebook->getLogoutUrl($params);
Yii::app()->facebook->destroySession(); <- 少了這行登出後的Session不會消失
$this->redirect($logout_url); 
}

基本上到這, 已經成功了8成了! 剩下的就是寫將抓到的id跟資料庫做比對的判斷式, 其實多嘗試就知道裡面的規則了! FB不是傻子, 不會寫一個難用的API啦~

像是$user_profile['name']抓的是用戶FB的姓名, 那 id呢? 當然就是$user_profile['id'] 啦^^

連最後的實做都寫出來的話就太汙辱大家的智慧了~ 那就這樣嘍, 晚安~

沒有留言:

張貼留言