Использование XML и PHP для создания единого списка контактов, адаптируемого к различным телефонам

Создание единого списка контактов для ваших телефонов с помощью XML

Людям, постоянно находящимся в разъездах, необходимо иметь согласованные и достоверные списки контактов во всех телефонах, которыми они пользуются. В этой статье рассмотрен пример, в котором данные для стационарного SIP-телефона и мобильного смартфона извлекаются из базы данных MySQL. Из статьи вы узнаете, как с помощью PHP получить настраиваемый XML-код из одной и той же базы данных, подходящий для использования как в стационарных, так и в мобильных телефонах.

Колин Бекингем, исследователь и автор, Freelance

Колин Бекингем (Colin Beckingham) ― независимый исследователь, писатель и программист из Канады. Имеет ученые степени Королевского университета в Кингстоне и Университета Виндзор. Работал в самых разных областях, включая банковские услуги, садоводство, конные скачки, преподавание, гражданскую службу, розничную торговлю, а также путешествия и туризм. Автор приложений на основе баз данных и многочисленных статей в газетах, журналах и в Интернете. В круг его научных интересов входят программирование с открытым исходным кодом, VoIP и управляемые голосом приложения для Linux. Адрес для контактов: colbec@start.ca.



20.12.2011

Даже если вы находитесь в командировке или где-то еще, вам необходимо иметь связь со всеми людьми из вашего списка контактов. Когда вы находитесь в офисе, вы совершаете звонки с помощью стационарного VoIP-телефона, а в пути пользуетесь смартфоном. Однако каждое устройство предъявляет свои требования к формату списка контактов, и форматы телефонных книг в каждом устройстве разные. При необходимости модно было бы работать с двумя списками контактов – сначала добавлять новую запись в обе телефонные книги, а затем редактировать обе книги при изменении информации о контактах. Конечно, более предпочтительным является вариант, когда оба телефона получают данные из одного и того же источника, позволяющего вносить изменения только в одном месте. Что ж, если вы подключены к Интернету или интрасети, это не проблема. В этой статье я покажу, как одна база данных MySQL может предоставлять информацию о контактах двум различным устройствам: стационарному VoIP-телефону семейства snom 300 и мобильному смартфону (в нашем примере используется Nokia E71). Дополнительные ссылки вы найдете в разделе Ресурсы.

Стационарное устройство: телефон семейства snom 300

Часто используемые сокращения:

  • HTML: Hypertext Markup Language – язык разметки гипертекстовых документов
  • HTTP: Hypertext Transfer Protocol – протокол передачи гипертекста
  • LAN: Local area network – локальная сеть
  • LDAP: Lightweight Directory Access Protocol – облегченный протокол доступа к каталогам
  • SQL: Structured Query Language – язык структурированных запросов
  • VoIP: Voice over IP – передача голоса по IP-протоколу
  • XML: Extensible Markup Language – расширяемый язык разметки

Семейство snom 300 представляет собой линейку надежных VoIP-телефонов с широким набором важных офисных функций, таких как удержание, переадресация вызова и конференц-связь. Хотя в этих телефонах не реализована поддержка получения данных с LDAP-сервера, в них есть мини-браузер (см. раздел Ресурсы), позволяющий читать HTML-код. Кроме того, он умеет выводить текст на дисплей телефона в формате, позволяющем инициировать телефонный вызов.

В листинге 1 приведен пример XML-формата телефонной книги, используемого мини-браузером snom.

Листинг 1. Пример XML-кода для мини-браузера snom
<?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 имеет три дочерних элемента: Title, DirectoryEntry и SoftKeyItem. Заголовок (Title) отображается в верхней части дисплея телефона и остается на месте при прокрутке. За ним следуют записи каталога (DirectoryEntry); каждая запись занимает одну строку, и эти строки можно прокручивать. Программируемые клавиши (SoftKeyItem) относятся к четырем кнопкам, расположенным под дисплеем. Эти кнопки могут выполнять различные функции, например, инициализировать вызов абонента, чье имя подсвечено на дисплее. В этом примере имеются две записи каталога, состоящие из отображаемого имени абонента и его телефонного номера, используемого для набора, и активируется только одна кнопка – F1, нажатие на которую инициирует набор телефонного номера.


Мобильное устройство: смартфон Nokia E71

Nokia E71 - хороший пример современного смартфона. Он умеет соединяться с сотовыми и беспроводными локальными сетями, имеет встроенные SIP-клиент и Интернет-браузер и поддерживает голосовое управление.

