PHP 表单验证

什么是 $_SERVER["PHP_SELF"] 变量?

$_SERVER["PHP_SELF"] 是一种超全局变量,它返回当前执行脚本的文件名。

因此,$_SERVER["PHP_SELF"] 将表单数据发送到页面本身,而不是跳转到另一张页面。这样,用户就能够在表单页面获得错误提示信息。

什么是 htmlspecialchars() 函数?

htmlspecialchars() 函数把特殊字符转换为 HTML 实体。这意味着 < 和 > 之类的 HTML 字符会被替换为 < 和 > 。这样可防止攻击者通过在表单中注入 HTML 或 JavaScript 代码(跨站点脚本攻击)对代码进行利用。

关于 PHP 表单安全性的重要提示

$_SERVER["PHP_SELF"] 变量能够被黑客利用!

如果您的页面使用了 PHP_SELF,用户能够输入下划线然后执行跨站点脚本(XSS)又叫css。

提示:跨站点脚本(Cross-site scripting,XSS)是一种计算机安全漏洞类型,常见于 Web 应用程序。XSS 能够使攻击者向其他用户浏览的网页中输入客户端脚本。

假设我们的一张名为 "test_form.php" 的页面中有如下表单:

<form method="post" action="<?php echo $_SERVER["PHP_SELF"];?>">

现在,我们使用URL来指定提交地址 "test_form.php",以上代码修改为如下所示:

<form method="post" action="test_form.php">

这样做就很好了。

但是,考虑到用户会在浏览器地址栏中输入以下地址:

http://www.php.cn/test_form.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E

以上的 URL 中,将被解析为如下代码并执行:

<form method="post" action="test_form.php/"><script>alert('hacked')</script>

代码中添加了 script 标签,并添加了alert命令。 当页面载入时会执行该Javascript代码(用户会看到弹出框)。 这仅仅只是一个简单的实例来说明PHP_SELF变量会被黑客利用。

请注意, 任何JavaScript代码可以添加在<script>标签中! 黑客可以利用这点重定向页面到另外一台服务器的页面上,页面 代码文件中可以保护恶意代码,代码可以修改全局变量或者获取用户的表单数据。

如何避免 $_SERVER["PHP_SELF"] 被利用?

$_SERVER["PHP_SELF"] 可以通过 htmlspecialchars() 函数来避免被利用。

form 代码如下所示:

<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
htmlspecialchars() 把一些预定义的字符转换为 HTML 实体。现在如果用户想利用 PHP_SELF 变量, 结果将输出如下所示:

<form method="post" action="test_form.php/"><script>alert('hacked')</script>">
尝试该漏洞失败!

通过 PHP 验证表单数据

我们要做的第一件事是通过 PHP 的 htmlspecialchars() 函数传递所有变量。

在我们使用 htmlspecialchars() 函数后,如果用户试图在文本字段中提交以下内容:

<script>location.href('http://www.hacked.com')</script>

  • 代码不会执行,因为会被保存为转义代码,就像这样:

<script>location.href('http://www.hacked.com')</script>

现在这条代码显示在页面上或 e-mail 中是安全的。

在用户提交该表单时,我们还要做两件事:

  1. (通过 PHP trim() 函数)去除用户输入数据中不必要的字符(多余的空格、制表符、换行)

  2. (通过 PHP stripslashes() 函数)删除用户输入数据中的反斜杠(\)

接下来我们创建一个检查函数(相比一遍遍地写代码,这样效率更好)。

我们把函数命名为 test_input()。

现在,我们能够通过 test_input() 函数检查每个 $_POST 变量,脚本是这样的:

<!DOCTYPE HTML>
 <html>
 <head>
     <meta charset="utf-8">
     <title>PHP中文网(php.cn)</title>
 </head>
 <body>
 
 <?php
 // 定义变量并默认设置为空值
 $name = $email = $gender = $comment = $website = "";
 
 if ($_SERVER["REQUEST_METHOD"] == "POST")
 {
     $name = test_input($_POST["name"]);
     $email = test_input($_POST["email"]);
     $website = test_input($_POST["website"]);
     $comment = test_input($_POST["comment"]);
     $gender = test_input($_POST["gender"]);
 }
 
 function test_input($data)
 {
     $data = trim($data);
     $data = stripslashes($data);
     $data = htmlspecialchars($data);
     return $data;
 }
 ?>
 
 <h2>PHP 表单验证实例</h2>
 <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
     名字: <input type="text" name="name">
     <br><br>
     E-mail: <input type="text" name="email">
     <br><br>
     网址: <input type="text" name="website">
     <br><br>
     备注: <textarea name="comment" rows="5" cols="40"></textarea>
     <br><br>
     性别:
     <input type="radio" name="gender" value="female">女
     <input type="radio" name="gender" value="male">男
     <br><br>
     <input type="submit" name="submit" value="提交">
 </form>
 
 <?php
 echo "<h2>您输入的内容是:</h2>";
 echo $name;
 echo "<br>";
 echo $email;
 echo "<br>";
 echo $website;
 echo "<br>";
 echo $comment;
 echo "<br>";
 echo $gender;
 ?>
 
 </body>

