# 注册 User/reg
![2015-06-23/5588acf96a306](http://box.kancloud.cn/2015-06-23_5588acf96a306.png)
注册页的地址是 user/reg。
然后模板就是一个表单
~~~
<extend name="Index/base" />
<block name="header"></block>
<block name="main">
<form class="form-signin" action="{:U('/user/reg')}" method="post">
<h2 class="form-signin-heading">注册</h2>
<label for="inputNickname" class="sr-only">用户名</label>
<input type="text" id="inputNickname" class="form-control hide-data" placeholder="用户名" required="" autofocus="" name="nickname">
<label for="inputPassword" class="sr-only">密码</label>
<input type="password" id="inputPassword" class="form-control hide-data" placeholder="密码" required="" name="pwd">
<button class="btn btn-lg btn-primary ajax-post" type="submit" target-form="form-signin">注册</button>
<a href="{:U('/user/login')}" class="btn btn-text">有账号了?点我去登录</a>
</form>
</block>
<block name="sidebar"></block>
~~~
至于提交表单的ajax,前面已经说过了,common.js里 ajax-post
由于注册和登录逻辑里面有特殊session处理,干脆就没有用rest。rest预留着给后台这种只可能批量添加用户数据,而不需要登录逻辑处理的使用。
//注册
~~~
public function reg(){
if(IS_POST){ //注册用户
$Member = D('Member');
$nickname = I('post.nickname');
$pwd = I('post.pwd');
$data = $Member->create(array('nickname'=>$nickname, 'pwd'=>$pwd));
if($data){
$Member->startTrans();
if($Member->add()){
if($Member->login($uid, $nickname)){
$Member->commit();
$this->success('注册成功',U('/user/login'));
} else {
$Member->rollback();
$this->error($Member->getError());
}
}else{
$Member->rollback();
$this->error($Member->getError());
}
}else{
$this->error($Member->getError());
}
} else { //显示注册表单
$this->display();
}
}
~~~
注意的几点:
1. 一个方法里通过IS_POST判断是否是提交数据还是页面显示
2. 使用了事务(数据表必须是支持事务的数据引擎,mysql的是innodb)
3. 插入数据前用模型验证
4. 注册完毕后自动登录(可以选择不自动登录)
## 注册验证和登录
~~~
protected $_validate = array(
array('nickname','','帐号名称已经存在!',0,'unique',self::MODEL_INSERT), // 在新增的时候验证name字段是否唯一
);
protected $_auto = array (
array('status','1'), // 新增的时候把status字段设置为1
array('settings', '{}'),
array('pwd','password',1,'function') , // 对password字段在新增的时候使password函数处理
array('create_at','datetime',self::MODEL_INSERT,'function'), // 对create_at字段在更新的时候写入当前时间戳
array('update_at','datetime',self::MODEL_BOTH,'function'), // 对create_time字段在更新的时候写入当前时间戳
);
~~~
自动验证和自动完成:
注册时需要验证账号是否被注册过
完成里序列化字段setting的初始化。密码字段pwd的加密处理。以及时间字段的自动完成。
PS:自动完成和自动验证里的时间参数最好用self::MODEL_INSERT 和self::MODEL_BOTH 及self::MODEL_UPDATE 这几个类静态常量,这样不用在0、1、2中记混了。
# 登录 User/login
![2015-06-23/5588c0ac83775](http://box.kancloud.cn/2015-06-23_5588c0ac83775.png)
~~~
public function login(){
if(IS_POST){ //登录验证
$Member = D('Member');
$nickname = I('post.nickname');
$pwd = I('post.pwd');
$uid = $Member->checkLogin($nickname, $pwd);
if(0 < $uid){
//登录用户
if($Member->login($uid, $nickname)){
$this->success('登录成功!',U('/mine'));
} else {
$this->error($Member->getError());
}
} else { //登录失败
switch($uid) {
case -1: $error = '用户不存在或被禁用!'; break; //系统级别禁用
case -2: $error = '密码错误!'; break;
default: $error = '未知错误!'; break; // 0-接口参数错误(调试阶段使用)
}
$this->error($error);
}
} else { //显示登录表单
$this->display();
}
}
~~~
登录逻辑也很简单,我们直接看POST部分,checkLogin用于检测用户是否存在以及密码是否对。正确后然后执行Mmember模型的login方法并跳转个人空间。
MemberModel里的checkLogin
~~~
public function checkLogin($nickname, $pwd){
$member = $this->where("nickname = '{$nickname}'")->find();
if($member){
if(password($pwd) == $member['pwd']){
return $member['id'];
}else{
return -2;
}
}else{
return -1;
}
}
~~~
Member里的login方法
~~~
public function login($uid, $nickname){
$array = array(
'uid' =>$uid,
'nickname'=>$nickname
);
try {
session('user', $array);
return true;
} catch (Exception $e) {
$this->error = '未知错误';
return false;
}
}
~~~
其实登录就是保存一个session到服务器里,然后用到登录的地方用于获取用户id和账号。
密码相关函数:
~~~
//密码加密
function password($password){
$md5str=md5($password);
$salt=get_password_salt($md5str);
return hash('sha256',$md5str.$salt);
}
function get_password_salt($md5str,$d=1001){
$crc32_value = floatval(sprintf("%u", crc32($md5str)));
$crc32_value = ($crc32_value > PHP_INT_MAX) ?
(($crc32_value - PHP_INT_MAX ) % $d + PHP_INT_MAX % $d) % $d : $crc32_value % $d;
return $crc32_value;
}
~~~
高级应用:
- session 设置前缀和过期时间
- cookie 自动登录
- [session存入数据库持久化](http://www.jb51.net/article/52557.htm)
- 序
- 前言
- 内容简介
- 目录
- 基础知识
- 起步
- 控制器
- 模型
- 模板
- 命名空间
- 进阶知识
- 路由
- 配置
- 缓存
- 权限
- 扩展
- 国际化
- 安全
- 单元测试
- 拿来主义
- 调试方法
- 调试的步骤
- 调试工具
- 显示trace信息
- 开启调试和关闭调试的区别
- netbeans+xdebug
- Socketlog
- PHP常见错误
- 小黄鸭调试法,每个程序员都要知道的
- 应用场景
- 第三方登录
- 图片处理
- 博客
- SAE
- REST实践
- Cli
- ajax分页
- barcode条形码
- excel
- 发邮件
- 汉字转全拼和首字母,支持带声调
- 中文分词
- 浏览器useragent解析
- freelog项目实战
- 需求分析
- 数据库设计
- 编码实践
- 前端实现
- rest接口
- 文章发布
- 文件上传
- 视频播放
- 音乐播放
- 图片幻灯片展示
- 注册和登录
- 个人资料更新
- 第三方登录的使用
- 后台
- 微信的开发
- 首页及个人主页
- 列表
- 归档
- 搜索
- 分页
- 总结经验
- 自我提升
- 进行小项目的锻炼
- 对现有轮子的重构和移植
- 写技术博客
- 制作视频教程
- 学习PHP的知识和新特性
- 和同行直接沟通、交流
- 学好英语,走向国际
- 如何参与
- 浏览官网和极思维还有看云
- 回答ThinkPHP新手的问题
- 尝试发现ThinkPHP的bug,告诉官方人员或者push request
- 开发能提高效率的ThinkPHP工具
- 尝试翻译官方文档
- 帮新手入门
- 创造基于ThinkPHP的产品,进行连带推广
- 展望未来
- OneThink
- ThinkPHP4
- 附录