私達は、たとえ外出中であっても連絡先に登録された人たちと連絡を取る必要があります。デスクに向かっているときには卓上の VoIP 電話機で相手を呼び出し、外出や出張の際にはスマートフォンを使用します。しかし、それぞれの電話機の電話番号リストは、その電話機に特有のフォーマットでなければならず、それぞれの電話機には明らかに異なる独自フォーマットの連絡先リストや電話帳が使われています。そのため、すべての連絡先を 2 度入力する羽目になることもあります (つまりそれぞれの連絡先リストに 1 度ずつ入力し、変更がある都度、両方のリストを変更します)。当然、両方の電話機が同じバックエンド・ソースからデータを取得するようにし、そのバックエンド・ソースの 1 ヶ所のみで名前と番号を変更すれば済むようにしたいものですが、それは問題なく実現することができます。皆さんはインターネット接続またはイントラネット接続を介してそうした技術を利用することができます。この記事では、2 つのまったく異なる電話機に対し、1 つの MySQL データベースのデータを連絡先情報として提供する方法を学びます。1 つの電話機は snom 300 ファミリーに代表される VoIP 電話機であり、もう 1 つは Nokia E71 という形式のスマートフォンです (「参考文献」のリンクを参照)。
snom 300 ファミリーは、優れた性能を持ち、信頼性の高い VoIP 電話機であり、オフィス用途の多様な機能 (保留、転送、電話会議機能など) を備えています。snom 300 ファミリーの電話機は LDAP サーバーから提供されるデータをネイティブでサポートしていますが、HTML の読み取りが可能なミニブラウザー (「参考文献」を参照) も備えています。さらに、あるフォーマットで電話機の画面に文字列を表示し、その文字列に対する操作によって電話をかける機能も備えています。
リスト 1 には、snom のミニブラウザーが要求する XML フォーマットの例として、電話帳のフォーマットを示してあります。
リスト 1. snom の XML ミニブラウザーの例
<?xml version="1.0" encoding="UTF-8"?>
<SnomIPPhoneDirectory>
<Title>PhoneList - Snom</Title>
<DirectoryEntry>
<Name>Friend, First</Name>
<Telephone>555-456-7890</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Person, Second</Name>
<Telephone>555-654-0987</Telephone>
</DirectoryEntry>
<SoftKeyItem>
<Name>F1</Name>
<Label>Dial</Label>
<SoftKey>F_ENTER</SoftKey>
</SoftKeyItem>
</SnomIPPhoneDirectory>
|
このコードのルート要素 SnomIPPhoneDirectory には 3 つの子があります (Title、DirectoryEntry、SoftKeyItem)。タイトルは電話機の画面の一番上に表示され、スクロール中も同じ場所に維持されます。タイトルの後にはディレクトリーのエントリーが続いており、1 行に 1 つのエントリーが表示され、これらのエントリーはスクロールされます。ソフトキーの項目は画面のすぐ下にある 4 つのボタンを表しています。これらのボタンにより、現在強調表示されているディレクトリー・エントリーに対する電話の発信などを実行することができます。この例のデータは電話番号のエントリー (電話の発信に使用される表示名と番号) が 2 つあります。このコードによってアクティブになるボタンは 1 つのみであり、F1 ボタンを押すと電話の発信が開始されます。
Nokia E71 は最近のスマートフォンの好例です。無線 LAN または携帯電話のサービスを利用できる Nokia E71 は、SIP (Session Initiation Protocol) クライアントを実装しており、独自のネイティブ・ブラウザーでインターネットを閲覧することや、外出先で音声通話を行うことができます。
E71 は WAP (Wireless Application Protocol) バージョン 2.0 (WAP2 ― 「参考文献」を参照) に対応しています (WAP2 を WPA2 (Wi-Fi Protected Access II) 機能と混同しないでください)。WAP2 対応であるということは、E71 は XML フォーマットのファイルを読み取ることができ、この XML ファイルによって電話機内部のさまざまな特殊機能 (ウィンドウを開いて電話を発信する、など) と通信できるということです。
リスト 2 は、このスマートフォンに必要な WAP2/XML フォーマットの例を示しています。この例はリスト 1 と同じ架空の 2 つのエントリーを使用しています。
リスト 2. WAP2 の XML の例
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml_1.1.xml" >
<wml>
<card id="main" title="PhoneList - Nokia">
Tel (WTAI): <a href="wtai://wp/mc;%2B555-456-7890">Friend, First</a><br />
Tel (WTAI): <a href="wtai://wp/mc;%2B555-654-0987">Person, Second</a>
</card>
</wml>
|
WAP2 ではカード・デッキの形式でデータを提供する必要があります。ルート要素 <wml> には 1 つの子要素 <card> (つまりページ) があり、この子要素の内容が改行によって 2 つの行に分けられています。ページのタイトルはルート要素の属性の中に記述されています。電話番号はアンカー (<a>) 要素の中に <href> 属性を使って記述されています。<href> 属性には WTAI (Wireless Telephony Applications Interface: 「参考文献」を参照) が使われています。このページを電話機のブラウザーで開いて電話番号のリンクをクリックすると、その番号に電話をかけるかどうかを尋ねるウィンドウがポップアップ表示されます。この時点で、電話機は発信経路を検索します (つまり無線 LAN 経由で発信するのか、または契約電話回線を使用するのかを判断します)。
このスマートフォンは LDAP をネイティブではサポートしておらず、一方の卓上電話機は WAP2 に対応していないため、2 つの電話機の間にはほとんど共通点がないように思えます。しかしスクリプトを使用して、XML の適応性の高さを利用したソリューションを実現することができます。スマートフォンを使用して LDAP サーバーと連絡先を同期する方法はあるかもしれませんが、その方法は情報に直接動的にアクセスする方法に比べると、あまりすっきりした方法ではないかもしれません。幸いなことに、2 つのスキーマで XML のフォーマットは変わるかもしれませんが、データは基本的に同じままです。
どちらの電話機も、いつでもどこでもインターネットにアクセスすることができます。そこで、共通の電話帳を実現するための 1 つのソリューションとして、すべてのデータをデータベースに保持し、スクリプト・エンジンを使って XML ファイルを生成するようにします。そしてユーザーにとって便利な方の電話機のブラウザーで、その XML ファイルを表示するようにします。どちらの電話機でスクリプトが使用されているかをユーザーが認識している限り、出力を適切に表示することができます。また必要に応じて、表示のためのアクセス制御や情報のフィルタリングもスクリプトによって行うことができます。
データは必要に応じて多種多様な形式のいずれかで格納、抽出することができます。選択肢としては、PostgreSQL、XML、プレーン・テキスト、IBM® DB2®、その他数多くの形式があります。リスト 3 は MySQL のサンプル・スキーマを示しています。
リスト 3. データベース・スキーマの例
CREATE TABLE IF NOT EXISTS 'mycontacts' (
'id' int(11) NOT NULL auto_increment,
'firstName' varchar(30) default NULL,
'lastName' varchar(30) default NULL,
'number' varchar(20) default NULL,
PRIMARY KEY ('id')
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
|
このテーブルには、4 つのフィールド (使い勝手を良くするための ID、苗字、名前、電話番号) と、1 つの索引しか含まれていません。このスキーマは最低限必要な情報を示しています。必要に応じて、さらにフィールドや索引を追加することもできます。データの内容の編集には LibreOffice の Base や、phpMyEdit (「参考文献」を参照) などの任意のエディターを使用することができます。
リスト 4 に示すのは、バックエンドからデータを取得して出力をプレーン・テキスト・フォーマットで表示するための最低限のスクリプトです。この時点では、このスクリプトによって意味のあるデータが返されるかどうかどうかをテストしているにすぎません。
リスト 4. 基本的なデータベース生成プログラム
<?php
$dev = "";
$db_host = "your.database.server";
$db_user = "your_user";
$db_pass = "your_password";
$db_name = "your_database";
$mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name);
if (mysqli_connect_errno()) show_err($dev,"Could not connect to database");
$query = "SELECT * FROM mycontacts order by lastName asc";
$result = $mysqli->query($query);
$num = $result->num_rows;
$i = 0;
while ($row = $result->fetch_array()) {
$myarr[$i]['first']=$row["firstName"];
$myarr[$i]['last']=$row["lastName"];
$myarr[$i]['phone']=$row["number"];
$i++;
}
$mysqli->close();
switch ($dev) {
case 'snom':
echo mysnom($myarr);
break;
case 'noki':
echo mynoki($myarr);
break;
default:
echo mytest($myarr);
break;
}
function mytest($myarr) {
$cont = "Header\n";
foreach ($myarr as $a) {
$cont .= " ".$a['first']." ".$a['last']." ".$a['phone']."\n";
}
$cont .= "Footer\n";
return $cont;
}
function show_err($dev,$msg) {
die($msg);
}
?>
|
このコードはまず、データベースへのアクセスに使用される変数を定義し、接続を開き、結果セットを返すか、あるいはデータベースに接続できない場合にはメッセージを返します。次に while ループによってデータセットに繰り返し処理を行い、適当な配列に情報を格納して後で表示できるようにします。デバイス変数 $dev は長さゼロのストリングに初期化されるため、switch が実行されると default: に進み、mytest() 関数が呼び出されます。この mytest() 関数は単純なヘッダーを表示するのに続けて、配列の内容とフッターも出力します (すべてプレーン・テキストです)。
このスクリプトでは、データベースへの接続失敗という 1 つのエラーしか処理することができないので、他の条件を処理する手段を検討してみてください (例えばデータベースへの接続は成功したものの、テーブルが空の場合など)。そうしたエラー条件でトラップをかけ、show_err() と同様の関数を使用して、そのエラーを処理することができます。
これで、このスクリプトを一般化して他のタイプの電話機も扱えるようにする上で必要な部分のほとんどが用意できました。switch には 2 つの電話機のための case がありますが、そのための関数はまだ存在していません。ここでの課題は、他の電話機に合わせた出力を作成し、必要に応じて詳細情報を XML 形式で追加することです。
リスト 1 の例と比べながらリスト 5 を見ると、卓上 VoIP 電話機に対処するために必要な部分がリスト 5 の関数によって追加されていることがわかります。
リスト 5. 卓上電話機のミニブラウザーを扱うための関数
function mysnom($myarr) {
$cont = "<?xml version=\"1.0\"?>
<SnomIPPhoneDirectory>
<Title>MySQL Directory</Title>";
foreach ($myarr as $a) {
$cont .= "
<DirectoryEntry>
<Name>".$a['first']." ".$a['last']."</Name>
<Telephone>".$a['phone']."</Telephone>
</DirectoryEntry>\n";
}
$cont .= "</SnomIPPhoneDirectory>\n";
return $cont;
}
function show_err($dev,$msg) {
switch ($dev) {
case 'snom':
echo "<?xml version=\"1.0\"?>
<SnomIPPhoneText>
<Text>
$msg
</Text>
</SnomIPPhoneText>
";
break;
default:
echo $msg;
break;
}
die();
}
|
リスト 5 をリスト 4 と比べると、リスト 5 の新しい関数はプレーン・テキストを出力する代わりに、ミニブラウザーで想定される要素の中にラップされたデータを出力しています。また、mysnom() 関数がスクリプトに追加されており、show_err() 関数は置き換えられています。ミニブラウザーはプレーン・テキストを表示することはできず、プレーン・テキストに対しては何もしません。そのため、通常の出力にも例外出力にも XML 出力が必要です。使用しているのは電話機なので、電話機にエラー・メッセージを表示する必要があります。データベースへの接続に失敗した場合には、スクリプトは電話機に接続エラーをレポートします。データベースへの接続に成功した場合には、スクリプトは while ループを開始する前にルート要素を表示します。ループが進行していくと、各レコードはそれぞれが DirectoryEntry タグにラップされ、ループが完了すると、ボタンのセットアップが開始されます。ボタンは 4 個しかないので、ボタンもデータベースの中にエンコードしておく必要があるのかどうかは疑問です。最後に、このコードはルート要素を閉じています。
上記の関数が適切に動作するためには、コードの先頭で変数 $dev が以下のように適切に設定されている必要があります。
$dev = "snom"; |
Nokia の電話機の場合には、出力に関する詳細情報を追加します。この詳細情報は、WTAI を参照する WAP2 フォーマットで、このスマートフォン用の XML を提供します。そのコードをリスト 6 に示します。
リスト 6. スマートフォンの WAP2 を扱う
function mynoki($myarr) {
$cont = "<?xml version=\"1.0\"?>
<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\"
\"http://www.wapforum.org/DTD/wml_1.1.xml\" >
<wml>\n
<card id=\"main\" title=\"PhoneList - Nokia\">\n";
foreach ($myarr as $a) {
$cont .= "\nTel (WTAI): <a href=\"wtai://wp/mc;%2B".$a['phone']."\">
".$a['last']." ".$a['first']."</a><br />";
}
$cont .= "</card></wml>\n";
return $cont;
}
|
この場合も、このコードによって Nokia の電話機に必要な XML が提供されます。データベースへの接続エラーが発生した場合のテキスト出力をラップするマークアップはありませんが、その理由は単純な出力はマークアップなしでも適切に、電話機に表示されるからです。電話帳のエントリーを表示する場合、このスクリプトはループの開始前に XML と DOCTYPE の情報を送信し、その後でルートの <wml> 要素と <card> 要素を開いています。次にループが開始され、WTAI 情報の中に含まれた各行が表示されます。最後に、このコードはカードとルートの <wml> 要素を閉じています。
上記の関数が適切に動作するためには、コードの先頭で変数 $dev が以下のように適切に設定されている必要があります。
$dev = "noki"; |
この記事で Nokia E71 電話機の連絡先情報に関して提案する手法は、ネイティブの連絡先アプリケーションの完全な置き換えを意図したものではないことに注意してください。ネイティブの連絡先アプリケーションには、当然ながら電話システムの一部としてのメリットがいくつかあり、従って他のアプリケーションと内部で緊密に連携されています。ただし、上記と同じプロセスを使用してネイティブの連絡先リストを同じ MySQL データベースから生成することもできます。その場合は中間出力を vCard (VCF) ファイル・フォーマット (「参考文献」を参照) で生成し、それを電話機にインポートします。
パズルの最後のピースは、どちらの電話機用の出力が必要であるかを実行時にスクリプトによって判断する方法です。そのための方法はいくつもありますが、1 つの方法として、HTTP リクエストのクエリー・ストリングの中に GET 情報を入れて送信する方法があります。例えば、以下のようなリクエストを送信するとしましょう。このリクエストは電話機とユーザーを明示的に記述しています。
http://www.myserver.tld/phonebook/myscript.php?device=snom&user=jim |
次に、リスト 7 の完全なスクリプトを見るとわかるように、実行時にクエリー・ストリングを構文解析し、その情報をスクリプトに挿入します。
リスト 7. 電話機を検出する
<?php
if ($_GET['user'] != 'jim') show_err($dev,'Unauthorised access');
$dev = $_GET['device'];
$db_host = "your.database.server";
$db_user = "your_user";
$db_pass = "your_password";
$db_name = "your_database";
$mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name);
if (mysqli_connect_errno()) show_err($dev,"Could not connect to database");
$query = "SELECT * FROM mycontacts order by lastName asc";
$result = $mysqli->query($query);
$num = $result->num_rows;
$i = 0;
while ($row = $result->fetch_array()) {
$myarr[$i]['first']=$row["firstName"];
$myarr[$i]['last']=$row["lastName"];
$myarr[$i]['phone']=$row["number"];
$i++;
}
$mysqli->close();
switch ($dev) {
case 'snom':
echo mysnom($myarr);
break;
case 'noki':
echo mynoki($myarr);
break;
default:
echo mytest($myarr);
break;
}
function mytest($myarr) {
$cont = "Header\n";
foreach ($myarr as $a) {
$cont .= " ".$a['first']." ".$a['last']." ".$a['phone']."\n";
}
$cont .= "Footer\n";
return $cont;
}
function mynoki($myarr) {
$cont = "<?xml version=\"1.0\"?>
<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\"
\"http://www.wapforum.org/DTD/wml_1.1.xml\" >
<wml>\n
<card id=\"main\" title=\"PhoneList - Nokia\">\n";
foreach ($myarr as $a) {
$cont .= "\nTel (WTAI): <a href=\"wtai://wp/mc;%2B".$a['phone']."\">
".$a['last']." ".$a['first']."</a><br />";
}
$cont .= "</card></wml>\n";
return $cont;
}
function mysnom($myarr) {
$cont = "<?xml version=\"1.0\"?>
<SnomIPPhoneDirectory>
<Title>MySQL Directory</Title>";
foreach ($myarr as $a) {
$cont .= "
<DirectoryEntry>
<Name>".$a['first']." ".$a['last']."</Name>
<Telephone>".$a['phone']."</Telephone>
</DirectoryEntry>\n";
}
$cont .= "</SnomIPPhoneDirectory>\n";
return $cont;
}
function show_err($dev,$msg) {
switch ($dev) {
case 'snom':
echo "<?xml version=\"1.0\"?>
<SnomIPPhoneText>
<Text>
$msg
</Text>
</SnomIPPhoneText>
";
break;
default:
echo $msg;
break;
}
die();
}
?>
|
このコードは基本的にリスト 4 と同じですが、リスト 5 とリスト 6 の関数が追加されており、最初にユーザーが誰であるかの簡単なチェックを行い、不適切なユーザーが情報にアクセスしようとしていた場合には、制御された条件の下で終了します。不適切なユーザーでなかった場合には、クエリー・ストリングから電話機の情報を取得し、その電話機の種類に応じた出力を行います。
それぞれの電話機は、その電話機独自のリクエストとクエリー・ストリングをデータベースに送信するため、データベースから返される出力は、その電話機で表示可能なフォーマットで素早く簡単に受信されます。
共通のソースに基づく連絡先リストを他のプラットフォームで使用するためには、XML 出力を変更します。Nokia 用の関数は、WAP 2.0 準拠のすべての電話機で動作するはずです。snom 関数を他の電話機にも使えるようにするのは難しいかもしれませんが、XML を活用できる場合には、必要となるのは適切なスキーマを用意することだけです。どのようなスクリプト言語であれ、最も便利と思える任意のスクリプト言語を使用することで、必要に応じてスクリプトを容易に保守、拡張することができます。
学ぶために
- snom VoIP 電話機の一覧を見てください。そして snom ファミリーの VoIP 電話機について学んでください。
- snom のミニブラウザーのサイトを訪れ、snom370、snom360、snom320、snom300 のファームウェア V7、そして snom820 と snom870 のファームウェア V8 でサポートされている、XML オブジェクトについての資料を読んでください。
- QWERTY キーボードを備えたスマートフォン、Nokia E71 について調べてみてください。
- ウィキペディアで WAP (Wireless Application Protocol) の項目を見てください。WAP は小型のモバイル機器 (携帯電話など) のための Web ブラウザーとしてよく使われています。
- 12.1.8. CREATE TABLE 構文の項目を読み、MySQL でテーブルを作成、変更する方法を学んでください。
- PHP でスクリプトを作成するための資料を読んでください。PHP は汎用のスクリプト言語として特に Web 開発に適しており、HTML に埋め込むことができます。
- Wireless Telephony Applications Protocol の資料を読み、無線通信ネットワークを介して動作するアプリケーションについて学んでください。
- VCF と vCard ファイル・フォーマットの資料を読み、電子名刺のための vCard ファイル・フォーマット標準について学んでください。
- 著者の Colin Beckingham が developerWorks に寄稿した他の記事も読んでください (2009年3月から現在まで)。XML、音声認識、XHTML、PHP、SMIL、その他の技術が解説されています。
- developerWorks の XML ゾーンには、XML の領域でのスキルを磨くためのリソースが豊富に用意されています。
- My developerWorks で developerWorks のエクスペリエンスをパーソナライズしてください。
- XML および関連技術において IBM 認定技術者になる方法については、IBM XML certification を参照してください。
- developerWorks の XML ゾーンを XML の技術ライブラリーとして利用してください。広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、および IBM Redbooks などが用意されています。また、他にも XML に関するヒント記事があります。
- developerWorks の Technical events and webcasts で最新情報を入手してください。
- 今すぐ Twitter に参加して developerWorks のツイートをフォローしてください。
- developerWorks podcasts でソフトウェア開発者のための興味深いインタビューや議論を聞いてください。
- developerWorks On demand demos をご覧ください。初心者のための製品インストール方法やセットアップのデモから、上級開発者のための高度な機能に至るまで、多様な話題が解説されています。
製品や技術を入手するために
- Windows、Macintosh、Linux のためのオープンソースの個人用オフィス・スイート、LibreOffice について学んでください。そして文書作成やデータ処理のための 6 つのアプリケーションを試してみてください (Writer、Calc、Impress、Draw、Math、Base)。
- このユーティリティー、phpMyEdit を使用して単純な呼び出しプログラムを作成すると、HTML で MySQL テーブルを表示、編集できる PHP コードを生成することができます。
- IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。
議論するために
- XML zone discussion forums では XML に関する議論が行われています。
- developerWorks コミュニティーで開発者向けのブログ、フォーラム、グループ、ウィキなどを利用しながら、他の developerWorks ユーザーとやり取りしてください。