差不多花了四天的时间做了登录、注册功能,做这个的原因是想巩固一下刚学的JavaScript和Ajax技术,代码都是一个个字母码出来的,用了不少的js特效做判断,其中页面间的数据传递用了Ajax技术、cookie缓存,数据库表字段看注册界面应该就知道,做出来的效果如下,还没怎么用css,引入了bootstrap文件:
1、登录界面(使用Ajax的post请求响应),以及一些登录情况的特效:
2、首页,都没有写,放两张美女图片就好(‘wuyuhua’就是通过cookie缓存获取)
3、用户管理页(这里只实现了Ajax异步删除。修改界面还没做,感觉和注册差不多)
4、注册页面(这里也是用的Ajax异步post请求响应)
5、文件目录如下:
一、步骤说明:
1、先画了一下登录、注册的流程图,清楚哪里该用什么判断等,因为登录、注册涉及到的判断太多;
2、然后开始布局文件:首先,肯定是登录文件login.php;其次,对登录页面提交的数据需要做判断check.php;然后,后台首页index.php、用户管理界面adminuser.php、用户删除界面delete.php;再然后,注册文件register;最后就是对注册提交的数据做判断的界面register_check.php;其他文件:connectdb.php为数据库连接文件,logout为退出登录清除cookie的文件,另外就是引入的bootstrap文件了;当然,一开始也不会想到有这些文件,只要知道个大概,以及从页面间的传值来考虑需要哪些文件;
3、最后就是开始写代码了。
4、总结了下:排除一些简单使用表单提交的方式做登录的情况,我目前所清楚的就是这几种做登录、注册功能的方式:
a.form表单提交的方式,必须定义其中<input>的name属性值,然后通过post、或者get方式提交,提交按钮为submit,然后可以在后台设置cookie或者session缓存,cookie缓存:保存在浏览器上;session缓存保存在服务器上;
b.Ajax异步提交的方式:form表单的<input type='submit'>需要改为<input type='button'>,也就是说,我们不会点击提交按钮,就直接跳转页面到后台了;而是点击按钮触发一些事件,并且这个点击需要自己通过js定义事件onclick;后台处理后,也可以进行cookie或session缓存;
大致方式如下:
二、代码解释
1、login.php代码,下面很多都是js特效做的判断,本来此文件不想加入PHP代码的,但是不用又不行,当用户点击历史回退时,又可以历史前进到后台,这一步我也查了不少的资料,都没有看到此类的解决方案,我不知道其它系统的登录是怎么做的,他们点击历史回退就不能在历史前进到后台了!我也考虑过加入其它判断,但是找不到在哪里加合适;在地址栏中引入参数也试过了,不行,历史回退后依然带着参数;
说的就是浏览左上角这两个历史纪录按钮;有没有点击这两个按钮的触发事件?或者其它方法实现?或者这是因为cookie原理的问题,换成session就好了?
<?php
if(isset($_COOKIE['username'])){
setcookie('username','',time()-1,'/');
//echo "<script>location.reload();</script>";
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Ajax+js+php++html+css+mysql+cookie+验证码实现登录退出及注册</title>
<link href='bs2/css/bootstrap.min.css' rel="stylesheet" >
<script src="bs2/js/bootstrap.min.js"></script>
<style>
#username{
font-size:10px;
color:red;
}
#password{
font-size:10px;
color:red;
}
.in{
width:150px;
height:20px;
}
*{
font-family:微软雅黑;
}
label{
font-size:18px;}
</style>
</head>
<body>
<div class='container' style=''>
<h3>欢迎登录WU系统!</h3>
<form action='javascript:' method='POST'>
<div class='form-group'>
<label >用户:
<input type='text' name='username' class='form-control' id='inuser'>
<span id='username'></span></label>
</div>
<div class='form-group'>
<label>密码:
<input type='password' name='password' class='form-control' id='inpassword'>
<span id='password'></span></label>
</div>
<div class='form-group' style=''>
<input type='button' value='登录' id='submit' class='btn btn-info'>
<input type='reset' value='重置' id='reset' class='btn btn-default'>
</div>
<!-- <input type='button' value='注册' οnclick="location='register.php'"> -->
</form>
<p>
还没有账号?
<a href="register.php">前往注册</a>>>
</p>
</div>
</body>
<script>
//获取对象
usernameobj = document.getElementById('username');
passwordobj = document.getElementById('password');
inuserobj = document.getElementById('inuser');
inpasswordobj = document.getElementById('inpassword');
submitobj = document.getElementById('submit');
//当用户聚焦于用户输入框时,提示消失
inuserobj.οnfοcus=function(){
usernameobj.innerHTML='';
inuserobj.style.borderColor='blue';
}
//当用户输入框失去焦点,且无值输入时,提示用户输入用户名,且边框变成红色!
inuserobj.οnblur=function(){
value=inuserobj.value;
if(value=='' || value==null){
inuserobj.style.borderColor='red';
usernameobj.innerHTML='请输入用户名!';
}else{
inuserobj.style.borderColor='grey';
}
}
//当用户聚焦于密码框
inpasswordobj.οnfοcus=function(){
//用户框中无输入时,提示用户输入用户名
value=inuserobj.value;
if(value=='' || value==null){
inuserobj.style.borderColor='red';
usernameobj.innerHTML='请输入用户名!';
}
//密码提示框消失
passwordobj.innerHTML='';
inpasswordobj.style.borderColor='grey';
}
//当密码输入框失去焦点,且密码框中无输入时,提示用户输入密码,且边框变为红色!
inpasswordobj.οnblur=function(){
value=inpasswordobj.value;
if(value=='' || value==null){
inpasswordobj.style.outline='none';
inpasswordobj.style.borderColor='red';
passwordobj.innerHTML='请输入密码!';
}else{
inpasswordobj.style.borderColor='grey';
}
}
//Ajax实现异步登录
//将常用的封装在函数里,不过这里对post方法进行封装反倒复杂了!
var xhr;
function XmlObj(method,url,cfunc){
xhr = new XMLHttpRequest();
//get请求方法,这在登录功能上肯定是不行的!
/* xhr.open('get','check.php?username='+username+'&password='+password,true);
xhr.send(); */
//post请求方法,需要用send传输数据
xhr.open(method,url,true);
//如果要传输数据,就需要设置请求头
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.onreadystatechange=cfunc;
}
//点击事件
submitobj.οnclick=function(){
username = inuserobj.value;
password = inpasswordobj.value;
//加入用户名或密码为空的判断,此处一定要注意用==,两次都在这里捣鼓半天!
if(password=='' || password==null || username=='' || username==null){
alert('请输入用户名或密码!');
}else{
XmlObj('post','check.php',function(){
if(xhr.readyState==4 && xhr.status==200){
r = xhr.responseText;
if(r==1){
location='index.php';
}else{
alert('用户名或密码不正确!请重新输入用户名和密码!');
inuserobj.value='';
inpasswordobj.value='';
}
}
});
xhr.send("username="+username+"&password="+password);
}
}
</script>
</html>
2、登录提交数据的判断页面check.php,需要用到PHP的PDO扩展,连接数据库,获取数据:
<?php
require_once('connectdb.php');
//判断是否正常登录用户
if(isset($_POST['username']) && isset($_POST['password'])){
$username = $_POST['username'];
$password = md5($_POST['password']);
/* $username = $_GET['username'];
$password = $_GET['password']; */
//这里的变量一定需要加单引号!原因就是原生的sql语句等号后面的字符串都有引号!
$sql1 = "select user from users where user='$username';";
$sql2 = "select*from users where user='$username' and password='$password';";//判断
$smt1 = $pdo->query($sql1);
$smt2 = $pdo->query($sql2);
$rows1 = $smt1->fetch(PDO::FETCH_BOTH);
$rows2 = $smt2->fetch(PDO::FETCH_BOTH); //这里用fetch比较好,不要用fetchAll,fetchAll打印所有行数,生成二维数组;
if(empty($rows1['user'])){
echo "<script>alert('用户名不存在!请重新登录!');</script>";
}
if(!empty($rows2['user'])){
//当存在用户名时,设置cookie缓存
$user = $rows2['user'];
setcookie('username',$user,time()+3600,'/');
echo 1;//"<script>location='index.php'</script>";
}else{
echo 0;//"<script>location='login.php'</script>";
}
}else{
//这里也加一个判断,非正常登录用户强制返回登录界面!
echo "<script>location='login.php'</script>";
}
?>
3、后台首页index.php,这个随便怎么写了,只不过还是需要做一定的判断,防止用户直接通过地址访问进入后台:
<?php
//判断是否是通过登录过来的用户,不是就强制返回到登录界面!isset的用法真的重要!
if(!isset($_COOKIE['username'])){
echo "<script>location='login.php'</script>";
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>首页</title>
<link href='bs2/css/bootstrap.min.css' rel="stylesheet" >
<script src="bs2/js/bootstrap.min.js"></script>
</head>
<body>
<div class='container'>
<h1 class='page-header'>
<?php
$username = $_COOKIE['username'];
echo $username;
?>
,欢迎来到后台!</h1>
<div>
<img src='meinv.jpg' style='width:450px;height:350px;'>
<a href='http://www.27270.com/ent/meinvtupian/'>惊喜</a>
<img src='meinv2.jpg' style='width:450px;height:350px;'>
</div>
<p>
</p>
<div>
<a href='adminuser.php' class="btn btn-success">管理用户</a>
<a href='javascript:' id='aid' class="btn btn-default">退出登录</a>
</div>
</div>
</body>
<script>
aidobj = document.getElementById('aid');
aidobj.οnclick=function(){
location='logout.php';
}
</script>
</html>
4、退出登录logout.php,这里也比较重要,可能是因为我用的cookie缓存,而cookie的原理是此页面将cookie删除了,如果另外一个页面不刷新,它还是可以用cookie,这个问题我没有解决好,想知道谁有比较好的方法:
<?php
//删除cookie;需要删除了,后台的判断才能生效!
//退出登录了,当点击历史返回时,也可以进入后台,再点击刷新会自动跳转到登录界面,这和cookie原理有关
setcookie('username','',time()-1,'/');
/* if(isset($_COOKIE['username'])){
echo $_COOKIE['username'];
}else{
echo 1;
} */
//把页面先重新加载一下,删除cookie(重点,之前一直在考虑这个问题!也算是解决了cookie多留一次的问题);再跳转到登录界面
echo "<script>location.reload();location='login.php'</script>";
5、注册界面register.php,需要做的判断更多,因此js写的判断也比较多:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>欢迎注册</title>
<link href='bs2/css/bootstrap.min.css' rel="stylesheet" >
<script src="bs2/js/bootstrap.min.js"></script>
<style>
.coll{
font-size:15px;
color:red;
}
</style>
</head>
<body>
<div class='container'>
<h1 class='page-header'>欢迎注册!</h1>
<form action='javascript:' method='post'>
<p>
<label>用户:<span style="font-size:;color:red">*</span>
<input type='text' name='username' id='username' class='collection' placeholder='请输入用户名'>
<span class='coll'></span></label>
</p>
<p>
<label>密码:<span style="font-size:;color:red">*</span>
<input type='password' name='password' id='password' class='collection' placeholder='请输入密码'>
<span class='coll'></span></label>
</p>
<p>
<label>确认密码:<span style="font-size:;color:red">*</span>
<input type='password' name='sepassword' id='sepassword' class='collection' placeholder='请确认密码'>
<span class='coll'></span></label>
</p>
<p>
<label>邮箱:
<input type='email' name='email' id='email' class='collection' placeholder='请输入邮箱'>
<span class='coll'></span></label>
</p>
<p>
<label>手机号:<span style="font-size:;color:red">*</span>
<input type='text' name='number' id='number' class='collection' placeholder='请输入手机号'>
<a href=''>发送验证码</a>
<span class='coll'></span></label>
</p>
<p>
<label>验证码:<span style="font-size:;color:red">*</span>
<input type='text' name='validate' id='validate' class='collection' placeholder='请输入验证码'>
<span class='coll'></span></label>
</p>
<p>
<span style="font-size:10px;color:red">*必填</span>
<input type='button' name='' id='register' class='btn btn-success' value='注册'>
<input type='reset' name='' id='reset' class='btn btn-default' value='取消'>
</p>
</form>
<a href='login.php'>返回登录</a>
</div>
</body>
<script>
//获取对象集合,0-5分别表示用户名、密码、确认密码、邮箱、手机号、验证码
collobjs = document.getElementsByClassName('collection');
spancollobjs = document.getElementsByClassName('coll');
//用户输入框聚焦时
collobjs[0].οnfοcus=function(){
this.style.outlineColor='blue';
}
//用户输入框失去焦点时
collobjs[0].οnblur=function(){
if(this.value==null || this.value=='' || this.value=='请输入密码'){
this.style.borderColor='red';
spancollobjs[0].innerHTML='请输入用户名';
}else{
this.style.borderColor='grey';
spancollobjs[0].innerHTML='';
}
}
//密码输入框聚焦时
collobjs[1].οnfοcus=function(){
this.style.borderColor='blue';
}
//密码输入框失去焦点时
collobjs[1].οnblur=function(){
//判断输入值
if(this.value==null || this.value=='' || this.value=='请输入密码'){
this.style.borderColor='red';
spancollobjs[1].innerHTML='请输入密码'; //innerHTML后面的一定要大写!
}else{
this.style.borderColor='grey';
spancollobjs[1].innerHTML='';
//密码框与下面的确认密码框都需要对输入的密码进行比对!
if(collobjs[2].value){ //首先判断确认密码框的值是否设置!
if(collobjs[1].value != collobjs[2].value){
spancollobjs[2].innerHTML='两次输入密码不一致!';
//alert('两次输入密码不一致!');
}else{
spancollobjs[2].innerHTML='';
}
}
}
}
//密码确认框失去焦点时
collobjs[2].οnblur=function(){
//判断输入值
if(this.value==null || this.value=='' || this.value=='请输入密码'){
this.style.borderColor='red';
spancollobjs[2].innerHTML='请输入密码'; //innerHTML后面的一定要大写!
}else{
this.style.borderColor='grey';
spancollobjs[2].innerHTML='';
//密码比对
if(collobjs[1].value != collobjs[2].value){
spancollobjs[2].innerHTML='两次输入密码不一致!';
//alert('两次输入密码不一致!');
}else{
spancollobjs[2].innerHTML='';
}
}
}
//邮箱输入框失去焦点时
collobjs[3].οnblur=function(){
//判断值是否为空
if(this.value==null || this.value=='' || this.value=='请输入邮箱'){
spancollobjs[3].innerHTML='请输入邮箱!';
}else{
this.style.borderColor='grey';
spancollobjs[3].innerHTML='';
//匹配邮箱格式
if(!this.value.match(/^\w+@\w+\.\w+$/)){
spancollobjs[3].innerHTML='邮箱格式不正确!';
}
}
}
//手机输入框失去焦点时
collobjs[4].οnblur=function(){
//判断值是否为空
if(this.value==null || this.value=='' || this.value=='请输入手机号'){
spancollobjs[4].innerHTML='请输入手机号!';
}else{
this.style.borderColor='grey';
spancollobjs[4].innerHTML='';
//匹配手机号位数,规定11位
if(!this.value.match(/^\d{11}$/)){
spancollobjs[4].innerHTML='请输入正确手机号!';
}
}
}
//验证码输入框失去焦点时
collobjs[5].οnblur=function(){
//判断值是否为空
if(this.value==null || this.value=='' || this.value=='请输入验证码'){
spancollobjs[5].innerHTML='请输入验证码!';
}else{
this.style.borderColor='grey';
spancollobjs[5].innerHTML='';
//匹配验证码,4位
if(!this.value.match(/^\w{4}$/)){
spancollobjs[5].innerHTML='请输入正确验证码!';
}
}
}
//获取注册对象并生成点击事件,用Ajax请求响应
registerobj = document.getElementById('register');
registerobj.οnclick=function(){
username = collobjs[0].value;
password = collobjs[1].value;
sepassword = collobjs[2].value;
email = collobjs[3].value;
number = collobjs[4].value;
validate = collobjs[5].value;
//alert(username+'-'+password+'-'+sepassword+'-'+email+'-'+number+'-'+validate);
xhr = new XMLHttpRequest();
xhr.open('post','register_check.php',true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send("username="+username+"&password="+password+"&sepassword="+sepassword+"&email="+email
+"&number="+number+"&validate="+validate);
xhr.onreadystatechange = function(){
if(xhr.readyState==4 && xhr.status==200){
r = xhr.responseText;
if(r==1){
location='login.php';
}else if(r==2){
alert('两次输入密码不一致!');
}else if(r==3){
alert('该用户已存在!');
}else if(r==4){
alert('请输入正确的手机号!');
}else if(r==5){
alert('请输入用户名!');
}else if(r==6){
alert('请输入密码!');
}else{
alert('注册失败,请重新注册!');
}
}
}
}
</script>
</html>
6、register_check.php注册判断文件,因为注册页面我也是用的Ajax异步提交数据,所以需要通过判断返回类似状态码的东西:
<?php
require_once('connectdb.php');
//echo $_POST['username'];
if(isset($_POST['username']) && isset($_POST['password']) && isset($_POST['sepassword']) && isset($_POST['number']) && isset($_POST['validate'])){
if($_POST['username']==null || $_POST['username']==''){
echo 5; //无用户名输入返回码,注册失败
}else{
if($_POST['password']==null && $_POST['password']==''){
echo 6; //无密码输入返回码,注册失败
}else{
$username = $_POST['username'];
$passwordsub = $_POST['password'];
$password = md5($_POST['password']);//插入数据库中的数据需要md5加密
$sepassword = $_POST['sepassword'];
$number = $_POST['number'];
$validate = $_POST['validate'];
$getusersql="select user,number from users where user='$username';";
$smt = $pdo->query($getusersql);
$userrows = $smt->fetch(PDO::FETCH_BOTH);
//判断用户是否存在
if($userrows['user']){
echo 3; // 该用户已存在返回码,注册失败
}else{
//两次密码输入不一致判断
if($passwordsub != $sepassword){
echo 2; //密码不一致返回码,注册失败
}else{
//判断手机号位数,规定11位
if(preg_match('/^\d{11}$/',$number)){
if(isset($_POST['email'])){
$email = $_POST['email'];
$sql="insert into users(user,password,number,email,validate) values('$username','$password','$number','$email','$validate')";
}else{
$sql="insert into users(user,password,number,validate) values('$username','$passord','$number','$validate')";
}
if($pdo->exec($sql)){
echo 1;//注册成功
}else{
echo 0;//注册失败(sql执行语句失败,服务器原因)
}
}else{
echo 4; //手机号非11位返回码,注册失败
}
}
}
}
}
}else{
echo 0;//注册失败
}
?>
7、后台用户管理界面adminuser,php,Ajax异步删除:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>用户管理</title>
<link href='bs2/css/bootstrap.min.css' rel="stylesheet" >
<script src="bs2/js/bootstrap.min.js"></script>
</head>
<body>
<div class='container'>
<h1 class='page-header'>用户管理</h1>
<p>
<?php
require_once('connectdb.php');
/* $pdo = new PDO('mysql:host=localhost;dbname=test','root','shapolang');
$pdo->exec('set names utf8'); */
$sql="select * from users";
$smt=$pdo->query($sql);
$rows=$smt->fetchAll();
echo "<table class='table table-striped table-hover table-bordered' width='1000px' border='1px' cellspacing='0'>";
echo "<tr>";
echo "<th>用户id</th>";
echo "<th>用户名</td>";
echo "<th>邮箱</th>";
echo "<th>手机号</th>";
echo "<th>操作</th>";
echo "</tr>";
foreach($rows as $row){
echo "<tr id='{$row['id']}'>";
echo "<td >$row[id]</td>";
echo "<td>$row[user]</td>";
echo "<td>$row[email]</td>";
echo "<td>$row[number]</td>";
echo "<td><a href='javascript:' class='btn btn-warning'>修改</a> <a href='javascript:' class='del' num='{$row['id']}'>删除</a></td>";//href='delete.php?id={$row['id']}'
echo "</tr>";
}
echo "</table>";
?>
</p>
<p>
<button class='btn btn-success' οnclick="location='index.php'">返回首页</button>
<button class='btn btn-default' οnclick="location='logout.php'">退出登录</button>
</p>
</div>
</body>
<script>
trobjs=document.getElementsByClassName('del');
//alert(trobjs);
for(i=0;i<trobjs.length;i++){
trobjs[i].οnclick=function(){
id=this.getAttribute('num');
//alert(id);
xhr=new XMLHttpRequest();
xhr.open('get','delete.php?id='+id,true);
xhr.send();
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
r=xhr.responseText;
//alert(r);
if(r==1){
tr=document.getElementById(id);
tr.style.display='none';//后台删除成功后让这行隐藏掉,你看到就会是点击删除,页面不会有任何跳转,这一行就没了!这就是异步删除!
}
}
}
}
}
</script>
</html>
8、用户管理后台处理页面,删除成功返回1;
<?php
$id = $_GET['id'];
require_once('connectdb.php');
/* $pdo = new PDO('mysql:host=localhost;dbname=test','root','shapolang');
$pdo->exec('set names utf8'); */
$sql="delete from users where id={$id}";
if($pdo->query($sql)){
echo 1;
}else{
echo 0;
}
?>
以上就是整个代码,如果一步步将异步的实现机制详细讲解,我讲的还不如相关教程或视频来得快,因此,我对关键的逻辑进行了注释;但是通过这几天的不断进攻js、Ajax,也可以谈谈我对Ajax的理解:你请求某个地址,通过post或者get的方式去请求某个地址,这个地址做出反应之前,它在后台一直默默的准备着随时响应你的请求,该地址做出反应并响应一个json或者xml格式的数据给你,你获取这个数据就可以使用。
三、另外就是一些检查工具的使用了,浏览器自带的检查工具,下面这几个地方,可以让你观察异步请求的状态,以及一些错误提示:
好,写了也有这么多了,这篇文章一开始是打算纪录我的JavaScript学习之旅,结果最后弄成了Ajax占据主导地位,当然,js特效判断也不少!之前本来也打算把所有的登录方式都实现一遍,不过现在看来,其实也就两种,如果再笼统一点,归根结底就一种方式:那就是form表单提交!
写这个登录注册功能,真的学到了不少的东西,一是逻辑判断;二是原来一直模模糊糊的md5加密,不知道在哪用,怎么用,写了这个之后,就清晰了:将登录用户的密码md5加密一次,与数据库已经md5加密过的密码进行比对就行了;三是真的弄懂了Ajax技术实现的机制,包括post与get异步提交方式的不同;四是深刻理解了cookie原理,同时也被cookie原理坑得死去活来;五是完完全全用自己写的代码、一个字母一个字母敲出来的实现还算不错的登录注册功能(至少在很多逻辑上及js特效上还不错)……总之,收获颇丰!当然,也有很多不足,代码上的封装较少、逻辑代码冗余等;之后可能还会加入登录验证码,注册时的短信验证码功能!
未来的路很长,将一直在路上!