LINEでお客様にメッセージ送信

LINE APIでお客様にメッセージ送信STEPまとめ
1. LINE developerで無料アカウント登録
2. プロバイダーを作成
3. LINEログインAPIを作成
4. Messaging APIを作成
5. 友達追加URLを確認する
6. サイト実装

#1. LINE developerで無料アカウント登録

　開発者名とメールアドレスと　「LINE Developers Agreementの内容に同意します」チェックしてアカウントを作成します。
![account_step1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/7a43dd06-114b-dcd2-1867-9874d0a1d838.png)


#2. プロバイダーを作成

##a. アカウント登録出来たら、https://developers.line.biz/console/?status=success に遷移します。
「新規プロバイダー作成」ボタンクリックしたら、新規プロバイダー作成画面が表示されます。
![create_provider.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/ed2c6eb3-4dba-088b-8417-fc8ef0db53b5.png)

##b. 新規プロバイダー作成画面で「プロバイダー名」を記入します。例：「株式会社テスト」を記入します。

##c. 「作成」ボタンをクリックで「株式会社テスト」という名前で「プロバイダー」を作成完了になります。作成出来たら、LINE developerのコンソール（ホーム）に遷移します　→　https://developers.line.biz/console/provider/xyz
![console_home.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/db7187e3-ccd9-f076-2c01-fae88663ce10.png)

#3. LINEログインAPIを作成
##a. LINE developerのコンソール（ホーム）から自分が作成した「プロバイダー」を選んで、「チャネル設定」タブから「LINEログイン」を選択してログインAPIを作成の項目記入してください。
・チャネルの種類：「LINEログイン」、「Messaging API」、「Clovaスキル」から「LINEログイン」を選択してください。
・プロバイダー：「株式会社テスト」、「新規プロバイダー作成」から自分が作成されたプロバイダー「株式会社テスト」を選んで下さい。
・チャネルアイコン：アイコンアップロードしてください。
・チャネル名：お好きな「チャネル名」を記入してください。例：TEST会社ログイン
・チャネル説明：お好きな「チャネル説明」を記入してください。例：TEST会社の窓口です。
・アプリタイプ：ウェブアプリ / ネイティブアプリを選択ください。
・メールアドレス：メアド記入、例：test@test.com
・プライバシーポリシーURL（任意）：
・サービス利用規約URL（任意）：
・「LINE Developers Agreement の内容に同意します」

![login_api_create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/7356af27-676f-cb0d-52d9-0f588f3d1ac2.png)


作成ボタン押したら、「チャネル（TEST会社ログイン）が作成されました。」お知らせが出ます。

##b. 自動で「LINEログイン」の「チャネルID」、「チャネルシークレット」、「あなたのユーザーID」発行されますのでこちらの値はサイト側でLINEログインAPIの設定で接続できます。
　　・「チャネルID」：xyz；例：1111111
　　・「チャネルシークレット」:abc；例：2222222
　　・「あなたのユーザーID」:klm；例：33333333

##c. 「LINEログイン設定」タブの「コールバックURL」をご自分サイトのURLを設定してください。例：https://site-sample/index.php
※ロカール、開発、本番のURLがそれぞれ違う場合は別のプロバイダー作成して別のログインAPI作成して「コールバックURL」をサーバ名と合わせて記入する必要があります。

##d. ログインAPIの設定完了出来たら、ログインアプリのステータスを「非公開」を「公開」をします。


#4. Messaging APIを作成
##a. プロバイダーから「新規チャネル作成」をクリックしてチャネルの種類から「Messaging API」を選択ください。
　　・チャネルの種類：「LINEログイン」、「Messaging API」、「Clovaスキル」から「Messaging API」を選択してください。
　　・プロバイダー：「株式会社テスト」、「新規プロバイダー作成」から自分が作成されたプロバイダー「株式会社テスト」を選んで下さい。
　　・チャネルアイコン：アイコンアップロードしてください。
　　・チャネル名：お好きな「チャネル名」を記入してください。例：TEST会社ログイン
　　・チャネル説明：お好きな「チャネル説明」を記入してください。例：TEST会社の窓口です。
　　・大業種：好きな大業種を選んで下さい。例：ウエブサービス
　　・小業種：好きな小業種を選んで下さい。例：ウエブサービス（ビジネス）
　　・メールアドレス：メアド記入。例：test@test.com
　　・プライバシーポリシーURL（任意）：
　　・サービス利用規約URL（任意）：
　　・「LINE公式アカウント利用規約 の内応に同意します」、「LINE公式アカウントAPI利用規約  の内応に同意します」をチェック

