image

В этом кратком руководстве от Фила Леггеттера мы рассмотрим, как отправлять и получать SMS в приложении Laravel. Мы реализуем эту возможность, используя Nexmo — платформу облачных коммуникаций, которая предлагает API-интерфейсы для инициализации телефонных номеров, отправки и приема SMS (что мы и будем использовать), а так же для совершения звонков.


Предварительные требования


Нам понадобится учетная запись Nexmo, установленный Nexmo CLI (интерфейс командной строки), а так же ваше предустановленное приложение Laravel. Кроме того, понадобится локальное туннеллирование, что бы служба Nexmo могла сделать HTTP запрос на локальный веб-сервер. Мы рекомендуем ngrok.


Введение


Первым делом мы создадим наше приложение Laravel SMS:
composer create-project --prefer-dist laravel/laravel laravel-sms
cd laravel-sms

Далее, добавим пакет Nexmo Laravel в composer.json:
"require": {
    ...,
    "nexmo/laravel": "dev-master as 1.0",
    "nexmo/client": "dev-master as 1.0"
},

Примечание: когда эти пакеты выйдут из бета-версии, вам нужно всего лишь включить пакет nexmo/laravel, а nexmo/client будет добавлен автоматически в качестве зависимости.

Добавим сервис-провайдер Nexmo в ваш конфигурационный файл app.php:
'providers' => [
    ...,
    Nexmo\Laravel\NexmoServiceProvider::class
]

Примечание: вы так же можете добавить его в aliases, если хотите использовать фасад.

Установим пакеты и скопируем конфигурационный файл Nexmo:
› composer update
php artisan vendor:publish

Наконец, добавьте Nexmo API Key и API Secret в /config/nexmo.php, обновите значения API_KEY и API_SECRET, основываясь на значениях, содержащихся в настройках API в Nexmo Dashboard.
'api_key' => 'API_KEY',
'api_secret' => 'API_SECRET',

Примечание: при желании вы можете объявить значения в .env и env(...).


Отправка SMS


Примечание: для простоты мы добавим весь функционал в app/Http/routes.php.

Добавьте следующий маршрут в app/Http/routes.php:
Route::get('/sms/send/{to}', function(\Nexmo\Client $nexmo, $to){
    $message = $nexmo->message()->send([
        'to' => $to,
        'from' => '@leggetter',
        'text' => 'Sending SMS from Laravel. Woohoo!'
    ]);
    Log::info('sent message: ' . $message['message-id']);
});

Стоит отметить, что в приведенном коде from содержит значение @leggetter. Это сработает в Великобритании, но не в других странах.

image


Для тех из вас, кому нужно использовать реальный номер, давайте рассмотрим использование существующего номера, а так же его покупку.


Листинг, поиск и аренда номеров


Одной из предпосылок для этого урока был Nexmo CLI. Мы можем использовать его для множества действий, в том числе для работы с телефонными номерами (виртуальными номерами, если быть точным), которые связаны с нашей учетной записью. Если вы еще не сделали этого, вы должны установить и настроить CLI, где API_KEY и API_SECRET должны быть заменены учетными данными API, которые использовались ранее:
› npm install -g nexmo-cli
nexmo setup API_KEY API_SECRET

Теперь мы можем просмотреть доступные номера, которые мы уже арендовали, искать номера, доступные для аренды, а так же арендовать или отменить аренду определенного номера. Давайте начнем с того, что посмотрим на список номеров, которые уже доступны на нашей учетной записи:
› nexmo number:list
14155550123

В приведенном выше примере у меня есть номер. Если у вас нет номера, вы можете произвести поиск по номерам для аренды. Все, что вам необходимо для этого знать — это два символа кода страны в формате ISO 3166-1 alpha-2. На самом деле, это проще, чем кажется. Например, для Великобритании это GB, а для Соединенных Штатов — US (прим. пер.: а для России — RU). Давайте найдем номер для аренды в США:
› nexmo number:search US
14155550111
14155550222
14155550333

Если у вас нет номера, вы должны его купить, после чего вы сможете отправлять и получать SMS в тех странах, которые требуют реального исходящего номера.
› nexmo number:buy 14155550111 --confirm
Number purchased: 14155550111


Отправка SMS, наконец-то!


Теперь вам необходимо обновить код, что бы использовать только что купленный номер. Для этого нужно изменить значение from на env('NEXMO_NUMBER'), как на примере ниже:
Route::get('/sms/send/{to}', function(\Nexmo\Client $nexmo, $to){
    $message = $nexmo->message()->send([
        'to' => $to,
        'from' => env('NEXMO_NUMBER'),
        'text' => 'Sending SMS from Laravel. Woohoo!'
    ]);
    Log::info('sent message: ' . $message['message-id']);
});

Затем запустите сервер:
› php artisan serve
Laravel development server started on http://localhost:8000/

