Телефонный справочник из таблиц SQL Asterisk FreePBX (web-справочник, выгрузка в xml-файл для телефонов Grandstream)

Для изучения могут пригодиться следующие моменты.

1) Подключение к серверу SQL для выполнения запросов:

mysql -u freepbxuser -p
после нажатия Enter будет запрошен пароль для пользователя. 
После ввода пароля и нажатия Enter, будет выведено приглашение MySQL:
mysql>_

2) Основные команды sql

Вывод списка имеющихся баз:
SHOW DATABASES;
Подключение к необходимой базе:
USE dbtest;
Просмотр всех таблиц из базы:
SHOW tables;
Просмотр содержания нужной таблицы:
SELECT * FROM page;
Просмотр структуры таблицы:
DESCRIBE testtable;

3) Подлючение к sql из внешней сети:

CREATE USER 'ИМЯ-НОВОГО-ПОЛЬЗОВАТЕЛЯ'@'localhost' IDENTIFIED BY '!!!ПАРОЛЬ!!!';
GRANT ALL PRIVILEGES ON * . * TO 'ИМЯ-НОВОГО-ПОЛЬЗОВАТЕЛЯ'@'localhost';

GRANT SELECT ON * . * TO 'ИМЯ-НОВОГО-ПОЛЬЗОВАТЕЛЯ'@'localhost';

use mysql
SELECT Host,User,Password FROM user;

UPDATE user SET Host='%' WHERE User='ИМЯ-НОВОГО-ПОЛЬЗОВАТЕЛЯ' AND Host='localhost';
FLUSH PRIVILEGES;

4) Формат xml-файла:

<?xml version="1.0" encoding="UTF-8"?>
<AddressBook>
	<pbgroup>
		<id>70</id>
		<name>User Manager Group</name>
	</pbgroup>
	<Contact>
		<id>760</id>
		<FirstName>Иванов</FirstName>
		<LastName>Иван</LastName>
		<Frequent>0</Frequent>
		<Phone type="Work">
			<phonenumber>101</phonenumber>
			<accountindex>1</accountindex>
		</Phone>
		<Group>70</Group>
		<Primary>0</Primary>
	</Contact>
</AddressBook>

Шаг 1. Создание php-скрипта чтения sql-таблицы Asterisk и формирования xml-файла

Создаем два файла config.php и phonebook.php, указывая необходимые параметры.

Файл config.php

<?php
return array(
"db" => "mysql:host=localhost;dbname=asterisk",
"pb_file_gs" => "/var/www/html/phonebook/phonebook.xml",
"username" => "freepbxuser", //Mysql login
"password" => "пароль freepbxuser", //Mysql password
"options" => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8')
);

Файл phonebook.php

<?php
$config = include("db/config.php");

$db = new PDO($config["db"], $config["username"], $config["password"], $config["options"]);

// Делаем выборку записей книги
$sql = "SELECT userman_users.username, userman_users.displayname, contactmanager_group_entries.groupid FROM asterisk.userman_users, asterisk.contactmanager_group_entries, asterisk.contactmanager_groups WHERE contactmanager_group_entries.user = userman_users.id AND contactmanager_group_entries.groupid = contactmanager_groups.id";   // Делаем выборку записей книги
$sqlgrp = "SELECT contactmanager_groups.name,contactmanager_groups.id FROM asterisk.contactmanager_groups";

//Грузим таблицу с номерами и именами
$q = $db->prepare($sql);
$q->execute();
$rows = $q->fetchAll();

//Грузим таблицу с группами
$q2 = $db->prepare($sqlgrp);
$q2->execute();
$rows2 = $q2->fetchAll();

unlink($config["pb_file_gs"]);  // Удалим старый файл

$fp = fopen($config["pb_file_gs"],"w+");
fputs($fp, '<?xml version="1.0" encoding="UTF-8"?><AddressBook>');

