- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток!
Недавно в универе мне была поставлена задача создать сервис смс-рассылки уведомлений старостами (деканатом и прочими) своим группам.
Основные требования к сервису были следующими:
— Сервис должен быть многопользовательским (старост более 1) с возможностью одновременной обработки запросов
— Не должен быть привязан к online сервисам рассылки (дабы не утекли базы пользователей)
— Должен быть достаточно легким и мобильным
— Максимально малозатратным
— Должен использовать только открытое программное обеспечение
— Должен обеспечивать отправку уведомлений, даже если у отправляющей стороны нет доступа к Интернету и/или компьютеру. (т.е. не только отправлять, но и принимать входящие смс сообщения от старост + определять от кого конкретно они поступили и делать рассылку по их группам)
Как удалось это реализовать — смотрите под катом.
Итак, начнем.
Для того, чтобы приступить к организации сервиса, нам будет нужно собрать все необходимые железки.
В принципе, на этом можно и ограничиться. Но для более комфортной работы я бы посоветовал еще:
Что касается охлаждения — сделать его совершенно элементарно. Возьмите старый 80 миллиметровый кулер, зачистите красный и черный проводки, идущие от него. Затем отрежьте половину от ненужного USB кабеля. Также зачистите на нем красный и черный провод. Смотайте провода от кулера и от USB вместе, заизолируйте и ваше охлаждение готово. Желательно разместить кулер под нетбуком на пластилиновых ножках, чтобы он громко не резонировал.
Собственно, вот как это выглядит:
Если кто-то не понял, вот подробный мануал [2].
Что касается зачистки проводов — я люблю сначала опалить их концы на керосиновой горелке, а потом ножом легко счистить остатки. Керосинку тоже покупать не стоит — ее можно сделать из обычной 60 Ваттной лампочки Ильича. Пробиваете верхушку цоколя, заливаете туда керосин, вставляете кусок старой тряпки вместо фитиля и готово. Вот как это выглядит:
В виде операционной системы для нетбука я выбрал EasyPeasy — система для нетбуков, основанная на ядре Linux и модифицированная для слабых компьютеров. Скачать ее, установить на флешку, а затем на нетбук можно тут. [3]
После того, как операционная система заняла свое место, подключаем bluetooth-адаптер в свободный USB порт. Система должна распознать его автоматически. Включаем Nokia и спариваем телефон и компьютер.
Нужно установить gnokii. Я уже и раньше ссылался на эту статью [4] по его установке на Линукс. Думаю, разберетесь.
После установки наберите в консоли что-то вроде echo «Привет, друг!» | gnokii --sendsms '+7номер_вашего_друга' и проверьте, отправилась ли смска.
Возможно, Вам подойдет какой-либо другой способ организации многопользовательской работы, но я использовал возможности Joomla ACL (уровней доступа). Как это настроить — очень подробно описано в этой статье [5]. Я лишь хочу заметить, что на выходе у Вас должен получиться сайт, где каждый из пользователей (те, кто будет отправлять смски) будет иметь свой личный кабинет, попасть в который он сможет введя номер своего мобильного телефона (в качестве логина, в формате 79XX XXX XX XX) и пятизначный цифровой код в качестве пароля. К примеру, как на сайте vamsms.ru [6]
Внимание! Все программки я писал сам. Можете использовать их как вам хочется, только дайте обратную связь, если найдете какой-либо серьезный косяк.
Итак, наша задача состоит в том, чтобы научить наш сервер общаться с удаленным сайтом, собирать с него заявки на отправку и отправлять сообщения. Кроме того, сервер должен уметь принимать входящие сообщения (на Nokia, с которой смски отправляются), осознавать, что они отправлены старостами и также ставить в очередь на рассылку по той группе, к которой конкретная староста принадлежит. Плюс, все это нужно синхронизировать. Ну и вести логи, конечно.
Для начала необходимо сделать БД, относящуюся к
Внутри этой БД нужно создать 3 таблицы. У меня они имеют следующую структуру:
starosti (идентификация и ареолы действий для старост)
— number
— group
— course
— facultet
— pass
telephones (все телефоны в базе)
— number
— groups
— course
— facultet
on_demand (тут хранятся сообщения на отправку)
— message
— group
— course
— id_this_trans
— date_log
Отлично, на этом с базами данных все.
Теперь нужно сделать так, чтобы нетбук каждые 10 минут проверял:
1) Поступили ли новые сообщения с сайта? Если да, то отправляю их нужным группам.
2) Поступили новые входящие смски? Если да, то от старост ли они? Если нет, то просто удаляю их, если да, то определяю, за какую группу отвечает староста и делаю рассылку сообщения по той группе.
Привожу листинг shell-скрипта:
#!/bin/bash
a=1 #заглушка для бесконечного цикла
test_trigger=`cat cache_test_trig.txt` #исходное значение триггера при старте программы
while [ $a == 1 ] #начало бесконечного цикла
do
if ping -c1 ya.ru &> /dev/null
then
test_trigger_now=$(wget http://site.ru/trigger.txt --quiet -O -) # получаем значение триггера
if [ $test_trigger_now -eq $test_trigger ]; then #совпадает ли текущий триггер с новым?
echo "Nothing new :(" #если совпадает, уход в сон до след цикла
###############################
######### Mobile extention
###############################
aa=1 #переменная для поддержания цикла
#count=1 #счетчик для выбора смс из памяти по 1
while [ $aa == 1 ] # получение смсок из памяти по 1
do
sms_test=$(gnokii --getsms IN 1 1) #считали 1 сообщение в цикле (1 1,2 2 и т.д.)
echo $sms_test>mobile_temp.txt #поместили ответ системы в файл
answer_test=$(grep -c Date/time: mobile_temp.txt) #ищем в ответе ключевое слово, присущее сообщению(Date/time:)
if [ "$answer_test" != "1" ]; then #если ключевое слово не найдено, память закончилась, вышла ошибка
aa=2 # прерываем цикл
echo "messages over! Stop"
elif [ "$answer_test" == "1" ]; then #если ключевое слово найдено,
echo "Here is 1 message"
#let count=$count+1 #работа со счетчиком выборки из памяти
#Теперь в переменной sms_test находится сообщение вида '1. Inbox Message (Unread) Date/time: 07/02/2013 15:33:16 +0400 Sender: +7904xxxxxx Msg Center: Text: 51235 Мое сообщение.'
server_send=$(wget http://site.ru/serv_mobile.php?text="$sms_test" -O /dev/null) #передаем сообщение на сервер для записи/незаписи в бд
sleep 1
gnokii --deletesms IN 1 1 #очищает память телефона 1 сообщение
fi
sleep 3
done
###############################
######### Mobile extention
###############################
sleep 500
else #если не совпадает, запуск программы смс-отправки
echo "i need to do something!"
let different=$test_trigger_now-$test_trigger #(стало-было), сколько нового
#echo $different #разницу выдает правильно
get_sender=$(wget http://site.ru/trigger.php?diff=$different --quiet -O -) # в скрипт на реме передается количество новых записей (сколько папок создавать)
#echo $get_sender # скрипт на реме воспринимает переменную different нормально
echo $get_sender #возвращает ОК от рема
sleep 3 #дадим рему время очухаться
#Start SMS-sending
n=0
while [ $n -lt $different ] # пока n < different
do
let n=$n+1
#!!!!!!!!!!!SENDING!!!!!!!!!!!!!!
echo "send files from send$n folder" #место для запуска gnokii
mess_for_gnok=$(wget http://site.ru/send$n/message.txt --quiet -O -) #скачиваем сообщение
numb_for_gnok=$(wget http://site.ru/send$n/numbers.txt) #скачиваем номера
cat numbers.txt | while read line
do
inp=$line
echo "$mess_for_gnok" | gnokii --sendsms $inp
echo $line
echo $mess_for_gnok
sleep 2
done
rm numbers.txt #delete temporary files
sleep 1
#!!!!!!!!!!!SENDING!!!!!!!!!!!!!!
done
terminator=$(wget http://site.ru/terminate.php?kill=$different --quiet -O -) # delete all temperal folders in root
#echo "i kill all files"
test_trigger=$test_trigger_now #задание выполнено, поднимаемся и ждем новых изменений в trigger.txt
echo $test_trigger>cache_test_trig.txt
sleep 10 #засыпает после всех действий
fi
else
echo "Here is no Internet. Find it!"
sleep 500
fi
done
Кроме того, в папке со скриптом нужно создать файл cache_test_trig.txt со значением 1 (и в таблице on_demand сделать первую запись какую-нибудь)
В личном кабинете пользователя в joomla должна быть форма следующего содержания:
<script type="text/javascript">
function isNotMax(e){ e = e || window.event;var target = e.target || e.srcElement;var code=e.keyCode?e.keyCode:(e.which?e.which:e.charCode)switch(code){case13:case8:case9:case46:case37:case38:case39:case40:returntrue;}return target.value.length <= target.getAttribute('maxlength');}
</script>
<p><strong>Форма смс-отправки.</strong></p>
<form action="http://site.ru/handler.php" method="POST">Кому отправляется уведомление:<br />
<select name="Group">
<option value="11">группа 11 </option>
</select>
<select name="Course">
<option value="4">курс 4 </option>
</select>
<select name="Facult">
<option value="1">Факультет экономический </option>
</select>
<br />
<br />
<hr style="color:#B4B4B4; border:thin groove"/>
<b>Внимание!</b> Вы можете ввести не более <b>70</b> любых символов(русский/английский, знаки препинания)<hr style="color:#B4B4B4; border:thin groove"/><br />
Текст уведомления:<br />
<textarea name="message" rows="4" cols="46" maxlength="70" onkeypress="return isNotMax(event)"></textarea> <br />
<input type="submit" value="Начать отправку!" /></form>
Очевидно, данные из формы передаются в файл, лежащий в корневой директории
Вот его листинг:
<?php
$prev_page = $_SERVER['HTTP_REFERER'];
$who_is_you = substr_count("$prev_page", "http://site.ru/index.php/"); //защита от многократных запросов и запросов извне
if ($who_is_you == 1)
{
$message=$_POST['message'];
$message=htmlspecialchars(stripslashes($message)); // обработка от спецсимволов
$course=$_POST['Course'];
$course=htmlspecialchars(stripslashes($course)); // обработка от спецсимволов
$groups=$_POST['Group'];
$groups=htmlspecialchars(stripslashes($groups)); // обработка от спецсимволов
$facult=$_POST['Facult'];
$facult=htmlspecialchars(stripslashes($facult)); // обработка от спецсимволов
//validation-----------------------------
if (empty($message))
{
echo "
<body style='background-image: url(body_bg.gif); background-repeat: repeat-x'>
<div align='center' style='margin-top: 14%'>
<p style='color: #666666; font-family: Verdana,Helvetica,sans-serif; font-size: 18px; line-height: 1.8em;'><i>Ваше сообщение НЕ отправлено!</i> <br>Текст уведомления не указан. <a href = '$prev_page'>Вернитесь назад и заполните поле.</a> </p>
</div>
</body>
";
}
//validation-----------------------------
else
{
//connect_to_BD--------------------------
include(db_connect.php);
//connect_to_BD--------------------------
mysql_query("SET NAMES 'utf8'");
$r = mysql_query("SELECT id_this_trans FROM on_demand ORDER BY id_this_trans DESC LIMIT 0, 1"); // выводит номер последней трансакции
while($row = mysql_fetch_array($r))
{
$last_tranzaktion = $row['id_this_trans'];
}
$last_tranzaktion++; // подготовили id новой транзакции
$heutige_datum = date("Y-m-d H:i:s");
mysql_query ("INSERT INTO on_demand VALUES('$message','$groups','$course','$last_tranzaktion', '$heutige_datum')"); // новое указание для отправки
file_put_contents("trigger.txt", $last_tranzaktion);
echo "
<body style='background-image: url(body_bg.gif); background-repeat: repeat-x'>
<div align='center' style='margin-top: 14%'>
<p style='color: #666666; font-family: Verdana,Helvetica,sans-serif; font-size: 18px; line-height: 1.8em;'><i>Ваше сообщение принято к отправке!</i> <br> Вы можете завершить работу с сервисом, или <a href = 'http://site.ru/'>вернуться в Главное меню системы</a> </p>
</div>
</body>
";
}
}
else
{
echo "
<html>
<head><title> 404 Not Found
</title></head>
<body><h1> 404 Not Found
</h1>
The resource requested could not be found on this server!<hr />
Powered By <a href='http://www.litespeedtech.com'>LiteSpeed Web Server</a><br />
<font face='Verdana, Arial, Helvetica' size=-1>LiteSpeed Technologies is not responsible for administration and contents of this web site!</font></body></html>
";
}
?>
Далее, для того, чтобы удаленный
<?php
#$sms_text=mysql_real_escape_string($_GET['text']); // получаем очередную смску от хома + защита от инъекций
$sms_text=$_GET['text']; // получаем очередную смску от хома + защита от инъекций
file_put_contents("temp_mobile_mess.txt", $sms_text); //записываем всю смску во временное хранилище
$get_from_file = file_get_contents("temp_mobile_mess.txt"); //записываем всю смску в переменную
$number = substr("$get_from_file", 72, 11); //выделяем номер отправителя (не забывать про read/unread)
$pass = substr("$get_from_file", 103, 5); //выделяем пароль
$message = substr("$get_from_file", 109); //выделяем текст сообщения
//connect_to_BD--------------------------
include(db_connect.php);
//connect_to_BD--------------------------
mysql_query("SET NAMES 'utf8'");
//защита от инъекций
$number = mysql_real_escape_string($number);
$pass = mysql_real_escape_string($pass);
$message = mysql_real_escape_string($message);
//защита от инъекций
$r = mysql_query("SELECT COUNT(*) FROM `starosti` WHERE pass='$pass' AND number='$number'"); //проверяет наличие связки пароль/номер в базе
while($row = mysql_fetch_array($r))
{
if($row[0] == 1) //определил, что такая связка присутствует
{
//------------определяет заполнение поля id_this_trans---------------
$q = mysql_query("SELECT id_this_trans FROM on_demand ORDER BY id_this_trans DESC LIMIT 0, 1"); // выводит номер последней трансакции
while($rowq = mysql_fetch_array($q))
{
$last_tranzaktion = $rowq['id_this_trans'];
}
$last_tranzaktion++; // подготовили id новой транзакции
//------------определяет заполнение поля id_this_trans---------------
//------------вставляет все полученные данные в таблицу on_demand----
$second_r = mysql_query("SELECT * FROM `starosti` WHERE pass='$pass' AND number='$number'"); //узнаем курс и группу старосты, приславшей смску
while($second_row = mysql_fetch_array($second_r))
{
$groups = $second_row['group'];
$course = $second_row['course'];
$heutige_datum = date("Y-m-d H:i:s");
mysql_query ("INSERT INTO on_demand VALUES('$message','$groups','$course','$last_tranzaktion','$heutige_datum')"); // формирует указание для отправки
}
//------------вставляет все полученные данные в таблицу on_demand----
#не забыть обновить триггер на новое значение транзакции
file_put_contents("trigger.txt", $last_tranzaktion);
}
}
?>
Его листинг:
<?php
$inp_diff = $_GET['diff']; // принимает различия от хома
//connect_to_BD--------------------------
include(db_connect.php);
//connect_to_BD--------------------------
mysql_query("SET NAMES 'utf8'");
//Create files AND Folders---------------
for($i=1; $i<=$inp_diff;$i++)
{
mkdir("send$i");
file_put_contents("send$i/message.txt",'');
file_put_contents("send$i/numbers.txt",'');
}
//Create files AND Folders---------------
$counter=1;// счетчик для записи в папки, указывает на номер папки
// Вывод последних дифферент записей-----
$r = mysql_query("SELECT * FROM on_demand ORDER BY id_this_trans DESC LIMIT 0, $inp_diff"); // выводит последние записи
while($row = mysql_fetch_array($r))
{
file_put_contents("send$counter/message.txt",$row['message']); //заполняет текстом файл message.txt во всех папках
// заполняем файл numbers.txt во всех папках
$help_course = $row['course'];
$help_group = $row['group'];
$second_r = mysql_query("SELECT * FROM telephones WHERE course='$help_course' AND groups='$help_group'");
while($second_row = mysql_fetch_array($second_r))
{
$insert_number = $second_row['number']; // помогает записать в файл 1 номер на 1 итерации
$fp=fopen("send$counter/numbers.txt","a");
fputs($fp,$insert_number. "n");
fclose($fp);
}
// заполняем файл numbers.txt во всех папках
$counter++;
}
// Вывод последних дифферент записей-----
echo "ok";
?>
Его листинг:
<?php
$inp_diff = $_GET['kill']; // принимает различия от хома
//Delete files AND Folders---------------
for($i=1; $i<=$inp_diff;$i++)
{
unlink("send$i/message.txt");
unlink("send$i/numbers.txt");
rmdir("send$i");
}
//Delete files AND Folders---------------
?>
Прошу меня простить, если мой рассказ получился излишне сумбурным. Я правда старался максимально последовательно изложить тут свои мысли :) Удачной вам настройки, с радостью отвечу на вопросы в комментариях.
Кстати, вот как все это выглядит у меня:
Автор: light204
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/28229
Ссылки в тексте:
[1] хостинг: https://www.reg.ru/?rlink=reflink-717
[2] вот подробный мануал: http://www.cyberforum.ru/modding/thread340042.html
[3] тут.: http://www.geteasypeasy.com/
[4] на эту статью: http://debian.3dn.ru/blog/priem_i_otpravka_sms_v_linux/2011-02-01-17
[5] этой статье: http://joomlablog.ru/uroki-joomla/282-joomla-acl-urovni-dostupa
[6] vamsms.ru: http://site.ru/
[7] Источник: http://habrahabr.ru/post/170901/
Нажмите здесь для печати.