bisquare与lar_哈Lar 通过电话与PHP通信!

bisquare与lar

Vector icon of smartphone with weather icon overlay

Twilio is a SaaS application which enables developers to build telephone applications using web technologies. In this two-part series, we will leverage Twilio to build a weather forecast app that is accessed using the telephone system. The backend will be written with the Laravel framework (an exploratory video course is available for purchase here.

Twilio是SaaS应用程序,使开发人员可以使用Web技术构建电话应用程序。 在这个由两部分组成的系列文章中,我们将利用Twilio构建一个天气预报应用程序,该应用程序可以使用电话系统进行访问。 后端将使用Laravel框架编写(可在此处购买探索性视频课程。

In this part, we will create a simple program that will allow a user to call a phone number that we buy from Twilio, enter a zipcode, and receive the current weather forecast. The user can also get the weather for any day of the week via the voice menu prompts. In the second part of this series, we will leverage what was built in this article to allow the user to interact with the app via SMS (text message).

在这一部分中,我们将创建一个简单的程序,该程序将允许用户拨打从Twilio购买的电话号码,输入邮政编码,并接收当前的天气预报。 用户还可以通过语音菜单提示获取一周中任何一天的天气。 在本系列的第二部分中,我们将利用本文中构建的内容,允许用户通过SMS(文本消息)与应用程序进行交互。

先决条件 (Prerequisites)

开发环境 (Development Environment)

This article assumes Homestead Improved is installed. It is not necessary to use it, but the commands might differ slightly if you use a different environment. If you are not familiar with Homestead and want to produce similar results as this article aims to produce, please visit this SitePoint article that shows how to set up Homestead, and if you need a crash course in Vagrant, please see this post. Additionally, if this whets your appetite and you feel like exploring PHP development environments in depth, we have a book about that available for purchase.

本文假定已安装Homestead Enhanced 。 不必使用它,但是如果您使用其他环境,则命令可能会略有不同。 如果您不熟悉Homestead并想产生与本文旨在产生的结果相似的结果,请访问 SitePoint文章,其中显示了如何设置Homestead,并且如果您需要在Vagrant中学习速成班,请参阅本文 。 另外,如果这激起了您的胃口,并且您想深入探索PHP开发环境,那么我们会提供一本有关该书的书供您购买

依存关系 (Dependencies)

We will create a new Laravel project and then add the Twilio PHP SDK and Guzzle HTTP client library to the project:

我们将创建一个新的Laravel项目,然后将Twilio PHP SDK和Guzzle HTTP客户端库添加到该项目:

cd ~/Code
composer create-project --prefer-dist laravel/laravel Laravel 5.4.*
cd Laravel
composer require "twilio/sdk:^5.7"
composer require "guzzlehttp/guzzle:~6.0"

发展历程 (Development)

Let’s go through all the steps, one by one.

让我们一步一步地完成所有步骤。

路线 (Routes)

Open up the routes/web.php file and add the following ones:

打开routes/web.php文件并添加以下内容:

Route::group(['prefix' => 'voice', 'middleware' => 'twilio'], function () {
    Route::post('enterZipcode', 'VoiceController@showEnterZipcode')->name('enter-zip');

    Route::post('zipcodeWeather', 'VoiceController@showZipcodeWeather')->name('zip-weather');

    Route::post('dayWeather', 'VoiceController@showDayWeather')->name('day-weather');

    Route::post('credits', 'VoiceController@showCredits')->name('credits');
});

In this app, all requests will be under the /voice path. When Twilio first connects to the app, it will go to /voice/enterZipcode via HTTP POST. Depending on what happens in the telephone call, Twilio will make requests to other endpoints. This includes /voice/zipcodeWeather for providing today’s forecast, /voice/dayWeather, for providing a particular day’s forecast, and /voice/credits for providing information on where the data came from.

在此应用中,所有请求都将在/voice路径下。 当Twilio首次连接到应用程序时,它将通过HTTP POST转到/voice/enterZipcode 。 根据电话中发生的情况,Twilio将向其他端点发出请求。 其中包括/voice/zipcodeWeather用于提供今天的天气预报, /voice/dayWeather用于提供特定一天的天气预报,以及/voice/credits用于提供有关数据来源的信息。

服务层 (Service Layer)

We are going to add a service class. This class will hold a lot of the business logic that will be shared between the voice telephone app and the SMS app.

我们将添加一个服务类。 此类将包含许多将在语音电话应用程序和SMS应用程序之间共享的业务逻辑。

Create a new sub-folder called Services inside the app folder. Then, create a file called WeatherService.php and put the following content into it:

app文件夹中创建一个名为“ Services的新子文件夹。 然后,创建一个名为WeatherService.php的文件,并将以下内容放入其中:

<?php

namespace App\Services;

use Illuminate\Support\Facades\Cache;
use Twilio\Twiml;

class WeatherService
{
}

This is a large file in the project, so we will build it piece by piece. Put the following pieces of code in this section inside our new service class:

这是项目中的一个大文件,因此我们将逐步构建它。 在本节中,将以下代码片段放入我们的新服务类中:

public $daysOfWeek = [
        'Today',
        'Sunday',
        'Monday',
        'Tuesday',
        'Wednesday',
        'Thursday',
        'Friday',
        'Saturday'
    ];

We will use this array to map a day of the week to a number; Sunday = 1, Monday = 2, etc.

我们将使用该数组将一周中的某天映射到一个数字; 星期日= 1,星期一= 2,依此类推。

public function getWeather($zip, $dayName)
    {

        $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;
            }
        }

        $response = new Twiml();

        $weather = $day->name;
        $weather .= ' the ' . $tsObj->format('jS') . ': ';
        $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;
    }