foreach($rows2 as $row) {         // Пробежим по всем записям, добавляем группы
fputs($fp,'<pbgroup>');
fputs($fp,'<id>'.$row['id'].'</id>');
fputs($fp,'<name>'.$row['name'].'</name>');
fputs($fp,'</pbgroup>');
}

foreach($rows as $row) {         // Пробежим по всем записям, подготовив XML файл нужного вида
    if (strlen($row['username']) === 3) {
		$alln = $row['displayname'];
		//if ($alln = '') #alln = $row['username'];
		$ln = strstr($alln, ' ', true);
		$fn = strstr($alln, ' ', false);
		$fn = trim($fn);
		$i++;
		fputs($fp, '<Contact>
			<id>'.$i.'</id>
			<FirstName>'.$ln.'</FirstName>
                        <LastName>'.$fn.'</LastName>
                        <Phone type="Work">
                                   <phonenumber>'.$row['username'].'</phonenumber>
                                   <accountindex>1</accountindex>
                        </Phone>
						<Group>'
						.$row['groupid'].						
						'</Group>
            </Contact>
        ');
	}
}
fputs($fp,'</AddressBook>');
fclose($fp);
?>

Шаг 2. Настраиваем телефон Grandstream для чтения телефонной книги из xml-файла

Внимание, важно при настройке «Phonebook Management» на телефоне Grandstream GXP16xx в поле «Путь к серверу XML» (Phonebook XML Server Path) указать только путь без имени файла.

  1. В поле «Enable Phonebook XML Download» выбрать «Enabled, use HTTP»
  2. В поле «Phonebook XML Server Path» указать путь к файлу xml, например: «192.168.0.220/phonebook»

Остальные параметры указываем по требованию.

Шаг 3. Создаем web-справочник телефонной книги



Создаем файл pb.php.

Основные моменты.

  1. Сначала загрузить из xml-файла и сформировать группы контактов
  2. Обрабатывать выбор группы и отображать контакты выбранной группы.

Файл config.php
<html>

<style>
<!--
/* наша HTML таблица */
table.sort{
	border-spacing:0em;
	margin-bottom:1em;
	margin-top:1em
}

/* ячейки таблицы */
table.sort td{
	border:1px solid #CCCCCC;
	padding:0.3em 1em
}

/* заголовки таблицы */
table.sort thead td{
	cursor:pointer;
	cursor:hand;
	font-weight:bold;
	text-align:center;
	vertical-align:middle
}


   tbody tr:hover {
    background: #999999; /* Цвет фона при наведении */
    color: #FFFFFF; /* Цвет текста при наведении */
   }


/* заголовок отсортированного столбца */
table.sort thead td.curcol{
	background-color:#999999;
	color:#FFFFFF
}
-->
</style>

<script type="text/javascript">

initial_sort_id = 0; // номер начального отсортированного столбца, начиная с нуля
initial_sort_up = 0; // 0 - сортировка вниз, 1 - вверх
var sort_case_sensitive = false; // чуствительновть к регистру при сотрировке

function _sort(a, b) {
	var a = a[0];
	var b = b[0];
	var _a = (a + '').replace(/,/, '.');
	var _b = (b + '').replace(/,/, '.');
	if (parseInt(_a) && parseInt(_b)) return sort_numbers(parseInt(_a), parseInt(_b));
	else if (!sort_case_sensitive) return sort_insensitive(a, b);
	else return sort_sensitive(a, b);
}

function sort_numbers(a, b) {
	return a - b;
}

function sort_insensitive(a, b) {
	var anew = a.toLowerCase();
	var bnew = b.toLowerCase();
	if (anew < bnew) return -1;
	if (anew > bnew) return 1;
	return 0;
}

function sort_sensitive(a, b) {
	if (a < b) return -1;
	if (a > b) return 1;
	return 0;
}

function getConcatenedTextContent(node) {
	var _result = "";
	if (node == null) {
		return _result;
	}
	var childrens = node.childNodes;
	var i = 0;
	while (i < childrens.length) {
		var child = childrens.item(i);
		switch (child.nodeType) {
			case 1: // ELEMENT_NODE
			case 5: // ENTITY_REFERENCE_NODE
				_result += getConcatenedTextContent(child);
				break;
			case 3: // TEXT_NODE
			case 2: // ATTRIBUTE_NODE
			case 4: // CDATA_SECTION_NODE
				_result += child.nodeValue;
				break;
			case 6: // ENTITY_NODE
			case 7: // PROCESSING_INSTRUCTION_NODE
			case 8: // COMMENT_NODE
			case 9: // DOCUMENT_NODE
			case 10: // DOCUMENT_TYPE_NODE
			case 11: // DOCUMENT_FRAGMENT_NODE
			case 12: // NOTATION_NODE
			// skip
			break;
		}
		i++;
	}
	return _result;
}

function sort(e) {
	var el = window.event ? window.event.srcElement : e.currentTarget;

	while (el.tagName.toLowerCase() != "td") el = el.parentNode;

	var a = new Array();
	var name = el.lastChild.nodeValue;
	var dad = el.parentNode;
	var table = dad.parentNode.parentNode;
	var up = table.up; // no set/getAttribute!

	var node, arrow, curcol;
	for (var i = 0; (node = dad.getElementsByTagName("td").item(i)); i++) {
		if (node.lastChild.nodeValue == name){
			curcol = i;
			if (node.className == "curcol"){
				arrow = node.firstChild;
				table.up = Number(!up);
			}else{
				node.className = "curcol";
				arrow = node.insertBefore(document.createElement("span"),node.firstChild);
			        arrow.appendChild(document.createTextNode(""));
				table.up = 0;
			}
			arrow.innerHTML=((table.up==0)?"↓":"↑")+" ";
		}else{
			if (node.className == "curcol"){
				node.className = "";
				if (node.firstChild) node.removeChild(node.firstChild);
			}
		}
	}

	var tbody = table.getElementsByTagName("tbody").item(0);
	for (var i = 0; (node = tbody.getElementsByTagName("tr").item(i)); i++) {
		a[i] = new Array();
		a[i][0] = getConcatenedTextContent(node.getElementsByTagName("td").item(curcol));
		a[i][1] = getConcatenedTextContent(node.getElementsByTagName("td").item(1));
		a[i][2] = getConcatenedTextContent(node.getElementsByTagName("td").item(0));
		a[i][3] = node;
	}

	a.sort(_sort);

	if (table.up) a.reverse();

	for (var i = 0; i < a.length; i++) {
		tbody.appendChild(a[i][3]);
	}
}

function init(e) {
	if (!document.getElementsByTagName) return;
	
	if (document.createEvent) function click_elem(elem){
		var evt = document.createEvent("MouseEvents");
		evt.initMouseEvent("click", false, false, window, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, elem);
		elem.dispatchEvent(evt);
	}

	for (var j = 0; (thead = document.getElementsByTagName("thead").item(j)); j++) {
		var node;
		for (var i = 0; (node = thead.getElementsByTagName("td").item(i)); i++) {
			if (node.addEventListener) node.addEventListener("click", sort, false);
			else if (node.attachEvent) node.attachEvent("onclick", sort);
			node.title = "Нажмите на заголовок, чтобы отсортировать колонку";
		}
		thead.parentNode.up = 0;
		
		if (typeof(initial_sort_id) != "undefined"){
			td_for_event = thead.getElementsByTagName("td").item(initial_sort_id);
			if (td_for_event.dispatchEvent) click_elem(td_for_event);
			else if (td_for_event.fireEvent) td_for_event.fireEvent("onclick");
			if (typeof(initial_sort_up) != "undefined" && initial_sort_up){
				if (td_for_event.dispatchEvent) click_elem(td_for_event);
				else if (td_for_event.fireEvent) td_for_event.fireEvent("onclick");
			}
		}
	}
}

var root = window.addEventListener || window.attachEvent ? window : document.addEventListener ? document : null;
if (root){
	if (root.addEventListener) root.addEventListener("load", init, false);
	else if (root.attachEvent) root.attachEvent("onload", init);
}

	
//передача переменной	
function getCookie(name) {
	var cookie = " " + document.cookie;
	var search = " " + name + "=";
	var setStr = null;
	var offset = 0;
	var end = 0;
	if (cookie.length > 0) {
		offset = cookie.indexOf(search);
		if (offset != -1) {
			offset += search.length;
			end = cookie.indexOf(";", offset)
			if (end == -1) {
				end = cookie.length;
			}
			setStr = unescape(cookie.substring(offset, end));
		}
	}
	return(setStr);
}

//Обработка нажатия выбора группы
function selectChanged() {
	var sel = document.getElementById('myselect');
	var str = sel.selectedIndex+1 ? (sel.options[sel.selectedIndex].innerHTML) : 'Ничего не выбрано';
	
	document.cookie = "sgrp="+str+";";
	//document.getElementById('nameslist').innerHTML = '<?php $hello = $_COOKIE["sgrp"]; echo $hello; ?>';
	location.reload();
}
	
</script>
	
	
<strong>
<div style="text-align: center;">ТЕЛЕФОННЫЙ СПРАВОЧНИК</div>
<br>
</strong>

<?php

$xml = simplexml_load_file('http://192.168.0.220/phonebook/phonebook.xml');
$conts_cnt = count($xml->Contact); 
$grp_cnt = count($xml->pbgroup);

//Загрузка групп в список
echo '<div id="groupslist" style="width: 20%; float:left">
	<strong>ГРУППЫ:</strong> <br> <br>
	<select id="myselect" size="20" onchange="javascript:selectChanged();">';
echo "<option>Все</option>";
for($ig = 0; $ig < $grp_cnt; $ig++) {
        $Groups = $xml->pbgroup[$ig];
		if ($Groups->name <> 'User Manager Group') echo "<option>{$Groups->name}</option>";
    }
echo "</select>
</div>";

//Отображение списка контактов
echo '<div id="nameslist" style="width: 80%; float:right">';
echo "<strong>{$_COOKIE['sgrp']}</strong>";
echo "<table class=sort align=center width=100%>";
echo "<thead>";
echo "<tr>";
echo "<td>Фамилия</td>";
echo "<td>Имя</td>";
echo "<td>Номер</td>";
//echo "<td>Группа</td>";
echo "</tr>";
echo "</thead>";
echo "<tbody>";

for($i = 0; $i < $conts_cnt; $i++) {
	$Contacts = $xml->Contact[$i]; 
	$FirstName = $Contacts->FirstName;
	$LastName = $Contacts->LastName;
	$phonenumber = $Contacts->Phone->phonenumber;
    echo "<tr>";
	for($ig = 0; $ig < $grp_cnt; $ig++) {
        $Groups = $xml->pbgroup[$ig];
        if (strcasecmp($Contacts->Group, $Groups->id) == 0) {
			if ($_COOKIE["sgrp"] == trim($Groups->name)) {
            	echo "<td class=col1>{$FirstName}</td>";
    			echo "<td class=col1>{$LastName}</td>";
    			echo "<td class=col1>{$phonenumber}</td>";			
				//echo "<td class=col1>{$Groups->name}</td>";
			} else if ("Все" == $_COOKIE["sgrp"]) {
            	echo "<td class=col1>{$FirstName}</td>";
    			echo "<td class=col1>{$LastName}</td>";
    			echo "<td class=col1>{$phonenumber}</td>";
			}
		}
    }

    echo "</tr>";
}
    echo "</tbody>";
    echo "</table>";
echo '</div>';
?>

</html>

Источник: habr.ru