Статьи

Привет, Ларавел? Общение с PHP через SMS!

Эта статья была рецензирована Верной Анчетой . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!


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

Примечание: если вас смущает среда разработки, которую мы используем, это Homestead Improved, и вы можете узнать больше об этом здесь или узнать подробнее, купив нашу книгу о средах PHP .

Векторный icon телефона с наложенным значком погоды

Добавление маршрутов

Чтобы разрешить SMS-общение, нам нужно еще несколько маршрутов. Откройте файл routes/web.php и добавьте в него следующий код:

 Route::group(['prefix' => 'sms', 'middleware' => 'twilio'], function () { Route::post('weather', 'SmsController@showWeather')->name('weather'); }); 

Префикс для маршрута — это sms , поэтому маршруты будут иметь такой же путь, как /sms/weather , как показано в примере. Это единственный маршрут, который нам нужен для SMS, так как Twilio будет повторять один и тот же маршрут снова и снова. Twilio получит к нему доступ через HTTP POST . Мы могли бы также сделать это без префикса, но это более гибкий способ, если мы решим добавить больше функциональности стороне SMS позже.

Сервисный уровень

Далее мы изменим сервис, который мы написали ранее. Откройте файл app/Services/WeatherService.php и удалите текущий метод getWeather , а затем замените его следующим:

  public function getWeather($zip, $dayName, $forSms = false) { $point = $this->getPoint($zip); $tz = $this->getTimeZone($point); $forecast = $this->retrieveNwsData($zip); $ts = $this->getTimestamp($dayName, $zip); $tzObj = new \DateTimeZone($tz->timezoneId); $tsObj = new \DateTime(null, $tzObj); $tsObj->setTimestamp($ts); foreach ($forecast->properties->periods as $k => $period) { $startTs = strtotime($period->startTime); $endTs = strtotime($period->endTime); if ($ts > $startTs and $ts < $endTs) { $day = $period; break; } } $weather = $day->name; $weather .= ' the ' . $tsObj->format('jS') . ': '; $response = new Twiml(); if ($forSms) { $remainingChars = 140 - strlen($weather); if (strlen($day->detailedForecast) > $remainingChars) { $weather .= $day->shortForecast; $weather .= '. High of ' . $day->temperature . '. '; $weather .= $day->windDirection; $weather .= ' winds of ' . $day->windSpeed; } else { $weather .= $day->detailedForecast; } $response->message($weather); } else { $weather .= $day->detailedForecast; $gather = $response->gather( [ 'numDigits' => 1, 'action' => route('day-weather', [], false) ] ); $menuText = ' '; $menuText .= "Press 1 for Sunday, 2 for Monday, 3 for Tuesday, "; $menuText .= "4 for Wednesday, 5 for Thursday, 6 for Friday, "; $menuText .= "7 for Saturday. Press 8 for the credits. "; $menuText .= "Press 9 to enter in a new zipcode. "; $menuText .= "Press 0 to hang up."; $gather->say($weather . $menuText); } return $response; } 

Эта функция очень похожа на старую. Единственное отличие состоит в том, что он принимает во внимание, что запрос погоды может поступать с телефонного устройства с помощью SMS, поэтому он гарантирует, что прогноз погоды не слишком длинный, и пытается ограничить его до менее 140 символов. Ответ на SMS по-прежнему TwiML, только что отформатированный для SMS .

контроллер

Создайте файл с именем SmsController.php в SmsController.php app/Http/Controllers и поместите в него следующий код:

 <?php namespace App\Http\Controllers; use App\Services\WeatherService; use Illuminate\Http\Request; use Twilio\Twiml; class SmsController extends Controller { protected $weather; public function __construct(WeatherService $weatherService) { $this->weather = $weatherService; } public function showWeather(Request $request) { $parts = $this->parseBody($request); switch ($parts['command']) { case 'zipcode': $zip = $parts['data']; $request->session()->put('zipcode', $zip); $response = $this->weather->getWeather($zip, 'Today', true); break; case 'day': $zip = $request->session()->get('zipcode'); $response = $this->weather->getWeather($zip, $parts['data'], true); break; case 'credits': $response = new Twiml(); $response->message($this->weather->getCredits()); break; default: $response = new Twiml(); $text = 'Type in a zipcode to get the current weather. '; $text .= 'After that, you can type the day of the week to get that weather.'; $response->message($text); break; } return $response; } private function parseBody($request) { $ret = ['command' => '']; $body = trim($request->input('Body')); if (is_numeric($body) and strlen($body) == 5) { $ret['command'] = 'zipcode'; $ret['data'] = $body; } if (in_array(ucfirst(strtolower($body)), $this->weather->daysOfWeek) !== false) { $ret['command'] = 'day'; $ret['data'] = ucfirst(strtolower($body)); } if (strtolower($body) == 'credits') { $ret['command'] = 'credits'; } return $ret; } } 