The getWeather method takes a zipcode with the day of the week and crafts the text of a weather forecast. First, it figures out the reference time for the day requested, and then looks up the weather forecast by doing a foreach over the array of forecast data. After that, it returns a Voice TwiML response. Below is a sample of what is returned:

getWeather方法采用星期几中的邮政编码,并编制天气预报的文本。 首先,它计算出所请求的一天的参考时间,然后通过对预报数据数组进行搜索来查找天气预报。 之后,它将返回语音TwiML响应。 以下是返回的示例:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="1" action="/voice/dayWeather">
    <Say>
      This Afternoon the 31st: Sunny, with a high near 72. South southwest wind around 8 mph. Press 1 for Sunday, 2 for Monday, 3 for Tuesday, 4 for Wednesday, 5 for Thursday, 6 for Friday, 7 for Saturday. Press 8 for the credits. Press 9 to enter in a new zipcode. Press 0 to hang up.
    </Say>
  </Gather>
</Response>

The <Gather> tag tells Twilio to expect input from the user’s keypad. The numDigits attribute says how many digits to expect. The action attribute says what endpoint to contact next.

<Gather>标签告诉Twilio期望来自用户键盘的输入。 numDigits属性表示期望的位数。 action属性说明下一步要联系的端点。

protected function retrieveNwsData($zip)
    {
        return Cache::remember('weather:' . $zip, 60, function () use ($zip) {
            $point = $this->getPoint($zip);

            $point = $point->lat . ',' . $point->lng;
            $url = 'https://api.weather.gov/points/' . $point . '/forecast';

            $client = new \GuzzleHttp\Client();

            $response = $client->request('GET', $url, [
                'headers' => [
                    'Accept' => 'application/geo+json',
                ]
            ]);

            return json_decode((string)$response->getBody());
        });
    }

