Что нового

Функции для отправки и проверки доставки СМС по HTTP на alfa-sms.ru

Pavel

Новичок
Сообщения
125
Репутация
3
Версия AutoIt: 3.
любая
Описание:
прошу реализовать функцию отправки СМС-сообщений по HTTP через сервис alfa-sms.ru
Подробнее: http://alfa-sms.ru/support/http_protocol/
Примечания:
каких-либо интерфейсов делать вовсе необязательно. Главное реализовать саму функции отправки и проверки статуса. Спасибище!
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Протокол позволяет отправлять сообщения и проверять статусы сообщений с помощью отправки POST-запросов.
Подробное описание доступно для зарегистрированных пользователей (Регистрация).
Так что кинь эту информацию сюда...
 
Автор
P

Pavel

Новичок
Сообщения
125
Репутация
3
Протокол отправки через HTTP
1. Описание отправки сообщений через HTTP протокол.
Протестировать протокол "вручную" (с помощью WEB формы): alfa-sms.ru.ru:8080/smw/webapi_aisms.html
Скачать PHP-класс для работы и примеры на PHP - http.zip
Адрес обращения: http://smpp.alfa-sms.ru:8080/smw/aisms или https://smpp.alfa-sms.ru/smw/aisms (корневой сертификат можно получить по ссылке).
Тип авторизации: PLAIN (открытым текстом).
Формат входных данных: Content-Type: application/x-www-form-urlencoded; charset=windows-1251 (по умолчанию).
При использовании другой кодировки, отличной от windows-1251, требуется указать её в заголовке Content-Type запроса.
Например: Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Результат: Content-Type: text/xml, кодировка: UTF-8; content-encoding: gzip (опционально)
Login/password: уникальные login/password выданные Вам при регистрации
Максимальная длина сообщений: 4000 символов.

2. Параметры для запросов
2.1 Авторизация
В каждом запросе требуется отправить параметры для авторизации.
user - зарегистрированное в системе имя SMS-пользователя (см. SMS-пользователи)
pass - пароль SMS-пользователя.
2.2. Отправка SMS
Передаются POST-переменные:
action = post_sms
message - текст сообщения
target - адресаты. Список через запятую. Например: +79171234567, 79057654321
sender - имя отправителя зарегистрированного для вас в системе. NULL = подставить имя отправителя по умолчанию.
send_dt - время отправки в формате ГодМесяцДеньЧасМинутаСекундаЧПояс, например 120131235802016+, на PHP это будет выглядеть как date('ymdHis016+'). Часовой пояс задается как разница с Гринвичем в четвертях часа, для московского времени он выглядит так 016+.
2.3. Получение информации об отправленных сообщениях
action = status
sms_id = уникальный идентификатор SMS, назначенный при отправке.
2.4. Получение текущего баланса (количество SMS)
action = balance

3. Примеры запросов/ответов
Пример 1. Отправка сообщения адресатам
Код:
POST= (
[user] => userX
[pass] => blabla
[action] => post_sms
[message] => test message
[target] => +79171234567,79057654321, 1 ,zz
)
Примерный вид сгенерированного запроса:
action=post_sms&user=userX&pass=blabla&sender=NULL&target=%2B79171234567%2C79057654321%2C1%2Czz&message=test+message
Результат XML
Код:
<output>
<result>
<sms id="8535020" phone="79171234567"/>
<sms id="8535021" phone="79057654321"/>
</result>
<errors>
<error phone="1">Неправильный номер телефона: 1</error>
<error phone="zz">Неправильный номер телефона: zz</error>
</errors>
</output>

Атрибут id - это уникальный идентификатор сообщения, назначенный при отправке.
Номера телефонов очищаются от мусорных символов (+, -, скобки, пробелы)

Пример 2. Получение данных сообщения id=8535020
POST= ( [action] => status
[sms_id] => 8535020
[user] => userX
[pass] => blabla )
Примерный вид сгенерированного запроса:
user=userX&pass=blabla&sms_id=8535020&action=status

