oops-OAUTH2
[ class tree: oops-OAUTH2 ] [ index: oops-OAUTH2 ] [ all elements ]

Source for file GITHUB.php

Documentation is available at GITHUB.php

  1. <?php
  2. /**
  3.  * Project: GITHUB:: GITHUB oauth2 pear package<br>
  4.  * File:    GITHUB.php<br>
  5.  * Dependency:
  6.  *   - {@link http://pear.oops.org/docs/li_HTTPRelay.html oops/HTTPRelay}
  7.  *   - {@link http://pear.oops.org/docs/li_myException.html oops/myException}
  8.  *
  9.  * oops/GITHUB pear package는 GITHUB oauth2 login을 위한 pear package이다
  10.  *
  11.  * 이 package를 사용하기 위해서는 먼저 GITHUB Developers Console 에서
  12.  * Applicaion ID와 Application Secret을 발급받아야 한다.
  13.  * https://developers.google.com/accounts/docs/OAuth2?hl=ko 를 참고하라.
  14.  *
  15.  *
  16.  * @category  HTTP
  17.  * @package   oops\OAUTH2
  18.  * @subpackage   oops\OAUTH2\GITHUB
  19.  * @author    JoungKyun.Kim <http://oops.org>
  20.  * @copyright (c) 2019, OOPS.org
  21.  * @license   BSD License
  22.  * @example   OAUTH2/tests/github.php GITHUB pear package 예제 코드
  23.  * @filesource
  24.  */
  25.  
  26. namespace oops\OAUTH2;
  27.  
  28. /**
  29.  * import HTTPRelay class
  30.  */
  31. require_once 'HTTPRelay.php';
  32.  
  33.  
  34. /**
  35.  * GITHUB pear pcakge의 main class
  36.  *
  37.  * OAuth2를 이용하여 GITHUB 로그인을 진행하고, 로그인된 사용자의
  38.  * 정보를 얻어온다.
  39.  *
  40.  * @package   oops\OAUTH2
  41.  * @subpackage   oops\OAUTH2\GITHUB
  42.  * @author    JoungKyun.Kim <http://oops.org>
  43.  * @copyright (c) 2019, OOPS.org
  44.  * @license   BSD License
  45.  * @example   OAUTH2/tests/github.php GITHUB pear 예제 코드
  46.  */
  47. Class GITHUB {
  48.     // {{{ properities
  49.     /**#@+
  50.      * @access private
  51.      */
  52.     /**
  53.      * 세션 이름
  54.      * @var string 
  55.      */
  56.     private $sessid   '_OAUTH2_';
  57.     /**
  58.      * login url
  59.      * @var string 
  60.      */
  61.     private $reqAuth  'https://github.com/login/oauth/authorize';
  62.     /**
  63.      * token url
  64.      * @var string 
  65.      */
  66.     private $reqToken 'https://github.com/login/oauth/access_token';
  67.     /**
  68.      * revoke url
  69.      * @var string 
  70.      */
  71.     private $reqRevoke 'https://github.com/logout';
  72.     /**
  73.      * user information url
  74.      * @var string 
  75.      */
  76.     private $reqUser  'https://api.github.com/user';
  77.     /**
  78.      * app information
  79.      * @var stdClass memebr는 다음과 같음
  80.      *    - id     : GITHUB login Application ID
  81.      *    - secret : GITHUB login Application Secret key
  82.      *    - callback : 이 class를 호출하는 페이지
  83.      */
  84.     private $apps;
  85.     /**
  86.      * SSL type
  87.      * @var string 
  88.      */
  89.     private $proto 'http';
  90.     /**#@-*/
  91.     /**
  92.      * GITHUB 로그인에 필요한 session 값
  93.      * @access public
  94.      * @var stdClass 
  95.      */
  96.     public $sess;
  97.     // }}}
  98.  
  99.     // {{{ +-- public (void) __construct ($v)
  100.     /**
  101.      * GITHUB 로그인 인증 과정을 수행한다. 인증 과정 중에
  102.      * 에러가 발생하면 myException 으로 에러 메시지를
  103.      * 보낸다.
  104.      *
  105.      * logout 시에 globale 변수 $_OAUTH2_LOGOUT_TEMPALTE_ 로 사용자 logout template
  106.      * 을 지정할 수 있다. template 파일은 pear/OAUTH2/login-no-auto.template 를 참조하면 된다.
  107.      *
  108.      * @access public
  109.      * @param stdClass $v 
  110.      *    - id       발급받은 GITHUB login Application ID
  111.      *    - secret   발급받은 GITHUB login Application Scret key
  112.      *    - callback 이 클래스가 호출되는 url
  113.      * @return void 
  114.      */
  115.     function __construct ($v{
  116.         if isset ($_SESSION[$this->sessid]) ) {
  117.             $_SESSION[$this->sessidnew \stdClass;
  118.             $_SESSION[$this->sessid]->appId = (object) $v;
  119.         }
  120.         $this->sess = &$_SESSION[$this->sessid];
  121.         $this->apps = (object) $v;
  122.  
  123.         if isset ($_SERVER['HTTPS']) )
  124.             $this->proto .= 's';
  125.  
  126.         if isset ($_GET['logout']) ) {
  127.             $this->reqLogout ();
  128.             return;
  129.         }
  130.  
  131.         $this->checkError ();
  132.         $this->reqLogin ();
  133.         $this->reqAccessToken ();
  134.     }
  135.     // }}}
  136.  
  137.     // {{{ +-- private (string) mkToken (void)
  138.     /**
  139.      * 세션 유지를 위한 token 값
  140.      *
  141.      * @access private
  142.      * @return string 
  143.      */
  144.     private function mkToken ({
  145.         $mt microtime ();
  146.         $rand mt_rand ();
  147.         return md5 ($mt $rand);
  148.     }
  149.     // }}}
  150.  
  151.     // {{{ +-- private (void) reqLogin (void)
  152.     /**
  153.      * 로그인 창으로 redirect
  154.      *
  155.      * @access private
  156.      * @return void 
  157.      */
  158.     private function reqLogin ({
  159.         $app &$this->apps;
  160.         $this->sess->state $this->mkToken ();
  161.  
  162.         if $_GET['code'|| isset ($this->sess->oauth)  )
  163.             return;
  164.  
  165.         $url sprintf (
  166.             '%s?scope=user:email&' 
  167.             'client_id=%s&redirect_uri=%s&state=%s',
  168.             $this->reqAuth$app->id,
  169.             rawurlencode ($app->callback)$this->sess->state
  170.         );
  171.  
  172.         Header ('Location: ' $url);
  173.         exit;
  174.     }
  175.     // }}}
  176.  
  177.     // {{{ +-- private (void) reqAccessToken (void)
  178.     /**
  179.      * Authorization code를 발급받아 session에 등록
  180.      *
  181.      * GITHUB::$sess->oauth 를 stdClass로 생성하고 다음의
  182.      * member를 등록한다.
  183.      *
  184.      *   - access_token:      발급받은 access token. expires_in(초) 이후 만료
  185.      *   - refresh_token:     access token 만료시 재발급 키 (14일 expire)
  186.      *   - token_type:        Bearer or MAC
  187.      *   - expires_in:        access token 유효시간(초)
  188.      *   - error:             error code
  189.      *   - error_description: error 상세값
  190.      *
  191.      * @access private
  192.      * @return void 
  193.      */
  194.     private function reqAccessToken ({
  195.         $sess &$this->sess;
  196.         $app  &$this->apps;
  197.  
  198.         if $_GET['code'|| isset ($sess->oauth) )
  199.             return;
  200.  
  201.         $post array (
  202.             'code' => $_GET['code'],
  203.             'client_id' => $app->id,
  204.             'client_secret' => $app->secret,
  205.             'redirect_uri' => $app->callback,
  206.             'state' => $_GET['state']
  207.         );
  208.  
  209.         $http new \HTTPRelay;
  210.         $buf $http->fetch ($this->reqToken10''$post);
  211.  
  212.         // json으로 처리하려면 reuqest header로 "Accept: application/json"을 보내주도록 한다.
  213.         #$r = json_decode ($buf);
  214.         parse_str ($buf$r);
  215.  
  216.         if $r->error )
  217.             $this->error ($r->error_description);
  218.         
  219.         $sess->oauth = (object) $r;
  220.     }
  221.     // }}}
  222.  
  223.     // {{{ +-- private (void) checkError (void)
  224.     /**
  225.      * 에러 코드가 존재하면 에러 처리를 한다.
  226.      *
  227.      * @access private
  228.      * @return void 
  229.      */
  230.     private function checkError ({
  231.         $sess &$this->sess;
  232.  
  233.         if $_GET['error')
  234.             $this->error ($_GET['error_description']);
  235.  
  236.         if $_GET['state'&& $_GET['state'!= $sess->state )
  237.             $this->error ('Invalude Session state: ' $_GET['state']);
  238.     }
  239.     // }}}
  240.  
  241.     // {{{ +-- private (void) error ($msg)
  242.     /**
  243.      * 에러를 Exception 처리한다.
  244.      *
  245.      * @access private
  246.      * @return void 
  247.      */
  248.     private function error ($msg{
  249.         $msg $_SERVER['HTTP_REFERER'"\n" $msg;
  250.         throw new \myException ($msgE_USER_ERROR);
  251.     }
  252.     // }}}
  253.  
  254.     // {{{ +-- private (string) redirectSelf (void)
  255.     /**
  256.      * 현재 URL에 after argument를 set한다.
  257.      *
  258.      * @access private
  259.      * @return string 
  260.      */
  261.     private function redirectSelf ({
  262.         if trim ($_SERVER['QUERY_STRING']) )
  263.             $qs sprintf ('?%s&after'$_SERVER['QUERY_STRING']);
  264.         else
  265.             $qs '?after';
  266.  
  267.         $req preg_replace ('/\?.*/'''trim ($_SERVER['REQUEST_URI']));
  268.         if $req $req '/';
  269.  
  270.         return sprintf (
  271.             '%s://%s%s%s',
  272.             $this->proto$_SERVER['HTTP_HOST']$req$qs
  273.         );
  274.     }
  275.     // }}}
  276.  
  277.     // {{{ +-- public (stdClass) Profile (void)
  278.     /**
  279.      * 로그인 과정이 완료되면 발급받은 oops\OAUTH2\GITHUB::$sess->oauth 에
  280.      * 등록된 키를 이용하여 로그인 사용자의 정보를 가져온다.
  281.      *
  282.      * @access public
  283.      * @return stdClass 다음의 object를 반환
  284.      *    - id     사용자 UID
  285.      *    - name   사용자 별칭
  286.      *    - email  이메일
  287.      *    - img    프로필 사진 URL 정보
  288.      *    - r      GITHUB profile 원본 값
  289.      */
  290.     public function Profile ({
  291.         $sess &$this->sess;
  292.  
  293.         if isset ($sess->oauth) )
  294.             return false;
  295.  
  296.         $req $sess->oauth->token_type ' ' $sess->oauth->access_token;
  297.  
  298.         $header array ('Authorization' => $req);
  299.         $http new \HTTPRelay ($header);
  300.         $buf $http->fetch ($this->reqUser);
  301.  
  302.         if $buf )
  303.             $this->error (sprintf ('[OAUTH2] Failed get user profile for %s'__CLASS__));
  304.  
  305.         $r json_decode ($buf);
  306.  
  307.         $re array (
  308.             'id' => $r->id,
  309.             'name' => $r->name,
  310.             'email' => $r->email,
  311.             'img'  => $r->avatar_url,
  312.             'r' => $r
  313.         );
  314.  
  315.         return (object) $re;
  316.     }
  317.     // }}}
  318.  
  319.     // {{{ +-- public (void) reqLogout (void)
  320.     /**
  321.      * GITHUB 로그인의 authorization key를 만료 시키고
  322.      * 세션에 등록된 정보(oops\OAUT2\GITHUB::$sess)를 제거한다.
  323.      *
  324.      * @access public
  325.      * @return void 
  326.      */
  327.     public function reqLogout ({
  328.         $sess &$this->sess;
  329.         $app  &$this->apps;
  330.  
  331.         if isset ($sess->oauth) )
  332.             return;
  333.  
  334.         if isset ($_GET['after']) ) {
  335.             if trim ($_SERVER['QUERY_STRING']) )
  336.                 $qs sprintf ('?%s&after'$_SERVER['QUERY_STRING']);
  337.             else
  338.                 $qs '?after';
  339.  
  340.             $redirect $_SERVER['SCRIPT_URI'$qs;
  341.  
  342.             $logoutDocPath 'OAUTH2/logout-no-auto.template';
  343.             if $GLOBALS['_OAUTH2_LOGOUT_TEMPALTE_'{
  344.                 if file_exists ($GLOBALS['_OAUTH2_LOGOUT_TEMPALTE_']) )
  345.                     $logoutDocPath $GLOBALS['_OAUTH2_LOGOUT_TEMPALTE_'];
  346.             }
  347.             $logoutDoc file_get_contents ($logoutDocPathtrue);
  348.             $src array (
  349.                 '/{%VENDOR%}/',
  350.                 '/{%REDIRECT%}/',
  351.                 '/{%LOGOUT-URL%}/',
  352.                 '/{%WIN-WIDTH%}/',
  353.                 '/{%WIN-HEIGHT%}/',
  354.             );
  355.             $dst array (
  356.                 'GITHUB',
  357.                 $redirect,
  358.                 $this->reqRevoke,
  359.                 600400
  360.             );
  361.             $logoutDoc preg_replace ($src$dst$logoutDoc);
  362.             echo $logoutDoc;
  363.             exit;
  364.         }
  365.  
  366.         unset ($_SESSION[$this->sessid]);
  367.     }
  368.     // }}}
  369. }
  370.  
  371. /*
  372.  * Local variables:
  373.  * tab-width: 4
  374.  * c-basic-offset: 4
  375.  * End:
  376.  * vim600: noet sw=4 ts=4 fdm=marker
  377.  * vim<600: noet sw=4 ts=4
  378.  */
  379. ?>

Documentation generated on Tue, 14 May 2019 02:00:03 +0900 by phpDocumentor 1.4.4