Когда приходит SMS-сообщение от пользователя, Twilio всегда будет идти по одному и тому же маршруту. Это приложение не имеет перенаправлений. Вот почему мы определили только один маршрут, то есть все запросы будут проходить через метод showWeather . Пользователь может отправлять текстовые сообщения в приложении parseBody , поэтому мы проанализируем тело запроса, чтобы выяснить, чего они хотят, используя метод parseBody .

Метод parseBody сначала создает возвращаемое значение по умолчанию. Затем он удаляет пробелы. Это делается для того, чтобы, если пользователь вводит «90210» (обратите внимание на пробел), программа все равно будет работать как положено. После удаления пробела тело текста сравнивается с тремя операторами if . Первый оператор if проверяет, ввел ли пользователь почтовый индекс. Второй оператор if проверяет, введен ли пользователь в день недели. Он нормализует ввод, проверяя, что только первая буква $daysOfWeek заглавной буквы, и сравнивает его с содержимым $daysOfWeek массива $daysOfWeek в классе WeatherService чтобы определить, был ли указан день недели. Последний оператор if проверяет, запрашивал ли пользователь кредиты. Если ни один из трех операторов if true то программа не может понять, чего хочет пользователь, и вернет значение по умолчанию. Это значение по умолчанию заставит метод weather отправлять пользователю справочное сообщение, объясняющее, как использовать приложение.

Метод parseBody возвращает массив с двумя ключами. Ключ command — это то, что было определено намерением пользователя. Ключ data — это данные, которые идут вместе с командой. Внутри метода showWeather , после parsebody , оператор switch используется для просмотра значения ключа массива command .

Если анализатор определяет, что пользователь отправил текстовый почтовый индекс, мы сохраняем почтовый индекс в сеансе и возвращаем сегодняшний прогноз для этого почтового индекса. Пример ответа TwiML выглядит следующим образом:

 <?xml version="1.0" encoding="UTF-8"?> <Response> <Message>This Afternoon the 31st: Sunny, with a high near 72. South southwest wind around 8 mph. </Message> </Response> 

Если определено, что день недели был введен, то прогноз на этот день возвращается. Пример ответа TwiML выглядит следующим образом:

 <?xml version="1.0" encoding="UTF-8"?> <Response> <Message>Monday the 3rd: Sunny, with a high near 70. </Message> </Response> 

Если анализатор определяет запрашиваемые кредиты, приложение возвращает ответ TwiML с кредитами:

 <?xml version="1.0" encoding="UTF-8"?> <Response> <Message>Weather data provided by the National Weather Service. Zipcode data provided by GeoNames. </Message> </Response> 

Если синтаксический анализатор не может определить намерение пользователя, то возвращается сообщение справки с этим TwiML:

 <?xml version="1.0" encoding="UTF-8"?> <Response> <Message>Type in a zipcode to get the current weather. After that, you can type the day of the week to get that weather. </Message> </Response> 

Twilio

Войдите в свою учетную запись Twilio и перейдите к настройкам своего номера телефона. Вы можете увидеть свой номер, перейдя на эту страницу . В разделе SMS http://NGROK_HOST/sms/weather URL-адрес в следующем формате: http://NGROK_HOST/sms/weather , где NGROK_HOST — это имя хоста в URL-адресе, который вы отметили в программе Ngrok.

Изображение веб-страницы на Twilio

Использование приложения

Откройте приложение обмена текстовыми сообщениями на своем телефоне и отправьте почтовый индекс, например 92010 на свой номер телефона Twilio. Через пару секунд вы получите ответ с сегодняшним прогнозом.

Изображение приложения iPhone для SMS с погодой введенного почтового индекса

Далее вы можете отправить день недели на номер, и он ответит прогнозом на этот день.

Изображение приложения iPhone для SMS с погодой за указанный день

Вы также можете отправить слово credits и он вернет кредиты.

Изображение приложения iPhone для SMS с кредитами для приложения

Если вы вводите команду, которую приложение погоды не понимает, оно возвращает текст справки.

Изображение приложения для iPhone с поддержкой погоды

Вывод

В двух статьях мы увидели, как создать приложение, способное взаимодействовать с пользователями через систему голосового телефона с помощью голосовых меню и взаимодействовать с ними с помощью SMS. Это было реализовано с использованием Laravel для серверной части приложения и Twilio для интеграции телефон / SMS. Написав немного больше кода, мы увидели, что можно расширить голосовое приложение, чтобы те же функции были доступны пользователям через SMS.

Вы можете найти пример кода для этой серии статей на Github .

Существует множество возможностей для приложений, которые вы можете реализовать с помощью Twilio и PHP, это лишь небольшое представление о том, что можно сделать. Проверьте документацию здесь для вдохновения.