「作成」ボタン押したら、「情報利用に関する同意について」ポップアップから「同意する」ボタン押してください。「チャネル（TEST会社ログイン）が作成されました。」お知らせが出ます。

##b. 自動で「LINEログイン」の「チャネルID」、「チャネルシークレット」、「あなたのユーザーID」発行されますのでこちらの値はサイト側でLINEログインAPIの設定で接続できます。
　　・「チャネルID」：xyz；例：1111111
　　・「チャネルシークレット」:abc；例：2222222
　　・「あなたのユーザーID」:klm；例：33333333

##c. 「Messaging API設定」タブの「チャネルアクセストークン」を「発行」を押したら、トークンを作ってくれます。このトークンもMessaging APIを使用する時必要になります。例：

チャネルアクセストークン（ロングターム）
55555555

#5. 友達追加URLを確認する

追従フッタから「Line for Business」を選んでLINE business（https://www.linebiz.com/jp-en/login/）から管理画面に入ります。
![line_business_admin.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/733abbac-f40c-44dd-65d3-c963f6e29574.png)
上記の画面から「Admin Panel」に入ってアカウントリストからアカウントクリックでMessage APIの設定画面に入ります。「友達追加URL」押したら、
![line_business_friend.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/00d3444b-c3a3-5f01-5fb8-973499368819.png)

上記の画面で友だち追加のURL、QRコード、ボタンのリンクをサイト側で使われてmessage送信できます。

-------------------------------
#6. サイト実装
MVCパターンサイト実装形で以下の手順でController,　Modelと Viewを作成します。

##a. composer.jsonを作成します
```php5:composer.json
{
  "autoload": {
    "psr-4": {
      "Controllers\\":"Controllers/",
      "Models\\OAuthV2\\" : "Models/OAuthV2/",
      "Models\\Token\\" : "Models/Token/",
      "Models\\Profile\\" : "Models/Profile/",
      "Models\\View\\" : "Models/View/"
    }
  },
  "require": {
    "vlucas/phpdotenv": "^4.1"
  },
    "require-dev": {
        "phpunit/phpunit": "*"
    }
}

```

作成したら、以下の手順でcomposerをインストールします。
1. 「composer install」でインストールします.
2. 最適化しないautoloaderを用いた場合「composer dump-autoload」コマンドで実行
3. 最適化したautoloaderを用いた場合「 composer dump-autoload --optimize」コマンドで実行

##b .env ファイルを作成します


```php5:.env
＃レスポンスタイプ
RESPONSE_TYPE=code

#チャネルID
CHANNEL_ID=11111111

#リダイレクトURL
#コンソールで指定したURLと同じ必要がある
REDIRECT_URI=https://site_sample.localhost/index.php

#スコープ(%20で区切ってprofile,openid,emailの複数を指定できる)
#https://developers.line.biz/ja/docs/line-login/web/integrate-line-login/#scopes
SCOPE=profile

#secret
SECRET=22222222

#https://developers.line.biz/ja/docs/line-login/web/link-a-bot/
BOT_PROMPT=normal

PROMPT=consent

#Message APIのアクセストークン
MESSAGE_API_TOKEN=55555555

#LINE友達追加URL
LINE_FRIEND_URL=https://lin.ee/xxx

```

**上記の変数の値はログインAPIやMessaging APIの設定からコピーしてください。**


##c. Controllerを作成します。

###Controllers\Common.phpを作成します

```php5:Common.php
<?php
namespace Controllers;
use Dotenv;
use Models\View\View;
use Models\OAuthV2\GenerateURL_LINELOGIN;
use Models\Token\TokenAnalyzer;
use Models\Profile\ProfileAnalyzer;

class Common{

    protected function run( $page_name ){
        session_start();
        // envファイルの読みこみ
        $dotenv = Dotenv\Dotenv::createImmutable(dirname(__DIR__). '/');
        $dotenv->load();
        $redirect_url = './';

        if (!$_GET["code"]){
            #ログインURLの取得
            $cls = new GenerateURL_LINELOGIN();
            $cls -> setResponseType($_ENV['RESPONSE_TYPE']);
            $cls -> setClientID($_ENV['CHANNEL_ID']);
            $cls -> setRedirectURI($_ENV['REDIRECT_URI']);
            $cls -> setState(rand(0,100));
            $cls -> setScope($_ENV['SCOPE']);
            $cls -> setSecret($_ENV['SECRET']);
            $cls -> setBotPrompt($_ENV['BOT_PROMPT']);
            $cls -> setPrompt($_ENV['PROMPT']);
            $_SESSION['cls'] = $cls;
            $data['login_url'] = $cls -> getURI();
            $_SESSION['line_send_flag'] = false;
            $view = new View($page_name, $data);
            echo $view -> forge();
        }else{
            $analy = new TokenAnalyzer($_GET["code"],$_SESSION['cls']);
            $token = $analy->geToken();
            if($token['isSuccess']){
                $jsonObj = json_decode($token['value']);
                if(isset($jsonObj->error)){
                    $_SESSION['error'] = $jsonObj->error_description;
                    // header('Location:' . $redirect_url);
                    // exit;
                }
                $profile = new ProfileAnalyzer($jsonObj->access_token);
                $data = json_decode($profile -> getProfile(), true);
                $line_id = $data['userId'];
                if(!$_SESSION['line_send_flag']){
                    // lineユーザIDをLINE連携APIサーバに送信
                    $_SESSION['line_send_flag'] = $result ? true: false;
                }
                $data['line_friend_url'] = $_ENV['LINE_FRIEND_URL'];
                $view = new View($page_name, $data);
                echo $view -> forge();
                exit;
            }else{
                $_SESSION['error'] = $token['value'];
                header('Location:' . $redirect_url);
            }
        }
    }
}

```

**`$data['userId']`がユーザのIDになります。これを使用してREST APIでメッセージ送信できます。**

###Controllers\Index.phpを作成します

```php5:Index.php
<?php
namespace Controllers;

class Index extends Common{

    public function run($page_name){
        parent::run($page_name);
    }
}

```

##d. Modelを作成します。

###Models\OAuthV2\OAuth.phpを作成します

```php5:OAuth.php
<?php
namespace Models\OAuthV2;

/**
 * ラインログインのURLを作成するクラス
 */
class GenerateURL_LINELOGIN {

    // パラメータ集合体
    private $_PARAM = array();

    /**
     * @return void
     * レスポンスコード設定
     */
    public function setResponseType($response_type){
        $this->_PARAM["response_type"] = $response_type;
    }

    /**
     * @param String $ClientID チャネルID
     * チャネルID設定
     */
    public function setClientID($ClientID){
        $this->_PARAM["client_id"] = $ClientID;
    }

    /**
     *  @return String $ClientID チャネルID取得
     */
    public function getClientID(){
        return $this->_PARAM['client_id'];
    }

    /***
     * @param $URI リダイレクト先URI
     */
    public function setRedirectURI($URI) {
        $this->_PARAM['redirect_uri'] = $URI;
    }

    /**
     * @return String リダイレクトURL
     */
    public function getRedirectURI(){
        return $this->_PARAM['redirect_uri'];
    }

    /***
     * @param $State クロスサイトリクエストフォージェリ対策（乱数でOK）
     */
    public function setState($State) {
        $this->_PARAM["state"] = $State;
    }

    /***
     * @param Enum\SCOPE $SCOPE スコープ
     */
    public function setScope($SCOPE){
        $this->_PARAM["scope"] = $SCOPE;
    }

    /***
     * @param $nonce リプレイアタック防止
     */
    public function setNonce($nonce) {
        $this->_PARAM["nonce"] = $nonce;
    }

    /**
     * @param $PROMPT
     */
    public function setPrompt($PROMPT){
        $this->_PARAM["prompt"] =  $PROMPT;
    }

    /**
     * @param integer max_age
     */
    public function setMaxAge($max_age){
        $this->_PARAM["max_age"] = $max_age;
    }

    /***
     * @param Enum\BOT_PROMPT $BOT_PROMPT
     */
    public function setBotPrompt($BOT_PROMPT){
        $this->_PARAM["bot_prompt"] = $BOT_PROMPT;
    }

    /***
     * @return bool|string ほぼJsonString
     */
    public function getURI(){
        $Base_Uri = "https://access.line.me/oauth2/v2.1/authorize?";
        // URL を作成
        foreach ($this->_PARAM as $key => $value){
            $Base_Uri .= $key . "=" . (string)$value . "&";
        }
        // 最後の＆を消す
        $Base_Uri = rtrim($Base_Uri, "&");
        return $Base_Uri;
    }

    /**
     * @param String secret
     */
    public function setSecret($secret){
        $this->_PARAM['secret']=$secret;
    }

    /**
     * @return String secret
     */
    public function getSecret(){
        return $this->_PARAM['secret'];
    }
}

```

###Models\Profile\ProfileAnalyzer.phpを作成します

```php5:ProfileAnalyzer.php
<?php
namespace Models\Profile;

class ProfileAnalyzer
{
    private $token;

    /**
     * tokenAnalyzer constructor.
     * @param $ACCESS_TOKEN call back code => tokenCode
     */
    public function __construct($ACCESS_TOKEN){
        $this->token = $ACCESS_TOKEN;
    }

    public function getProfile(){

        $headers = [
            "Authorization:" . "Bearer " . $this->token
        ];

        $ch = curl_init("https://api.line.me/v2/profile");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        $return_value = curl_exec($ch);
        curl_close($ch);

        return $return_value;
    }
}

```

###Models\Token\TokenAnalyzer.phpを作成します

```php5:TokenAnalyzer.php
<?php
namespace Models\Token;

/**
 * アクセストークンを取得するクラス
 */
class TokenAnalyzer
{
    private $_CODE;
    private $cls;

    /**
     * tokenAnalyzer constructor.
     * @param $_CODE call back code => tokenCode
     */
    public function __construct($_CODE,$cls){
        $this->code = $_CODE;
        $this->cls=$cls;
    }

    /**
     * アクセストークンを取得する
     * @return Sting アクセストークン
     */
    public function geToken(){

        $data = [
            "grant_type" => "authorization_code",
            "code" => $this->code,
            "redirect_uri" => $this->cls->getRedirectURI(),
            "client_id" => $this->cls->getClientID(),
            "client_secret" => $this->cls->getSecret()
        ];

        $headers = [
            "Content-Type:application/x-www-form-urlencoded"
        ];

        $ch = curl_init("https://api.line.me/oauth2/v2.1/token");

        curl_setopt($ch, CURLOPT_RETURNTRANSFER , 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        try {
            $return_value['value'] = curl_exec($ch);
            $return_value['isSuccess']=true;
        } catch (\Throwable $th) {
            $return_value['value']=$th;
            $return_value['isSuccess']=false;
        }

        curl_close($ch);

        return $return_value;
    }
}

```

###Models\View\View.phpを作成します

```php5:View.php
<?php
namespace Models\View;

class View
{
	/**
	 * @var  string  The view's filename
	 */
	protected $file_name = null;

	public function __construct($file = null, $data = null, $filter = null)
	{
		if (is_object($data) === true)
		{
			$data = get_object_vars($data);
		}
		elseif ($data and ! is_array($data))
		{
			throw new \InvalidArgumentException('The data parameter only accepts objects and arrays.');
		}


		if ($data !== null)
		{
			// Add the values to the current data
			extract($data);
		}
		ob_start(); // 記録開始

		require_once __DIR__ . '/../../Views/'.$file.'.php';
	}

	public function forge()
	{
		$data = ob_get_contents(); // 記録結果を変数に代入
		ob_end_clean(); // 記録終了
		return $data;
	}
}

```

##e. Viewページ作成します。

###htdocs\index.phpページを作成します

```php5:index.php
<?php
require_once __DIR__ . "/../vendor/autoload.php";
use Controllers\Index;

$app = new Index;
$app->run('index');

```

###テンプレート「Views\index.php」ページを作成します

```php5:index.php
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<a href="<?php echo $login_url;?>" class="js-show_add">LINEログイン</a>

<?php if(isset($_GET['code'])):?>

<div>
    <a href="<?php echo $line_friend_url; ?>"><img src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png"  height="36" border="0"></a>
</div>

<table>
    <tr>
        <th>ユーザーID</th>
        <td><?php echo $userId;?></td>
    </tr>
    <tr>
        <th>表示名</th>
        <td><?php echo $displayName;?></td>
    </tr>
    <tr>
        <th>画像</th>
        <td><img src="<?php echo $pictureUrl;?>" class="img-thumbnail" style="width:50%"></td>
    </tr>
    <tr>
        <th>メッセージ</th>
        <td><?php echo $statusMessage;?></td>
    </tr>
</table>
<?php endif;?>
</body>
</html>

```

##f.サイト確認
###サイトアクセスして「https://site_sample/index.php」LINEログインボタンを押したら以下の画面が出ます。
![line_authorize.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/04c8c282-ddf3-905d-e0f5-633681b2899c.png)

###ログインしたら、LINEのログインアプリの許可すれば、callbackの関数でログイン出来てトップに戻ります。URLに?code=xyzを付いてきます。
![top_page.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488641/5ae78a5c-6ed2-47b1-bc23-3d8685bcdd4a.png)