The retrieveNwsData method gets the weather forecast data. First, the method checks to see if a copy of the zipcode’s weather forecast is in cache. If not, then the Guzzle HTTP client is used to make an HTTP GET request to the National Weather Service’s (NWS) API endpoint https://api.weather.gov/points/{point}/forecast. To get the geographic point of the zipcode, a call is made to the getPoint method before doing the request to the weather API. The response from the API endpoint is the weather forecast in GeoJSON format. The forecast is for every day and night for a week (with some exceptions we will discuss later); 14 entries in all. We cache the API response for an hour because making the request is slow, plus we do not want to hit the government servers too frequently and get banned.

retrieveNwsData方法获取天气预报数据。 首先,该方法检查以查看邮政编码的天气预报副本是否在缓存中。 如果不是,则使用Guzzle HTTP客户端向国家气象局(NWS) API端点https://api.weather.gov/points/{point}/forecast发出HTTP GET请求。 要获取邮政编码的地理位置,请在对天气API进行请求之前先调用getPoint方法。 API端点的响应是GeoJSON格式的天气预报。 该预测是针对一周中每天晚上的预报(某些例外情况我们将在后面讨论); 总共14个条目。 我们将API响应缓存了一个小时,因为发出请求的速度很慢,而且我们不想太频繁地访问政府服务器并被禁止。

protected function getPoint($zip)
    {
        return Cache::remember('latLng:' . $zip, 1440, function () use ($zip) {
            $client = new \GuzzleHttp\Client();
            $url = 'http://api.geonames.org/postalCodeSearchJSON';

            $response = $client->request('GET', $url, [
                'query' => [
                    'postalcode' => $zip,
                    'countryBias' => 'US',
                    'username' => env('GEONAMES_USERNAME')
                ]
            ]);

            $json = json_decode((string)$response->getBody());

            return $json->postalCodes[0];
        });
    }

The getPoint method maps a zipcode to a geographic point. This is done by using the GeoNames API. The results are cached for a day because using the API is slow.

getPoint方法将邮政编码映射到一个地理点。 这是通过使用GeoNames API完成的。 由于使用API​​的速度很慢,结果会被缓存一天。

protected function getTimeZone($point)
    {
        $key = 'timezone:' . $point->lat . ',' . $point->lng;

        return Cache::remember($key, 1440, function () use ($point) {
            $client = new \GuzzleHttp\Client();
            $url = 'http://api.geonames.org/timezoneJSON';

            $response = $client->request('GET', $url, [
                'query' => [
                    'lat' => $point->lat,
                    'lng' => $point->lng,
                    'username' => env('GEONAMES_USERNAME')
                ]
            ]);

            return json_decode((string) $response->getBody());
        });
    }

The getTimeZone method is used to get the timezone that a geographic point resides inside. The GeoNames API is also used and the results are cached for a day for the same reasons.

getTimeZone方法用于获取地理位置所在的时区。 出于相同的原因,还使用GeoNames API,并且将结果缓存一天。

protected function getTimestamp($day, $zip)
    {
        $point = $this->getPoint($zip);
        $tz = $this->getTimeZone($point);

        $tzObj = new \DateTimeZone($tz->timezoneId);

        $now = new \DateTime(null, $tzObj);

        $hourNow = $now->format('G');
        $dayNow = $now->format('l');

        if ($day == $dayNow and $hourNow >= 18) {
            $time = new \DateTime('next ' . $day . ' noon', $tzObj);
            $ts = $time->getTimestamp();
        } elseif (($day == 'Today' or $day == $dayNow) and $hourNow >= 6) {
            $ts = $now->getTimestamp();
        } else {
            $time = new \DateTime($day . ' noon', $tzObj);
            $ts = $time->getTimestamp();
        }

        return $ts;
    }

The getTimestamp method returns a reference time that is used to look up a forecast for a particular date. Most of the time, the forecast data has a day and night forecast, but sometimes it has an overnight (before 6 am), and an afternoon forecast (the afternoon, before 6 pm) for the current day. Because of this, we have to do some calculations to get a good reference timestamp. In most cases, it returns the zipcode’s noon time for the day requested.

