2019-10-10

PHP5.3, CakePHP2.x に Twilio 導入あれこれ

以前紹介したシステムtwilioを導入して、集合要請時に携帯電話に自動通話を行いメール確認を促す仕組みを作ることになりました。メールだけでなく電話も来たら急かされるようで鬱陶しいと個人的には思いますが、人命にかかわる緊急事態なので仕方ないのでしょう。twilioについては以前SMSメッセージを送るスクリプト(例えばこちらを参照)を作ったことがあったので通話発信も同様にやればいいだろうと考えていましたが、早速つまずきました。以前と同じようにこちらなどを参考にスクリプトを書いたのですが500番エラーが出てどうにもなりません。エラーログにversion, upgradeなどの単語が入っていたのでテスト用のサーバがPHP5.3と古いものなので読み込むTwilio PHPライブラリーのバージョンが問題なのかと見当をつけ、手動ではなく昔よく使ったPEARでインストールすることにしました。

https://docs.microsoft.com/ja-jp/azure/partner-twilio-php-how-to-use-voice-sms

を参考にして

[root@xxxxxxx ~]#  pear channel-discover twilio.github.com/pear
[root@xxxxxxx ~]#  pear install twilio/Services_Twilio

とすると

[root@xxxxxxx ~]# pear install twilio/Services_Twilio
Unknown remote channel: pear.survivethedeepend.com
Did not download optional dependencies: channel://pear.survivethedeepend.com/Mockery, use --alldeps to download automatically
twilio/Services_Twilio can optionally use package "channel://pear.survivethedeepend.com/Mockery"
downloading Services_Twilio-3.12.6.tgz ...
Starting to download Services_Twilio-3.12.6.tgz (85,763 bytes)
........done: 85,763 bytes
install ok: channel://twilio.github.io/pear/Services_Twilio-3.12.6

となり上手くインストールされたようですが、エラーは消えませんでした。PHPパッケージのインストールは今ではPEARではなくcomposerというのが主流のようで、公式サイト


でもサーバ環境にあったパッケージを自動でインストールしてくれるcomposerを推薦しているので


を参考にしてまずcomposerをインストールしてみると

[homepage@xxxxxxx ~]# php composer-setup.php
Downloading...

Composer (version 1.9.0) successfully installed to: /home/homepage/composer.phar
Use it: php composer.phar

Some settings on your machine may cause stability issues with Composer.
If you encounter issues, try to change the following:

Your PHP (5.3.3) is quite old, upgrading to PHP 5.3.4 or higher is recommended.
Composer works with 5.3.2+ for most people, but there might be edge case issues.

となりPHP5.3.3はかなり古いよ!との警告が出ました。とりえず無視してtwilio/sdkをインストールすると

[root@xxxxxxx ~]# composer require twilio/sdk
Using version ^5.19 for twilio/sdk
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing twilio/sdk (5.19.3): Downloading (100%)
Writing lock file
Generating autoload files

無事インストールされたようです。twilio/sdkのパッケージリスト


によると現時点で最新のバージョンは5.36.1でPHP5.5以上に対応しています。PHP5.3に対応している最新版が5.19.3なのでしょう。

これでバージョン問題は解決したはずなのですがまだエラーが解消しませんでした。エラーログにversion, upgradeなどと出ていたのでてっきりPHPパッケージのバージョンが問題なのだと勘違いしていましたが、試行錯誤の末たどり着いた解決策は

結局サーバが https になっていなかっただけ!!!

でした。2年以上前のtwilio開発時にはSSL化していなくてもtwilioのAPIを叩けたのですが今ではもうダメのようです。SSL化している本番環境(PHP5.3, CentOS 6.7)で以下のようなスクリプト置くとすんなり通話発信ができました。

 require_once './twilio-php-5.19.0/Twilio/autoload.php';
 use Twilio\Rest\Client;

    \$tel_from = "+8150xxxxxxxx"; // From a Twilio number in your account : CallerID
    \$tel_to = "+8180xxxxxxxx"; // Call any number
    \$sid = "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // Your Twilio account sid
    \$token = "fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // Your Twilio auth token

\$client = new Client(\$sid, \$token);
\$calls =  \$client->calls->create( \$tel_to, \$tel_from,
array('url' => "http://demo.twilio.com/docs/voice.xml", )
);

 print(\$calls->sid);

ネットで検索すると2013年、2015年頃の解説サイトがいろいろとありますが、読み込むPHPライブラリや$clientの呼び出し方などが異なるため上手くいきませんでした。今回とても参考になったサイトは

https://tomosoft.jp/design/?p=11227

です。

とにかく通話発信ができたのであとはTwiMLで自動音声生成ファイル(xml形式)を作成してそのURLを上記のものと置き換えればいいだけです。ただ、原理的には確かにそうなのですが、実際にアプリケーションに組み込むにはフレームワークの文法に則る必要があります。CakePHPの該当controllerファイルの中で上記のように

 require_once './twilio-php-5.19.0/Twilio/autoload.php';
 use Twilio\Rest\Client;

と書くと use が使えないとパースエラーになりますし、phpパッケージの読み込みもCakePHPでは作法があります。twilio-php-5.19.0フォルダをControllerフォルダと同じappディレクトリ直下のVendorフォルダにおいて

 App::import('Vendor', 'autoload', array('file' => 'twilio-php-5.19.0/Twilio/autoload.php'));

と呼び出せば\$clientの生成は

 \$client = new Twilio\Rest\Client(\$sid, \$token); 

とすると問題ありませんでした。(\$sid, \$tokenは以前と同じ)App::importの書き方については


を参考にしました。あとは使用する電話番号を国際電話番号のE.164形式にする必要があります。例えば、

https://qiita.com/okkn/items/19e4eeb5a6bca36bd51a

を参考にして変換関数を

private function tel_convert(\$number) {
\$number = preg_replace('/\D+/', '', \$number); // 半角数字以外消去
    if (preg_match('/^[0-9]+\$/', \$number) && (strlen(\$number) == 10 || strlen(\$number) == 11)) {
        return preg_replace( '/^0/', '+81', \$number);
    } else if (preg_match('/^81[0-9]+\$/', \$number) && (strlen(\$number) == 11 || strlen(\$number) == 12)) {
        return preg_replace( '/^81/', '+81', \$number);
    } else {
        return false;
    }
}

とすると通話発信部分のスクリプトは次のように書くことができます。

foreach (\$list as \$key => \$val) {
   if(!is_null(\$val['tel'])){ // tel がある場合のみ発信
 //twiML
\$twiml = "https://aaa.example.co.jp/files/call01.xml";
\$tel_to = self::tel_convert(\$val['tel']);
    if(\$tel_to){ //国際電話番号形式のものだけに発信
 \$client = new Twilio\Rest\Client(\$sid, \$token);
 \$calls =  \$client->calls->create( \$tel_to, \$tel_from, array('url' => \$twiml, ) );
    }
  }
}

ただし、\$listは電話番号情報を含むデータ配列。

0 件のコメント: