Introduction
In the prior episode, I wrote about preparing your application for SMS using Twilio, a commonly used texting service. In today's tutorial, I'll show you how to verify user phone numbers before transmitting a high volume of texts and running up your costs.
Before we get started, I want to encourage you to post questions and feedback in the comments. If you'd like to keep up on my future Envato Tuts+ tutorials and other series, please visit my instructor page or follow @lookahead_io.
Outlining the Process
After the user provides their phone number, we want to perform a handful of straightforward steps:
- Generate a unique four-digit code.
- Store their cell number and the four-digit code in our database (or encrypt the code locally as a hidden form variable on the page).
- Send a text to the unverified number with the four-digit code.
- Display a form asking the user to provide the code they received.
- Verify the codes match.
- Designate the number as verified in the database.
The User's Contact Page
In Meeting Planner, each user can add multiple contact methods, e.g. Skype, phone, etc. Each cell number must be verified to be used for SMS notifications.
The third row below shows a checkmark box which they can click to request verification:
Clicking that transfers the user to the actionVerify()
controller below; note that it takes them to the else
block at first because they've not yet submitted a code:
public function actionVerify($id) { $model = $this->findModel($id); if ($model->load(Yii::$app->request->post())) { ... } else { $canRequest = $model->canRequest(); if ($canRequest) { // send a text to this number $model->requestCode(); return $this->render('verify', [ 'model' => $model, ]); } else { Yii::$app->getSession()->setFlash('error', $canRequest); return $this->redirect(['/user-contact']); } } }
The method canRequest()
checks if they've been requesting codes repeatedly or too frequently:
public function canRequest() { if ($this->request_count<UserContact::MAX_REQUEST_COUNT) { if (time() - $this->requested_at>=60) { return true; } else { return Yii::t('frontend','Sorry, you must wait a minute between requests.'); } } else { return Yii::t('frontend','You have exceeded the maximum number of attempts.'); } }
I make them wait a minute between attempts to reduce abuse.
Transmitting the Verification Code
If allowed, it calls requestCode()
:
public function requestCode() { $this->verify_code = rand(0,9999); $this->requested_at = time(); $this->request_count+=1; $this->update(); $sms = new Sms; $sms->transmit($this->info,Yii::t('frontend', 'Please return to the site and type in {code}',['code'=>sprintf("%04d",$this->verify_code)])); }
This does the following:
- Generates a random four-digit code.
- It records the last moment in time (unix seconds) that a request to verify was made.
- It increments the attempts of verification for this number.
- And it stores all of this in the database.
- Then, it transmits a text with the code that looks like the image below.
After requesting the code, saving it in the database behind the scenes and transmitting the code to the user, it loads the following form asking for the code:
Verifying the Code
When the user attempts to submit a code, it runs the upper part of actionVerify()
:
public function actionVerify($id) { $model = $this->findModel($id); if ($model->load(Yii::$app->request->post())) { // display verification form $model->verify = Yii::$app->request->post()['UserContact']['verify']; if (strval($model->verify_code) == strval($model->verify)) { $model->status = UserContact::STATUS_VERIFIED; $model->update(); Yii::$app->getSession()->setFlash('success',Yii::t('frontend','Thank you, your number is confirmed.')); return $this->redirect(['/user-contact']); } else { Yii::$app->getSession()->setFlash('error', Yii::t('frontend','Sorry, that is incorrect. Please request a new code.')); return $this->redirect(['/user-contact']); } } else { ... } }
It checks that the codes match. If they do, it updates the database to reflect the number has been verified. And it tells the user:
If not, it displays an error message:
Try It Yourself
If you want to see this in action, you can sign up at Simple Planner or Meeting Planner (which is easy with a social account like Facebook or Google) and add a phone number. Then click the checkmark in the list that you'll see. That's it.
Wrapping Up
Obviously, if your application sends a lot of text messages, it's a notable cost of the business, and you want to limit abuse. That begins with setting up a firewall against invalid numbers—or valid numbers not actually owned by the impostor.
I hope you found this helpful. If you have any questions or suggestions, please post them in the comments. If you'd like to keep up on my future Envato Tuts+ tutorials and other series, please visit my instructor page or follow @lookahead_io. Definitely check out my startup series and Meeting Planner.
Comments