Если вы активировали данный функционал в вашем смартфоне, то ваша книга контактов полностью слита на сервера Truecaller'а? Проверить, есть ли ваш номер в базе можно по ссылке, например: https://www.truecaller.com/ru/74996813210 (необходима аутентификация).
На данный момент сервис насчитывает 1.6 миллиарда номеров по всему миру. Выписать свой номер из базы возможно по ссылке https://www.truecaller.com/unlist.
Прикручиваем Truecaller к Asterisk'у
На сайте Truecaller'а есть возможность определить имя абонента по номеру телефона. Вход на сайт возможен только через сторонние сервисы и социальные сети. Для аутентификации я выбрал Вконтакте (протокол Oauth).
1. Вручную войти на сайт truecaller.com, используя ранее зарегистрированную учетную запись вконтакте, разрешить доступ.
2. Необходимо создать внутреннюю БД для хранения уже однажды звонивших контактов. Это необходимо чтобы каждый раз не обращаться к сервису truecaller'а.
3. Написать скрипт прохождения аутентификации на сайте truecaller.com через сеть вконтакте, а также функцию для проверки номеров на наличие имени абонента.
Скрипт написан на PHP для удобства внедрения под AGI и общей читаемости.
Создадим БД в MySQL:
USE asterisk;
CREATE TABLE asterisk.phonebook (
id int(11) NOT NULL AUTO_INCREMENT,
create_date timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
number varchar(20) NOT NULL,
name varchar(80) NOT NULL,
temporary_contact tinyint(1) NOT NULL DEFAULT 1,
PRIMARY KEY (id)
)
ENGINE = INNODB
AUTO_INCREMENT = 9
AVG_ROW_LENGTH = 8192
CHARACTER SET utf8
COLLATE utf8_general_ci;
PHP скрипт /var/lib/asterisk/agi-bin/phonebook.php (для тех кто делает через PHP-AGI, не забудьте раскомментировать соответствующие строчки, результат вы получите в переменную канала CID_NAME):
#!/usr/bin/php -q
<?php
$error_level = error_reporting(0);
set_time_limit(30);
//require('phpagi.php');
//$agi = new AGI();
if (isset($argv[1])) {$num=$argv[1];} else {$num=NULL;}
$cookie_file='/tmp/asterisk_truecaller_vk.cookie';
$vk = array("login"=> "логин_вконтакте", "password"=> "пароль_вконтакте");
$mysql = array("hostname" => "localhost", "login"=> "root", "password"=> "пароль_mysql", "database"=> "asterisk");
if (!is_null($num))
{
$callerid_name=get_num($num,$vk,$mysql,$cookie_file,true);
return $callerid_name;
}
else
{
echo "Номер телефона не задан\n";
//$agi->set_variable("CID_NAME", "");
return false;
}
// поиск номера на сервисе truecaller
function get_num($num,$vk,$mysql,$cookie_file,$isauth)
{
// ищем в своей базе
mysql_connect($mysql['hostname'],$mysql['login'],$mysql['password']);
mysql_select_db($mysql['database']) or die(mysql_error());
mysql_query("SET NAMES 'utf8'"); mysql_query("SET CHARACTER SET 'utf8'"); mysql_query("SET SESSION collation_connection = 'utf8_general_ci'");
$query = "SELECT * FROM phonebook WHERE `number`=$num";
$res = mysql_query($query);
$count = mysql_num_rows($res);
if ($count>0)
while ($row=mysql_fetch_array($res))
{
$name=$row['name'];
echo "Найден контакт в MySQL '".$name."'\n";
//$agi->set_variable("CID_NAME", "$name");
return $name;
}
mysql_close();
// ищем в truecaller
if ($isauth)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.truecaller.com/ru/'.$num );
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
$data = curl_exec($ch);
curl_close($ch);
if (preg_match("/You need to sign in to view the result/i", $data)) {
echo "Необходима аутентификация TC\n";
$isauth = oauth_vk($vk, $cookie_file);
get_num($num,$vk,$mysql,$cookie_file,$isauth);
} else {
preg_match("/<div class=\"detailView__nameText\">\n\s*(.+)\s\n\s*<\/div>/i", $data, $matches);
if (count($matches)>0)
{
$name=$matches[1];
echo "Найден контакт в TC '".$name."'\n";
mysql_connect($mysql['hostname'],$mysql['login'],$mysql['password']);
mysql_select_db($mysql['database']) or die(mysql_error());
mysql_query("SET NAMES 'utf8'"); mysql_query("SET CHARACTER SET 'utf8'"); mysql_query("SET SESSION collation_connection = 'utf8_general_ci'");
$query = "INSERT INTO phonebook (`name`,`number`) VALUE ('".$name."','".$num."')";
$res = mysql_query($query);
mysql_close();
//$agi->set_variable("CID_NAME", "$name");
return $name;
} else {
echo "Совпадения в TC не найдены\n";
//$agi->set_variable("CID_NAME", "");
return false;
}
}
}
else
{
echo "Аутентификация TC не была пройдена, попробуйте в следующий раз\n";
//$agi->set_variable("CID_NAME", "");
return false;
}
}
// авторизация через кнопку "зайти через вконтакте"
function oauth_vk($vk, $cookie_file)
{
unlink($cookie_file);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://oauth.vk.com/authorize?client_id=4951501&scope=friends%2Coffline&redirect_uri=http%3A%2F%2Fwww.truecaller.com%2Fsign-in%2Fvk&response_type=code&state=KKoLuT0vbWEOXfqIW9C0yAvoX7uoEDszIrVOxYSr');
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file); // сохранять куки в файл
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
$data = curl_exec($ch);
curl_close($ch);
preg_match("/<form method=\"post\" action=\"(.+)\">/i", $data, $matches); if (count($matches)>0) $action=$matches[1];
preg_match("/<input type=\"hidden\" name=\"_origin\" value=\"(.+)\">/i", $data, $matches); if (count($matches)>0) $origin=$matches[1];
preg_match("/<input type=\"hidden\" name=\"ip_h\" value=\"(.+)\" \/>/i", $data, $matches); if (count($matches)>0) $ip_h=$matches[1];
preg_match("/<input type=\"hidden\" name=\"lg_h\" value=\"(.+)\" \/>/i", $data, $matches); if (count($matches)>0) $lg_h=$matches[1];
preg_match("/<input type=\"hidden\" name=\"to\" value=\"(.+)\">/i", $data, $matches); if (count($matches)>0) $to=$matches[1];
if (isset($action) && isset($origin) && isset($ip_h) && isset($lg_h) && isset($to))
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $action );
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'_origin'=>$origin,
'ip_h'=>$ip_h,
'lg_h'=>$lg_h,
'to'=>$to,
'email'=>$vk['login'],
'pass'=>$vk['password']
));
$data = curl_exec($ch);
curl_close($ch);
preg_match('/Location: (http\:\/\/www\.truecaller\.com\/sign\-in\/vk\?code\=.+)\&state.+/', $data, $matches); if (count($matches)>0) $location=$matches[1];
if (isset($location))
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $location);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
$data = curl_exec($ch);
curl_close($ch);
if (preg_match("/\<title\>Signed In \| Truecaller\<\/title\>/i", $data)) {
echo "Аутентификация VK пройдена успешно\n";
return true;
} else {
echo "Ошибка при прохождении авторизации через VK / не найдена строка о успешной авторизации\n";
return false;
}
} else {
echo "Ошибка при прохождении авторизации через VK / переменная location не получена\n";
return false;
}
} else {
echo "Ошибка при прохождении авторизации через VK / не все переменные получены action='".$action."', origin='".$origin."', ip_h='".$ip_h."', lg_h='".$lg_h."', to='".$to."'\n";
return false;
}
}
?>
У меня диалплан на LUA, поэтому в extensions.lua:
local call = {}
call.cid_num = channel["CALLERID(num)"]:get()
call.cid_name = ""
-- ищем телефонный номер в базе
local handle = io.popen("/var/lib/asterisk/agi-bin/phonebook.php "..call.cid_num)
local founded_name = handle:read("*a")
handle:close()
app.Noop(founded_name)
_, _, call.cid_name = string.find(founded_name,"Найден%sконтакт%sв.+%s'(.+)'")
channel["CALLERID(name)"]:set(call.cid_name)
В данном скрипте нет учета блокировки спам контактов. Данная статья описана как «обзорная» по возможности интеграции столь чудесного сервиса Truecaller с вашей PBX.
Комментарии (10)
realscorp
15.09.2015 08:45Ух ты, не знал об сервисе Truecaller. Спасибо за информацию, будет очень полезно иногда определять, кто звонил.
Truecaller
21.09.2015 17:59Привет! Мы рады оказаться на Хабре.
alex_bosenko, мы заметили ваш пост и хотели бы немного подробнее рассказать как же все-таки работает Truecaller.
Truecaller — это приложение полностью основанное на разрешениях от пользователей, это означает, что на каждом шаге взаимодействия с приложением пользователь получает информацию о том, какие разрешения ему необходимо дать приложению для получения полного функционала.
Приложение, скаченное с Google Play/Apple App Store не загружает телефонную книгу и тем более не делает номера публично доступными.
Мы следуем правилам и принципам всех магазинов приложений.
Доступ к телефонной книге пользователя на Android/iPhone необходим только для построения социального графа, который нужен для использования функции “Найти”. Пользователи не могут получить доступ к номеру другого пользователя Truecaller до тех пор, пока пользователь сам не выдаст такого разрешения (с лимитом до 2го уровня связей). По умолчанию, не публичные номера не отображаются и вместо номера вы увидите пометку “номер доступен по запросу’. Это значит, что для получения номера необходимо отправить запрос пользователю, при этом вы всегда можете отправить отказ или не использовать данную фунцкию.
Для устройств с CyanogenOS работа Truecaller не является обязательной — вы можете согласиться или отказаться от использования во всплывающем окне, а также в настройках.
Для других OS, в том числе Windows Phone и BlackBerry, пользователей спрашивают готовы ли они помочь сообществу Truecaller стать наиболее полным и аккуратным в определении номеров, которые уже известны в их телефоне. Функция называется “Расширенный поиск” и она отключена по умолчанию. Пользователи, которые включили данную функцию могут отключить ее в любой момент в настройках аккаунта (что удалит все контакты, полученные от пользователя, в нашей системе).
У Truecaller более 150 миллионов пользователей по всему миру и ежедневно мы помогаем пользователям понять кто же им все-таки звонит. Наши пользователи сами выбирают путь помощи друг другу и тем самым, экономят время и нервы при звонках с незнакомых номеров или от спама.
Для тех, кто котел бы удалить свой номер из нашей базы, вы можете сделать это через наш вебсайт в любое время (www.truecaller.com).
Для тех, кто желает знать кому принадлежит пропущенный вызов, определять входящие вызовы или блокировать спам звонки, рекомендуем ссылкуalex_bosenko
21.09.2015 20:31Спасибо за разъяснения. Хотелось бы узнать о возможности подключения к API для возможности полноценной интеграции вашего сервиса. На Вашем сайте я не нашел информации.
dannyzubarev
21.09.2015 22:10Присоединюсь к alex_bosenko в вопросе доступа к API. Спасибо.
Truecaller
22.09.2015 13:41Спасибо за вопрос и внимание к нашему API, к сожалению, API больше не доступен.
webportal
У них же апи есть. Чем не устроило? Лимиты есть через апи и через ваш вариант?
alex_bosenko
API есть, но похоже в закрытом варианте. Нет описания где и как получать API_KEY для доступа. www.truecaller.com/developer — страница не найдена.
На ТехКранче от 2013 года были озвучено о открытии API с ссылкой на цены. В данный момент данная ссылка ценами тоже мертва.
webportal
https://dev.truecaller.com/docs да точно https://dev.truecaller.com/login есть логин нет реги.
alex_bosenko
По лимитам запросов ничего сказать не могу, т.к. нагрузочное тестирование не проводилось. Но надо понимать, что слишком частое обращение рано или поздно неизбежно приведет к блокировке. Поэтому и сделана прослойка в виде таблицы MySQL для сохранения имен ранее звонивших абонентов.