利用PDO 查询数据渲染到页面中

  1. <?php
  2. /**
  3. * pdo fetch() 返回结果集下一行 +while()
  4. */
  5. $pdo = new PDO('mysql:host=localhost;dbname=mydb','root','root');
  6. $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
  7. $sql = "SELECT * FROM student WHERE ssex= ?";
  8. echo "<h1>男同学</h1>";
  9. $sth = $pdo -> prepare($sql);
  10. $sth->bindValue(1,"男");
  11. $sth->execute();
  12. $html = "<ul>";
  13. while ($res = $sth -> fetch()) {
  14. $html .= "<li>学号:{$res['sno']} ,姓名: {$res['sname']} ,性别: {$res['ssex']} ,出生日期: {$res['sbirthday']} ,所在班级:{$res['sclass']}</li>";
  15. }
  16. $html .= "</ul>";
  17. echo $html;
  18. echo "<h1>女同学</h1>";
  19. $sth->execute(["女"]);
  20. $html = "<ul>";
  21. while ($res = $sth -> fetch()) {
  22. $html .= "<li>学号:{$res['sno']} ,姓名: {$res['sname']} ,性别: {$res['ssex']} ,出生日期: {$res['sbirthday']} ,所在班级:{$res['sclass']}</li>";
  23. }
  24. $html .= "</ul>";
  25. echo $html;
  26. ?>

  1. <?php
  2. /**
  3. * pdostatement->fetchAll() foreach
  4. */
  5. $pdo = new PDO('mysql:host=localhost;dbname=mydb','root','root');
  6. $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);
  7. $sql = "SELECT * FROM student WHERE ssex= ?";
  8. echo "<h1>男同学</h1>";
  9. $sth = $pdo -> prepare($sql);
  10. $sex = "男";
  11. $sth->bindParam(1,$sex);
  12. $sth->execute();
  13. $html = "<ul>";
  14. foreach($sth->fetchAll() as $key => $value) {
  15. $html .= "<li>学号:{$value['sno']} ,姓名: {$value['sname']} ,性别: {$value['ssex']} ,出生日期: {$value['sbirthday']} ,所在班级:{$value['sclass']}</li>";
  16. }
  17. $html .= "</ul>";
  18. echo $html;
  19. echo "<h1>女同学</h1>";
  20. $sth->execute(["女"]);
  21. $html = "<ul>";
  22. foreach($sth->fetchAll() as $key => $value) {
  23. $html .= "<li>学号:{$value['sno']} ,姓名: {$value['sname']} ,性别: {$value['ssex']} ,出生日期: {$value['sbirthday']} ,所在班级:{$value['sclass']}</li>";
  24. }
  25. $html .= "</ul>";
  26. echo $html;
  27. ?>

页面数据的作用域:

当前页共享数据:变量、常量

两个页面间传递数据:get,post

跟踪用户的多页面数据共享(会话):session、cookie

全局数据共享:文件、数据库、memcached

Cookie:

数据存储在浏览器文件中

数据通过请求头携带信息(Cookie:)进行页面cookie数据传递

Session:

数据默认保存在服务器文件中

客户端对应cookie中只保存sessionID($_COOKIE[“PHPSESSID”];)

会话控制

http是无状态的协议,也就是说,http没有一个 内建机制来维护两个事物之间的状态。比如说当用户登陆一个站点后,再去请求一个页面时,http无法告诉我们此用户已登陆。

会话控制是一种面向连接的可靠通信方式,通常用来判断用户的登录行为。例如,当我们在某个 E-mail 系统上成功登录以后,在这之间的查看邮件、收信、发信等过程可能需要访问多个页面来完成,但在同一个系统上,多个页面之间互相切换时,还能保持用户登录的状态,并且访问的都是登录用户自己的信息。这种能够在网站中跟踪一个用户,并且可以处理在同一个网站中同一个用户在多个页面共享数据的机制,都需要使用会话控制来完成的。

会话控制包括 Session 和 Cookie 两种技术。两者既有区别又有相通之处,它们的主要功能都是把客户端与服务器端有机地关联起来,以便能够有效管理和查看用户在网站中的状态。

Cookie 是在 HTTP 协议下,服务器或脚本用来维护客户端上信息的一种方式。Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息。无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息。

有些 Cookie 是临时的,有些则是持续的。临时的 Cookie 只在浏览器上保存一段规定的时间,一旦超过规定的时间,该 Cookie 就会被系统清除。

持续的 Cookie 则保存在用户的 Cookie 文件中,下一次用户返回时,仍然可以对它进行调用。在 Cookie 文件中保存 Cookie,有些用户担心 Cookie 中的用户信息被一些别有用心的人窃取,而造成一定的损害。

