access_control();

此外,我们可以利用以下方法测试客户端登录(实际上不须要登录):

if (access_control(TRUE)) { / CLIENT IS ALREADY LOGGED IN / }

phpcmsv9registerhtmlPHP客户端注册登录刊出和轻松拜访掌握 Angular

本文结尾处有一些注释和后记。
如果有韶光,您可能须要向下滚动并立即阅读。
当您考试测验利用此设计时,它们会更深入地先容您可能碰着的问题。
然后回来并连续。
约定和标准1.我们赞许在所有页面上都利用session_start()的约定,没有例外。
您可能希望将session_start()添加到通用脚本的顶部,该脚本会包含在所有页面脚本的顶部,以便您网站的每个页面都可以这样开始:

<?php require_once('RAY_EE_config.php'); // PHP AND HTML CODE FOLLOWS BELOW

“ config”脚本也是放置数据库连接和选择代码以及define()语句以及局部变量,类和函数的利益所,您可能已经知道要在一个数据库中包含这些公共元素。
单一,易于查找的脚本。
2.我们赞许这样的约定:我们将access_control()语句添加到要保护的每个页面的非常顶部。
为什么要顶?由于我们可能须要利用header()函数,并且这是HTTP的协议限定,以是必须在所有浏览器输出之前呈现并完成所有标头。
header()语句将失落败,并且如果违反此协议,则脚本将失落败。
在创建浏览器输出的同时,有多种方法可以遵照此协议。
PHP函数ob_start()可以帮助您办理此问题。
但是ob_start()对付这里的任务不是必需的-只有在完成所有标头命令之后,我们才能以精确的顺序处理数据并产生浏览器输出(如果有)。
有了这些理解之后,让我们开始为访问掌握系统构建框架。
通用元素-配置脚本第一步将是创建“配置”脚本,个中包含我们所有网页脚本所需的通用元素。
您将须要对这些示例进行一些自定义。
特殊是,您将要不才面的脚本的第15-20行附近添加自己的数据库凭据。
有了这些信息,您该当能够将这些代码片段中的每一个安装在您自己的做事器上,并运行它们以查看实际的“移动部件”。
有了数据库凭据后,我们连接到数据库做事器并选择数据库(第21-34行)。
看一看在第36行定义的access_control()函数。
它所做的第一件事是保存客户真个入口点,以便我们在客户端认证之后可以返回到精确的页面。
我们利用REQUEST_URI字符串而不是PHP_SELF,由于REQUEST_URI不仅包含我们的URL地址,还包含URL参数。
PHP_SELF仅具有URL地址。
接下来,我们测试会话UID变量。
如果设置了此选项,则客户端已经登录,因此不须要进一步处理,并且我们返回TRUE。
如果客户端未登录,则仅进入此函数的下一行。
如果客户端未登录,则查看$ test参数。
默认情形下,它设置为FALSE,但是如果调用脚本将其设置为TRUE,我们将返回一个指示信息,表明客户端未登录。
如果客户端未登录,这不是测试,我们必须保护页面。
因此,我们将客户端浏览看重定向到我们的登录页面并退出脚本。
我们还须要一个函数来完成我们的事情-设置“记住我” cookie的函数。
该定义从第53行开始。
我们将Cookie的“ uuk”命名为“唯一用户密钥”,并将其生存期取决于在第10行定义的常数REMEMBER的定义。
有关setcookie()的更多信息,请拜会PHP在线手册,位于:http : //php.net/manual/en/f unction.se tcookie.ph p有了“ config”框架,我们就可以通过实行从第80行开始的通用代码来开始每个网页。
我们测试的第一件事是会话数组中是否存在“ uid”。
如果有的话,我们就有一个经由身份验证的客户端,不须要其他处理。
但是,如果未设置$ _SESSION [“ uid”],我们仍旧可以通过“ uuk” cookie中的信息来记住该客户端。
如果设置了cookie,则我们可以在数据库中查找客户端并自动完成登录,从而实现“记住我”的承诺。
由于$ _COOKIE数组包含存储在客户端打算机上的数据,以是必须将其视为“污染的”外部数据。
因此,最最少的检讨是在查询中利用mysqli :: real_escape_string ()之前运行数据。
利用这样准备的数据,我们可以查询用户表并考试测验查找与该唯一用户密钥匹配的UID。
如果我们在数据库中找到该UID,则将其复制到会话数组(第101行)中,并且客户端现在已登录。
我们的末了一步是在第104行调用Remember_me()函数,从而扩展了该客户真个内存。
通过在此调用此功能,可以使被记住并常常访问该站点的客户得到反复记住,乃至永久被记住。
这是常见的“ config”脚本:

<?php // RAY_EE_config.php// WHEN WE ARE DEBUGGING OUR CODE, WE WANT TO SEE ALL THE ERRORS!error_reporting(E_ALL);// REQUIRED FOR PHP 5.1+date_default_timezone_set('America/Chicago');// THE LIFE OF THE "REMEMBER ME" COOKIEdefine('REMEMBER', 6060247); // ONE WEEK IN SECONDS// WE WANT TO START THE SESSION ON EVERY PAGEsession_start();// CONNECTION AND SELECTION VARIABLES FOR THE DATABASE$db_host = "localhost"; // PROBABLY THIS IS OK$db_name = "??"; // GET THESE FROM YOUR HOSTING COMPANY$db_user = "??";$db_word = "??";// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB$mysqli = new mysqli($db_host, $db_user, $db_word, $db_name);// DID THE CONNECT/SELECT WORK OR FAIL?if ($mysqli->connect_errno){ $err = "CONNECT FAIL: " . $mysqli->connect_errno . ' ' . $mysqli->connect_error ; trigger_error($err, E_USER_ERROR);}// DEFINE THE ACCESS CONTROL FUNCTIONfunction access_control($test=FALSE){ // REMEMBER HOW WE GOT HERE $_SESSION["entry_uri"] = $_SERVER["REQUEST_URI"]; // IF THE UID IS SET, WE ARE LOGGED IN if (isset($_SESSION["uid"])) return $_SESSION["uid"]; // IF WE ARE NOT LOGGED IN - RESPOND TO THE TEST REQUEST if ($test) return FALSE; // IF THIS IS NOT A TEST, REDIRECT TO CALL FOR A LOGIN header("Location: RAY_EE_login.php"); exit;}// DEFINE THE "REMEMBER ME" COOKIE FUNCTIONfunction remember_me($uuk){ // CONSTRUCT A "REMEMBER ME" COOKIE WITH THE UNIQUE USER KEY $cookie_name = 'uuk'; $cookie_value = $uuk; $cookie_expires = time() + date('Z') + REMEMBER; $cookie_path = '/'; $cookie_domain = NULL; $cookie_secure = FALSE; $cookie_http = TRUE; // HIDE COOKIE FROM JAVASCRIPT (PHP 5.2+) // SEE http://php.net/manual/en/function.setcookie.php setcookie ( $cookie_name , $cookie_value , $cookie_expires , $cookie_path , $cookie_domain , $cookie_secure , $cookie_http ) ;}// DETERMINE IF THE CLIENT IS ALREADY LOGGED IN BECAUSE OF THE SESSION ARRAYif (!isset($_SESSION["uid"])){ // DETERMINE IF THE CLIENT IS ALREADY LOGGED IN BECAUSE OF "REMEMBER ME" FEATURE if (isset($_COOKIE["uuk"])) { $uuk = $mysqli->real_escape_string($_COOKIE["uuk"]); $sql = "SELECT uid FROM EE_userTable WHERE uuk = '$uuk' LIMIT 1"; $res = $mysqli->query($sql); // IF THE QUERY SUCCEEDED if ($res) { // THERE SHOULD BE ONE ROW $num = $res->num_rows; if ($num) { // RETRIEVE THE ROW FROM THE QUERY RESULTS SET $row = $res->fetch_assoc(); // STORE THE USER-ID IN THE SESSION ARRAY $_SESSION["uid"] = $row["uid"]; // EXTEND THE "REMEMBER ME" COOKIE remember_me($uuk); } } }}

数据库表-我们的客户数据模型现在,我们已经创建了常见的“ config”脚本,是时候创建将有助于访问掌握功能的数据库表了。
下面“创建”代码段中的这段代码该当做得很好。
EE_userTable包含三列。
这些是“ uid”列中的用户身份,“ pwd”列中的用户密码和“ uuk”列中的用户唯一键。
在现实生活中,我们永久不会以明文形式存储密码;我们将存储密码的抽象或加密版本。
(请参阅本文结尾处的后记)。
但是对付此示例,如果我们以明文形式处理密码,则可使设计更易于理解。

<?php // RAY_EE_create.phprequire_once('RAY_EE_config.php');// ACTIVATE THIS TO DROP THE OLD EE_userTable// $mysqli->query("DROP TABLE EE_userTable");$sql= "CREATE TABLE EE_userTable( _key INT NOT NULL AUTO_INCREMENT, uid VARCHAR(16) NOT NULL DEFAULT '?', pwd VARCHAR(16) NOT NULL DEFAULT '?', uuk VARCHAR(32) NOT NULL DEFAULT '?', PRIMARY KEY (_key))";if (!$res = $mysqli->query($sql)) trigger_error( $mysqli->error, E_USER_ERROR );

测试工具此时,最好为我们的新脚本和我们的新数据库表创建测试平台。
我们将须要两个脚本进行测试。
一个将完备由访问掌握。
另一个将是一个公共页面,该页面仅测试访问掌握并利用相应来确定要创建哪种输出。
这两个脚本符合这些哀求。

<?php // RAY_EE_controlled.phprequire_once('RAY_EE_config.php');// ACCESS TO THIS PAGE IS CONTROLLED$uid = access_control();echo "<br/>HELLO $uid AND WELCOME TO THE ACCESS CONTROLLED PAGE";

<?php // RAY_EE_public.phprequire_once('RAY_EE_config.php');// ACCESS TO THIS PAGE IS TESTED BUT NOT CONTROLLEDif ($uid = access_control(TRUE)){ echo "<br/>HELLO $uid AND WELCOME TO THE PUBLIC PAGE";}else{ echo "<br/>HELLO STRANGER."; echo "<br/>YOU MIGHT WANT TO <a href=\"RAY_EE_register.php\">REGISTER</a> ON THIS SITE"; echo "<br/>IF YOU ARE ALREADY REGISTERED, YOU CAN <a href=\"RAY_EE_login.php\">LOG IN HERE</a>";}

方便客户利用-注书页面如果我们只有几个用户,则可以利用phpMyAdmin手动注册所有用户,但是如果我们有一个面向公众年夜众的网站,则将须要很多事情。
相反,我们想要创建一个页面,以便我们的用户可以注书籍身。
下面的页面将为我们完成注册事情。
补充解释:如果您想轻微扩展一下这个观点,此处的EE文章可能对您有所帮助。
HTTP://www.experts-exchang e.com/Web_发展吨/ Web_Lang uages-斯坦dards / PHP / A_3939-Reg中istration-和-的电子邮件- Confirmati上功能于PHP。
html与我们所有的脚本一样,此脚本以PHP命令开始,以第2行的办法加载“ config”脚本require_once('RAY_EE_confi g.php'),我们利用include()函数的require形式,由于脚本无法运行没有我们的配置文件。
我们利用include()函数的一次形式,由于配置文件包含函数定义,并且任何重新定义PHP函数的考试测验都将导致致命缺点。
要开始注册过程,假设没有缺点,我们乐不雅观地将$ err变量设置为NULL(第5行)。
我们稍后可以检讨它是否有任何缺点。
然后,我们查看$ _POST数组以查看是否拥有处理注册所需的所有信息。
如果我们还没有注册信息,该脚本将落到第53行,个中将显示注册表格。
如果我们拥有表格中的所有注册信息,我们可以考试测验创建客户记录。
创建客户记录的第一步是努力清理外部输入。
除了这里的根本知识,我们没有做任何其他事情;在现实生活中,可能会有更广泛的过滤和测试。
但是对付此示例,我们只是通过转义从表单输入吸收到的三个文本字段来保护数据库。
我们的第一个主要测试是查看两个密码字段是否匹配。
我们这样做是由于客户端正在键入type =“ password”的表单输入字段,并且浏览器将在输入时粉饰输入内容。
为了让我们的客户满意,我们哀求她输入两次密码,然后检讨是否匹配。
如果她以相同的办法两次输入密码,我们可以肯定的是,打字缺点不会导致将假造的密码分配给她的帐户。
如果不匹配,我们将缺点附加到$ err变量。
接下来,我们检讨数据库以查看是否已利用UID。
如果是这种情形,我们将其视为缺点,并且将设置缺点指示器的办法与设置密码不匹配的缺点指示器的办法相同-通过将缺点添加到$ err变量的末端。
(您可能考虑利用UNIQUE标记MySQL表中的uid列。
如果考试测验将重复的信息放入UNIQUE列中,MySQL将抛出错误#1062)。
编辑完成后(第25行),我们将测试$ err值。
由于利用PHP if()语句测试时,NULL字符串将返回FALSE,因此我们可以大略地检讨$ err是否为空。
我们利用PHP的“ not”表达式,即感叹号。
如果我们有缺点,则该测试将失落败,代码将低落至第48行,在此处显示缺点并再次出示注册表格。
如果没有阻挡注册的缺点,我们可以在第28行连续进行处理。
我们结合利用用户ID,密码和随机数来创建一个完备唯一且不可预测的值。
这是我们可以在cookie中利用的“唯一用户密钥”。
为什么不但利用数据库中的auto_increment键?由于Cookie中的可预测值会引起黑客入侵。
例如,如果黑客看到其cookie值为“ 123”,则可能会考试测验将其cookie变动为“ 122”,然后看看会发生什么。
当我们利用唯一数据组合的md5()哈希值时,我们很难预测被黑客入侵的cookie中可能起浸染的值。
我们的查询将用户ID,密码和唯一的用户密钥放入表中,并且我们的注册已完成。
我们的客户现在可以登录。
但是,为什么要让他们在注册后分别登录?仅需一行代码(第33行),我们便可以在注册时完成其登录。
我们一贯希望对我们的客户好!
接下来,我们将把稳力转向客户是否希望我们记住登录状态的问题。
如果选中了“ rme”复选框,它将在$ POST数组中设置,我们可以对其进行测试以查看是否须要记住客户端。
(与type =“ text”的空输入字段不同,未选中的type =“ checkbox”字段根本不会涌如今$ _POST数组中)。
因此,如果存在“ rme”,我们将调用Remember_me()函数并将其通报给唯一的用户密钥。
如果没有,我们将跳过此步骤,并且不会设置任何cookie。
现在我们的注册和登录事情已经完成,我们在第42行欢迎客户并在第44行结束脚本。
这是注册脚本:

<?php // RAY_EE_register.phprequire_once('RAY_EE_config.php');// WE ASSUME NO ERRORS OCCURRED$err = NULL;// WAS EVERYTHING WE NEED POSTED TO THIS SCRIPT?if ( (!empty($_POST["uid"])) && (!empty($_POST["pwd"])) && (!empty($_POST["vwd"])) ){ // YES, WE HAVE THE POSTED DATA. ESCAPE IT FOR USE IN A QUERY $uid = $mysqli->real_escape_string($_POST["uid"]); $pwd = $mysqli->real_escape_string($_POST["pwd"]); $vwd = $mysqli->real_escape_string($_POST["vwd"]); // DO THE PASSWORDS MATCH? if ($pwd != $vwd) $err .= "<br/>FAIL: CHOOSE AND VERIFY PASSWORDS DO NOT MATCH"; // DOES THE UID ALREADY EXIST? $sql = "SELECT uid FROM EE_userTable WHERE uid = '$uid' LIMIT 1"; if (!$res = $mysqli->query($sql)) trigger_error( $mysqli->error, E_USER_ERROR ); $num = $res->num_rows; if ($num) $err .= "<br/>FAIL: UID $uid IS ALREADY TAKEN. CHOOSE ANOTHER"; // IF THERE WERE NO ERRORS THAT PREVENT REGISTRATION if (!$err) { // MAKE THE UNIQUE USER KEY $uuk = md5($uid . $pwd . rand()); $sql = "INSERT INTO EE_userTable (uid, pwd, uuk) VALUES ('$uid', '$pwd', '$uuk')"; if (!$res = $mysqli->query($sql)) trigger_error( $mysqli->error, E_USER_ERROR ); // STORE THE USER-ID IN THE SESSION ARRAY $_SESSION["uid"] = $uid; // IS THE "REMEMBER ME" CHECKBOX SET? if (isset($_POST["rme"])) { remember_me($uuk); } // REGISTRATION AND LOGIN COMPLETE echo "<br/>WELCOME $uid. REGISTRATION COMPLETE. YOU ARE LOGGED IN."; echo "<br/>CLICK <a href=\"/\">HERE</a> TO GO TO THE HOME PAGE"; die(); } // IF THERE WERE ERRORS else { echo $err; echo "<br/>SORRY, REGISTRATION FAILED"; }} // END OF FORM PROCESSING - PUT UP THE FORM?><form method="post">PLEASE REGISTER<br/>CHOOSE USERNAME: <input name="uid" /><br/>CHOOSE PASSWORD: <input name="pwd" type="password" /><br/>VERIFY PASSWORD: <input name="vwd" type="password" /><br/><input type="checkbox" name="rme" />KEEP ME LOGGED IN (DO NOT CHECK THIS ON A PUBLIC COMPUTER)<br/><input type="submit" value="REGISTER" /></form>

客户端身份验证-登录页面现在我们可以注册用户,并且我们拥有测试页面,可让我们查看实际的注册,我们须要创建登录和注销页面。
登录页面利用类似于注书页面的构造。
我们须要我们的“配置”页面,然后进行测试以查看是否供应了必要的凭据(第5行)。
我们过滤并清理外部输入(第8-9行),然后查询数据库,在UID和PWD字段(第12-20行)中查找完备匹配的一个。
如果找不到在UID和PWD上都匹配的行,则第20行的if()语句将失落败,脚本将低落至第46行,在此我们可以见告客户端身份验证失落败,并可以显示登录名再次形成。
如果确实找到了要查找的一行,则检索该行(第23行)并将UID值复制到会话数组(第26行)中,以显示客户端现在已登录。
我们的下一步是查看是否客户选中了“记住我”框。
我们测试该复选框(第29行),如果已选中该复选框,我们将调用Remember_me()函数,并通报在注册时创建的唯一用户密钥。
Remember_me()函数可在浏览器上设置一个龟龄命的cookie。
如果没有此cookie,则仅利用会话cookie来记住客户端。
当浏览器窗口关闭时,会话cookie也会过期。
登录处理的末了一步是确定客户端下一步要去哪里。
我们通过测试会话数组中的“ entry_uri”来做到这一点。
如果它是由配置脚本中的access_control()函数设置的,我们可以在header()命令中利用该地址将客户端带回到原始页面。
如果未设置该选项(如果客户端直接进入登录页面,则会发生这种情形),我们可以改为重定向到主页。
大概该当不用说,但是我还是要说:不要在您的登录脚本中放入access_control()函数,否则您的代码可能会导致做事器循环!
这是登录脚本:

<?php // RAY_EE_login.phprequire_once('RAY_EE_config.php');// WAS EVERYTHING WE NEED POSTED TO THIS SCRIPT?if ( (!empty($_POST["uid"])) && (!empty($_POST["pwd"])) ){ // YES, WE HAVE THE POSTED DATA. ESCAPE IT FOR USE IN A QUERY $uid = $mysqli->real_escape_string($_POST["uid"]); $pwd = $mysqli->real_escape_string($_POST["pwd"]); // CONSTRUCT AND EXECUTE THE QUERY - COUNT THE NUMBER OF ROWS RETURNED $sql = "SELECT uid, uuk FROM EE_userTable WHERE uid = '$uid' AND pwd = '$pwd' LIMIT 1"; $res = $mysqli->query($sql); // IF THE QUERY FAILED, GIVE UP if (!$res) trigger_error( $mysqli->error, E_USER_ERROR ); // THERE SHOULD BE ONE ROW IF THE VALIDATION WAS PROCESSED SUCCESSFULLY $num = $res->num_rows; if ($num) { // RETRIEVE THE ROW FROM THE QUERY RESULTS SET $row = $res->fetch_assoc(); // STORE THE USER-ID IN THE SESSION ARRAY $_SESSION["uid"] = $row["uid"]; // IS THE "REMEMBER ME" CHECKBOX SET? if (isset($_POST["rme"])) { remember_me($row["uuk"]); } // REDIRECT TO THE ENTRY PAGE OR TO THE HOME PAGE if (isset($_SESSION["entry_uri"])) { header("Location: {$_SESSION["entry_uri"]}"); exit; } else { header("Location: /"); exit; } } // END OF SUCCESSFUL VALIDATION else { echo "SORRY, VALIDATION FAILED USING $uid AND $pwd \n"; }} // END OF FORM PROCESSING - PUT UP THE LOGIN FORM?><form method="post">PLEASE LOG IN<br/>UID: <input name="uid" /><br/>PWD: <input name="pwd" type="password" /><br/><input type="checkbox" name="rme" />KEEP ME LOGGED IN (DO NOT CHECK THIS ON A PUBLIC COMPUTER)<br/><input type="submit" value="LOGIN" /></form>

客户端取消身份验证-退出页面如果我们的客户端登录,并且未选中“记住我”框,则当浏览器窗口关闭或会话垃圾网络例程检测到永劫光不活动时,他将自动注销。
(常日约24分钟)。
但是,我们的客户可能希望刻意注销,或者可能是在谨慎的情形下在公共打算机上注销。
因此,我们还必须供应一个注销脚本,如下所示。
与往常一样,我们的第一步是加载“ config”脚本。
接下来,我们从会话数组中网络UID,或设置一个替代值。
我们将在“再见”中利用此,因此,纵然客户端连续两次登录注销脚本,或者试图以某种办法在客户端未登录时设法去到那里,我们都考试测验选择一个故意义的数据字符串这是在三元运算符语句(第5行)中完成的。
我们处理“记住我” cookie(如果有的话)(第7-12行)。
下一步是打消会话数组(第15行)。
这可能看起来有些束手无策,您可能会考虑完备肃清该会话是否故意义。
如果纵然在客户端注销后,会话中仍有其他信息要保留,则可以仅在第15行取消设置($ _SESSION [“ uid”])并跳过别的代码。
但是,您永久不要利用unset($ _ SESSION)打消数组。
请参阅此处的把稳事变:http : //php.net/manual/en/s ession.exa mples.basi c.php末了,您可以利用我们在第5行创建的数据字符串说“再见”。
浏览器输出,而是激活标题(“位置:/” 看一下“出口”;末了一行的声明。
只管这里并不是严格哀求的,但是在标题(“ Location”)语句之后利用“ exit”是一种养成的好习气。
为什么?由于您的脚本在发送header()之后将连续正常运行,并且将运行一段不可预知的韶光-直到浏览器收到该标头并通过重定向停滞脚本。
有很多适当的header()语句可以作为完全脚本的一部分内联利用,但是当您利用旨在作为脚本中末了一条语句的语句时,则须要采纳额外的步骤来确保它是,实际上是末了一条要实行的语句。
这是注销脚本:

<?php // RAY_EE_logout.phprequire_once('RAY_EE_config.php');// GRAB THE UID OR A CONSTANT FOR THE GOODBYE MESSAGE$uid = (isset($_SESSION["uid"])) ? ', ' . $_SESSION["uid"] : ' NOW';// IF THE "REMEMBER ME" COOKIE IS SET, FORCE IT TO EXPIRE$cookie_expires= time() - date('Z') - REMEMBER;if (isset($_COOKIE["uuk"])){ setcookie("uuk", '', $cookie_expires, '/');}// CLEAR THE INFORMATION FROM THE $_SESSION ARRAY$_SESSION = array();// IF THE SESSION IS KEPT IN COOKIE, FORCE SESSION COOKIE TO EXPIREif (isset($_COOKIE[session_name()])){ setcookie(session_name(), '', $cookie_expires, '/');}// TELL PHP TO ELIMINATE THE SESSIONsession_destroy();session_write_close();// SAY GOODBYE...echo "YOU ARE LOGGED OUT$uid. GOODBYE.";// OR REMOVE THE GOODBYE MESSAGE AND ACTIVATE THESE LINES TO REDIRECT TO THE HOME PAGE// header("Location: /");// exit;

客户安全-密码页面我们都知道我们该当时时变动密码。
为客户供应这种功能非常随意马虎。
与注书页面在设计上相似,密码页面采取一对新密码,检讨是否匹配并更新数据库以存储新密码。
但是有一些主要的差异。
每当我们变动数据模型中的某些内容时,我们都须要重新验证客户的密码。
为什么?由于我们都是人类,以是我们可能会欠妥心使打算机保持登录状态。
一个偷偷摸摸的人可能会在我们不查看时考试测验变动我们的密码(或其他信息)。
为了减少这种风险,我们利用与当代ATM掌握台所利用的设计模式相似的设计模式。
在每次提款之前,您必须重新输入PIN码。
这是一个小麻烦,也是一种强大的安全方法。
因此,我们将在“变动密码”脚本中实行相同的操作。
每当我们变动客户记录中的主要内容(例如电子邮件地址或送货地址)时,我们都将利用此设计模式。
我们的第一步是加载“ config”脚本,并调用访问掌握功能以检索客户端uid。
我们假设没有发生缺点(第8行)。
我们哀求客户端供应三项信息-旧密码和新密码,键入两次以确保精确键入新密码。
如果我们拥有所有这三个条件(第11行),则可以开始处理要求。
我们清理在查询中利用的值(第14-17行)。
接下来,我们测试两个密码字段是否匹配。
我们这样做是由于客户端正在键入type =“ password”的表单输入字段,并且浏览器将在输入时粉饰输入内容。
为了使我们的客户满意,我们哀求她两次输入密码,然后检讨是否匹配(第20行)。
如果不匹配,我们将缺点附加到$ err变量。
接下来,我们检讨数据库,以确保UID记录与旧密码一起存在。
用户表中该当只有这样一行。
如果不是这种情形,我们将其视为缺点,并以与为密码不匹配设置缺点指示符相同的办法设置缺点指示符(第26行)-通过将缺点添加到密码末端$ err变量。
编辑完成后(第29行),我们将测试$ err值。
如果我们有缺点,则该测试将失落败,代码将低落至第42行,在此处显示缺点并再次显示密码表单。
如果没有阻挡密码变动的缺点,我们可以在第32行连续进行处理。
请把稳,第32行的UPDATE查询中的WHERE子句–与我们在第23行的SELECT查询中利用的WHERE子句完备相同。
我们已经知道只有一行知足该WHERE子句。
因此,我们确定将利用新密码更新精确的行。
为了表示MySQL的性能,我们见告数据库限定为一行。
这避免了表扫描。
更新匹配行后,MySQL将在知道其事情完成后停滞运行。
密码变动完成,我们向客户发送成功(第36行)。
如果您的实际实现在用户表中有客户的电子邮件地址(险些可以肯定),那么您可以扩展此地址以向她发送有关密码变动的电子邮件。
良好的安全做法会阻挡您发送实际密码。

<?php // RAY_EE_password.phprequire_once('RAY_EE_config.php');// ACCESS TO THIS PAGE IS CONTROLLED$uid = access_control();// WE ASSUME NO ERRORS OCCURRED$err = NULL;// WAS EVERYTHING WE NEED POSTED TO THIS SCRIPT?if ( (!empty($_POST["old"])) && (!empty($_POST["pwd"])) && (!empty($_POST["vwd"])) ){ // YES, WE HAVE THE NEEDED DATA. ESCAPE IT FOR USE IN A QUERY $uid = $mysqli->real_escape_string($uid); $old = $mysqli->real_escape_string($_POST["old"]); $pwd = $mysqli->real_escape_string($_POST["pwd"]); $vwd = $mysqli->real_escape_string($_POST["vwd"]); // DO THE PASSWORDS MATCH? if ($pwd != $vwd) $err .= "<br/>FAIL: CHOOSE AND VERIFY PASSWORDS DO NOT MATCH"; // DOES THE UID AND OLD PASSWORD COMBINATION EXIST? $sql = "SELECT uid FROM EE_userTable WHERE uid = '$uid' AND pwd = '$old' LIMIT 1"; if (!$res = $mysqli->query($sql)) trigger_error( $mysqli->error, E_USER_ERROR ); $num = $res->num_rows; if ($num != 1) $err .= "<br/>FAIL: $uid DOES NOT HAVE PASSWORD $old"; // IF THERE WERE NO ERRORS TO PREVENT THE PASSWORD CHANGE if (!$err) { // UPDATE THE TABLE TO CHANGE THE PASSWORD $sql = "UPDATE EE_userTable SET pwd = '$pwd' WHERE uid = '$uid' AND pwd = '$old' LIMIT 1"; if (!$res = $mysqli->query($sql)) trigger_error( $mysqli->error, E_USER_ERROR ); // PASSWORD CHANGE IS COMPLETE echo "<br/>THANK YOU, $uid. PASSWORD CHANGE IS COMPLETE."; echo "<br/>CLICK <a href=\"/\">HERE</a> TO GO TO THE HOME PAGE"; die(); } // IF THERE WERE ERRORS else { echo $err; echo "<br/>SORRY, PASSWORD CHANGE FAILED"; }} // END OF FORM PROCESSING - PUT UP THE FORM?><form method="post">CHANGE YOUR PASSWORD<br/>FORMER PASSWORD: <input name="old" type="password" /><br/>CHOOSE PASSWORD: <input name="pwd" type="password" /><br/>VERIFY PASSWORD: <input name="vwd" type="password" /><br/><input type="submit" value="CHANGE" /></form>

简介-付诸实践这便是利用基本的PHP身份验证来密码保护网页的所有步骤。
一旦有了这种构造,就可以显示公共注册和登录页面,并通过公共,受保护和部分受保护的网页的组合来构建站点。
最主要的是,您可以利用一行PHP代码进行身份验证测试。
这些脚本利用PHP会话来标识已登录的客户端。
客户可以哀求您的网站记住他们的状态,您可以帮他们。
他们可以随时注销,也可以在一段韶光不活动后自动注销。
他们可以随时变动密码来保护自己的帐户信息。
此处的注释和代码将在大多数PHP安装中正常运行,但是它们仅作为传授教化示例,并不打算在生产环境中“按原样”利用-因此,请随意复制和修正它们以适宜您的特定需求。
后记:理解PHP会话只管这些脚本以合理的办法利用PHP会话,但我创造很随意马虎过分思考PHP会话的事情办法。
它们比您预期的要随意马虎得多!
您可能须要阅读这两篇文章,以更好地理解我们的PHP客户端身份验证所依赖的根本技能。
关于PHP会话的文章。
有关 HTTP客户端/做事器协议的文章。
后记:防止自动注册曾经想知道在线论坛如何得到这么多垃圾的伟哥广告吗?广告由“攻击”机器人脚本放置,这些脚本会找到注册表格并注册一个帐户,然后利用该帐户发布不须要的材料。
结合利用两种技能可以减少这种入侵的风险。
首先是在注册表上利用CAPTCHA测试。
第二个是利用“握手”,这须要一个额外的步骤来通过电子邮件中的解释确认注册。
这两种方法都可以单独有效。
综合起来,它们乃至更有效。
后记:MySQL和MySQL i (2014年春季)本文最初写于几年前,当时PHP支持MySQL数据库扩展。
此后发生了变革,如果您利用本文的旧版本作为辅导,则可能须要变动脚本。
幸运的是,如果选择面向工具的MySQL i,则变动非常随意马虎完成。
要理解PHP为什么取消MySQL支持,以及如何使脚本保持运行状态,请参阅这篇文章,该文章教您如何将过程式MySQL代码转换为MySQL i或PDO。
后记:PHP session_unregister() (2014年秋季)一些过期的代码集包含利用session_unregister()函数的“注销”示例。
PHP在很多年前不推举利用此功能,而在最近将其删除。
不幸的是,PHP代码示例没有到期日期,因此您可能会碰着没有任何警告标签的过期期码。
如果您有一个利用session_unregister()的脚本,则应利用相同的函数调用参数将函数名称更换为unset()。
今后,请勿利用session_unregister(),session_register()或session_is_registered()。
要理解本文的别的部分,您可能想刷新有关PHP会话如何事情的影象。
后记:关于存储密码实际上,您不会以明文形式存储客户端密码。
您可以利用PHP md5()函数对密码进行编码。
MD5是“择要”的缩写。
请在这里阅读评论。
我不同意这样的不雅观念,即如果您理解自己在做什么并且精确利用md5(),那么md5()哈希对付大多数用例来说是不足的。
但是,许多专家附和利用密码哈希。
或至少是加密。
这是我对md5()的意见。
1.假设您屈曲地以明文形式存储了客户端密码。
优点:当客户端忘却密码时,脚本可以发送客户端密码。
缺陷:如果您的数据库遭到毁坏,则将公开所有客户端密码。
2.假设您没有存储明文密码,但是却屈曲地存储了密码的md5()择要。
看起来像这样...5f4dcc3b5aa765d61d8327deb8 82cf99...这是“密码”的md5()。
您不能仅通过查看就随意马虎判断出此md5()字符串与“ password”匹配,但是md5()择要的问题在于它们在编程上是幂等的。
无论您对“密码”进行散列多少次,都将始终得到相同的md5()字符串。
如果两个人选择相同的密码,则md5()字符串将相同。
黑客知道最受欢迎的密码md5()字符串,因此,如果您的数据库遭到毁坏,则会暴露许多客户端密码。
黑客知道多少个普通密码?您会相信数百万吗?你最好相信它!
3.如果让客户选择他们自己的密码,而个中一个选择“密码”,则黑客更有可能破译其他常用密码。
与盛行密码的md5()字符串匹配的暴力破解方法在打算上是微不足道的。
每个字典单词与其md5()择要匹配最多须要几秒钟。
4.为了使密码更难破解,一个子行业呈现出了各种各样的伏都教徒和关于密码学的废话。
您可以避免废话,并从OWASP项目中理解更多信息。
您可以利用密码哈希来增强密码安全性。
5.由于md5()是幂等的,以是安全性哀求必须采纳某些方法来毁坏“密码”和5f4dcc3b5aa765d61d8327deb8 82cf99之间的直接链接。
那是在编码过程中添加到密码的“盐”。
在密码后面附加一个盐字符串,幂等关系不仅须要密码,还须要盐。
因此,如果客户端选择“密码”,则做事器将存储诸如“密码XYZ ”之类的md5字符串,其结果择要为cceef54fde042f058f57108433 8e2c40。
比较这些md5字符串,看看是否可以看到关系。
我不能6.您的盐不必很随意马虎预测。
但是必须将其存储在某个位置,以使其在脚本实行期间可以编程办法供PHP利用。
您可能要小心保护它。
如果盐析字符串和算法遭到毁坏,则可能暴露您客户的密码。
大概您想将其放入存储在WWW根目录上方的PHP脚本中,并通过include()函数将其引入Web根脚本的范围。
7.您可以在密码的两端加盐加盐胡椒粉))。
您可以利用非常长且任意的字符串来放入盐和胡椒。
只要将相同的盐和胡椒粉添加到客户端输入密码框中的任何内容,您的md5()算法就会创建幂等择要。
您可以利用大略的SQL查询来匹配密码。
8. md5()冲突的可能性(两个不同的输入字符串匹配相同的择要)与您的DNA序列碰着其他人的可能性险些相同。
从理论上讲这是可能的,但不要打赌。
9.加盐的密码有多坚固?我将向任何人买啤酒,谁能见告我创建此md5()择要的原始输入字符串: e0f1299ed629d3c8826e2dd2be 4780cf为了方便您搜索原始输入字符串,这里是md5()算法解释的链接。
http://www.faqs.org/rfcs/r fc1321.htm l并且我已经在做事器上安装了此易于利用的脚本。
在此处进行实验:http : //www.iconoun.com/dem o / md5.php10.如果您选择了好的盐和胡椒粉字符串并将其保密,则在大多数情形下,您的md5()择要将足以保护客户端密码。
但是你不能办理屈曲的问题。
如果客户选择“密码”,而您的登录过程仅须要一个电子邮件地址和密码,则没有太多保护该客户免于暴露的机会。
内部如何对“密码”进行编码并不主要。
知道站点中电子邮件地址的任何人都可以考试测验将每个人与“密码”或其他常用密码配对,以查看配对是否有效。
毫无疑问,如果您的人口足够多,则您的客户社区中会有人利用“密码”,并且她将成为任何攻击的首批受害者之一。
11.由于第10个缘故原由,某些密码选择过程哀求您利用字母和数字的组合,利用大写和小写等。
我以为这些令人讨厌,并且方向于利用多字密码短语的观点。
而不是一个密码。
我敢肯定会有盛行和常用的词组,并且明智的选择是在词组中选择随机单词,并包含一些乃至根本不是单词的内容。
高盐短语至少与高盐密码一样好。
12. md5()字符串始终为32个字符的十六进制数字,无论输入字符串包含什么内容。
因此,数据库存储必须具有32字节的列宽。
ArsTechnica的这篇文章供应了内部人士对黑客可能如何攻击您的编码密码的意见。
终极,您的密码就像是防火保险箱的门。
根据韶光和温度对它们进行评级。
坚固的门意味着您有更多的韶光来点火物品。
不幸的是,像ArsTechnica所做的那样,每一项练习都将基本密码和密码短语添加到字典中,并且字典攻击是最快成功的。
而您要保护的内容至关主要。
如果您有保龄球得分,购买历史,医疗记录,财务细节或核发射代码,则安全方法可能会有所不同。