Примеры ответов:
a) В процессе доставки
Код:
<output>
<MESSAGES>
<MESSAGE SMS_ID="8535020">
<SMS_STATUS>1000000</SMS_STATUS>
<SMSSTC_CODE>queued</SMSSTC_CODE>
<SMS_SENT>0</SMS_SENT>
</MESSAGE>
</MESSAGES>
</output>

b) Доставлено
Код:
<output>
<MESSAGES>
<MESSAGE SMS_ID="8535020">
<SMS_STATUS>2000000</SMS_STATUS>
<SMS_CLOSE_TIME>30.04.10 00:01:07</SMS_CLOSE_TIME>
<sent_dt>100430000050916+</sent_dt>
<SMSSTC_CODE>delivered</SMSSTC_CODE>
<SMS_SENT>1</SMS_SENT>
</MESSAGE>
</MESSAGES>
</output>

Данные по сообщению:
SMS_ID - ID сообщения
SMS_STATUS - hex значения полей message_state (согласно SMPP API v5 раздел 4.7.15) и network_error_code
SMSSTC_CODE - Код статуса доставки сообщения
SMS_SENT - 0 - сообщение в процессе доставки/не доставлено, 1 = сообщение доставлено абоненту
SMS_CLOSE_TIME - дата и время прихода отчета о доставке - окончание работ по данному сообщению.
sent_dt - первая попытка доставки SMS абоненту

SMSSTC_CODE - Код статуса доставки сообщения
КодОписание
queuedсообщение в очереди отправки
waitпередано в SMSC на отправку - в очереди отправки SMSC
accepted(редко) был получен промежуточный отчет от SMSC - сообщение в очереди отправки SMSC
deliveredсообщение доставлено на телефон
failedошибка при работе по сообщению - сообщение не доставлено
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Блин, WinHttpRequest.5.1 не хочет отдавать ResponseText потому что Content-Encoding: gzip. Подскажите что делать?
Приходит не XML, а всего два символа "?", хотя Content-Length: 96
ResponseBody возвращает
Код:
0x1F8B0800000000000000B3B1AFC8CD51284B2D2ACECCCFB35532D43350B2B7E3B2C92F2D29282DB1B3492D2ACA2F2A86D276A1C5A9450A89A52519A9792599C98925402D0A69899939A92936FA1015501AA8431F6A0417006630B61262000000