Смартфон E71 поддерживает протокол WAP (Wireless Application Protocol – протокол беспроводной связи) версии 2.0 (не путайте WAP2 с протоколом защиты беспроводных сетей WPA2). Это означает, что E71 может считывать XML-файлы, осуществляющие внутренние взаимодействия с его специальными функциями, например, открытие окна для начала телефонного вызова. Более подробную информацию о WAP2 вы найдете в разделе Ресурсы.

В листинге 2 приведен пример требуемого смартфону содержимого в формате WAP2/XML. В этом примере используются те же самые записи каталога (два вымышленных контакта), что и в листинге 1.

Листинг 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> включает в себя один дочерний элемент (или страницу) <card>, содержащий две строки, разделенных тегом перевода строки. Заголовок страницы указан в атрибуте корневого элемента. Телефонные номера указаны в виде ссылок (<a>) внутри атрибута <href>, использующего протокол WTAI (Wireless Telephony Applications Interface – протокол приложений беспроводной телефонии, см. раздел Ресурсы). При открытии страницы в браузере телефона и нажатии на ссылку с телефонным номером появляется всплывающее окно с запросом подтверждения вызова; на этом этапе телефон выбирает маршрут вызова – беспроводная локальная сеть или другая доступная услуга связи.

Поскольку в смартфоне не предусмотрена поддержка протокола LDAP, а стационарный телефон не умеет работать с WAP2, то может показаться, что между ними мало общего. Тем не менее можно найти общее решение, используя гибкость XML и командные сценарии. Можно было бы попытаться найти способ синхронизировать адресную книгу смартфона с LDAP-сервером, но сделать это было бы не так просто, как при использовании прямого динамического доступа к информации. К счастью, несмотря на то, что формат 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 ;

Всего таблица содержит четыре поля – идентификатор (для удобства), имя, фамилия, телефонный номер – и один индекс. В этой схеме используется только самая необходимая информация. При желании в эту схему можно добавить дополнительные поля и индексы. Для редактирования содержимого MySQL-таблиц вы можете воспользоваться инструментами LibreOffice Base или phpMyEdit на ваш выбор (см. раздел Ресурсы).

Генератор вывода на PHP

В листинге 4 представлен базовый код сценария, извлекающего информацию из базы данных и генерирующего вывод в обычном текстовом формате. На этом этапе нам необходимо лишь убедиться в том, что генератор возвращает правильные данные.

Листинг 4. Базовый код генератора вывода
<?php
    $dev = "";
    $db_host = "имя.сервера.БД";
    $db_user = "имя.пользователя.БД";
    $db_pass = "пароль.пользователя.БД";
    $db_name = "имя.БД";
    $mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name);
    if (mysqli_connect_errno()) show_err($dev,"Невозможно подключиться к базе данных!");
    $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(). Эта функция выводит заголовок, содержимое массива и нижний колонтитул в виде обычного текста.

В этом сценарии обрабатывается лишь одна ошибка – неудачное подключение к базе данных. Вы можете написать дополнительный код для обработки других ошибок – например, успешного подключения к пустой базе данных. Для отслеживания и обработки этих событий можно использовать подобные вызовы функции show_err().

Теперь у нас имеется все необходимое для того, чтобы научить наш сценарий работать с разными типами устройств. В операторе switch имеются условия для двух телефонов, но функции еще не определены. Наша задача состоит в том, чтобы сгенерировать вывод для других устройств в требуемом XML-формате.

Мини-браузер стационарного телефона

Если вы проанализируете листинг 1, то поймете, что функции из листинга 5 добавляют функциональность, необходимую для работы со стационарным VoIP-телефоном.

Листинг 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();
}

В отличие от листинга 4, в котором вывод генерируется в виде обычного текста, функции, добавленные в листинге 5, упаковывают данные в формат, используемый мини-браузером телефона. В сценарий была добавлена новая функция mysnom(), а функция show_err() была заменена. Мини-браузер не умеет отображать простой текст (в этом случае он просто ничего не делает), поэтому как обычные данные, так и сообщения об ошибках необходимо выводить в формате XML. Поскольку вы пользуетесь телефоном, то именно на нем должны отображаться сообщения об ошибках. В случае невозможности подключения к базе данных сценарий отправляет сообщение об ошибке на телефон. В случае успешного подключения на телефон отправляется корневой элемент, а затем начинает выполняться цикл while. В этом цикле каждая запись упаковывается в свои собственные теги элемента каталога, после чего начинается настройка кнопок телефона. Поскольку телефон имеет всего четыре функциональные кнопки, вряд ли стоит хранить их значения в базе данных. И, наконец, последняя часть кода закрывает корневой элемент.