其实,网站以外的用户无法跨过网站来获得 Cookie 信息。如果因为这种担心而屏蔽 Cookie,肯定会因此拒绝访问许多站点页面。因为,当今有许多 Web 站点开发人员使用 Cookie 技术,例如 Session 对象的使用就离不开 Cookie 的支持。

  1. <?php
  2. /**
  3. * 会话控制
  4. *
  5. * 网页间传递数据
  6. * 1. 超链接 http post get input hidden , header()url重定向 header('Location:https:php.cn?id=1');
  7. *
  8. *
  9. * 2. 会话控制 保存用户信息 在多个网页之间共享
  10. *
  11. */
  12. //cookie 保存用户信息在客户端
  13. //cookie 会员卡 姓名 手机号 注册时间
  14. //http 打卡机 只认会员卡 不认人 http是无状态的 短连接
  15. //为了将你识别 就给你发会员卡 叫cookie
  16. // setcookie($name,$value,$expire,$path,$domain,$secure);
  17. setCookie('uname','chloe');//没有设置$expire,cookie由浏览器维护
  18. echo $_COOKIE['uname'];
  19. //服务端: 第一步解析setCookie('uname','chloe');(通过响应头告诉浏览器我要设置一个cookie 值 为chloe),服务端返回信息Set-Cookie: uname=chloe, 浏览器接收这个响应头, 把cookie储存的信息放到客户端的某个文件中
  20. // 刷新浏览器 cookie会被带到请求头中发送,就能取到值
  21. // js document.cookie;

Cookie 是 HTTP 响应头的一部分,而响应头必须在页而其他内容之前发送,它必须最先输出。若在 setcookie() 函数前输出一个 HTML 标记或 echo 语句,甚至一个空行都会导致程序出错。

  1. session.use_cookies = 1 //设置cookie是否开启
  2. session.cookie_path = "d:/tmp" //|"d:/tmp" :设置cookie路径,一定在使用cookie之前设置
  3. // PHP中使用 setcookie() 函数用户客户端cookie数据
  4. setcookie(string $name [, string $value = "" [, int $expire = 0 [, string $path = "" [, string $domain = "" ]]]])

参数说明如下:

参数说明
$name设置 Cookie 的名称
$value用来设置 Cookie 的值。可以通过 $_COOKIE[‘$name’] 的形式来获取 $value 的值
$expires用来设置 Cookie 的过期时间,这个时间是 Unix 时间戳的形式,可以使用time()函数加上希望它到期之前的秒数来设置它。如果设置成零或者忽略该参数,Cookie 会在会话结束时过期(也就是关掉浏览器时);。
$path用来设置 服务器上可以使用cookie的有效路径。如果设置为“/”,Cookie 对整个域名 $domain 有效,如果设置成’/foo/‘,则 Cookie 仅仅对 $domain 中 /foo/ 目录及其子目录有效(比如 /foo/bar/)。默认值为设置 Cookie 时的目录;
$domain用来设置 Cookie 的有效域名/子域名。设置成子域名(例如 ‘php.zhang.com’),会使 Cookie 对这个子域名和它的三级域名有效(例如 v.php.zhang.com)。 要让 Cookie 对整个域名有效(包括它的全部子域名),只要设置成域名就可以了(例如 ‘zhang.com’);
$secure表示cookie应仅通过客户端的安全HTTPS连接传输
$httponlyTRUEcookie只能通过HTTP协议访问时。这意味着脚本语言(例如JavaScript)无法访问cookie。

注意:如果在调用 setcookie() 函数以前产生了输出,setcookie() 会调用失败并返回 FALSE。 如果 setcookie() 成功运行,则会返回 TRUE。

  1. <?php
  2. // cookie是客户端存储数据的手段,并在请求服务器时自动携带cookie数据
  3. //设置cookie 参数(键,值,时间)
  4. //时间不写或者为0,则会保存至关闭浏览器程序
  5. //时间其他值为xx秒
  6. if(!empty($_COOKIE)){
  7. echo '<pre>';
  8. print_r($_COOKIE);
  9. }else{
  10. setcookie('Website', 'php中文网');
  11. setcookie('Title', 'Cookie', time()+3600); // 设置 Cookie 1 小时后过期
  12. setcookie('Url', 'http://zhang.com', time()+3600);
  13. }
  14. ?>

提示:当第一次运行这个脚本文件时并不会有任何输出信息,因此设置完 Cookie 后需要刷新一下页面,这样在下次请求时 HTTP 头部才会携带上一次设置的 Cookie 信息,这时才能读取到 Cookie。

如果 Cookie 设置成功,客户端就拥有了 Cookie 文件,用来保存 Web 服务器为其设置的用户信息。以 Chrome 浏览器为例,其 Cookie 文件就存放在“C:\Users\用户名\AppData\Local\Google\Chrome\User Data\Default”目录下的 Cookies 文件中。

Cookie 是一个以文本形式记录信息的,当我们再次访问一个网站时,浏览器会自动把与该站点对应的 Cookie 信息全部发送给服务器。

