PHP邮箱验证示例教程


Posted in PHP onJune 01, 2016

在用户注册中最常见的安全验证之一就是邮箱验证。根据行业的一般做法,进行邮箱验证是避免潜在的安全隐患一种非常重要的做法,现在就让我们来讨论一下这些最佳实践,来看看如何在PHP中创建一个邮箱验证。

让我们先从一个注册表单开始:

<form method="post" action="http://mydomain.com/registration/">
 <fieldset class="form-group">
 <label for="fname">First Name:</label>
 <input type="text" name="fname" class="form-control" required />
  </fieldset>

  <fieldset class="form-group">
 <label for="lname">Last Name:</label>
 <input type="text" name="lname" class="form-control" required />
  </fieldset>

  <fieldset class="form-group">
 <label for="email">Last name:</label>
 <input type="email" name="email" class="form-control" required />
  </fieldset>

  <fieldset class="form-group">
 <label for="password">Password:</label>
 <input type="password" name="password" class="form-control" required />
  </fieldset>

  <fieldset class="form-group">
 <label for="cpassword">Confirm Password:</label>
 <input type="password" name="cpassword" class="form-control" required />
  </fieldset>

  <fieldset>
    <button type="submit" class="btn">Register</button>
  </fieldset>
</form>

接下来是数据库的表结构:

CREATE TABLE IF NOT EXISTS `user` (
 `id` INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
 `fname` VARCHAR(255) ,
 `lname` VARCHAR(255) ,
 `email` VARCHAR(50) ,
 `password` VARCHAR(50) ,
 `is_active` INT(1) DEFAULT '0',
 `verify_token` VARCHAR(255) ,
 `created_at` TIMESTAMP,
 `updated_at` TIMESTAMP,
);

一旦这个表单被提交了,我们就需要验证用户的输入并且创建一个新用户:

// Validation rules
$rules = array(
  'fname' => 'required|max:255',
  'lname' => 'required|max:255',
 'email' => 'required',
 'password' => 'required|min:6|max:20',
 'cpassword' => 'same:password'
);

$validator = Validator::make(Input::all(), $rules);

// If input not valid, go back to registration page
if($validator->fails()) {
 return Redirect::to('registration')->with('error', $validator->messages()->first())->withInput();
}

$user = new User();
$user->fname = Input::get('fname');
$user->lname = Input::get('lname');
$user->password = Input::get('password');

// You will generate the verification code here and save it to the database

// Save user to the database
if(!$user->save()) {
 // If unable to write to database for any reason, show the error
 return Redirect::to('registration')->with('error', 'Unable to write to database at this time. Please try again later.')->withInput();
}

// User is created and saved to database
// Verification e-mail will be sent here

// Go back to registration page and show the success message
return Redirect::to('registration')->with('success', 'You have successfully created an account. The verification link has been sent to e-mail address you have provided. Please click on that link to activate your account.');

 注册之后,用户的账户仍然是无效的直到用户的邮箱被验证。此功能确认用户是输入电子邮件地址的所有者,并有助于防止垃圾邮件以及未经授权的电子邮件使用和信息泄露。

 整个流程是非常简单的——当一个新用户被创建时,在注册过过程中,一封包含验证链接的邮件便会被发送到用户填写的邮箱地址中。在用户点击邮箱验证链接和确认邮箱地址之前,用户是不能进行登录和使用网站应用的。

 关于验证的链接有几件事情是需要注意的。验证的链接需要包含一个随机生成的token,这个token应该足够长并且只在一段时间段内是有效的,这样做的方法是为了防止网络攻击。同时,邮箱验证中也需要包含用户的唯一标识,这样就可以避免那些攻击多用户的潜在危险。

现在让我们来看看在实践中如何生成一个验证链接:

// We will generate a random 32 alphanumeric string
// It is almost impossible to brute-force this key space
$code = str_random(32);
$user->confirmation_code = $code;

一旦这个验证被创建就把他存储到数据库中,发送给用户:

Mail::send('emails.email-confirmation', array('code' => $code, 'id' => $user->id), function($message)
{
$message->from('my@domain.com', 'Mydomain.com')->to($user->email, $user->fname . ' ' . $user->lname)->subject('Mydomain.com: E-mail confirmation');
});

邮箱验证的内容:

<!DOCTYPE html>
<html lang="en-US">
 <head>
 <meta charset="utf-8" />
 </head>

 <body>
 <p style="margin:0">
  Please confirm your e-mail address by clicking the following link:
  <a href="http://mydomain.com/verify?code=<?php echo $code; ?>&user=<?php echo $id; ?>"></a>
 </p>
 </body>
</html>

现在让我们来验证一下它是否可行:

$user = User::where('id', '=', Input::get('user'))
  ->where('is_active', '=', 0)
  ->where('verify_token', '=', Input::get('code'))
  ->where('created_at', '>=', time() - (86400 * 2))
  ->first();

if($user) {
 $user->verify_token = null;
 $user->is_active = 1;

 if(!$user->save()) {
 // If unable to write to database for any reason, show the error
 return Redirect::to('verify')->with('error', 'Unable to connect to database at this time. Please try again later.');
 }

 // Show the success message
 return Redirect::to('verify')->with('success', 'You account is now active. Thank you.');
}

// Code not valid, show error message
return Redirect::to('verify')->with('error', 'Verification code not valid.');

结论:
上面展示的代码只是一个教程示例,并且没有通过足够的测试。在你的web应用中使用的时候请先测试一下。上面的代码是在Laravel框架中完成的,但是你可以很轻松的把它迁移到其他的PHP框架中。同时,验证链接的有效时间为48小时,之后就过期。引入一个工作队列就可以很好的及时处理那些已经过期的验证链接。

本文实PHPChina原创翻译,原文转载于http://www.phpchina.com/portal.php?mod=view&aid=39888,小编认为这篇文章很具有学习的价值,分享给大家,希望对大家的学习有所帮助。

PHP 相关文章推荐
用PHP实现登陆验证码(类似条行码状)
Oct 09 PHP
树型结构列出指定目录里所有文件的PHP类
Oct 09 PHP
PHP伪造referer实例代码
Sep 20 PHP
php json_encode奇怪问题说明
Sep 27 PHP
PHP随机字符串生成代码(包括大小写字母)
Jun 24 PHP
PHP中round()函数对浮点数进行四舍五入的方法
Nov 19 PHP
PHP面向对象程序设计实例分析
Jan 26 PHP
ThinkPHP中limit()使用方法详解
Apr 19 PHP
Joomla语言翻译类Jtext用法分析
May 05 PHP
PHP简单实现遍历目录下特定文件的方法小结
May 22 PHP
PHP实现网站访问量计数器
Oct 27 PHP
thinkPHP3.2使用RBAC实现权限管理的实现
Aug 27 PHP
PHP微信公众号自动发送红包API
Jun 01 #PHP
PHP模块化安装教程
Jun 01 #PHP
深入理解PHP之源码目录结构与功能说明
Jun 01 #PHP
基于PHP生成简单的验证码
Jun 01 #PHP
深入理解PHP原理之执行周期分析
Jun 01 #PHP
深入理解PHP之OpCode原理详解
Jun 01 #PHP
深入理解PHP中的count函数
May 31 #PHP
You might like
PHP set_error_handler()函数使用详解(示例)
2013/11/12 PHP
解决laravel资源加载路径设置的问题
2019/10/14 PHP
JavaScript confirm选择判断
2008/10/18 Javascript
JS获取父节点方法
2009/08/20 Javascript
JS解析XML的实现代码
2009/11/12 Javascript
13 个JavaScript 性能提升技巧分享
2012/07/26 Javascript
JS定时关闭窗口的实例
2013/05/22 Javascript
Egret引擎开发指南之视觉编程
2014/09/03 Javascript
js阻止事件追加的具体实现
2014/10/15 Javascript
js实现弹窗居中的简单实例
2016/10/09 Javascript
详解Vue CLI3 多页应用实践和源码设计
2018/08/30 Javascript
详解React中传入组件的props改变时更新组件的几种实现方法
2018/09/13 Javascript
vuex实现及简略解析(小结)
2019/03/01 Javascript
setTimeout与setInterval的区别浅析
2019/03/23 Javascript
JavaScript中的null和undefined用法解析
2019/09/30 Javascript
vue.js循环radio的实例
2019/11/07 Javascript
vue远程加载sfc组件思路详解
2019/12/25 Javascript
JS script脚本中async和defer区别详解
2020/06/24 Javascript
[13:25]VP vs VICI (BO3)
2018/06/07 DOTA
Tornado服务器中绑定域名、虚拟主机的方法
2014/08/22 Python
python 查找文件名包含指定字符串的方法
2018/06/05 Python
11个Python Pandas小技巧让你的工作更高效(附代码实例)
2019/04/30 Python
python nmap实现端口扫描器教程
2020/05/28 Python
基于SpringBoot构造器注入循环依赖及解决方式
2020/04/26 Python
Python 私有属性和私有方法应用场景分析
2020/06/19 Python
使用纯 CSS 创作一个脉动 loader效果的源码
2018/09/28 HTML / CSS
HTML5 weui使用笔记
2019/11/21 HTML / CSS
中国海淘族值得信赖的海淘返利网站:55海淘
2017/01/16 全球购物
Manduka官网:瑜伽垫、瑜伽毛巾和服装
2018/07/02 全球购物
瑞士男士时尚网上商店:Babista
2020/05/14 全球购物
优秀团队获奖感言
2014/02/19 职场文书
空气的环保标语
2014/06/12 职场文书
群众路线教育实践活动民主生活会个人检查对照思想汇报
2014/10/04 职场文书
2014年仓库保管员工作总结
2014/12/03 职场文书
刑事附带民事上诉状
2015/05/23 职场文书
纪委立案决定书
2015/06/24 职场文书