# Masked Phone Numbers with PHP and Laravel

This [PHP Laravel](https://laravel.com/docs/5.1) sample application models an amazing rental experience that a vacation rental company might provide, but with more [Klingons](https://en.wikipedia.org/wiki/Klingon).

Host users can offer rental properties which other guest users can reserve. The guest and the host can then anonymously communicate via a disposable Twilio phone number created just for a reservation. In this tutorial, we'll show you the key bits of code to make this work.

To run this sample app yourself, [download the code and follow the instructions on GitHub](https://github.com/TwilioDevEd/airtng-laravel/tree/airtng-masked-numbers).

> \[!WARNING]
>
> If you choose to manage communications between your users, including voice calls, text-based messages (e.g., SMS), and chat, you may need to comply with certain laws and regulations, including those regarding obtaining consent. Additional information regarding legal compliance considerations and best practices for using Twilio to manage and record communications between your users, such as when using Twilio Proxy, can be found [here](https://help.twilio.com/hc/en-us/articles/360011435554-Best-Practices-for-Using-Twilio-to-Manage-and-Record-Communications-Between-Users).
>
> *Notice*: Twilio recommends that you consult with your legal counsel to make sure that you are complying with all applicable laws in connection with communications you record or store using Twilio.

*[Read how Lyft uses masked phone numbers to let customers securely contact drivers.](https://customers.twilio.com/249/lyft/)*

## Create a Reservation

The first step in connecting a guest and host is creating a reservation. Here, we handle a form submission for a new reservation which contains the guest's name and phone number.

```php title="Create a Reservation" description="app/Http/Controllers/ReservationController.php"
// !mark(34:61)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Authenticatable;
use App\Reservation;
use App\User;
use App\VacationProperty;
use DB;
use Twilio\Rest\Client;
use Twilio\Twiml;
use Log;

class ReservationController extends Controller
{
    public function index(Authenticatable $user)
    {
        $reservations = array();

        foreach ($user->propertyReservations as $reservation)
        {
            array_push($reservations, $reservation->fresh());
        }
        return view(
            'reservation.index',
            [
                'hostReservations' => $reservations,
                'guestReservations' => $user->reservations
            ]
        );
    }

    /**
     * Store a new reservation
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function create(Client $client, Request $request, Authenticatable $user, $id)
    {
        $this->validate(
            $request, [
                'message' => 'required|string'
            ]
        );
        $property = VacationProperty::find($id);
        $reservation = new Reservation($request->all());

        $reservation->user()->associate($user);

        $property->reservations()->save($reservation);

        $this->notifyHost($client, $reservation);

        $request->session()->flash(
            'status',
            "Sending your reservation request now."
        );
        return redirect()->route('reservation-index', ['id' => $property->id]);
    }

    public function acceptReject(Client $client, Request $request)
    {
        $hostNumber = $request->input('From');
        $smsInput = strtolower($request->input('Body'));
        $host = User::where(DB::raw("CONCAT('+',country_code::text, phone_number::text)"), 'LIKE', "%".$hostNumber."%")
            ->get()
            ->first();

        $reservation = $host->pendingReservations()->first();
        $smsResponse = null;
        if (!is_null($reservation))
        {
            $reservation = $reservation->fresh();

            if (strpos($smsInput, 'yes') !== false || strpos($smsInput, 'accept') !== false)
            {
                $reservation->confirm($this->getNewTwilioNumber($client, $host));
            }
            else
            {
                $reservation->reject();
            }

            $smsResponse = 'You have successfully ' . $reservation->status . ' the reservation.';
        }
        else
        {
            $smsResponse = 'Sorry, it looks like you don\'t have any reservations to respond to.';
        }

        return response($this->respond($smsResponse, $reservation))->header('Content-Type', 'application/xml');
    }

    public function connectSms(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');
        $messageBody = $request->input('Body');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectSmsResponse($messageBody, $outgoingNumber))->header('Content-Type', 'application/xml');
    }

    public function connectVoice(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectVoiceResponse($outgoingNumber))->header('Content-Type', 'application/xml');
    }

    private function getReservationFromNumber($twilioNumber)
    {
        return Reservation::where('twilio_number', '=', $twilioNumber)->first();
    }

    private function connectVoiceResponse($outgoingNumber)
    {
        $response = new Twiml();
        $response->play('http://howtodocs.s3.amazonaws.com/howdy-tng.mp3');
        $response->dial($outgoingNumber);

        return $response;
    }

    private function connectSmsResponse($messageBody, $outgoingNumber)
    {
        $response = new Twiml();
        $response->message(
            $messageBody,
            ['to' => $outgoingNumber]
        );

        return $response;
    }

    private function respond($smsResponse, $reservation)
    {
        $response = new Twiml();
        $response->message($smsResponse);

        if (!is_null($reservation))
        {
            $response->message(
                'Your reservation has been ' . $reservation->status . '.',
                ['to' => $reservation->user->fullNumber()]
            );
        }
        return $response;
    }

    private function notifyHost($client, $reservation)
    {
        $host = $reservation->property->user;

        $twilioNumber = config('services.twilio')['number'];

        $messageBody = $reservation->message . ' - Reply \'yes\' or \'accept\' to confirm the reservation, or anything else to reject it.';

        try {
            $client->messages->create(
                $host->fullNumber(), // Text any number
                [
                    'from' => $twilioNumber, // From a Twilio number in your account
                    'body' => $messageBody
                ]
            );
        } catch (Exception $e) {
            Log::error($e->getMessage());
        }
    }

    private function getNewTwilioNumber($client, $host)
    {
        $numbers = $client->availablePhoneNumbers('US')->local->read(
            [
                'areaCode' => $host->areaCode(),
                'voiceEnabled' => 'true',
                "smsEnabled" => 'true'
            ]
        );

        if (empty($numbers)) {
            $numbers = $client->availablePhoneNumbers('US')->local->read(
                [
                    'voiceEnabled' => 'true',
                    "smsEnabled" => 'true'
                ]
            );
        }
        $twilioNumber = $numbers[0]->phoneNumber;

        $newNumber = $client->incomingPhoneNumbers->create(
            [
                "phoneNumber" => $twilioNumber,
                "smsApplicationSid" => config('services.twilio')['applicationSid'],
                "voiceApplicationSid" => config('services.twilio')['applicationSid']
            ]
        );

        if ($newNumber) {
            return $twilioNumber;
        } else {
            return 0;
        }
    }
}
```

Part of our reservation system is receiving reservation requests from potential renters. However, these reservations need to be confirmed. Let's see how we would handle this step.

## Confirm the Reservation

Before the reservation is finalized, the host needs to confirm that the property is still available. Learn how to automate this process in [our first AirTNG tutorial, Workflow Automation](https://github.com/TwilioDevEd/airtng-laravel).

Once the reservation is confirmed, we need to create a Twilio number that the guest and host can use to communicate in the `getNewTwilioNumber` method.

```php title="Confirm Reservation Method" description="app/Http/Controllers/ReservationController.php"
// !mark(63:94)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Authenticatable;
use App\Reservation;
use App\User;
use App\VacationProperty;
use DB;
use Twilio\Rest\Client;
use Twilio\Twiml;
use Log;

class ReservationController extends Controller
{
    public function index(Authenticatable $user)
    {
        $reservations = array();

        foreach ($user->propertyReservations as $reservation)
        {
            array_push($reservations, $reservation->fresh());
        }
        return view(
            'reservation.index',
            [
                'hostReservations' => $reservations,
                'guestReservations' => $user->reservations
            ]
        );
    }

    /**
     * Store a new reservation
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function create(Client $client, Request $request, Authenticatable $user, $id)
    {
        $this->validate(
            $request, [
                'message' => 'required|string'
            ]
        );
        $property = VacationProperty::find($id);
        $reservation = new Reservation($request->all());

        $reservation->user()->associate($user);

        $property->reservations()->save($reservation);

        $this->notifyHost($client, $reservation);

        $request->session()->flash(
            'status',
            "Sending your reservation request now."
        );
        return redirect()->route('reservation-index', ['id' => $property->id]);
    }

    public function acceptReject(Client $client, Request $request)
    {
        $hostNumber = $request->input('From');
        $smsInput = strtolower($request->input('Body'));
        $host = User::where(DB::raw("CONCAT('+',country_code::text, phone_number::text)"), 'LIKE', "%".$hostNumber."%")
            ->get()
            ->first();

        $reservation = $host->pendingReservations()->first();
        $smsResponse = null;
        if (!is_null($reservation))
        {
            $reservation = $reservation->fresh();

            if (strpos($smsInput, 'yes') !== false || strpos($smsInput, 'accept') !== false)
            {
                $reservation->confirm($this->getNewTwilioNumber($client, $host));
            }
            else
            {
                $reservation->reject();
            }

            $smsResponse = 'You have successfully ' . $reservation->status . ' the reservation.';
        }
        else
        {
            $smsResponse = 'Sorry, it looks like you don\'t have any reservations to respond to.';
        }

        return response($this->respond($smsResponse, $reservation))->header('Content-Type', 'application/xml');
    }

    public function connectSms(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');
        $messageBody = $request->input('Body');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectSmsResponse($messageBody, $outgoingNumber))->header('Content-Type', 'application/xml');
    }

    public function connectVoice(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectVoiceResponse($outgoingNumber))->header('Content-Type', 'application/xml');
    }

    private function getReservationFromNumber($twilioNumber)
    {
        return Reservation::where('twilio_number', '=', $twilioNumber)->first();
    }

    private function connectVoiceResponse($outgoingNumber)
    {
        $response = new Twiml();
        $response->play('http://howtodocs.s3.amazonaws.com/howdy-tng.mp3');
        $response->dial($outgoingNumber);

        return $response;
    }

    private function connectSmsResponse($messageBody, $outgoingNumber)
    {
        $response = new Twiml();
        $response->message(
            $messageBody,
            ['to' => $outgoingNumber]
        );

        return $response;
    }

    private function respond($smsResponse, $reservation)
    {
        $response = new Twiml();
        $response->message($smsResponse);

        if (!is_null($reservation))
        {
            $response->message(
                'Your reservation has been ' . $reservation->status . '.',
                ['to' => $reservation->user->fullNumber()]
            );
        }
        return $response;
    }

    private function notifyHost($client, $reservation)
    {
        $host = $reservation->property->user;

        $twilioNumber = config('services.twilio')['number'];

        $messageBody = $reservation->message . ' - Reply \'yes\' or \'accept\' to confirm the reservation, or anything else to reject it.';

        try {
            $client->messages->create(
                $host->fullNumber(), // Text any number
                [
                    'from' => $twilioNumber, // From a Twilio number in your account
                    'body' => $messageBody
                ]
            );
        } catch (Exception $e) {
            Log::error($e->getMessage());
        }
    }

    private function getNewTwilioNumber($client, $host)
    {
        $numbers = $client->availablePhoneNumbers('US')->local->read(
            [
                'areaCode' => $host->areaCode(),
                'voiceEnabled' => 'true',
                "smsEnabled" => 'true'
            ]
        );

        if (empty($numbers)) {
            $numbers = $client->availablePhoneNumbers('US')->local->read(
                [
                    'voiceEnabled' => 'true',
                    "smsEnabled" => 'true'
                ]
            );
        }
        $twilioNumber = $numbers[0]->phoneNumber;

        $newNumber = $client->incomingPhoneNumbers->create(
            [
                "phoneNumber" => $twilioNumber,
                "smsApplicationSid" => config('services.twilio')['applicationSid'],
                "voiceApplicationSid" => config('services.twilio')['applicationSid']
            ]
        );

        if ($newNumber) {
            return $twilioNumber;
        } else {
            return 0;
        }
    }
}
```

Once the reservation is confirmed, we need to purchase a Twilio number that the guest and host can use to communicate.

## Purchase a Twilio Number

Here we use a [Twilio REST API Client](https://github.com/twilio/twilio-php) to search for and buy a new phone number to associate with the reservation. When we buy the number, we designate a [Twilio application](/docs/usage/api/applications) that will handle [webhook](https://en.wikipedia.org/wiki/Webhook) requests; when the new number receives an incoming call or text.

We then save the new phone number on our `Reservation` model, so when our app receives calls or texts to this number, we'll know which reservation the call or text belongs to.

```php title="Purchase a Twilio Number" description="app/Http/Controllers/ReservationController.php"
// !mark(200:233)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Authenticatable;
use App\Reservation;
use App\User;
use App\VacationProperty;
use DB;
use Twilio\Rest\Client;
use Twilio\Twiml;
use Log;

class ReservationController extends Controller
{
    public function index(Authenticatable $user)
    {
        $reservations = array();

        foreach ($user->propertyReservations as $reservation)
        {
            array_push($reservations, $reservation->fresh());
        }
        return view(
            'reservation.index',
            [
                'hostReservations' => $reservations,
                'guestReservations' => $user->reservations
            ]
        );
    }

    /**
     * Store a new reservation
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function create(Client $client, Request $request, Authenticatable $user, $id)
    {
        $this->validate(
            $request, [
                'message' => 'required|string'
            ]
        );
        $property = VacationProperty::find($id);
        $reservation = new Reservation($request->all());

        $reservation->user()->associate($user);

        $property->reservations()->save($reservation);

        $this->notifyHost($client, $reservation);

        $request->session()->flash(
            'status',
            "Sending your reservation request now."
        );
        return redirect()->route('reservation-index', ['id' => $property->id]);
    }

    public function acceptReject(Client $client, Request $request)
    {
        $hostNumber = $request->input('From');
        $smsInput = strtolower($request->input('Body'));
        $host = User::where(DB::raw("CONCAT('+',country_code::text, phone_number::text)"), 'LIKE', "%".$hostNumber."%")
            ->get()
            ->first();

        $reservation = $host->pendingReservations()->first();
        $smsResponse = null;
        if (!is_null($reservation))
        {
            $reservation = $reservation->fresh();

            if (strpos($smsInput, 'yes') !== false || strpos($smsInput, 'accept') !== false)
            {
                $reservation->confirm($this->getNewTwilioNumber($client, $host));
            }
            else
            {
                $reservation->reject();
            }

            $smsResponse = 'You have successfully ' . $reservation->status . ' the reservation.';
        }
        else
        {
            $smsResponse = 'Sorry, it looks like you don\'t have any reservations to respond to.';
        }

        return response($this->respond($smsResponse, $reservation))->header('Content-Type', 'application/xml');
    }

    public function connectSms(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');
        $messageBody = $request->input('Body');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectSmsResponse($messageBody, $outgoingNumber))->header('Content-Type', 'application/xml');
    }

    public function connectVoice(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectVoiceResponse($outgoingNumber))->header('Content-Type', 'application/xml');
    }

    private function getReservationFromNumber($twilioNumber)
    {
        return Reservation::where('twilio_number', '=', $twilioNumber)->first();
    }

    private function connectVoiceResponse($outgoingNumber)
    {
        $response = new Twiml();
        $response->play('http://howtodocs.s3.amazonaws.com/howdy-tng.mp3');
        $response->dial($outgoingNumber);

        return $response;
    }

    private function connectSmsResponse($messageBody, $outgoingNumber)
    {
        $response = new Twiml();
        $response->message(
            $messageBody,
            ['to' => $outgoingNumber]
        );

        return $response;
    }

    private function respond($smsResponse, $reservation)
    {
        $response = new Twiml();
        $response->message($smsResponse);

        if (!is_null($reservation))
        {
            $response->message(
                'Your reservation has been ' . $reservation->status . '.',
                ['to' => $reservation->user->fullNumber()]
            );
        }
        return $response;
    }

    private function notifyHost($client, $reservation)
    {
        $host = $reservation->property->user;

        $twilioNumber = config('services.twilio')['number'];

        $messageBody = $reservation->message . ' - Reply \'yes\' or \'accept\' to confirm the reservation, or anything else to reject it.';

        try {
            $client->messages->create(
                $host->fullNumber(), // Text any number
                [
                    'from' => $twilioNumber, // From a Twilio number in your account
                    'body' => $messageBody
                ]
            );
        } catch (Exception $e) {
            Log::error($e->getMessage());
        }
    }

    private function getNewTwilioNumber($client, $host)
    {
        $numbers = $client->availablePhoneNumbers('US')->local->read(
            [
                'areaCode' => $host->areaCode(),
                'voiceEnabled' => 'true',
                "smsEnabled" => 'true'
            ]
        );

        if (empty($numbers)) {
            $numbers = $client->availablePhoneNumbers('US')->local->read(
                [
                    'voiceEnabled' => 'true',
                    "smsEnabled" => 'true'
                ]
            );
        }
        $twilioNumber = $numbers[0]->phoneNumber;

        $newNumber = $client->incomingPhoneNumbers->create(
            [
                "phoneNumber" => $twilioNumber,
                "smsApplicationSid" => config('services.twilio')['applicationSid'],
                "voiceApplicationSid" => config('services.twilio')['applicationSid']
            ]
        );

        if ($newNumber) {
            return $twilioNumber;
        } else {
            return 0;
        }
    }
}
```

Now that each reservation has a Twilio Phone Number, we can see how the application will look up reservations as guest or host calls come in.

## Find a Reservation

When someone sends an SMS or calls one of the Twilio numbers you have configured, Twilio makes a request to the URL you set in the TwiML app. In this request, Twilio includes some useful information including:

* the `From` number that originally called or sent an SMS
* the `To` Twilio number that triggered this request

Take a look at [Twilio's SMS Documentation](/docs/messaging/twiml) and [Twilio's Voice Documentation](/docs/voice/twiml) for a full list of the parameters you can use.

In our controller we use the `To` parameter sent by Twilio to find a reservation that has the number we bought stored in it, as this is the number both hosts and guests will call and send sms to.

```php title="Find a Reservation" description="app/Http/Controllers/ReservationController.php"
// !mark(96:102,118:123)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Authenticatable;
use App\Reservation;
use App\User;
use App\VacationProperty;
use DB;
use Twilio\Rest\Client;
use Twilio\Twiml;
use Log;

class ReservationController extends Controller
{
    public function index(Authenticatable $user)
    {
        $reservations = array();

        foreach ($user->propertyReservations as $reservation)
        {
            array_push($reservations, $reservation->fresh());
        }
        return view(
            'reservation.index',
            [
                'hostReservations' => $reservations,
                'guestReservations' => $user->reservations
            ]
        );
    }

    /**
     * Store a new reservation
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function create(Client $client, Request $request, Authenticatable $user, $id)
    {
        $this->validate(
            $request, [
                'message' => 'required|string'
            ]
        );
        $property = VacationProperty::find($id);
        $reservation = new Reservation($request->all());

        $reservation->user()->associate($user);

        $property->reservations()->save($reservation);

        $this->notifyHost($client, $reservation);

        $request->session()->flash(
            'status',
            "Sending your reservation request now."
        );
        return redirect()->route('reservation-index', ['id' => $property->id]);
    }

    public function acceptReject(Client $client, Request $request)
    {
        $hostNumber = $request->input('From');
        $smsInput = strtolower($request->input('Body'));
        $host = User::where(DB::raw("CONCAT('+',country_code::text, phone_number::text)"), 'LIKE', "%".$hostNumber."%")
            ->get()
            ->first();

        $reservation = $host->pendingReservations()->first();
        $smsResponse = null;
        if (!is_null($reservation))
        {
            $reservation = $reservation->fresh();

            if (strpos($smsInput, 'yes') !== false || strpos($smsInput, 'accept') !== false)
            {
                $reservation->confirm($this->getNewTwilioNumber($client, $host));
            }
            else
            {
                $reservation->reject();
            }

            $smsResponse = 'You have successfully ' . $reservation->status . ' the reservation.';
        }
        else
        {
            $smsResponse = 'Sorry, it looks like you don\'t have any reservations to respond to.';
        }

        return response($this->respond($smsResponse, $reservation))->header('Content-Type', 'application/xml');
    }

    public function connectSms(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');
        $messageBody = $request->input('Body');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectSmsResponse($messageBody, $outgoingNumber))->header('Content-Type', 'application/xml');
    }

    public function connectVoice(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectVoiceResponse($outgoingNumber))->header('Content-Type', 'application/xml');
    }

    private function getReservationFromNumber($twilioNumber)
    {
        return Reservation::where('twilio_number', '=', $twilioNumber)->first();
    }

    private function connectVoiceResponse($outgoingNumber)
    {
        $response = new Twiml();
        $response->play('http://howtodocs.s3.amazonaws.com/howdy-tng.mp3');
        $response->dial($outgoingNumber);

        return $response;
    }

    private function connectSmsResponse($messageBody, $outgoingNumber)
    {
        $response = new Twiml();
        $response->message(
            $messageBody,
            ['to' => $outgoingNumber]
        );

        return $response;
    }

    private function respond($smsResponse, $reservation)
    {
        $response = new Twiml();
        $response->message($smsResponse);

        if (!is_null($reservation))
        {
            $response->message(
                'Your reservation has been ' . $reservation->status . '.',
                ['to' => $reservation->user->fullNumber()]
            );
        }
        return $response;
    }

    private function notifyHost($client, $reservation)
    {
        $host = $reservation->property->user;

        $twilioNumber = config('services.twilio')['number'];

        $messageBody = $reservation->message . ' - Reply \'yes\' or \'accept\' to confirm the reservation, or anything else to reject it.';

        try {
            $client->messages->create(
                $host->fullNumber(), // Text any number
                [
                    'from' => $twilioNumber, // From a Twilio number in your account
                    'body' => $messageBody
                ]
            );
        } catch (Exception $e) {
            Log::error($e->getMessage());
        }
    }

    private function getNewTwilioNumber($client, $host)
    {
        $numbers = $client->availablePhoneNumbers('US')->local->read(
            [
                'areaCode' => $host->areaCode(),
                'voiceEnabled' => 'true',
                "smsEnabled" => 'true'
            ]
        );

        if (empty($numbers)) {
            $numbers = $client->availablePhoneNumbers('US')->local->read(
                [
                    'voiceEnabled' => 'true',
                    "smsEnabled" => 'true'
                ]
            );
        }
        $twilioNumber = $numbers[0]->phoneNumber;

        $newNumber = $client->incomingPhoneNumbers->create(
            [
                "phoneNumber" => $twilioNumber,
                "smsApplicationSid" => config('services.twilio')['applicationSid'],
                "voiceApplicationSid" => config('services.twilio')['applicationSid']
            ]
        );

        if ($newNumber) {
            return $twilioNumber;
        } else {
            return 0;
        }
    }
}
```

Next, let's see how to connect the guest and the host via SMS.

## Connect Via SMS

Our [Twilio application](/docs/usage/api/applications) should be configured to [send HTTP requests](/docs/voice/twiml) to this controller method on any incoming text message. Our app responds with [TwiML](/docs/voice/twiml) to tell Twilio what to do in response to the message.

If the initial message sent to the anonymous number was sent by the host, we forward it on to the guest. Conversely, if the original message was sent by the guest, we forward it to the host.

```php title="Connect Via SMS" description="app/Http/Controllers/ReservationController.php"
// !mark(96:116)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Authenticatable;
use App\Reservation;
use App\User;
use App\VacationProperty;
use DB;
use Twilio\Rest\Client;
use Twilio\Twiml;
use Log;

class ReservationController extends Controller
{
    public function index(Authenticatable $user)
    {
        $reservations = array();

        foreach ($user->propertyReservations as $reservation)
        {
            array_push($reservations, $reservation->fresh());
        }
        return view(
            'reservation.index',
            [
                'hostReservations' => $reservations,
                'guestReservations' => $user->reservations
            ]
        );
    }

    /**
     * Store a new reservation
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function create(Client $client, Request $request, Authenticatable $user, $id)
    {
        $this->validate(
            $request, [
                'message' => 'required|string'
            ]
        );
        $property = VacationProperty::find($id);
        $reservation = new Reservation($request->all());

        $reservation->user()->associate($user);

        $property->reservations()->save($reservation);

        $this->notifyHost($client, $reservation);

        $request->session()->flash(
            'status',
            "Sending your reservation request now."
        );
        return redirect()->route('reservation-index', ['id' => $property->id]);
    }

    public function acceptReject(Client $client, Request $request)
    {
        $hostNumber = $request->input('From');
        $smsInput = strtolower($request->input('Body'));
        $host = User::where(DB::raw("CONCAT('+',country_code::text, phone_number::text)"), 'LIKE', "%".$hostNumber."%")
            ->get()
            ->first();

        $reservation = $host->pendingReservations()->first();
        $smsResponse = null;
        if (!is_null($reservation))
        {
            $reservation = $reservation->fresh();

            if (strpos($smsInput, 'yes') !== false || strpos($smsInput, 'accept') !== false)
            {
                $reservation->confirm($this->getNewTwilioNumber($client, $host));
            }
            else
            {
                $reservation->reject();
            }

            $smsResponse = 'You have successfully ' . $reservation->status . ' the reservation.';
        }
        else
        {
            $smsResponse = 'Sorry, it looks like you don\'t have any reservations to respond to.';
        }

        return response($this->respond($smsResponse, $reservation))->header('Content-Type', 'application/xml');
    }

    public function connectSms(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');
        $messageBody = $request->input('Body');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectSmsResponse($messageBody, $outgoingNumber))->header('Content-Type', 'application/xml');
    }

    public function connectVoice(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectVoiceResponse($outgoingNumber))->header('Content-Type', 'application/xml');
    }

    private function getReservationFromNumber($twilioNumber)
    {
        return Reservation::where('twilio_number', '=', $twilioNumber)->first();
    }

    private function connectVoiceResponse($outgoingNumber)
    {
        $response = new Twiml();
        $response->play('http://howtodocs.s3.amazonaws.com/howdy-tng.mp3');
        $response->dial($outgoingNumber);

        return $response;
    }

    private function connectSmsResponse($messageBody, $outgoingNumber)
    {
        $response = new Twiml();
        $response->message(
            $messageBody,
            ['to' => $outgoingNumber]
        );

        return $response;
    }

    private function respond($smsResponse, $reservation)
    {
        $response = new Twiml();
        $response->message($smsResponse);

        if (!is_null($reservation))
        {
            $response->message(
                'Your reservation has been ' . $reservation->status . '.',
                ['to' => $reservation->user->fullNumber()]
            );
        }
        return $response;
    }

    private function notifyHost($client, $reservation)
    {
        $host = $reservation->property->user;

        $twilioNumber = config('services.twilio')['number'];

        $messageBody = $reservation->message . ' - Reply \'yes\' or \'accept\' to confirm the reservation, or anything else to reject it.';

        try {
            $client->messages->create(
                $host->fullNumber(), // Text any number
                [
                    'from' => $twilioNumber, // From a Twilio number in your account
                    'body' => $messageBody
                ]
            );
        } catch (Exception $e) {
            Log::error($e->getMessage());
        }
    }

    private function getNewTwilioNumber($client, $host)
    {
        $numbers = $client->availablePhoneNumbers('US')->local->read(
            [
                'areaCode' => $host->areaCode(),
                'voiceEnabled' => 'true',
                "smsEnabled" => 'true'
            ]
        );

        if (empty($numbers)) {
            $numbers = $client->availablePhoneNumbers('US')->local->read(
                [
                    'voiceEnabled' => 'true',
                    "smsEnabled" => 'true'
                ]
            );
        }
        $twilioNumber = $numbers[0]->phoneNumber;

        $newNumber = $client->incomingPhoneNumbers->create(
            [
                "phoneNumber" => $twilioNumber,
                "smsApplicationSid" => config('services.twilio')['applicationSid'],
                "voiceApplicationSid" => config('services.twilio')['applicationSid']
            ]
        );

        if ($newNumber) {
            return $twilioNumber;
        } else {
            return 0;
        }
    }
}
```

Let's see how to connect the guest and the host via phone call next.

## Connect Via Phone Call

Our [Twilio application](/docs/usage/api/applications) will [send HTTP requests](/docs/voice/twiml) to this method on any incoming voice call. Our app responds with [TwiML instructions](/docs/voice/twiml) that tell Twilio to `Play` an introductory MP3 audio file and then`Dial` either the guest or host, depending on who initiated the call.

```php title="Connect Via Phone Call" description="app/Http/Controllers/ReservationController.php"
// !mark(118:137,144:151)
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Authenticatable;
use App\Reservation;
use App\User;
use App\VacationProperty;
use DB;
use Twilio\Rest\Client;
use Twilio\Twiml;
use Log;

class ReservationController extends Controller
{
    public function index(Authenticatable $user)
    {
        $reservations = array();

        foreach ($user->propertyReservations as $reservation)
        {
            array_push($reservations, $reservation->fresh());
        }
        return view(
            'reservation.index',
            [
                'hostReservations' => $reservations,
                'guestReservations' => $user->reservations
            ]
        );
    }

    /**
     * Store a new reservation
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function create(Client $client, Request $request, Authenticatable $user, $id)
    {
        $this->validate(
            $request, [
                'message' => 'required|string'
            ]
        );
        $property = VacationProperty::find($id);
        $reservation = new Reservation($request->all());

        $reservation->user()->associate($user);

        $property->reservations()->save($reservation);

        $this->notifyHost($client, $reservation);

        $request->session()->flash(
            'status',
            "Sending your reservation request now."
        );
        return redirect()->route('reservation-index', ['id' => $property->id]);
    }

    public function acceptReject(Client $client, Request $request)
    {
        $hostNumber = $request->input('From');
        $smsInput = strtolower($request->input('Body'));
        $host = User::where(DB::raw("CONCAT('+',country_code::text, phone_number::text)"), 'LIKE', "%".$hostNumber."%")
            ->get()
            ->first();

        $reservation = $host->pendingReservations()->first();
        $smsResponse = null;
        if (!is_null($reservation))
        {
            $reservation = $reservation->fresh();

            if (strpos($smsInput, 'yes') !== false || strpos($smsInput, 'accept') !== false)
            {
                $reservation->confirm($this->getNewTwilioNumber($client, $host));
            }
            else
            {
                $reservation->reject();
            }

            $smsResponse = 'You have successfully ' . $reservation->status . ' the reservation.';
        }
        else
        {
            $smsResponse = 'Sorry, it looks like you don\'t have any reservations to respond to.';
        }

        return response($this->respond($smsResponse, $reservation))->header('Content-Type', 'application/xml');
    }

    public function connectSms(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');
        $messageBody = $request->input('Body');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectSmsResponse($messageBody, $outgoingNumber))->header('Content-Type', 'application/xml');
    }

    public function connectVoice(Request $request)
    {
        $twilioNumber = $request->input('To');
        $incomingNumber = $request->input('From');

        $reservation = $this->getReservationFromNumber($twilioNumber);
        $host = $reservation->property->user;
        $guest = $reservation->user;

        if ($incomingNumber === $host->fullNumber())
        {
            $outgoingNumber = $guest->fullNumber();
        }
        else
        {
            $outgoingNumber = $host->fullNumber();
        }

        return response($this->connectVoiceResponse($outgoingNumber))->header('Content-Type', 'application/xml');
    }

    private function getReservationFromNumber($twilioNumber)
    {
        return Reservation::where('twilio_number', '=', $twilioNumber)->first();
    }

    private function connectVoiceResponse($outgoingNumber)
    {
        $response = new Twiml();
        $response->play('http://howtodocs.s3.amazonaws.com/howdy-tng.mp3');
        $response->dial($outgoingNumber);

        return $response;
    }

    private function connectSmsResponse($messageBody, $outgoingNumber)
    {
        $response = new Twiml();
        $response->message(
            $messageBody,
            ['to' => $outgoingNumber]
        );

        return $response;
    }

    private function respond($smsResponse, $reservation)
    {
        $response = new Twiml();
        $response->message($smsResponse);

        if (!is_null($reservation))
        {
            $response->message(
                'Your reservation has been ' . $reservation->status . '.',
                ['to' => $reservation->user->fullNumber()]
            );
        }
        return $response;
    }

    private function notifyHost($client, $reservation)
    {
        $host = $reservation->property->user;

        $twilioNumber = config('services.twilio')['number'];

        $messageBody = $reservation->message . ' - Reply \'yes\' or \'accept\' to confirm the reservation, or anything else to reject it.';

        try {
            $client->messages->create(
                $host->fullNumber(), // Text any number
                [
                    'from' => $twilioNumber, // From a Twilio number in your account
                    'body' => $messageBody
                ]
            );
        } catch (Exception $e) {
            Log::error($e->getMessage());
        }
    }

    private function getNewTwilioNumber($client, $host)
    {
        $numbers = $client->availablePhoneNumbers('US')->local->read(
            [
                'areaCode' => $host->areaCode(),
                'voiceEnabled' => 'true',
                "smsEnabled" => 'true'
            ]
        );

        if (empty($numbers)) {
            $numbers = $client->availablePhoneNumbers('US')->local->read(
                [
                    'voiceEnabled' => 'true',
                    "smsEnabled" => 'true'
                ]
            );
        }
        $twilioNumber = $numbers[0]->phoneNumber;

        $newNumber = $client->incomingPhoneNumbers->create(
            [
                "phoneNumber" => $twilioNumber,
                "smsApplicationSid" => config('services.twilio')['applicationSid'],
                "voiceApplicationSid" => config('services.twilio')['applicationSid']
            ]
        );

        if ($newNumber) {
            return $twilioNumber;
        } else {
            return 0;
        }
    }
}
```

That's it! We've just implemented anonymous communications that allow your customers to connect while protecting their privacy.

## Where to Next?

If you're a PHP developer working with Twilio, you might want to check out these other tutorials:

[**Click-To-Call**](/docs/voice/sdks/javascript/get-started)

Put a button on your web page that connects visitors to live support or sales people via telephone.

[**Automated Survey**](/blog/automated-survey-php-laravel)

Instantly collect structured data from your users with a survey conducted over a voice call or SMS text messages.

### Did this help?

Thanks for checking out this tutorial! If you have any feedback to share with us, we'd love to hear it. Tweet [@twilio](http://twitter.com/twilio) to let us know what you think.