从 PHP5 之后,任何 Cookie 信息都会被自动保存在超全局变量 $_COOKIE 中,所以在每个 PHP 脚本中都可以从 $_COOKIE 中读取相应的 Cookie 信息。$_COOKIE 中存储着所有通过 HTTP 传递的 Cookie 内容,并以 Cookie 的识别名称为索引值、内容值为元素。

在设置 Cookie 的脚本中,第一次读取它的信息并不会生效,必须刷新或下一个执行脚本时才可以看到 Cookie 值,因为 Cookie 要先被设置到浏览器中,当再次访问时才能被发送过来,这时才能被获取。所以要测试一个 Cookie 是否被成功设定,可以再其到期之前通过另外一个页面来访问其的值。

因为cookie保存在客户端并在请求时提交到后台服务器,所以可以在前台与后台访问到cookie。

  • 前台使用 document.cookie 获取cookie数据
  1. document.cookie
  • 后台使用超全避数组$_COOKIE读取
  1. print_r($_COOKIE);
  1. <?php
  2. if(!isset($_COOKIE['time'])){ //检测 Cookie 文件是否存在
  3. setcookie('time',date('Y-m-d H:i:s')); //设置一个 Cookie 变量
  4. echo "第一次访问<br>";
  5. }else{
  6. echo "上次访问的时间为:".$_COOKIE['time'].'<br>'; //输出上次访问网站的时间
  7. setcookie('time',date('Y-m-d H:i:s'),time()+60); //设置保存 Cookie 失效的时间的变量
  8. }
  9. echo "本次访问的时间为:".date('Y-m-d H:i:s'); //输出当前的访问时间
  10. ?>

当 Cookie 被创建后,如果没有设置它的失效时间,其 Cookie 文件会在关闭浏览器时被自动删除,如果要在关闭浏览器之前删除 Cookie 文件,同样需要使用 setcookie() 函数。

删除 Cookie 和创建 Cookie 的方式类似,只需要使用 setcookie() 函数将 Cookie 的值(也就是第二个参数)设置为空,或者将 Cookie 的过期时间(也就是第三个参数)设置为小于系统的当前时间即可。

  1. <?php
  2. echo '<pre>';
  3. if(!isset($_COOKIE['url']) && !isset($_COOKIE['name'])){
  4. setcookie('url','http://php.cn');
  5. setcookie('name','php中文网');
  6. setcookie('title','cookie');
  7. echo '首次运行,设置 url、name、title 的 Cookie 的值';
  8. }else if(isset($_COOKIE['url'])){
  9. echo '查看 Cookie 的值,如下所示:<br>';
  10. echo "<pre>";
  11. print_r($_COOKIE);
  12. echo '清除 url、name的值';
  13. // 将 Cookie 的值设置为空的方式来清除 Cookie
  14. setcookie('url','');
  15. // 通过将 Cookie 的过期时间设置为小于系统方式清除 Cookie
  16. setcookie('name','php中文网',time()-1);
  17. }else{
  18. print_r($_COOKIE);
  19. }
  20. ?>

设置会话cookie,当关闭浏览器时自动删除

  1. setcookie('web','houdunren.com');

设置七天内有效的cookie

  1. setcookie('web','houdunren.com',time()+60*60*24*7);

只允许cookie在 /app 访问路径中有效

  1. setcookie('web','houdunren.com',0,'/app')

设置访问域名

  1. setcookie('web','hdcms.com',0,'/','php.test')

设置只允许https访问

  1. setcookie('web','hdcms.com',0,'/','',true);

不允许javascript操作cookie

  1. setcookie('web','hdcms.com',0,'','',false,false,true);

cookie的到期时间设置为过去时间,就可以删除cookie。

  1. setcookie('name','',1);

大部分 Web 系统软件都会有登录和退出模块,这是为了维护系统的安全性,确保只有通过身份验证的用户才能访问该系统。而本节我们要介绍的自动登录,就是在用户第一次成功登录某个网站后的一段时间内,再次登录这个网站时就不再需要填写用户名和密码,而是可以直接进入。

要实现自动登录功能我们大多是利用浏览器的 Cookie 来实现。实现思路是在用户登陆成功后使用 Cookie 来保存用户的登陆信息,并在 PHP 脚本中跟踪登录用户的信息,在 Cookie 的有效期内让用户一直保持登陆状态。下面来看一下具体的实现代码:

  1. <?php
  2. /**
  3. * 首页
  4. */
  5. function index(){
  6. $logout = isset($_POST['logout'])?$_POST['logout']:'';
  7. $user = isset($_COOKIE['user'])?$_COOKIE['user']:'';
  8. $rem = isset($_COOKIE['remember'])?$_COOKIE['remember']:'';
  9. if($logout == 'true'){ //判断是否执行退出登陆
  10. logout();
  11. }else if($user == ''){ //如果Cookie中没有用户信息则执行登陆操作
  12. login();
  13. }else{ //显示首页
  14. //首页的html代码
  15. $str = <<<html
  16. <!DOCTYPE html>
  17. <html lang="en">
  18. <head>
  19. <meta charset="UTF-8">
  20. <title>php中文网</title>
  21. </head>
  22. <body>
  23. <form action="" method="post">
  24. <h1>欢迎{$user}登录成功!</h1>
  25. <p><input type="hidden" value="true" name="logout" /></p>
  26. <p><input type="submit" value="退出登陆" /></p>
  27. </form>
  28. </body>
  29. </html>
  30. html;
  31. echo $str;
  32. }
  33. }
  34. /**
  35. * 登陆
  36. */
  37. function login(){
  38. //获取提交的用户信息
  39. $user = isset($_POST['user'])?trim($_POST['user']):'';
  40. $pwd = isset($_POST['pwd'])?trim($_POST['pwd']):'';
  41. $rem = isset($_POST['remember'])?$_POST['remember']:'';
  42. if($user == ''){ //如果用户名为空,则显示登陆页面
  43. // 登陆页面的html代码
  44. $info = <<<html
  45. <!DOCTYPE html>
  46. <html lang="en">
  47. <head>
  48. <meta charset="UTF-8">
  49. <title>php中文网</title>
  50. </head>
  51. <body>
  52. <form action="" method="post">
  53. <p>用户名:<input type="text" name="user" /></p>
  54. <p>密&emsp;码:<input type="password" name="pwd" /></p>
  55. <p><input type="checkbox" name="remember" value='true'/>自动登陆</p>
  56. <p><input type="submit" value="登 陆" />&emsp;&emsp;<input type="reset" value="重 置" /></p>
  57. </form>
  58. </body>
  59. </html>
  60. html;
  61. echo $info;
  62. }else{
  63. if(!empty($user) && !empty($pwd)){ // 登陆成功,并记录Cookie信息
  64. if($rem != ''){
  65. setcookie('user',$user,time()+3600*24*7);
  66. setcookie('remember',$rem,time()+3600*24*7);
  67. }else{
  68. setcookie('user',$user);
  69. }
  70. echo '<script>alert(\'登陆成功\');location.replace(location.href);</script>';
  71. }else{ //登陆失败时,刷新页面
  72. echo '<script>alert(\'用户名或密码不能为空\');location.replace(location.href);</script>';
  73. }
  74. }
  75. }
  76. /**
  77. * 退出登陆
  78. */
  79. function logout(){
  80. // 清除 Cookie 信息,并刷新页面
  81. isset($_COOKIE['user']) ? setcookie('user','',time()-1) : '';
  82. isset($_COOKIE['remember']) ? setcookie('remember','',time()-1) : '';
  83. echo '<script>alert(\'退出成功\');location.replace(location.href);</script>';
  84. }
  85. index(); //执行 index 函数
  86. ?>

Session 服务器端

在 PHP 中,Session 是一种服务器端的机制,服务器使用一种散列表的结构(类似于 JSON)来保存信息。相比于保存在客户端的 Cookie,Session 将用户交互信息保存在了服务器端,使得同一个客户端每次和服务端交互时,不需要每次都传回所有的 Cookie 值,而是只需要传回一个 ID 即可,这个 ID 是客户端第一次访问服务器的时候生成的,而且是唯一的。

还有一点就是,因为 Cookie 存储在客户端,所以用户有权禁用 Cookie,而 Session 是存储在服务器端的,用户无法禁用。

php会话是通过唯一的会话ID来驱动的,会话ID是一个加密的随机数字,它由php生成,在会话的生命周期中都会保存在客户端,可以保存在用户机器的cookie中,或者通过url在网络上传递。在一些网站的URL中可以看到类似随机数字的字符串,可能就是某种形式的会话控制,cookie是与会话不同的解决方法,解决了在多个事务之间保持状态的问题,同时,他还可以保持一个整洁的 URL。

  1. <?php
  2. /**
  3. * session 保存用户信息在服务器
  4. * 用户只需要保存一个卡号 PHPSESSID = '文件名'
  5. */
  6. session_start();//开启session会话
  7. $_SESSION['uname'] = 'chloe';
  8. $_SESSION['pwd'] = md5('123456');
  9. //删除session,并不会删除session文件 只是清空
  10. // unset($_SESSION['pwd']);
  11. // unset($_SESSION['uname']);
  12. // $_SESSION = [];
  13. session_destroy();
  14. // session缺点
  15. 1. 用户量多的时候, 严重限制了服务器的扩展能力.
  16. 2. 负载均衡,转发请求 , session复制
  17. 3. Memcached 服务器 session id 集中储存到一个no sql数据库,

开启会话 Session

Session 的使用不同于 Cookie,在使用 Session 之前必须先启动,以便让 PHP 核心程序,将和 Session 相关的内建环境变量预先载入到内存中。

使用 session_start() 函数来开启一个新的 Session 会话

  1. //开启session//将会向客户端发送一个sessionID,保存在客户端cookie中session_start();

参数 $options(可选参数)为一个关联数组

https://www.php.net/manual/zh/session.configuration.php

也将php设置为当有用户访问时就自动启动会话一个会话。可以通过修改php.ini配置项 session.auto_start,自动开启会话(开启后将导致无法使用对象作为会话变量)

调用 sessionstart() 函数会生成一个唯一的 Session ID,并保存在浏览器的 Cookie 中,默认名称为“PHPSESSID”。同时,在服务器本地目录中生成一个以“sess”加上 Session ID 组成的 Session 文件,用来存储 Session 中的数据

设置和获取Session

$_SESSION 同 $_POST、$_GET 和 $_COOKIE 等一样成为了超级全局数组,但是在使用 $_SESSION 之前必须先使用 session_start() 函数来开启 Session 才行。

$_SESSION 为一个关联数组,和普通关联数组键值对的含义相同

  1. <?php
  2. //开启session
  3. //将会向客户端发送一个sessionID,保存在客户端cookie中
  4. session_start();
  5. //得到sessionID的键
  6. echo session_name()."<br>"; // PHPSESSID
  7. //得到sessionID的值
  8. echo session_id()."<br>"; // mvn8gbfnuonl4mnl889jq7jgon
  9. //得到本地保存的sessionID
  10. echo $_COOKIE["PHPSESSID"]."<br>"; // mvn8gbfnuonl4mnl889jq7jgon
  11. $str = 'zhangshuai';
  12. $arr = ['Session','$_SESSION'];
  13. $_SESSION['name'] = $str;
  14. $_SESSION['url'] = 'http://www.zhsh520.com';
  15. $_SESSION['title'] = $arr;
  16. foreach ($_SESSION as $key => $value) {
  17. if(is_array($value)){
  18. echo $key.':';
  19. print_r($value);
  20. }else{
  21. echo $key.' = '.$value.'<br>';
  22. }
  23. }
  24. /*
  25. name = zhangshuai
  26. url = http://www.zhsh520.com
  27. title:Array ( [0] => Session [1] => $_SESSION )
  28. */
  29. ?>

执行上面的脚本后,不仅会将这几个变量或数组保存到 $SESSION 中,还会被保存到服务器端由“sess”和 Session ID 所命名的文件中,这个文件的位置可以通过修改 php.ini 配置文件或使用 session.save_path 配置。而且这个文件可以直接使用文本编辑器打开,文件的内容结构如下所示:

变量名|类型:长度:值; // Session 中的每个变量都使用相同的结构保存

执行上面的脚本所创建的 Session 文件的内容如下所示:

Cookie: PHPSESSID=2l1bhjkdirtoi2u5tc5s4gk8er

如果想要修改设置好的 Session 的值,只需要像普通数组那样,重新为 Session 中指定的元素赋值即可,修改后的信息也会同步更新到对应的 Session 文件中。

清除和删除Session

当使用完一个 Session 变量后,可以将其删除;当完成一个会话后,也可以将其销毁。如果用户想退出 Web 系统,就需要为他提供一个注销的功能,把他的所有信息在服务器中销毁。

删除 Session 会话的方法主要有删除单个 Session 元素、删除多个 Session 元素和结束当前会话 3 种:

  • 删除单个 Session 元素

删除单个 Session 元素同数组的操作一样,直接注销 $_SESSION 数组的某个元素即可。例如,删除 $_SESSION[‘name’] 时,可以直接使用 unset() 函数,例如unset($_SESSION['name']);

  1. unset($_SESSION['title']) // 来销毁一个会话变量
  • 删除多个 Session 元素

如果想要一次性删除多个 Session 元素,即一次注销所有的会话变量,可以通过将一个空的数组赋值给 $_SESSION 来实现

  1. $_SESSION=array(); // 销毁所有的会话变量
  2. // session_unset() 函数也可以释放 Session 中的所有元素
  3. session_unset();
  • 结束当前会话

如果整个 Session 会话结束,可以使用 session_destroy() 函数销毁当前会话的全部数据,即彻底销毁 Session

  1. // 当使用完一个会话后,首先应该注销所有的变量,然后再调用session_destroy()来清除会话ID
  2. <?php
  3. session_start();
  4. echo '<pre>';
  5. $str = 'zhangshuai';
  6. $arr = ['删除 Session','$_SESSION'];
  7. $_SESSION['name'] = $str;
  8. $_SESSION['url'] = 'http://www.zhsh520.com';
  9. $_SESSION['title'] = $arr;
  10. echo '定义一个 Session,如下所示:<br>';
  11. print_r($_SESSION);
  12. echo '删除 Session 中的name元素:<br>';
  13. unset($_SESSION['name']);
  14. print_r($_SESSION);
  15. echo '删除 Session 中的全部元素:<br>';
  16. $_SESSION = array();
  17. print_r($_SESSION);
  18. session_destroy();
  19. ?>

注意:使用 $_SESSION = array() 清空 $_SESSION 数组的同时,也将这个用户在服务器端对应的 Session 文件内容清空。而使用 session_destroy() 函数时,则是将这个用户在服务器端对应的 Session 文件删除。

使用Session实现登录保持

login.php

  1. <?php
  2. session_start();
  3. if(!empty($_SESSION['username'])){
  4. header("location:http://zhang.com/0513/admin/index.php");
  5. }
  6. ?>
  7. <!DOCTYPE html>
  8. <html lang="en">
  9. <head>
  10. <meta charset="UTF-8">
  11. <title>用户登录页面</title>
  12. <link rel="stylesheet" type="text/css" href="css/regist.css">
  13. </head>
  14. <body>
  15. <div class="wrapper">
  16. <article>
  17. <h1><span>个人博客登录</span></h1>
  18. <div class="main">
  19. <form action="" method="post"onsubmit="return false">
  20. <div class="userName">
  21. <input type="text" name="userName" placeholder="请输入用户名" id="username" required>
  22. </div>
  23. <div class="password">
  24. <input type="password" name="pwd" placeholder="请输入密码" id="pwd" required>
  25. </div>
  26. <div class="captcha">
  27. <input type="text" name="captcha" id="captcha" placeholder="请输入验证码" required>
  28. <img width="60" height="37" onclick="this.src='../config/gd_captcha.php?'+new Date().getTime();" style="margin: 10px auto;vertical-align: bottom;" src="../config/gd_captcha.php">
  29. <p >
  30. <span><a href="../regist/regist.html" style="color: #b91f1f;text-decoration: none;">注册</a></span>
  31. <span style="float: right;" ><a href="#" style="color: #b91f1f;text-decoration: none;">忘记密码?</a></span>
  32. </p>
  33. </div>
  34. <button>登录</button>
  35. </form>
  36. </div>
  37. </article>
  38. </div>
  39. <script type="text/javascript">
  40. document.querySelector('button').addEventListener("click",function(e){
  41. const formdata = new FormData(document.querySelector('form'));
  42. const xhr = new XMLHttpRequest();
  43. xhr.open("post", "login_check.php");
  44. xhr.onload = () => {
  45. let json = JSON.parse(xhr.response);
  46. if(json.status==0){
  47. alert(json.msg);
  48. }else{
  49. alert(json.msg);
  50. window.location.href = 'http://zhang.com/0513/admin/index.php';
  51. }
  52. };
  53. xhr.send(formdata);
  54. });
  55. </script>
  56. </body>
  57. </html>

login_check.php

  1. <?php
  2. // 连接数据库服务
  3. require "./../config/connect.php";
  4. // 接受用户登陆时提交的验证码
  5. session_start();
  6. if(empty($_POST)) die("请勿非法访问");
  7. $username = $_POST['userName'];
  8. $password = $_POST['pwd'];
  9. $captcha = $_POST['captcha'];
  10. // 预处理SQL模板
  11. $sql = "select user_name,user_pwd from users where user_name = ?";
  12. // prepare()方法-准备一条预处理语句 返回 pdo statement对象
  13. $stmt = $pdo->prepare($sql);
  14. // 绑定参数到指定的变量名
  15. $stmt->bindParam(1,$username,PDO::PARAM_STR);
  16. // 执行预处理SQL
  17. $stmt->execute();
  18. // 获取结果集
  19. $res = $stmt->fetch();
  20. // 判断查询出的数据条数
  21. if($stmt->rowCount()==0){
  22. echo json_encode(['status'=>0,'msg'=>'该用户未注册……']);
  23. }else if(!password_verify($password,$res['user_pwd'])){
  24. echo json_encode(['status'=>0,'msg'=>'用户名或密码不正确']);
  25. }else if(strcasecmp($_SESSION["captcha"],$captcha)!== 0){
  26. echo json_encode(['status'=>0,'msg'=>'验证码错误……']);
  27. }else{
  28. echo json_encode(['status'=>1,'msg'=>'登录成功……']);
  29. $_SESSION['username'] = $res['user_name'];
  30. $_SESSION['password'] = $res['user_pwd'];
  31. }
  32. ?>

