TwilioのSMSをPHPで受け止めてAcrobits Softphoneで送受信してみる

福田です。今日は12/24、クリスマスイブ。僕はアメリカでクリぼっちですよ、ええ。悲しいなぁ…。さて、本日はPHP Advent Calendar 2016最終日の前日、24日目です。これといって書くネタもあまりなかったので、TwilioのSMSをAcrobits Softphoneで送受信してみようという企画を立てました。世界一雑な解説です。コピペでもほとんどできます。

Sponsored link

twilio

動作の仕組み

動作の仕組みを適当に解説します。受信の流れから。

  1. ユーザーがTextingする
  2. Twilioが受信する
  3. TwilioがTwiML Webhookを呼び出す
  4. 当該サーバが応答、情報をいただく
  5. 情報をもらってJSONに保管
  6. 受信者がJSONを読み出すPHPにHTTPリクエストを飛ばす
  7. 受信者がデータをもらうと同時にJSONから削除

送信は次の通り。

  1. Acrobits Softphoneからテキストを打つ
  2. PHPでデータを受信、Twilio SDKを読み込みTwilioにデータを送信
  3. Twilioが送信リクエストを受信し、当該番号宛にSMSを送る各電話会社でユーザーにTextを送る

ではまずはSMSの送信から作っていきましょう。なお前提条件としてあらかじめアメリカの電話番号取って置いてください(雑

SMSを送信するためにTwilioのSDKをダウンロード

ではまずTwilioのPHP SDKをインストールします。Composer入れておいてください。

composer require twilio/sdk

入れたら、そのディレクトリで送信用ファイルを作ります。

‹?php
require __DIR__ . '/vendor/autoload.php'; //Composerのオートロードを利用してライブラリを読み込む
use Twilio\Rest\Client; //TwilioのRESTクライアントを立ち上げる
$sid = '(チョメチョメ)'; //ログインしてすぐに表示されるAccount SIDをコピペ
$token = '(チョメチョメ)'; //ログインしてすぐに表示されるAccount Tokenをコピペ
$client = new Client($sid, $token); //クライアントを立ち上げる
$client->messages->create( //メッセージ送信実行
    "$_GET[to]", //宛先
    array(
        'from' => '+1チョメチョメ', //アカウントで取得した+1から始まる番号、差出人
        'body' => "$_GET[msg]" //本文
    )
);
?>
‹response›
  ‹error›0‹/error› <!--エラーの有無。0はエラーなし。-->
  ‹description›Success‹/description›<!--詳細。成功ならSuccessと。-->
‹/response›

これで送信側は完成。超簡単ですね。Acrobitsも特に指定してこないので超楽でした。では次は受信です。どちらかというとこちらが面倒です。

TwilioのTwiML WebHookに指定するプログラムを書く

TwilioはSMSを受信するとTwiMLで処理しますが、そのデータだけ渡してもらってあとは何もしないように指図します。それはResponseでXMLを囲うことでできます。
そしていただいたデータをJSONにリライトして保管しておきます。
そのほか具体的な解説はソースコードのコメント内でしています。

‹?php
header('Content-type: text/xml'); //XMLでないとTwiMLはダメですのでMIMEでレスポンスを明示する
echo '‹?xml version="1.0" encoding="UTF-8"?›'; //UTF-8エンコードのXML1.0と明示する
echo '‹Response›‹/Response›'; //何も返信しない=何もTwilio側ではアクションを起こさない
$file = __DIR__."/messages/unread.json"; //カレントディレクトリ下のmessages/unread.jsonにデータを保管
$SMS = json_decode(file_get_contents($file),true); //JSONを取得(上書きしてしまうと見てなかった場合にメッセージをロストするため)
$sms_id = strtoupper(uniqid(mt_rand())); //SMSに割り振る独自のID。重複検査で利用。Twilioデフォルトの30数文字だとバカ長いため、あえて13文字のランダムIDを独自生成
$SMS[$sms_id]["sending_date"] = date(DATE_RFC3339); //Acrobits Softphoneは受信日時をRFC3339形式で支持しているため受信日時をその形で保管
$SMS[$sms_id]["sender"] = "{$_REQUEST['From']}"; //Twilioから受付た電話番号をそのまま掲載
$SMS[$sms_id]["sms_text"] = "{$_REQUEST['Body']}"; //Twilioから受けたメッセージをそのまま掲載
file_put_contents($file, json_encode($SMS), LOCK_EX); //同時アクセスからの同時書き込みによるファイルの破損を防ぐためロックをかけて新規情報を書き込み

やっていることは単純ですが、一回データを保管しなければならないため面倒です。さらに続いてAcrobitsで読める形式に直します。そのために次のファイルを作ります。このあと、Twilioの電話番号管理画面からTwiML Webhookに先ほどのファイルのURLを指定しておいてください。

<?php
header('Content-type: text/xml'); //AcrobitsはXML推奨なためXMLと明示
$date = date(DATE_RFC3339); //返信日時を要求してくるので現在の時間をRFC3339型で取得
$file = __DIR__."/messages/unread.json"; //Twilioから受け取り、変換したJSONの場所
$SMS = json_decode(file_get_contents($file),true); //SMSを格納しているJSONを連想配列型に戻す
?>
<response>
    <date><?php echo $date;?><!--現在の時刻--></date>
    <unread_smss><!--未読SMS-->
        <?php foreach($SMS as $sms_id => $info) { //SMSを一件一件XMLに変換して落とし込む ?>
        <item>
            <sms_id><?php echo $sms_id; ?></sms_id><!--保管されているSMSの一意なID-->
            <sending_date><?php echo $info["sending_date"]; ?><!--受け取り日時--></sending_date>
            <sender><?php echo $info["sender"];?></sender><!--送信者-->
            <sms_text><?php echo $info["sms_text"]; ?></sms_text><!--本文-->
        </item>
        <?php
            unset($SMS[$sms_id]); //読み取ったのでサーバからデータを削除
        }
        file_put_contents($file, json_encode($SMS), LOCK_EX); //書き込みロックして破損を防止しつつ、削除後のデータを送り込む
        ?>
    </unread_smss>
</response>

以降はPHP使いませんのでPHP Advent Calendarから来た人はごめんなさい(てへ

これで完成。さらに、Acrobits Softphoneの設定では細かいことが指定できないのでaccount.xmlというものを作成してSMSを受け取れるように設定します。ついでに日本の呼び出し音になるようにも設定します。次のファイルを作成してサーバにおいておきます。

<account>
    <genericSmsFetchUrl>(サーバのAcrobits用の受信PHP)</genericSmsFetchUrl>
   <genericSmsSendUrl>(サーバの送信PHP)?msg=%sms_body%&to=%sms_to</genericSmsSendUrl>
   <tryingTone>periodic(sine(8000ms,2500,400Hz))</tryingTone>
    <ringingTone>periodic(sine(1000ms,2500,400Hz,415Hz),silence(2000ms))</ringingTone>
   <busyTone>periodic(sine(500ms,2500,400Hz),silence(500ms))</busyTone>
   <endCallTone>periodic(sine(1000ms,2500,400Hz),silence(1000ms))</endCallTone>
   <callWaitingTone>periodic(sine(500ms,2500,400Hz),silence(8000ms))</callWaitingTone>
</account>

これを保存したら、アカウントの設定→ウェブサービス→外部プロビジョニングという欄に上のデータを保管してあるところのURLを入力します。これでオッケー。かっこで囲ってあるところは上のプログラムを置いたところのURLで置き換えてください。

この記事は突貫工事で作ったので、Twilioの管理画面の手引きや実際の送受信の証拠などは後日気が向けば更新するかもです。そういう奴に限ってしない()
今こっちは深夜3:30です。2:50ではありません。

Sponsored link

Sponsored link

Leave a Reply