Найти тему
Merion Academy

Интеграция Asterisk и Instagram

Оглавление

На днях нам в голову пришла мысль: что получится, если интегрировать Asterisk и Instagram? Сценарий такой: приходит входящий звонок, Asterisk лезет в PHP скрипт через AGI с номером звонящего, параллельно, скрипт рисует картинку по заранее подготовленному шаблону, на которую накладывает номер звонящего и дату звонка, а потом через API отправляет публикацию в инстаграм?

Единственный вопрос, который у нас возник (и наверняка у вас) – зачем? Эту идею мы отложили в долгий ящик. Но один из наших инженеров не сдался, и довел до ума эту идею :) Предлагаем вам ознакомиться с тем, как это работает «just for fun» и для общего саморазвития.

Данная статья несет в себе развлекательно – ознакомительный характер, и не несет полезности для промышленной эксплуатации IP – АТС Asterisk. И мы это хорошо понимаем :)

СОЗДАНИЕ AGI – СКРИПТА НА PHP

Вся наша конструкцию будет состоять из 3 файлов:

  • instagram.php - файл, в котором мы будем цеплять из AGI CallerID, обращаться к скрипту, который сгенерирует картинку и отправлять данные в Instagram;
  • generate_pic.php - php – скрипт, который сгенерирует для нас картинку, с наложенным поверх номером звонящего и датой звонка;
  • pic.jpg - картинка – шаблон, на которую мы будем накладывать текст с номером и датой звонящего;

Кстати, картинка pic.jpg будет выглядеть вот так:

Важно! Картинка должна быть квадратной! В нашем случае, это размер 600x600.

Итак, а теперь сам скрипт. Важные строчки кода будут растолкованы с помощью комментариев после двойного обратного слеша \:

#!/usr/bin/php -q
<?php
error_reporting(0);
require('phpagi.php');
$agi = new AGI();
$cid = $agi->request['agi_callerid']; \парсим из AGI номер звонящего и записываем в переменную $cid;
copy(dirname( __FILE__ )."/pic.jpg", dirname( __FILE__ )."/picc.jpg"); \копируем нашу картинку шаблон в такую же, но с именем picc.jpg. После публикации она будет удалена;
$input = "
http://192.168.1.2/insta/generate_pic.php?num=$cid&pic=../../home/admin/instagram/pic.jpg"; \обращаемся к скрипту generate_pic.php, передавая в нем в переменной num номер звонящего, а в переменной pic = картинку, поверх которой, будем накладывать свой текст. Скрипт вернет нам картинку с наложенным текстом. Обратите внимание на путь /home/admin/instagram/pic.jpg – сюда мы загрузим картинку - шаблон;
$output = dirname( __FILE__ )."/picc.jpg";
file_put_contents($output, file_get_contents($input)); \ кладем нарисованное содержимое в файл picc.jpg, который ранее создали;
$image = dirname( __FILE__ )."/picc.jpg";
$date = date("Y-m-d H:i:s"); \ генерируем дату звонка - т.к AGI обращается к скрипту в момент звонка, она будет точной;
$text = "Входящий звонок от $date с номера $cid"; \ генерируем подпись к публикации в Instagram;
function SendRequest($url, $post, $post_data, $user_agent, $cookies) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, '
https://instagram.com/api/v1/'.$url);
curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

if($post) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}

if($cookies) {
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
} else {
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
}

$response = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

return array($http, $response);
}

function GenerateGuid() {
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(16384, 20479),
mt_rand(32768, 49151),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535));
}

function GenerateUserAgent() {
$resolutions = array('720x1280', '320x480', '480x800', '1024x768', '1280x720', '768x1024', '480x320');
$versions = array('GT-N7000', 'SM-N9000', 'GT-I9220', 'GT-I9100');
$dpis = array('120', '160', '320', '240');

$ver = $versions[array_rand($versions)];
$dpi = $dpis[array_rand($dpis)];
$res = $resolutions[array_rand($resolutions)];

return 'Instagram 4.'.mt_rand(1,2).'.'.mt_rand(0,2).' Android ('.mt_rand(10,11).'/'.mt_rand(1,3).'.'.mt_rand(3,5).'.'.mt_rand(0,5).'; '.$dpi.'; '.$res.'; samsung; '.$ver.'; '.$ver.'; smdkc210; en_US)';
}