Функции из листинга 5 срабатывают в том случае, если переменная $dev определена в начале кода следующим образом:

$dev = "snom";

Протокол WAP2 мобильного смартфона

В случае использования смартфона Nokia необходимо получить вывод в XML-формате WAP2 с учетом WTAI. Этот код представлен в листинге 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;
}

Этот код также преобразует данные в требуемый XML-формат, используемый в телефонах Nokia. В этом случае текст сообщения о неудачном подключении к БД не упаковывается в какие-либо XML-теги, поскольку телефон может отображать простой текст без каких-либо дополнительных требований. Когда все записи телефонной книги окажутся отображены на экране телефона, сценарий отправляет информацию XML и DOCTYPE, а также открывающие теги элементов <wml> и <card>, после чего начинается цикл foreach, в котором к каждой строке результирующего набора добавляется необходимая информация протокола WTAI. Наконец, последняя часть кода закрывает элементы <card> и <wml>.

Функция из листинга 6 срабатывает в том случае, если переменная $dev определена в начале кода следующим образом:

$dev = "noki";

Заметим, что предлагаемый вариант списка контактов для смартфона Nokia E71 не является полной заменой встроенной телефонной книги, которая, являясь частью системы, несомненно имеет ряд преимуществ, обеспечивающих ее тесное взаимодействие с остальными приложениями смартфона. Тем не менее список контактов для встроенной телефонной книги также можно сгенерировать на основе базы данных MySQL, используя тот же самый подход; отличие будет заключаться в том, что промежуточный вывод, который затем будет импортирован в телефон, необходимо генерировать в формате vCard (VCF). Дополнительную информацию о VCF-формате вы можете найти в разделе Ресурсы.


Определение устройства

Последняя наша задача состоит в том, чтобы сообщить сценарию, в каком формате требуется получить данные. Для этого можно воспользоваться разными способами, одним из которых является отправка информации GET в строке HTTP-запроса. Представьте, что вы отправляете следующий запрос, в котором явно указаны устройство и пользователь:

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, то все, что вам нужно – это подобрать правильную схему. Вы можете изменять и расширять функциональность сценария так, как вам это нужно, используя для этого наиболее удобный для вас язык сценариев.

Ресурсы

Научиться

  • Оригинал статьи: Create an adaptable phone book and contact list for your phones with XML and PHP (EN).
  • snom VoIP phones at a glance (EN) – узнайте больше о VoIP-телефонах семейства snom.
  • Мини-браузер snom (EN) – информация об XML-объектах, которые поддерживаются прошивкой версии V7 на телефонах snom370, snom360, snom320 и snom300 и прошивкой версии V8 на телефонах snom820 и snom870.
  • Смартфон Nokia E71 (EN) – узнайте больше об этом устройстве с QWERTY-клавиатурой.
  • Wireless Application Protocol (Википедия) – хорошая вводная статья о широко используемом Web-браузере для мобильных устройств, таких как сотовые телефоны.
  • 12.1.17. CREATE TABLE Syntax (EN) – узнайте, как создавать и модифицировать таблицы в MySQL.
  • Scripting in PHP (EN) – узнайте больше об универсальном языке сценариев PHP, который особенно полезен в Web-разработках и встраивается в HTML.
  • Wireless Telephony Applications Protocol (EN) – узнайте о приложениях, работающих в беспроводных сетях.
  • Формат VCF и vCard (Википедия)– узнайте больше о формате vCard – стандартном формате для обмена электронными визитными карточками.
  • Другие статьи этого автора (EN) (Колин Бекингэм, developerWorks, с марта 2009 г. по настоящее время) – прочтите другие статьи, посвященные XML, распознаванию речи, XHTML, PHP, SMIL и многим другим технологиям.
  • Программа сертификации IBM XML (EN)– узнайте, как стать сертифицированным IBM разработчиком в области XML и связанных технологий.

Получить продукты и технологии

  • LibreOffice (EN) – познакомьтесь с Open Source-набором персональных приложений для Windows, Macintosh и Linux. Испытайте в работе шесть приложений для создания документов и обработки данных – Writer, Calc, Impress, Draw, Math и Base.
  • phpMyEdit (EN) – эта утилита позволяет написать простую программу для генерации PHP-кода, позволяющего просматривать и редактировать MySQL-таблицы с помощью HTML.

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML, Open source
ArticleID=781885
ArticleTitle=Использование XML и PHP для создания единого списка контактов, адаптируемого к различным телефонам
publish-date=12202011