getTimestamp方法返回一个参考时间,该参考时间用于查找特定日期的预测。 在大多数情况下,预测数据具有白天和黑夜的预测,但是有时它具有当日的隔夜(上午6点之前)和下午的预测(下午下午6点之前)。 因此,我们必须进行一些计算才能获得良好的参考时间戳。 在大多数情况下,它将返回所请求日期的邮政编码中午时间。

public function getCredits()
    {
        $credits = "Weather data provided by the National Weather Service. ";
        $credits .= "Zipcode data provided by GeoNames.";

        return $credits;
    }
}

The getCredits method just returns some standard text about where the data came from.

getCredits方法仅返回有关数据来源的一些标准文本。

控制者 (Controller)

Create the file VoiceController.php in the app/Http/Controllers folder and put the following code into it:

app/Http/Controllers文件夹中创建文件VoiceController.php ,并将以下代码放入其中:

<?php

namespace App\Http\Controllers;

use App\Services\WeatherService;
use Illuminate\Http\Request;
use Twilio\Twiml;

class VoiceController extends Controller
{
    protected $weather;

    public function __construct(WeatherService $weatherService)
    {
        $this->weather = $weatherService;
    }

    public function showEnterZipcode()
    {
        $response = new Twiml();

        $gather = $response->gather(
            [
                'numDigits' => 5,
                'action' => route('zip-weather', [], false)
            ]
        );

        $gather->say('Enter the zipcode for the weather you want');

        return $response;
    }

    public function showZipcodeWeather(Request $request)
    {
        $zip = $request->input('Digits');

        $request->session()->put('zipcode', $zip);

        return $this->weather->getWeather($zip, 'Today');
    }

    public function showDayWeather(Request $request)
    {
        $digit = $request->input('Digits', '0');

        switch ($digit) {
            case '8':
                $response = new Twiml();
                $response->redirect(route('credits', [], false));
                break;
            case '9':
                $response = new Twiml();
                $response->redirect(route('enter-zip', [], false));
                break;
            case '0':
                $response = new Twiml();
                $response->hangup();
                break;
            default:
                $zip = $request->session()->get('zipcode');
                $day = $this->weather->daysOfWeek[$digit];
                $response = $this->weather->getWeather($zip, $day);
                break;
        }

        return $response;
    }

    public function showCredits()
    {
        $response = new Twiml();
        $credits = $this->weather->getCredits();

        $response->say($credits);
        $response->hangup();

        return $response;
    }
}

The showEnterZipcode method is executed when a request is made to the /voice/enterZipcode endpoint. This method returns TwiML that asks the caller to enter a zipcode. The TwiML also says a request to /voice/zipcodeWeather should be made when the caller has entered 5 digits. Here is a sample response:

当对/voice/enterZipcode端点发出请求时,将执行showEnterZipcode方法。 此方法返回TwiML,要求调用者输入邮政编码。 TwiML还说,当呼叫者输入5位数字时,应该向/voice/zipcodeWeather请求。 这是一个示例响应:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="5" action="/voice/zipcodeWeather">
    <Say>
      Enter the zipcode for the weather you want
    </Say>
  </Gather>
</Response>

The showZipcodeWeather method is executed when a request is made to the /voice/zipcodeWeather endpoint. This method returns the text of today’s forecast and a voice menu to navigate the app in TwiML format. Below is what a response looks like:

当对/voice/zipcodeWeather端点发出请求时,将执行showZipcodeWeather方法。 此方法返回今天的天气预报文本和语音菜单,以TwiML格式导航应用程序。 以下是响应的样子:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="1" action="/voice/dayWeather">
    <Say>
      This Afternoon the 31st: Sunny, with a high near 72. South southwest wind around 8 mph. Press 1 for Sunday, 2 for Monday, 3 for Tuesday, 4 for Wednesday, 5 for Thursday, 6 for Friday, 7 for Saturday. Press 8 for the credits. Press 9 to enter in a new zipcode. Press 0 to hang up.
    </Say>
  </Gather>
