PHP Discord OAuth2認証

# PHP Discord OAuth2認証
PHP Laravel環境でDiscord OAuth2認証を行ったので備忘録
## 環境
・Larave 5.7
・PHP 7.2.15
## 前提
・Discord Developerで「OAUTH2_CLIENT_ID」「OAUTH2_CLIENT_SECRET」を取得
・Discord DeveloperでCallback URLの設定

### ログイン時
```
    public function login(Request $request)
    {
            define('OAUTH2_CLIENT_ID', '<OAUTH2_CLIENT_ID>');
            define('OAUTH2_CLIENT_SECRET', '<OAUTH2_CLIENT_SECRET>');
    
            $authorizeURL = 'https://discord.com/api/oauth2/authorize';
            $tokenURL = 'https://discord.com/api/oauth2/token';
            $apiURLBase = 'https://discord.com/api/users/@me';
    
    
            $params = array(
                'client_id' => OAUTH2_CLIENT_ID,
                'redirect_uri' => '<Callback URL>',
                'response_type' => 'code',
                'scope' => 'identify guilds'
            );
            
            // Redirect the user to Discord's authorization page
            header('Location: https://discord.com/api/oauth2/authorize' . '?' . http_build_query($params));
            die();
    }
```
### Callbackで呼び出す関数
```
    public function message_login_callback_discord(Request $request)
    {
        define('OAUTH2_CLIENT_ID', '<OAUTH2_CLIENT_ID>');
        define('OAUTH2_CLIENT_SECRET', '<OAUTH2_CLIENT_SECRET>');

        $authorizeURL = 'https://discord.com/api/oauth2/authorize';
        $tokenURL = 'https://discord.com/api/oauth2/token';
        $apiURLBase = 'https://discord.com/api/users/@me';
        $apiURLGuild = 'https://discord.com/api/users/@me/guilds';

        if($request->input('code')) {
            // 初回のCallback
            $token = $this->apiRequest($tokenURL, array(
              "grant_type" => "authorization_code",
              'client_id' => OAUTH2_CLIENT_ID,
              'client_secret' => OAUTH2_CLIENT_SECRET,
              'redirect_uri' => '<Callback URL>',
              'code' => $request->input('code')
            ));
            // sessionにaccess_tokenを格納
            session(['access_token' => $token->access_token]);
            return redirect('/message_login_callback_discord');
        }

        //上記処理後のCallback
        if(session('access_token')) {
            $user = $this->apiRequest($apiURLBase);
            $guilds = $this->apiRequest($apiURLGuild);
            return $user;
        }

        return redirect('/login');

    }
```
### その他「API Request 関数」
```
    public function apiRequest($url, $post=FALSE, $headers=array()) {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
      
        $response = curl_exec($ch);
      
      
        if($post)
          curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
      
        $headers[] = 'Accept: application/json';
      
        if(session('access_token'))
          $headers[] = 'Authorization: Bearer ' . session('access_token');
      
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
      
        $response = curl_exec($ch);
        return json_decode($response);
      }
```
### おまけ「特定のDiscordサーバーに参加しているか確認」
```
            $user = $this->apiRequest($apiURLBase);
            $guilds = $this->apiRequest($apiURLGuild);

            $check_suiseicord_join = false;
            foreach ($guilds as $guild) {
                if ($guild->id=="<確認したいサーバー(guild)のID>") {
                    $check_suiseicord_join = true;
                }
            }
```