И перейдите к http://localhost:8000/sms/send/YOUR_NUMBER, где YOUR_NUMBER должен быть заменен на реальный номер, включая код страны, в формате E.164, т.е. в том же формате, который был показан во всех приведенных выше примерах.

В файле storage/logs/laravel.log вы увидите запись лога, относящуюся к сообщению, которое только что было отправлено, включая уникальный идентификатор сообщения в конце записи, например:
[2016-08-02 13:45:01] local.INFO: sent message: 03000000068F5D97


Приём входящего SMS


Для того, что бы наше приложение могло получать входящие SMS, нам необходимо выполнить несколько действий:
  1. Убедитесь, что приложение видно для Nexmo через локальный туннель
  2. Создайте маршрут для получения SMS
  3. Отключите CSRF для маршрута, получающего SMS
  4. Сообщите Nexmo, по какому маршруту вызывать вебхук при получении сообщения


Начнем с того, что дадим платформе Nexmo доступ к нашему приложению через локальный туннель. Если предположить, что вы используете ngrok и ваш веб-сервер Laravel прослушивает порт 8000, вы можете сделать это следующим образом:
› ngrok http 8000
ngrok by @inconshreveable                                                (Ctrl+C to quit)

Tunnel Status                 online
Version                       2.1.3
Region                        United States (us)
Web Interface                 http://127.0.0.1:4041
Forwarding                    http://814882e9.ngrok.io -> localhost:8000
Forwarding                    https://814882e9.ngrok.io -> localhost:8000

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

Выше вы можете увидеть, что поддомен на ngrok был успешно создан и теперь любые запросы к нему будут туннелироваться на наш локальный хост localhost:8000.

Теперь необходимо создать маршрут для получения SMS в файле routes.php:
Route::post('/sms/receive', function(\Nexmo\Client $nexmo){
});


По умолчанию Laravel не пропустит POST запросы на этот маршрут без CSRF токена. Так как запрос на этот маршрут будет сделан Nexmo, у которого нет токена, нам необходимо отключить CSRF для этого маршрута. Добавьте в App/Http/Middleware/VerifyCsrfToken.php следующее:
protected $except = [
    '/sms/receive'
];

И, наконец, давайте сообщим Nexmo, по какому маршруту сделать вызов вебхука, когда будет получено SMS. Мы можем сделать это с помощью Nexmo CLI. При выполнении следующей команды вы должны использовать номер телефона, который вы арендовали, а так же ваш поддомен ngrok:
› nexmo link:sms 14155550111 https://814882e9.ngrok.io/sms/receive
Number updated

При выполнении этой команды, служба Nexmo попытается вызвать ваш маршрут /sms/receive, и вы должны увидеть запрос в терминале ngrok:
HTTP Requests
-------------

POST /sms/receive              200 OK


Клиентская библиотека Nexmo PHP предоставляет возможность с легкостью захватывать параметры HTTP, которые были отправлены от Nexmo приложению Laravel и создавать объект входящего сообщения InboundMessage, с которым мы можем работать. Обновите код маршрута /sms/receive следующим образом:
Route::post('/sms/receive', function(\Nexmo\Client $nexmo){
    $message = \Nexmo\Message\InboundMessage::createFromGlobals();
    Log::info('got text: ' . $message->getBody());
});

После этого отправьте SMS на арендованный номер и проверьте storage/logs/laravel.log, в логе должно находиться отправленное вами сообщение.
[2016-08-02 13:45:01] local.INFO: sent message: 03000000068F5D97  
[2016-08-02 14:20:50] local.INFO: sent message: 0300000006917797  
[2016-08-02 14:21:17] local.INFO: got text: Sending one back.


image



Автоматический ответ на входящее SMS


И, наконец, давайте создадим автоответчик для входящего сообщения. Клиент Nexmo PHP обеспечивает хороший способ сделать это с помощью функции InboundMessage->createReply:
Route::post('/sms/receive', function(\Nexmo\Client $nexmo){
    $message = \Nexmo\Message\InboundMessage::createFromGlobals();
    Log::info('got text: ' . $message->getBody());
    $reply =$nexmo->message()->send($message->createReply('Laravel Auto-Reply FTW!'));
    Log::info('sent reply: ' . $reply['message-id']);
});

Отправьте сообщение на арендованный номер и вы получите автоматический ответ. Это ведь почти магия!

image



Заключение


В этом уроке мы рассмотрели все, что вам нужно знать, чтобы реализовать отправку и получение SMS, и даже автоматический ответ на SMS, в приложении Laravel с использованием платформы облачных коммуникаций Nexmo.

Вы можете найти код этого урока на github.com/nexmo-community/laravel-sms.
Поделиться с друзьями
-->