</Response>

When the /voice/dayWeather endpoint is requested, the showDayWeather method is executed. This returns the forecast for the day requested and a voice menu to navigate the app in TwiML format. The response for a Monday might look like this:

当请求/voice/dayWeather端点时,将执行showDayWeather方法。 这将返回所请求日期的预测以及语音菜单,以TwiML格式导航该应用程序。 星期一的响应可能如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Gather numDigits="1" action="/voice/dayWeather">
    <Say>
      Monday the 3rd: Sunny, with a high near 70. Press 1 for Sunday, 2 for Monday, 3 for Tuesday, 4 for Wednesday, 5 for Thursday, 6 for Friday, 7 for Saturday. Press 8 for the credits. Press 9 to enter in a new zipcode. Press 0 to hang up.
    </Say>
  </Gather>
</Response>

The last method, showCredits, is executed when the /voice/credits endpoint is requested. The TwiML response has the credits and an instruction to hang up. A response would look like this:

当请求/voice/credits端点时,执行最后一个方法showCredits 。 TwiML响应具有功劳和挂断指令。 响应如下所示:

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

中间件 (Middleware)

By default, Twilio makes requests to webhooks using HTTP POST. Because of this, Laravel requires that the POST submission have a CSRF token. In our case, we will not be using the CSRF token, so we must disable the middleware that checks for one. In the app/Http/Kernel.php file, remove or comment the line \App\Http\Middleware\VerifyCsrfToken::class,.

默认情况下,Twilio使用HTTP POST向Webhooks发送请求。 因此,Laravel要求POST提交具有CSRF令牌。 在我们的例子中,我们将不使用CSRF令牌,因此我们必须禁用检查1的中间件。 在app/Http/Kernel.php文件中,删除或注释\App\Http\Middleware\VerifyCsrfToken::class,

In another section, we will setup Ngrok – an application that will allow the internet to connect to our local environment. Because the app does not have CSRF protection any more, anyone on the internet will able to hit our endpoints. To make sure requests are coming from either Twilio, or from the unit tests, we have to create a custom middleware. We will use a middleware suggested in the Twilio docs, but modified to work with our setup.

在另一部分中,我们将设置Ngrok –一个允许Internet连接到我们本地环境的应用程序。 由于该应用程序不再具有CSRF保护,因此互联网上的任何人都可以访问我们的端点。 为了确保来自Twilio或单元测试的请求,我们必须创建一个自定义的中间件。 我们将使用Twilio文档中建议的中间件,但已对其进行了修改以适合我们的设置。

In the app/Http/Kernel.php file, add the following line to the end of the $routeMiddleware array:

app/Http/Kernel.php文件中, app/Http/Kernel.php添加到$routeMiddleware数组的末尾:

'twilio' => \App\Http\Middleware\TwilioRequestValidator::class,

Create a file called TwilioRequestValidator.php in the app/Http/Middleware folder and paste the following code into it:

app/Http/Middleware文件夹中创建一个名为TwilioRequestValidator.php的文件,并将以下代码粘贴到其中:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Response;
use Twilio\Security\RequestValidator;

class TwilioRequestValidator
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (env('APP_ENV') === 'test') {
            return $next($request);
        }

        $host = $request->header('host');
        $originalHost = $request->header('X-Original-Host', $host);

        $fullUrl = $request->fullUrl();

        $fullUrl = str_replace($host, $originalHost, $fullUrl);

        $requestValidator = new RequestValidator(env('TWILIO_APP_TOKEN'));

        $isValid = $requestValidator->validate(
            $request->header('X-Twilio-Signature'),
            $fullUrl,
            $request->toArray()
        );

        if ($isValid) {
            return $next($request);
        } else {
            return new Response('You are not Twilio :(', 403);
        }
    }
}