function GenerateSignature($data) {
return hash_hmac('sha256', $data, 'b4a23f5e39b5929e0666ac5de94c89d1618a2916');
}

function GetPostData($filename) {
if(!$filename) {
echo "The image doesn't exist ".$filename;
} else {
$post_data = array('device_timestamp' => time(),
'photo' => '@'.$filename);
return $post_data;
}
}


function sendInstagramm($filename, $caption) // пишем функцию, при вызове которой (с двумя входными параметрами, файлом и текстом) мы будем совершать публикацию;
{
$username = 'ваш_логин_в_инстаграм'; // укажите здесь логин от нужной учетной записи в Instagram;
$password = 'ваш_пароль_в_инстаграм'; // укажите здесь пароль от нужной учетной записи в Instagram;

$agent = GenerateUserAgent();
$guid = GenerateGuid();
$device_id = "android-" . $guid;
$data = '{"device_id":"' . $device_id . '","guid":"' . $guid . '","username":"' . $username . '","password":"' . $password . '","Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"}';
$sig = GenerateSignature($data);
$data = 'signed_body=' . $sig . '.' . urlencode($data) . '&ig_sig_key_version=4';
$login = SendRequest('accounts/login/', true, $data, $agent, false);
$text = '';

if (strpos($login[1], "Sorry, an error occurred while processing this request.")) {
$text .= "Request failed, there's a chance that this proxy/ip is blocked";
return $text;
}

if (empty($login[1])) {
$text .= "Empty response received from the server while trying to login";
return $text;
}
$obj = @json_decode($login[1], true);

if (empty($obj)) {
$text .= "Could not decode the response" ;
return $text;
}
$data = GetPostData($filename);
$post = SendRequest('media/upload/', true, $data, $agent, true);

if (empty($post[1])) {
$text .= "Empty response received from the server while trying to post the image";
return $text;
}
$obj = @json_decode($post[1], true);

if (empty($obj)) {
$text .= "Could not decode the response";
return $text;
}
$status = $obj['status'];

if ($status != 'ok') {
$text .= "Status isn't okay";
return $text;
}

$media_id = $obj['media_id'];
$device_id = "android-" . $guid;

$data = (object)array(
'device_id' => $device_id,
'guid' => $guid,
'media_id' => $media_id,
'caption' => trim($caption),
'device_timestamp' => time(),
'source_type' => '5',
'filter_type' => '0',
'extra' => '{}',
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8',
);
$data = json_encode($data);
$sig = GenerateSignature($data);
$new_data = 'signed_body=' . $sig . '.' . urlencode($data) . '&ig_sig_key_version=4';

$conf = SendRequest('media/configure/', true, $new_data, $agent, true);
print_r ($conf);

if (empty($conf[1])) {
$text .= "Empty response received from the server while trying to configure the image";
} else {
if (strpos($conf[1], "login_required")) {
$text .= "You are not logged in. There's a chance that the account is banned";
} else {
$obj = @json_decode($conf[1], true);
$status = $obj['status'];
if ($status != 'fail') {
$text .= "Success";
} else {
$text .= 'Fail';
}
}
}
return $text;
}
sendInstagramm($image, $text); \ вызываем функцию постинга;
unlink(dirname( __FILE__ )."/picc.jpg"); \ удаляем созданный в рамках скрипта файл picc.jpg - более он нам не нужен :);
?>

СКАЧАТЬ СКРИПТ AGI

В случае скачивания, поменяйте расширение файла с .txt на .php