index.php

  1. <?php
  2. session_start();
  3. if(empty($_SESSION['username'])){
  4. header("location:http://zhang.com/0513/admin/login/login.php");
  5. }
  6. if(!empty($_POST['logout'])&&$_POST['logout']==true){
  7. unset($_SESSION['username']);
  8. unset($_SESSION['password']);
  9. echo "<script>alert('退出成功');window.location.reload();</script>";
  10. }
  11. ?>
  12. <!DOCTYPE html>
  13. <html>
  14. <head>
  15. <title>首页</title>
  16. <style type="text/css">
  17. html{
  18. height: 100%;
  19. background: url(http://api.easys.ltd/api/api/api.php);
  20. display: flex;
  21. justify-content: center;
  22. align-items: center;
  23. }
  24. h1{
  25. color: red;
  26. padding: 20px;
  27. font-size: 70px;
  28. background-color: rgba(0, 0, 0, 0.6);
  29. }
  30. button{
  31. position: fixed;
  32. right: 30px;
  33. top: 30px;
  34. padding: 10px;
  35. font-size: 18px;
  36. background: rgba(0,0,0,.6);
  37. border: 0;
  38. color: white;
  39. cursor: pointer;
  40. }
  41. </style>
  42. </head>
  43. <body>
  44. <form method="POST">
  45. <input type="hidden" value="true" name="logout" />
  46. <button type="submit">退出登录</button>
  47. </form>
  48. <h1>欢迎<?=$_SESSION['username'] ?>登录成功!</h1>
  49. </body>
  50. </html>

未登录访问首页将被拦截跳转至登录页面

登录成功后再访问登录页面将被跳转至首页

浏览地址:http://www.zhsh520.com/admin

账号:admin 密码:admin

  • Cookie 仅由客户端生成、管理并使用,PHP 只是发出指令要求客户端如何生成 Cookie、何时过期等,但是客户端不一定会按照 PHP 的指令办事。

  • Cookie 不是很安全,不法分子可以通过分析本地的 Cookie 进行 Cookie 欺骗。考虑到安全问题,建议将用户的重要信息存放在 Session 中,其它不重要但需要保留的信息可以存放在 Cookie 中。

  • 使用本地文件处理跨页面传值,用户的基本信息加密后保存到本地
  • 安全性相对不高
  • 用户可以禁止cookie
  • 存储数据有大小限制(<4k)
  • 不同浏览器存储不同的cookie

SESSION 服务端

  • Session 是用户进入某个网站到关闭浏览器这段时间的会话,默认以文件形式存在服务器磁盘中,所以设置过多的 Session 会影响磁盘的性能,也可以用 Memory 引擎存入 MySQL,因为内存引擎读写速度快,现在也可以指定用 Redis 来处理 Session,这样更快,效率更高。

  • Session 的收回机制是被动的,一般来说,一旦关闭浏览器 Session 也就被 PHP 自动回收了,但有时即使设置了过期时间并且关闭浏览器也不一定会删除 Session,比如设置多目录多层级保存 Session 时,这时需要通过 PHP 脚本手动删除 Session。

  • 在服务器中一种解决方式,可以使用sessionid来唯一识别某个用户

  • 有时间周期大致24分钟
  • 安全性高
  • 存储的数据没有大小限制;

通常 Cookie 与 Session 是绑定的,即用户在没有禁用 Cookie 时,Cookie 一般会保存 Session ID 及 Session 生存周期,如果用户删除 Cookie 一般会退出系统;如果没有禁用 Cookie 关闭浏览器 Session 也会立即失效,要重新登录系统。

Cookie 与 Session 一般应于标识用户、权限认证、存储简单数据、还有就是利用 Cookie 实现单点登录。

Cookie 存储的数据在不同的浏览器会有不同的限制,一般在同一个域名下,Cookie 变量数量控制在 20 个以内,每个 Cookie 的值大小控制在 4kb 以内。

Session 值没有大小和数量限制,但如果数量过多,会增大服务器的压力。另外,Cookie 保存的内容是字符串,而 Session 保存的数据是对象。

Session 不能区分路径,同一个用户在访问一个网站期间,所有的 Session 在任何一个地方都可以访问到;而 Cookie 中如果设置了路径参数,那么同一个网站中不同路径下的 Cookie 是不能互相访问的。

【扩展】Token 认证

token是客户端频繁向服务器端请求数据,服务器频繁的去数据库查询用户名和密码进行对比,判断用户名和密码正确与否,并作出相应的提示,在这样的背景下,token便应运而生了。

Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。

因此,在用户登录成功之后,后台会返回一个token给前端,这个时候我们就需要把token暂时保存在本地,每次发送请求的时候需要在header里边带上token(无需再次带上请求名和密码),这个时候本地的token和后台数据库中的token进行一个验证,如果两者一致,则请求成功,否则失败。

使用tokent登录

前后端分离或者为了支持多个web应用,那么原来的cookies或者session在使用上就会有很大的问题
cookie和session认证需要在同一主域名下才可以进行认证(目前可以把session存储在redis内进行解决)。

  • jwt :是一种安全标准。基本思路就是用户提供用户名和密码给认证服务器,服务器验证用户提交信息信息的合法性;如果验证成功,会产生并返回一个token(令牌)
  • OAuth2 :是一个安全的授权框架。它详细描述了系统中不同角色、用户、服务前端应用(比如API),以及客户端(比如网站或移动APP)之间怎么实现相互认证。
    (这里采用jwt,这种JSON Web Token 这种方式进行认证)

生成TOken签名

  1. //用户名、此时的时间戳,并将过期时间拼接在一起
  2. $admin = $data['username']; //获取前台传来的用户账号
  3. $time = time();
  4. $end_time = time()+86400;
  5. $info = $admin. '.' .$time.'.'.$end_time;//设置token过期时间为一天
  6. $key = "siasqr";
  7. //根据以上信息信息生成签名(密钥为 siasqr)
  8. $signature = hash_hmac('md5',$info,$key);
  9. //最后将这两部分拼接起来,得到最终的Token字符串
  10. $token = $info . '.' . $signature;
  11. // 最后以JSON形式返回客户端
  12. echo json_encode(['token'=>$token],320);

验证token签名

  1. public function check_token($token)
  2. {
  3. /**** api传来的token ****/
  4. if(!isset($token) || empty($token))
  5. {
  6. $msg['code']='400';
  7. $msg['msg']='非法请求';
  8. return json_encode($msg,JSON_UNESCAPED_UNICODE);
  9. }
  10. //对比token
  11. $explode = explode('.',$token);//以.分割token为数组
  12. if(!empty($explode[0]) && !empty($explode[1]) && !empty($explode[2]) && !empty($explode[3]) )
  13. {
  14. $info = $explode[0].'.'.$explode[1].'.'.$explode[2];//信息部分
  15. $true_signature = hash_hmac('md5',$info,'siasqr');//正确的签名
  16. if(time() > $explode[2])
  17. {
  18. $msg['code']='401';
  19. $msg['msg']='Token已过期,请重新登录';
  20. return json_encode($msg,JSON_UNESCAPED_UNICODE);
  21. }
  22. if ($true_signature == $explode[3])
  23. {
  24. $msg['code']='200';
  25. $msg['msg']='Token合法';
  26. return json_encode($msg,JSON_UNESCAPED_UNICODE);
  27. }
  28. else
  29. {
  30. $msg['code']='400';
  31. $msg['msg']='Token不合法';
  32. return json_encode($msg,JSON_UNESCAPED_UNICODE);
  33. }
  34. }
  35. else
  36. {
  37. $msg['code']='400';
  38. $msg['msg']='Token不合法';
  39. return json_encode($msg,JSON_UNESCAPED_UNICODE);
  40. }
  41. }

Token存放位置

通常应该在请求的header头中的 Authorization字段使用 Bearer模式添加JWT(Authorization: Bearer ) (当然你也可以放在任意位置,如URL后面当成一个参数传递,只要客户端能识别就行,不过既然JWT是个规范,那么我们最好还是按照规范来)

HTTP请求头响应头中常用字段

https://www.cnblogs.com/huhu1020387597/p/10900782.html

  1. // 登录成功获取的TOken
  2. const token = res.token;
  3. localStroage.setItem('token',token);
  4. $.ajax({
  5. type: "GET",
  6. url: "/access/logout/" + userCode,
  7. headers: {'Authorization': token}
  8. });
  9. $.ajax({
  10. type: "GET",
  11. url: "/access/logout/" + userCode,
  12. beforeSend: function(request) {
  13. request.setRequestHeader("Authorization", token);
  14. },
  15. success: function(result) {
  16. }
  17. });

TOken的认证流程

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。流程是这样的:

  1. 客户端使用 用户名跟密码请求登录
  2. 服务端收到请求,php脚本连接mysql 去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 localStroage 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
  7. APP登录的时候发送加密的用户名和密码到服务器,服务器验证用户名和密码,如果成功,以某种方式比如随机生成32位的字符串作为token,存储到服务器中,并返回token到APP,以后APP请求时
  8. 凡是需要验证的地方都要带上该token,然后服务器端验证token,成功返回所需要的结果,失败返回错误信息,让他重新登录。其中服务器上token设置一个有效期,每次APP请求的时候都验证token和有效期。

token的认证优势

  1.无状态、可扩展

在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。如果我们将已验证的用户的信息保存在Session中,则每次请求都需要用户向已验证的服务器发送验证信息(称为Session亲和性)。用户量大时,可能会造成 一些拥堵。但是不要着急。使用tokens之后这些问题都迎刃而解,因为tokens自己hold住了用户的验证信息。

  2.安全性

  请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。

更多相关文章

  1. PHP:PDO->fetch()和fetchAll()遍历,session进行会话跟踪,用户退出
  2. 客户端自动化测试研究
  3. Python使用socket搭建TCP服务器(后期的客户端:GPRS模块)
  4. 如何使gateway_worker与客户端通信,有哪几个条件
  5. 一个SQL让导致整个数据库都整挂了!
  6. OpenDaylight实现轮询策略的负载均衡服务
  7. SaltStack 工作原理及安装配置实例详解 | 运维进阶
  8. 一问带你区分清楚Authentication,Authorization以及Cookie、Sess
  9. 如何用Redis实现分布式锁以及可用性

随机推荐

  1. 自定义视图(组合控件)
  2. 从gpu到chromium compositor(cc)详解andr
  3. Android 5.X Activity过渡动画,以及漂亮的
  4. GridView中实现元素填充剩余空间(自适应)
  5. android基础--获取sdcard的总容量
  6. android studio中的文本替换
  7. 测试Android真机访问电脑主机web项目服务
  8. Android Studio每日小技巧
  9. Android Things:“1024工场”店铺开张啦!树
  10. 微信 Tinker 的一切都在这里,包括源码