With each request that Twilio makes, it sends an HMAC computed with the URL and request variables as the data and the Twilio Auth Token as the secret key. This HMAC is sent in the X-Twilio-Signature request header. We can compare the X-Twilio-Signature sent in the request with an HMAC that we generate on the web server. This is done using the validate() method on the $requestValidator object.

对于Twilio发出的每个请求,它都会发送一个以URL和请求变量作为数据,并以Twilio Auth Token作为密钥计算出的HMAC 。 该HMAC在X-Twilio-Signature请求标头中发送。 我们可以将请求中发送的X-Twilio-Signature与在Web服务器上生成的HMAC进行比较。 这是使用$requestValidator对象上的validate()方法完成的。

Go to the Twilio Console Dashboard at https://www.twilio.com/console. Once there, unhide the AUTH TOKEN and take note of it.

转到位于https://www.twilio.com/console的Twilio控制台仪表板。 到达那里后,取消隐藏AUTH TOKEN并记下它。

Photo of Twilio console dashboard page

Then, open up the .env file and then append the following code to the end of the file.

然后,打开.env文件,然后将以下代码附加到文件末尾。

TWILIO_APP_TOKEN=YOUR_AUTH_TOKEN_HERE

Don’t forget to replace YOUR_AUTH_TOKEN_HERE with the value you took note of on the dashboard.

不要忘记用在仪表板上记下的值替换YOUR_AUTH_TOKEN_HERE

Because of how Ngrok works, it changes the host request header from what the original client defined (something like abc123.ngrok.io) to the host which we specified. In this case it will be homestead.app. We need to change the URL to take this into consideration to compute the correct HMAC. The middleware is skipped if it is determined that there are unit tests being run.

由于Ngrok的工作方式,它将host请求标头从原始客户端定义的内容(如abc123.ngrok.io )更改为我们指定的主机。 在这种情况下,它将是homestead.app 。 我们需要更改URL以考虑到这一点,以计算正确的HMAC。 如果确定正在运行单元测试,则跳过中间件。

地名 (GeoNames)

To be able to use the GeoNames API to do the zipcode and timezone queries, we must create a free account. After that, we must enable the ability to use the API by visiting the manage account page.

为了能够使用GeoNames API进行邮政编码和时区查询,我们必须创建一个免费帐户 。 之后,我们必须通过访问管理帐户页面启用使用API​​的功能。

Once registered, open your .env file and add the variable GEONAMES_USERNAME with the value being your GeoNames username.

注册后,打开您的.env文件,并添加变量GEONAMES_USERNAME ,其值为您的GeoNames用户名。

恩格罗克 (Ngrok)

Twilio requires your app to be accessible from the internet because Twilio calls the webhooks you implement. With the default design of Homestead, the web server is only available to your local machine. To get around this limitation, we use Ngrok. This program allows you to get an FQDN that works on the internet and forwards the traffic for that address to your Homestead instance, using a tunnel.

Twilio要求您的应用程序可以从Internet访问,因为Twilio调用您实现的webhook。 使用Homestead的默认设计,Web服务器仅可用于本地计算机。 为了解决这个限制,我们使用Ngrok 。 该程序允许您获取一个可以在Internet上运行的FQDN,并使用隧道将该地址的流量转发到您的Homestead实例。

To use Ngrok, you must first sign up for a free account. After that, download and install Ngrok. Once the app is installed, be sure to install the authtoken as per the Get Started documentation. Next, we will start up the tunnel:

要使用Ngrok,您必须首先注册一个免费帐户 。 之后,下载并安装Ngrok。 安装该应用程序后,请务必按照入门文档安装authtoken 。 接下来,我们将启动隧道:

./ngrok http 192.168.10.10:80 -host-header=homestead.app

This tunnel will allow incoming requests from the internet to be received by our local server. Homestead expects the host HTTP header to be homestead.app. The Ngrok command we used will copy the HTTP request’s original host header to the X-Original-Host header and then overwrites host with the value homestead.app.

该隧道将允许本地服务器接收来自Internet的传入请求。 Homestead希望host HTTP标头为homestead.app 。 我们使用的Ngrok命令将HTTP请求的原始host标头复制到X-Original-Host标头,然后使用值homestead.app覆盖host

Please make note of the HTTP URL given by the program as we will need the hostname in it later on when setting up the Twilio phone number to call.

请记下该程序提供的HTTP URL,因为稍后在设置要拨打的Twilio电话号码时,我们将需要使用该主机名。

Photo of Ngrok running in a terminal

特威里奥 (Twilio)

Create an account with Twilio and add money to your account. Adding ten dollars is more than enough to implement and test the app. The money is needed to procure a telephone number and to pay for the incoming calls. Go to the Find a Number page and purchase a number that has voice and SMS capability. I picked a toll-free number.

使用Twilio创建一个帐户,然后向您的帐户添加资金。 加十美元就足以实施和测试该应用程序。 需要这笔钱来购买电话号码并支付来电费用。 转到“ 查找号码”页面并购买具有语音和短信功能的号码。 我选了一个免费电话。

Photo of buy a number advanced search page

In the search page, click the “Advanced Search” link and make sure the “Voice” and “SMS” capabilities checkboxes are marked. Then click the “Search” button. After the list of results appears, pick a phone number.

在搜索页面中,单击“高级搜索”链接,并确保已选中“语音”和“ SMS”功能复选框。 然后点击“搜索”按钮。 结果列表出现后,选择一个电话号码。

After you have procured your number, go to the settings page for the phone number and replace the voice “a call comes in” webhook, https://demo.twilio.com/welcome/voice/ with a webhook that will go to your app, i.e. http://YOUR_NGROK_HOSTNAME/voice/enterZipcode, and save the change.

获取电话号码后,转到电话号码的设置页面,并用将要转到您的网络电话钩替换语音“来电” webhook https://demo.twilio.com/welcome/voice/ 。应用,即http://YOUR_NGROK_HOSTNAME/voice/enterZipcode ,然后保存更改。

Photo of the Twilio voice webhook setup page

使用应用程式 (Using the App)

With your app and the Ngrok program running, call your toll-free number. You should be asked to enter a zipcode. After entering a zipcode, you should get the current forecast and a voice menu to navigate the app.

在您的应用程序和Ngrok程序运行的情况下,拨打您的免费电话。 应该要求您输入一个邮政编码。 输入邮政编码后,您应该获得当前的预测和语音菜单以浏览该应用程序。

生产注意事项 (Production Considerations)

One thing not covered in this article but which can be done to improve this app is to make Twilio use HTTPS endpoints instead of HTTP. If you’d like to see how this is done, please request it in the comments below!

本文未涵盖但可以改进此应用程序的一件事是使Twilio使用HTTPS终结点而不是HTTP。 如果您想了解操作方法,请在下面的评论中提出要求!

结论 (Conclusion)

In this article, we built a web app that a user could call and interact with using Twilio. This app allowed a user to get the weather forecast for a particular zipcode. Please remember that there might be a date discrepancy between where a user calls from and the zipcode they enter, if the two are in different timezones.

在本文中,我们构建了一个Web应用程序,用户可以使用Twilio调用该Web应用程序并与之交互。 该应用程序允许用户获取特定邮政编码的天气预报。 请记住,如果两个用户位于不同的时区,则用户拨打电话的地方与他们输入的邮政编码之间可能存在日期差异。

You can find the code for the app in this article series on Github.

您可以在Github上的该系列文章中找到该应用程序的代码。

In the next part of this two-part series, we will leverage what we built here to make this app work over SMS.

在这个分为两部分的系列的下一部分中,我们将利用我们在此处构建的内容来使此应用程序可以在SMS上运行。

翻译自: https://www.sitepoint.com/hello-laravel-communicating-php-phone-calls/

bisquare与lar

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值