Комментарии (18)


  1. softshape
    08.08.2016 07:52
    +1

    К сожалению, ценник от Nexmo (2 рубля за СМС) ставит крест на использовании их API.


    1. Rampages
      08.08.2016 11:51

      Да и что-то про подмену номера ничего не сказано или я пропустил…
      Дорого и нет плюсов перед конкурентами, так и запишем.


  1. Shi
    08.08.2016 07:57

    Теоретически, можно же разобрать текст входящего смс, и на его основе произвести некие действия?


    1. Andrey_Volk
      08.08.2016 09:47
      +1

      Всё верно. Не теоретически, а вполне на практике такое возможно


  1. mihmig
    08.08.2016 09:23

    Все эти сервисы дороги и не надёжны. Сейчас проще купить пакет СМС (у всех операторов есть, цены примерно одинаковы) и отправлять через 3G-модем или смартфон на андроиде.

    Пользуясь случаем хочу спросить — можно ли как-то поймать подтверждение доставки (статус доставлено в смартфоне) — это что — технологическое смс или что-то иное?

    Сейчас конечно пользуемся сервисам web-шлюза, но веры им насчёт статуса особо нет.


    1. lopatoid
      08.08.2016 09:43
      +1

      >и отправлять через 3G-модем или смартфон на андроиде.
      На хабре была статья ребят, которые это делали, и их банили за рассылку.


      1. linakun
        08.08.2016 11:55
        +1

        Подтверждаю. Мы рассылали через старый Sony Ericsson используя собственное ПО и тариф с большим кол-вом СМС. Через день СИМки банились оператором. В итоге перешли на один из сервисов рассылки.


        1. shornikov
          08.08.2016 14:38

          Подскажите, много это сколько?
          Наоборот, хочу уйти от сервиса рассылки.


    1. MakarkinPRO
      08.08.2016 09:47

      Операторы большой тройки API к смс + пакеты (с заключением договора) не предоставляют? Я знаю у Мегафона есть возможность отправлять. но хотелось что-то более официальное.

      Для верификации нашел Twitter DIgits.


      1. palmich
        08.08.2016 10:26

        операторы предоставляют, ценник не сильно гуманный.
        например МТС


        1. MakarkinPRO
          08.08.2016 10:38

          угу… Хотя есть почти или (возможно) вообще безлимитные тарифы для физ. лиц (ну они наверно и созданы, что из них не буду выжимать максимум).

          Было бы круто, если у нас кто-то по 0,1 хотябы начал продавать СМС.


        1. mihmig
          10.08.2016 11:20

          Хм, спасибо за наводку (мы используем МТС-коммуникатор для юрлиц, а для физиков о такой программе не слышал.)
          Осталось только «подсмотреть» https-запросы к серверу. Не подскажете прокси с логгированием и SSL-MITM?


          1. palmich
            10.08.2016 11:32

            к сожалению, не подскажу, не ковыряли.


    1. lopatoid
      08.08.2016 09:50

      Вот тут, в комментариях:
      https://habrahabr.ru/post/305264/


  1. mihmig
    08.08.2016 11:58

    У нас задача немного хитрее:
    Сделать рассылку родителям учеников класса с номера председателя родительского комитета
    Рассматриваем вариант отправки через ЛК (опсос МТС)
    Плюсы: отправка идёт с номера председателя, в то время как симка в его телефоне (а не в GSM-шлюзе или 3G-свистке), он может сразу же принимать звонки от родителей, которые «ничего не поняли, что это за сообщение тут от вас пришло!»

    Но у МТС используется CSRF-токен (сайт вообще номинант конкурса на самый тормознутость и антиюзабильность) — поэтому приходится городить костыли на phantomjs.

    Есть ли ещё какие варианты?


    1. Rampages
      09.08.2016 10:38

      Большинство шлюзов (например sms.ru или epochtasms.ru) предлагают прямые каналы от МТС, Билайн, Мегафон с буквенным идентификаторов (например SHKOLA.RU) вместо номера телефона. Вроде бы можно и номер телефона указать, если подтвердите что он вам принадлежит. Также для этого нужно Юр. лицо и соответственно если вы хотите отправлять от имени какого-то номера, то подозревая, что придется переоформить его на юр.лицо.


    1. palmich
      09.08.2016 14:02

      как вариант, правда, ценник как обычно, не гуманный


  1. pavelklymenko
    11.08.2016 12:24
    +1

    Спасибо автору за предоставленный материал. Для нашего проекта мы, для первой аналогичной интеграции, остановились на Twilio.


    В процессе работы с Twilio мы столкнулись со следующими проблемами (доставка сообщений на локальные номера в Украине):


    • не доставляются сообщения (решается вместе со службой технической поддержки в течение нескольких дней путем перемаршрутизации траффика через альтернативного провайдера, но раз в два/ три месяца проблема появляется снова — нужно мониторить)
    • проблема с презентацией А-номера (в настоящий момент проблема так и не решена. Сообщения, отправленные с платформы Twilio, презентуются не корректно. Решение — ожидать, пока у Twilio появится локальный партнер в Украине, чего, судя по всему, в ближайшее время не предвидится)

    Подскажите, если есть опыт работы, какого рода проблемы возникали с Nexmo? Интересно с точки зрения интеграции с их сервисом.


    Заранее благодарю.