Великолепно. Сохраняем этот скрипт как Instagram.php и закидываем его в папку /var/lib/asterisk/agi-bin. Закинуть его можно с помощью WinSCP, например. Далее, в консоли через SSH доступ на сервер Asterisk дайте следующие команды:

dos2unix /var/lib/asterisk/agi-bin/instagram.php
chown asterisk:asterisk /var/lib/asterisk/agi-bin/instagram.php
chmod 775 /var/lib/asterisk/agi-bin/instagram.php

Теперь закидываем на сервер картинку – шаблон по пути /home/admin/instagram/pic.jpg, то есть так, как мы указали в скрипте и по аналогии даем права на этот файл. Приступаем к настройке скрипта генерации нужной нам «пикчи».

ГЕНЕРАЦИИ КАРТИНКИ НА PHP

Настало время генерации картинки. Реализация будет на PHP. Создаем файл generate_pic.php и добавляем в него следующее содержимое (комментарии в коде):

<?php
function writeTextOnImage($filename, $text) \ функция, при вызове которой, на вход мы даем 2 параметра: изображение, на которое нужно наложить текст и сам текст;
{
$size_img = getimagesize($filename);
if ($size_img[2]==2) $src_img = imagecreatefromjpeg($filename);
else if ($size_img[2]==1) $src_img = imagecreatefromgif($filename);
else if ($size_img[2]==3) $src_img = imagecreatefrompng($filename);
$color = imagecolorallocatealpha($src_img, 0, 0, 0, 0);
$font_file = "2211.ttf"; //файл расширения .ttf с нужным нам шрифтом;
$img_x = imagesx($src_img);
$img_y = imagesy($src_img);
$height_font = 28;
$angle = 0;
$box = imagettftext($src_img, $height_font, $angle, $img_x - 500, $img_y - 350, $color, $font_file, $text); \ здесь вы можете регулировать по оси X и Y позицию текста на картинке (смещение $img_x - 500, $img_y - 350);
if ($size_img[2]==2)
{
header ("Content-type: image/jpeg");
imagejpeg($src_img);
}
else if ($size_img[2]==1)
{
header ("Content-type: image/gif");
imagegif($src_img);
}
else if ($size_img[2]==3)
{
header ("Content-type: image/png");
imagepng($src_img);
}
return true;
}
$pic = $_GET['pic']; \ получаем путь к картинке;
$num = $_GET['num']; \ получаем номер звонящего
$img = "../../$pic"; \ относительный путь до картинки, на которую мы наложим текст;
$date = date("Y-m-d H:i:s"); \ генерируем дату;
writeTextOnImage($img, "Звонок от: $num\n Дата и время звонка:\n $date\n\n\n\n wiki.merionet.ru"); \ вызываем функцию;
?>

СКАЧАТЬ СКРИПТ ГЕНЕРАЦИИ

Теперь, создайте у себя на сервере Asterisk директорию /var/www/html/insta. В нее вам необходимо загрузить созданный файл generate_pic.php и файл шрифта 2211.ttf, а затем дать необходимые «пермишны»:

Вы можете назвать используемы файлы по своему усмотрению. Важно не забыть сменить их имена в самих скриптах.

dos2unix /var/www/html/insta/generate_pic.php
chown asterisk:asterisk /var/www/html/insta/generate_pic.php
chown asterisk:asterisk /var/www/html/insta/2211.ttf
chmod 775 /var/www/html/insta/generate_pic.php
chmod 775 /var/www/html/insta/2211.ttf

ВЫЗОВ СКРИПТА ИЗ ДИАЛПЛАНА

Осталось самое простое – вызвать скрипт instagram.php из диалплана Asterisk. Для этого, нужно вставить следующую строчку:

exten => _.,n,AGI(instagram.php)

Да, на этом все. Приступаем к тестированию. Наш скрипт расположился на входящем транке в тестовом контуре. Делаем звонок с мобильного телефона и смотрим в Instagram:

-2

Рассмотрим поближе, нажав на публикацию. Нас интересует подпись: