ライブラリを使わずにTwitter APIでダイレクトメッセージを送信する [PHP]

TwitterのAPIを利用して、任意のユーザーへダイレクトメッセージを送信するPHPのコードです。ライブラリは使わずに直接実装するケースを想定しています。

#前提条件
・送信元のアカウントで**APIを利用出来る**。（Twitter Developersに登録済み）
・送信相手の**ユーザーID**が判明している。
・**送信相手がこちら（送信元）のアカウントをフォロー**している。

#処理の流れ
1. 署名キーを作る
2. HTTPヘッダ用のパラメータを作る
3. パラメータ(2.)をソートする
4. 署名キー(1.)とパラメータ(3.)から署名を作る
5. パラメータ(3.)に署名(4.)を追加する
6. パラメータ(3.)からHTTPヘッダ用の配列を作る
7. POSTデータ用の配列を作る
8. cURLでエンドポイントにデータを投げる
9. エンドポイントの応答を受け取る

##接続先（エンドポイント）
https://api.twitter.com/1.1/direct_messages/events/new.json

##処理に必要な値
Twitter Developersで下記の値を予め取得しておく必要があります。

```php
$api_key = 'APIキー';
$api_secret = 'APIシークレット';
$access_token = 'アクセストークン';
$access_token_secret = 'アクセストークンシークレット';
```

#1. 署名キーを作る
APIシークレットとアクセストークンシークレットを用いて署名キーを作成します。

```php
$signature_key = rawurlencode( $api_secret )."&".rawurlencode( $access_token_secret );
```

#2. HTTPヘッダ用のパラメータを作る
エンドポイントへ渡すための認証データを連想配列で作成します。

```php
$paramData = array(
  "oauth_token" => rawurlencode( $access_token ),
  "oauth_consumer_key" => rawurlencode( $api_key ),
  "oauth_signature_method" => rawurlencode( "HMAC-SHA1" ),
  "oauth_timestamp" => time(),
  "oauth_nonce" => microtime(),
  "oauth_version" => rawurlencode( "1.0" )
);
```

#3. パラメータをソートする
ksortで連想配列をソートします。これを忘れると認証エラーが起き得ます。

```php
ksort( $paramData );
```
#4. 署名キーとパラメータから署名を作る
1で作成した署名キーと、2で作成したパラメータの配列を利用して、署名を作ります。

```php
$sig_param = rawurlencode('POST')."&".
  rawurlencode('https://api.twitter.com/1.1/direct_messages/events/new.json')."&".
  rawurlencode( http_build_query( $paramData , "", "&" ) );

$signature = hash_hmac( "sha1", $sig_param, $signature_key, TRUE );
$signature = base64_encode( $signature );
```

#5. パラメータに署名を追加する
連想配列に署名を追加します。

```php
$paramData['oauth_signature'] = $signature;
```

#6. パラメータからHTTPヘッダ用の配列を作る
cURLで使うための配列を新たに作成しておきます。

```php
$httpHeader = array(
  'Authorization: OAuth '.http_build_query( $paramData, "", "," ),
  'content-type: application/json'
);
```

#7. POSTデータ用の配列を作る
cURLで送信するボディにあたるデータを作成します。これは後にjsonエンコードします。
ここで送信先のユーザーIDと、送信したいメッセージもセットします。

```php
$postData = array(
  "event" => array(
    "type" => "message_create",
    "message_create" => array(
      "target" => array(
        "recipient_id" => '送信先のユーザID'  //送信先ID
      ),
      "message_data" => array(
        "text" => '送信メッセージ'  //送信したいメッセージ
      )
    )
  )
);
```
Eventオブジェクトの中に入れ子で情報を詰め込んでいます。
上記のサンプルコードは必須項目のみを記述していますが、message_dataオブジェクト（メッセージが入っているところ）にはオプションも追記可能です。

詳しくはTwitter公式のAPIリファレンスを確認してください。[^リファレンス]

#8. cURLでエンドポイントにデータを投げる
これまでに作成した各種配列をセットして、cURLでエンドポイントへデータを渡します。

```php
$ch = curl_init();

curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeader);
curl_setopt($ch, CURLOPT_URL, 'https://api.twitter.com/1.1/direct_messages/events/new.json');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, rawurlencode('POST'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode( $postData ));

$json = curl_exec($ch);

curl_close($ch);
```

#9. エンドポイントの応答を受け取る
ダイレクトメッセージの送信に成功すると、message_createイベントのIDやタイムスタンプを含んだjsonデータが返されます。ここでjsonデータを連想配列へ変換しておきます。

```php
$response = json_decode( $json, true );

echo var_dump( $response );
```
var_dumpした結果が下記です。

```php
array(1) {
  ["event"]=> array(4) {
    ["type"]=> string(14) "message_create"
    ["id"]=> string(19) "イベントID"
    ["created_timestamp"]=> string(13) "1561275503817"  //ミリ秒
    ["message_create"]=> array(3) {
      ["target"]=> array(1) {
        ["recipient_id"]=> string(10) "送信先のID"
      }
      ["sender_id"]=> string(19) "送信元のID"
      ["message_data"]=> array(2) {
        ["text"]=> string(24) "送信メッセージ"
        ["entities"]=> array(4) {
          ["hashtags"]=> array(0) { }
          ["symbols"]=> array(0) { }
          ["user_mentions"]=> array(0) { }
          ["urls"]=> array(0) { }
        }
      }
    }
  }
}
```

これ以降の処理は、idが含まれているか、などの条件で処理判定すればよいかと思います。

```php
if( empty( $response['event']['id'] ) ){
  //失敗時の処理
} else {
  //成功時の処理
}
```
尚、レスポンスデータに含まれるタイムスタンプはミリ秒で返ってきます。[^参考]
そのままでは日付表示が出来ないので、秒に変換する必要があります。

```php
$timestamp = $response['event']['created_timestamp'];
echo date('Y-m-d H:i:s', ( $timestamp / 1000 )); //1000で割って秒にする
```
結果
`2019-06-24 06:42:31`

#最後に
Qiitaに登録して初めて書く記事となります。コードや文章に稚拙な部分があるかもしれませんが、ご容赦ください。可読性を優先してわざと定数化していない箇所はあります。

誤りのご指摘やご意見などがありましたら、是非お願いいたします。

####注釈（参考サイト）
[^リファレンス]: [Twitter API Reference \[direct_messages/events/new\] ](https://developer.twitter.com/en/docs/direct-messages/sending-and-receiving/api-reference/new-event)
[^参考]: [LINEのMessaging APIで送られてくるタイムスタンプの変換にはまった](https://qiita.com/stmkza/items/9848a21b791b2319fce4)