注意:我们在执行以上脚本时,会通过$_SERVER["REQUEST_METHOD"]来检测表单是否被提交 。如果 REQUEST_METHOD 是 POST, 表单将被提交 - 数据将被验证。如果表单未提交将跳过验证并显示空白。

在以上实例中使用输入项都是可选的,即使用户不输入任何数据也可以正常显示。

PHP 表单 - 必需字段
<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>PHP中文网</title>
 </head>
 
 <style>
     .error {color: #FF0000;}
 </style>
 <body>
 <?php
 // 定义变量并设置为空值
 $nameErr = $emailErr = $genderErr = $websiteErr = "";
 $name = $email = $gender = $comment = $website = "";
 
 if ($_SERVER["REQUEST_METHOD"] == "POST") {
     if (empty($_POST["name"])) {
         $nameErr = "姓名是必填的";
     } else {
         $name = test_input($_POST["name"]);
     }
 
     if (empty($_POST["email"])) {
         $emailErr = "电邮是必填的";
     } else {
         $email = test_input($_POST["email"]);
     }
 
     if (empty($_POST["website"])) {
         $website = "";
     } else {
         $website = test_input($_POST["website"]);
     }
 
     if (empty($_POST["comment"])) {
         $comment = "";
     } else {
         $comment = test_input($_POST["comment"]);
     }
 
     if (empty($_POST["gender"])) {
         $genderErr = "性别是必选的";
     } else {
         $gender = test_input($_POST["gender"]);
     }
 }
 
 function test_input($data) {
     $data = trim($data);
     $data = stripslashes($data);
     $data = htmlspecialchars($data);
     return $data;
 }
 ?>
 
 <h2>PHP 验证实例</h2>
 <p><span class="error">* 必需的字段</span></p>
 <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
     姓名:<input type="text" name="name">
     <span class="error">* <?php echo $nameErr;?></span>
     <br><br>
     电邮:<input type="text" name="email">
     <span class="error">* <?php echo $emailErr;?></span>
     <br><br>
     网址:<input type="text" name="website">
     <span class="error"><?php echo $websiteErr;?></span>
     <br><br>
     评论:<textarea name="comment" rows="5" cols="40"></textarea>
     <br><br>
     性别:
     <input type="radio" name="gender" value="female">女性
     <input type="radio" name="gender" value="male">男性
     <span class="error">* <?php echo $genderErr;?></span>
     <br><br>
     <input type="submit" name="submit" value="提交">
 </form>
 
 <?php
 echo "<h2>您的输入:</h2>";
 echo $name;
 echo "<br>";
 echo $email;
 echo "<br>";
 echo $website;
 echo "<br>";
 echo $comment;
 echo "<br>";
 echo $gender;
 ?>
 
 </body>
 </html>

PHP 表单 - 验证邮件和URL

正则表达式

正则表达式是一种描述一段文本规则的方法,它不是精确的匹配,而是通过一些特定的符号来模糊匹配

在PHP中,我们使用preg_match函数来执行正则表达式的匹配,一个参数是我们的正则表达式规则,第二个参数是需要检查的文本

preg_match ( string $正则 , string $字符串 [, array &$结果] )

功能:根据$正则变量,匹配$字符串变量。如果存在则返回匹配的个数,把匹配到的结果放到$结果变量里。如果没有匹配到结果返回0。

^表示开始;$表示结束

<?php
 header("Content-type:text/html;charset=utf-8");    //设置编码
 $str = 'date20150121';
 if (preg_match('/^date/', $str)) {
     echo '匹配成功';
 } else {
     echo '匹配失败';
 }
 ?>
image.png

preg_matchede第三个参数是匹配的内容,通常我们会将一个空的数组传递进去,因为是传址调用,匹配结束后,数组中会得到具体匹配的内容

<?php
 header("Content-type:text/html;charset=utf-8");    //设置编码
 $str = 'date20150121';
 if (preg_match('/^date/', $str,$mat)) {
     print_r($mat);
 } else {
     echo '匹配失败';
 }
 ?>
image.png

在正则表达式中字母使用\w、而数字使用\d(\D表示非数字)来表示

• + 表示一个或者多个

• * 表示0个或者多个

• ? 表示有或者没有

• {n} 表示具体几位

• {m, n} 表示大于m个,小于n个

就像下面这样:

<?php
 header("Content-type:text/html;charset=utf-8");    //设置编码
 $name = "zhang"; // wang zhu hu ma tan
 
 if (preg_match('/an|hu/', $name, $arr)) {
     print_r($arr);
 } else {
     echo '匹配失败';
 }
 ?>
image.png

使用或条件可以用来匹配字符串,如果仅仅是单个的字母或者字符,则可以使用范围表示

使用[]可以表示一个字符的取值范围

'/[a0.]/' 可以匹配包含了a或者0或者.的任意字符串

另外,正则表达式还可以使用-来表示一组范围

• [a-z] 表示小写的26个字母中的任意一个

• [A-Z] 表示一个大写字母

• [0-9] 表示一位十进制数

PHP - 验证名称

以下代码将通过简单的方式来检测 name 字段是否包含字母和空格,如果 name 字段值不合法,将输出错误信息:

$name = test_input($_POST["name"]);
if (!preg_match("/^[a-zA-Z]*$/",$name)) {
    $nameErr = "只允许字母和空格";
}
PHP - 验证邮件

规则:邮箱名可以是字母、数字、下划线和点组成的任意字符;邮箱要包含@符号,后面的文字按域名规则处理

以下代码将通过简单的方式来检测 e-mail 地址是否合法。如果 e-mail 地址不合法,将输出错误信息:

$email = test_input($_POST["email"]);
if (!preg_match("/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/",$email)) {
    $emailErr = "无效的 email 格式!";
}
PHP - 验证 URL

以下代码将检测URL地址是否合法 (以下正则表达式运行URL中含有破折号:"-"), 如果 URL 地址不合法,将输出错误信息:

$website = test_input($_POST["website"]);
if (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%
=~_|]/i",$website)) {
    $websiteErr = "无效的 URL";
}
PHP验证实例
<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>PHP中文网</title>
 </head>
 
 <style>
     .error {color: #FF0000;}
 </style>
 <body>
 <?php
 // 定义变量并设置为空值
 $nameErr = $emailErr = $genderErr = $websiteErr = "";
 $name = $email = $gender = $comment = $website = "";
 
 if ($_SERVER["REQUEST_METHOD"] == "POST") {
     if (empty($_POST["name"])) {
         $nameErr = "姓名是必填的";
     } else {
         $name = test_input($_POST["name"]);
         // 检查姓名是否包含字母和空白字符
         if (!preg_match("/^[a-zA-Z ]*$/",$name)) {
             $nameErr = "只允许字母和空格";
         }
     }
 
     if (empty($_POST["email"])) {
         $emailErr = "电邮是必填的";
     } else {
         $email = test_input($_POST["email"]);
         // 检查电子邮件地址语法是否有效
         if (!preg_match("/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/",$email)) {
             $emailErr = "无效的 email 格式";
         }
     }
 
     if (empty($_POST["website"])) {
         $website = "";
     } else {
         $website = test_input($_POST["website"]);
         // 检查 URL 地址语法是否有效(正则表达式也允许 URL 中的斜杠)
         if (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i",$website)) {
             $websiteErr = "无效的 URL";
         }
     }
 
     if (empty($_POST["comment"])) {
         $comment = "";
     } else {
         $comment = test_input($_POST["comment"]);
     }
 
     if (empty($_POST["gender"])) {
         $genderErr = "性别是必选的";
     } else {
         $gender = test_input($_POST["gender"]);
     }
 }
 
 function test_input($data) {
     $data = trim($data);
     $data = stripslashes($data);
     $data = htmlspecialchars($data);
     return $data;
 }
 ?>
 
 <h2>PHP 验证实例</h2>
 <p><span class="error">* 必需的字段</span></p>
 <form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
     姓名:<input type="text" name="name">
     <span class="error">* <?php echo $nameErr;?></span>
     <br><br>
     邮箱:<input type="text" name="email">
     <span class="error">* <?php echo $emailErr;?></span>
     <br><br>
     网址:<input type="text" name="website">
     <span class="error"><?php echo $websiteErr;?></span>
     <br><br>
     评论:<textarea name="comment" rows="5" cols="40"></textarea>
     <br><br>
     性别:
     <input type="radio" name="gender" value="female">女性
     <input type="radio" name="gender" value="male">男性
     <span class="error">* <?php echo $genderErr;?></span>
     <br><br>
     <input type="submit" name="submit" value="提交">
 </form>
 
 <?php
 echo "<h2>您的输入:</h2>";
 echo $name;
 echo "<br>";
 echo $email;
 echo "<br>";
 echo $website;
 echo "<br>";
 echo $comment;
 echo "<br>";
 echo $gender;
 ?>
 
 </body>
 </html>

还能用正则表达式匹配手机号码哦,想想手机号码的验证?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容