А BinaryToString с флагом 4 возвращает
Код:
ˈ       ӱЈΑ(K-*όϳU2ԳPҷ㳉/-)(-ѳI-*ʯ*ǒv…ʅ
ɥ%ʹ%ډɥ@-
iə9ɩ6
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
alex33,
Если у Вас в заголовке content-encoding: gzip присутствует, то попробуйте его убрать.
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
madmasles сказал(а):
alex33,
Если у Вас в заголовке content-encoding: gzip присутствует, то попробуйте его убрать.
Я-то убрал, а сервер нет.
Кстати, сейчас все удивитесь.
Код:
;~ Global $sBinary = $oReq.responseBody
Global $sBinary = "0x1F8B0800000000000000B3B1AFC8CD51284B2D2ACECCCFB35532D43350B2B7E3B2C92F2D29282DB1B3492D2ACA2F2A86D276A1C5A9450A89A52519A9792599C98925402D0A69899939A92936FA1015501AA8431F6A0417006630B61262000000"
Global $hFile = FileOpen(@ScriptDir&"\response.xml.zip", 2+16)
FileWrite($hFile, $sBinary)
FileClose($hFile)

Появляется архив.
Потом берём и открываем этот архив в WinRAR и обнаруживаем там файл response.xml в котором содержится ответ в виде XML, всё как положено, тоесть:
Код:
<?xml version="1.0"?>
<output><errors><error>User authentication failed</error></errors></output>


Добавлено:
Сообщение автоматически объединено:

Только вот вопрос, как без использования архиватора и т.д. и т.п. получить результат XML в переменную?
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
alex33 [?]
Приходит не XML, а всего два символа

Если вы работаете с XML, используйте соответствующий объект.
Код:
Local $sUser = 'userX'
Local $sPass = 'blabla'
Local $sTarge = '+79171234567,79057654321, 1 ,zz'
Local $sMessage = 'Hallo Autoit!'
Local $sData = StringFormat('action=post_sms&user=%s&pass=%s&sender=NULL&target=%s&message=%s', $sUser, $sPass, $sTarge, $sMessage)

Local $s_Url = 'http://smpp.alfa-sms.ru:8080/smw/aisms'

$s_UserAgent = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16'
$oHTTP = ObjCreate("MSXML2.XMLHTTP")
$oHTTP.Open('POST', $s_Url, true, '', '')
$oHTTP.SetRequestHeader("User-Agent", $s_UserAgent)
$oHTTP.SetRequestHeader("Host", "smpp.alfa-sms.ru")
$oHTTP.SetRequestHeader("Accept", "*/*")
$oHTTP.SetRequestHeader("Content-Type", "text/xml; charset='utf-8'")
$oHTTP.Send(_URIComponent($sData))
$sHTML = $oHTTP.responseXML

$sHTML.setProperty('SelectionLanguage', 'XPath')
$sNodes = $sHTML.selectNodes('//error')
For $oNode In $sNodes
	ConsoleWrite(StringFormat('! ANSWER: %s\n', $oNode.text))
Next	
	
Func _URIComponent($s_URI, $s_Flag = 0)
	
	Local $o_Obj = ObjCreate("ScriptControl")
	$o_Obj.Language = "JScript"
	
	If $s_Flag Then
		$s_Ret = $o_Obj.Eval(StringFormat('decodeURIComponent("%s");', $s_URI))
	Else
		$s_Ret = $o_Obj.Eval(StringFormat('encodeURIComponent("%s");', $s_URI))
	EndIf
	
	Return $s_Ret
EndFunc   ;==>_URIComponent
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Garrett, Спасибо за наводку.
Я использовал WinHttp и парсил XML регулярными выражениями... Но этот способ конечно лучше...


Добавлено:
Сообщение автоматически объединено:

Только там надо было не true, а false написать, или же надо было в цикле / по таймауту проверять readyState, но я написал false, проще и лучше... :smile:
 
Автор
P

Pavel

Новичок
Сообщения
125
Репутация
3
Ребят, что-то не работает скрипт Garrett'a. Все данные в переменные подставил. Скрипт отрабатывает, завершается (почти мгновенно), в консоль ничего не пишет, смс не уходит.

Если не затруднит, зарегайтесь на alfa-sms. Там вроде бы бесплатные 10 тестовых смс дают после регистрации. Если нет, то готов оплатить 10 смс вам для тестов. Помогите добить функцию, у самого руки — в другой плоскости :smile:
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Вот UDF, только SMS_Status не работает, я не доделал...
Код:
#include-once
#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.12.0
 UDF Version: 1.1 Beta
 Author:         alex33
 thanks Garrett
 функция _SMS_Status не работает. Я её не доделал...

 Script Function:
 UDF for alfa-sms.ru.

#ce ----------------------------------------------------------------------------

#include <Array.au3>
Global $oError, $oHTTP, $oSC
Global $sUserAgent = 'Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0'
Global $GetAllResponseHeaders, $Status, $StatusText, $sHTML
Global $SMS_URL = "http://smpp.alfa-sms.ru:8080/smw/aisms"
Global $aSendErrorsText[0], $aSendResults[0], $aStatusResults[0][0]
Func _SMS_Send($user = "", $pass = "", $message = "", $target = "", $sender = "NULL")
__CreateNewObjects()
Local $send_dt = StringFormat("%s%s%s%s%s%s%s", @YEAR, @MON, @MDAY, @HOUR, @MIN, @SEC, "016+")
Local $sSendStr = ""
Local $oNodes
$user = __encodeURIComponent($user)
$pass = __encodeURIComponent($pass)
$message = __encodeURIComponent($message)
$target = __encodeURIComponent($target)
$sender = __encodeURIComponent($sender)
$send_dt = __encodeURIComponent($send_dt)
$sSendStr = StringFormat("action=post_sms&user=%s&pass=%s&message=%s&target=%s&sender=%s&send_dt=%s", $user, $pass, $message, $target, $sender, $send_dt)
ConsoleWrite($sSendStr&@CRLF)
__MakeDefaultRequest("POST", $SMS_URL, $sSendStr)
$sHTML = $oHTTP.responseXML
$sHTML.setProperty('SelectionLanguage', 'XPath')
$sNodes = $sHTML.selectNodes('/output/errors/error')
If IsObj($sNodes) Then
For $oNode In $sNodes
_ArrayAdd($aSendErrorsText, String($oNode.text))
Next
EndIf
;_ArrayDisplay($aSendErrorsText)
$sNodes = $sHTML.selectNodes('/output/result/sms')
If IsObj($sNodes) Then
For $oNode In $sNodes
_ArrayAdd($aSendResults, String($oNode.getAttribute('id')))
Next
EndIf
SetExtended(UBound($aSendErrorsText))
If UBound($aSendResults) < 1 Then Return SetError(-2)
;_ArrayDisplay($aSendResults)
;~ Return 1
Return $aSendResults
EndFunc
Func _SMS_Status($user = "", $pass = "", $sms_id = 0)
__CreateNewObjects()
Local $sSendStr = ""
Local $oNodes
$user = __encodeURIComponent($user)
$pass = __encodeURIComponent($pass)
$sms_id = __encodeURIComponent($sms_id)
$sSendStr = StringFormat("action=status&user=%s&pass=%s&sms_id=%s", $user, $pass, $sms_id)
ConsoleWrite($sSendStr&@CRLF)
__MakeDefaultRequest("POST", $SMS_URL, $sSendStr)
$sHTML = $oHTTP.responseXML
$sHTML.setProperty('SelectionLanguage', 'XPath')
$sNodes = $sHTML.selectNodes('/output/MESSAGES/MESSAGE')
;If IsObj($sNodes) Then
For $oNode In $sNodes
If Not IsObj($oNode.selectNodes('SMSSTC_CODE')) Or Not IsObj($oNode.selectNodes('SMS_SENT')) Then ContinueLoop
If $oNode.getAttribute('SMS_ID') <> $sms_id Then ContinueLoop
_ArrayAdd($aStatusResults, $oNodes.selectNodes('SMSSTC_CODE').item(0).text, 0)
_ArrayAdd($aStatusResults, $oNode.selectNodes('SMS_SENT').item(0).text, 1)
Next
;EndIf
If UBound($aStatusResults) < 1 Then Return SetError(-2)
;_ArrayDisplay($aStatusResults)
;~ Return 1
Return $aStatusResults
EndFunc

Func __CreateNewObjects()
$oError = 0
$oHTTP = 0
$oSC = 0
$sHTML = 0
$oNodes = 0
$oHTTP = ObjCreate("MSXML2.XMLHTTP")
$oSC = ObjCreate("ScriptControl")
If Not IsObj($oHTTP) Or Not IsObj($oSC) Then
Return SetError(1, 0, 0)
EndIf
$oSC.Language = "JavaScript"
Return 1
EndFunc
Func __SMS_ErrorFunc()
ConsoleWrite('COM Error' & @TAB & $oError.description&@CRLF)
EndFunc   ;==>__SMS_ErrorFunc
Func __encodeURIComponent($sTxt1)
If Not IsObj($oSC) Then __CreateNewObjects()
$sTxt1 = SpecialEncode($sTxt1)
Return StringReplace($oSC.Eval('encodeURIComponent("' & $sTxt1 & '");'), "%20", "+")
EndFunc   ;==>__encodeURIComponent
Func __decodeURIComponent($sTxt2)
If Not IsObj($oSC) Then __CreateNewObjects()
$sTxt2 = SpecialEncode($sTxt2)
Return StringReplace($oSC.Eval('decodeURIComponent("' & $sTxt2 & '");'), "+", "%20")
EndFunc   ;==>__decodeURIComponent
Func SpecialEncode($sTxt3)
$sTxt3 = StringReplace($sTxt3, '\', '\\')
$sTxt3 = StringReplace($sTxt3, @TAB, '\t"')
$sTxt3 = StringReplace($sTxt3, @CRLF, '\r\n"')
$sTxt3 = StringReplace($sTxt3, @CR, '\r"')
$sTxt3 = StringReplace($sTxt3, @LF, '\n"')
$sTxt3 = StringReplace($sTxt3, '"', '\"')
Return $sTxt3
EndFunc   ;==>SpecialEncode
Func __MakeDefaultRequest($_method = "GET", $_url = "", $_str = "")
If Not IsObj($oSC) Then __CreateNewObjects()
$oError = ObjEvent('AutoIt.Error', 'ErrorFunc')
$oHTTP.Open($_method, $_url, False, '', '')
If $_method = "POST" Then $oHTTP.SetRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
$oHTTP.SetRequestHeader('User-Agent', $sUserAgent)
$oHTTP.SetRequestHeader('Cache-Controle', 'no-cach')
$oHTTP.SetRequestHeader('Accept', 'text/xml,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
$oHTTP.SetRequestHeader('Accept-Language', 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3')
;$oHTTP.SetRequestHeader('Accept-Encoding', 'gzip, deflate');
;$oHTTP.SetRequestHeader('Connection', 'keep-alive');
$oHTTP.Send($_str)
$Status = $oHTTP.Status
$StatusText = $oHTTP.StatusText
$GetAllResponseHeaders = $oHTTP.GetAllResponseHeaders()
$oError = 0
EndFunc

Пример:
Код:
Local $aMsg_id = _SMS_Send("userX", "blabla", "test message", "+79171234567,79057654321, 1 ,zz")
If @error = 0 Then
    MsgBox(0, "send sms", "Сообщение отправленно")
EndIf
 
Автор
P

Pavel

Новичок
Сообщения
125
Репутация
3
Постоянно пишет в ArrayDisplay, — User authentication failed
Перепроверил пароль и имя пользователя. Ошибки быть не может. :scratch:

С аутентификацией разобрался. Там легко перепутать имена отправителей и учётные реквизиты.

Теперь иная проблема с часовым поясом:
send_dt: SMPP TIME ERROR: parseSmpp: wrong length of SMPP time string != 16 [20140628163638016+]: 18
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Pavel [?]
Если не затруднит, зарегайтесь на alfa-sms.
Это же сколько нужно регистрироваться, чтобы помочь всем нуждающимся?
Лучше Вы сами создайте тестовый аккаунт.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Исправь
Код:
Local $send_dt = StringFormat("%s%s%s%s%s%s%s", @YEAR, @MON, @MDAY, @HOUR, @MIN, @SEC, "016+")
на
Код:
Local $send_dt = StringFormat("%s%s%s%s%s%s%s", StringRight(@YEAR,2), @MON, @MDAY, @HOUR, @MIN, @SEC, "016+")
 
Автор
P

Pavel

Новичок
Сообщения
125
Репутация
3
inververs, да, спасибо. Только что сам дошёл до этого :smile:
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
Pavel [?]
Теперь иная проблема с часовым поясом
Код:
Local $send_dt = StringFormat('%2d%.2d%.2d%.2d%.2d%.2d%s', StringTrimLeft(@YEAR, 2), @MON, @MDAY, @HOUR, @MIN, @SEC, '016+')
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Я бы так сделал.
Код:
ConsoleWrite(StringFormat('%02d%02d%02d%02d%02d%02d%s', StringRight(@YEAR, 2), @MON, @MDAY, @HOUR, @MIN, @SEC, '016+') & @LF)
 
Автор
P

Pavel

Новичок
Сообщения
125
Репутация
3
alex33, Garrett, inververs, madmasles, большое спасибо за помощь! Всё работает.

Решение задачи проверки статуса заказа в принципе не критично. Лишним не будет, но если это требует чрезмерного времени, — нафиг.
Пока тему не ставлю решёной. Если времени не найдётся ни у кого, то будем считать решёной.

Чтобы вдруг кто не подумал, что мы тут бота для смс-спама пишем, заранее отвечу: скрипт делается для уведомления клиентов нашего небольшого магазинчика напитков со всего мира (не сочтите за рекламу). Если вдруг кого заинтересует из темы — с меня макс. скидка ;-)
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
madmasles [?]
Я бы так сделал.
Все макросы и так дополняется ведущим нулем, и имхо, StringFormat - здесь вообще не уместна.
Код:
Local $send_dt = StringRight(@YEAR,2) & @MON & @MDAY & @HOUR & @MIN & @SEC & "016+"
 
Верх