首页 > 技术文章 > PHP学习记录4

shawCE 2021-10-18 11:09 原文

PHP 表单和用户输入

我们在前面的学习PHP基础教程的时候就知道$_GET 和 $_POST 变量用于检索表单中的信息,比如用户输入

那么什么是表单呢?

Web表单的功能就是让浏览者和网站有一个互动的平台。表单主要用来在网页中发送数据到服务器,例如,你注册信息是所使用的表单,当你填写完信息时,你要提交(submit),提交就是将你表单中的内容从客户端浏览器传送到服务器端,经过PHP程序进行处理后,再将用户所需要的信息传递回客户端浏览器上,通过获取用户的信息,使PHP与Web表单实现交互。

 

<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>PHP中文网</title>
 </head>
 <body>
 
 <form action="form.php" method="post">
     名字: <input type="text" name="fname"><br>
     年龄: <input type="text" name="age"><br>
     <input type="submit" value="提交">
 </form>
 
 </body>
 </html>

 

当我们点击提交的时候,我们表单中的数据就会以POST 的形式。发送到form.php这个页面。

<?php
 header("Content-type:text/html;charset=utf-8");    //设置编码
 
 echo "欢迎你:".$_POST["fname"] ."<br/>";
 echo "你的年龄是:".$_POST['age'];
 ?>

表单验证

应该在任何可能的时候对用户输入进行验证(通过客户端脚本)。浏览器验证速度更快,并且可以减轻服务器的负载。

如果用户输入需要插入数据库,您应该考虑使用服务器验证。在服务器验证表单的一种好的方式是,把表单传给它自己,而不是跳转到不同的页面。这样用户就可以在同一张表单页面得到错误信息。用户也就更容易发现错误了。

PHP 表单验证

在处理PHP表单时我们需要考虑安全性。

本章节我们将展示PHP表单数据安全处理,为了防止黑客及垃圾信息我们需要对表单进行数据安全验证。

 


在本章节介绍的HTML表单中包含以下输入字段: 必须与可选文本字段,单选按钮,及提交按钮:

 

<!DOCTYPE HTML>
<html>
<head>
 <meta charset="utf-8">
 <title>PHP.cn</title>
</head>
<body>
<h2>PHP 表单验证实例</h2>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

 名字: <input type="text" name="name" value="">
 <br>
 E-mail: <input type="text" name="email" value="">
 <br>
 网址: <input type="text" name="website" value="">
 <br>
 备注: <textarea name="comment" rows="5" cols="40"></textarea>
 <br>
 性别:
 <input type="radio" name="gender" value="female"><input type="radio" name="gender" value="male"><br>
 <input type="submit" name="submit" value="提交">
</form>
</body>
</html>

 

上述表单验证规则如下:

          字段         验证规则
    名字 必须。 +只能包含字母和空格
    E-mail 必须。 + 必须是一个有效的电子邮件地址(包含'@'和'.')
    网址 可选。如果存在,它必须包含一个有效的URL
    备注 可选。 多行输入字段(文本域)
    性别 必须。 必须选择一个

 

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

 

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

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


什么是 htmlspecialchars() 函数?

 

htmlspecialchars() 函数把特殊字符转换为 HTML 实体。这意味着 < 和 > 之类的 HTML 字符会被替换为 &lt; 和 &gt; 。这样可防止攻击者通过在表单中注入 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/&quot;&gt;&lt;script&gt;alert('hacked')&lt;/script&gt;">

 

尝试该漏洞失败!

 


 

 

 

通过 PHP 验证表单数据

 

 

 

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

 

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

 

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

 

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

 

&lt;script&gt;location.href('http://www.hacked.com')&lt;/script&gt;

 

现在这条代码显示在页面上或 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 表单 - 必需字段

在上一节中,所有输入字段都是可选的,因为我们没有对它们进行验证。

PHP - 必需字段

必须字段就是我们填写资料的时候,必须填写的,不然是没有办法通过的,

在上一章节我们已经介绍了表单的验证规则,我们可以看到"名字", "E-mail", 和 "性别" 字段是必需的,各字段不能为空,这就是必须字段。

            字段          验证规则
    名字 必须。 +只能包含字母和空格
    E-mail 必须。 + 必须是一个有效的电子邮件地址(包含'@'和'.')
    网址 可选。如果存在,它必须包含一个有效的URL
    评论 可选。 多行输入字段(文本域)
    性别 必须。 必须选择一个

  在以下代码中我们加入了一些新的变量: $nameErr, $emailErr, $genderErr, 和 $websiteErr.。这些错误变量将显示在必需字段上。 我们还为每个$_POST变量增加了一个if else语句。 这些语句将检查 $_POST 变量是 否为空(使用php的 empty() 函数)。如果为空,将显示对应的错误信息。 如果不为空,数据将传递给test_input() 函数:

<?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"]);
     }
 }
 ?>

上面得代码的意思就是,如果我们在 名字,邮箱,性别 这三个必须字段输入框内什么都不写就提交的话,那么在页面上就会显示相应的错误信息,什么名字是必需的,邮箱是必需的。如果不是空白,那么就会通过验证,执行else 语句里面的内容。

PHP - 显示错误信息

在以下的HTML实例表单中,我们为每个字段中添加了一些脚本, 各个脚本会在信息输入错误时显示错误信息。(如果用户未填写信息就提交表单则会输出错误信息):

<!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>

 

 

 

 接下来是验证输入数据,即“Name 字段是否只包含字母和空格?”,以及“E-mail 字段是否包含有效的电子邮件地址语法?”,并且如果填写了 Website 字段,“这个字段是否包含了有效的 URL?”。

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 '匹配失败';
 }
 ?>

上面的代码就是匹配以date 开始的编号。匹配结果如下:

匹配成功

 

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

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

程序运行结果:

Array (    [0] => date )

 

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

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

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

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

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

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

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

 

正则表达式

1.正则表达式的作用:分割,查找,匹配,替换 字符串

2.分隔符:正斜线(/),hash符(#)以及取反符号(~)。

3.通用原子:\d \D \s \S \w \W

834cd8fd80be2e883f5edb55143fac3.png

4.原子符

f0d067dbe0ba1d47cf39614ccafa887.png

5. 模式修正符

6796e666aa1eda636de1dc652fbeea3.png

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";

}

<!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>

正则表达式验证实例

检测文件上传类型

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<form method="post" action="">
 <input type="file" name="text"><input type="submit" name="sub" value="上 传">
</form>
<?php
 if($_POST&&$_POST["text"])
 {
  if(preg_match("/.jpg/",strtolower($_POST['text'])))
  {
   echo "上传为JPG类型图片。";
  }
  else if(preg_match("/.png/",strtolower($_POST['text'])))
  {
   echo "上传为PNG类型图片。";
  }
  else if(preg_match("/.gif/",strtolower($_POST['text'])))
  {
   echo "上传为GIF类型图片。";
  }
  else if(preg_match("/.rar/",strtolower($_POST['text'])))
  {
   echo "上传为RAR类型压缩文件。";
  }
  else
  {
   echo "没有可上传文件,或者是JPG、PNG、GIF、RAR类型之外的文件";
  }
 }
?>
</body>
</html>
验证邮政编码:
preg_match("/[0-9]{6}/",$data)

验证IP地址:
$pattern = '/^(?:(?:2[0-4][0-9]\.)|(?:25[0-5]\.)|(?:1[0-9][0-9]\.)|(?:[1-9][0-9]\.)|(?:[0-9]\.)){3}(?:(?:2[0-4][0-9])|(?:25[0-5])|(?:1[0-9][0-9])|(?:[1-9][0-9])|(?:[0-9]))$/';


 

推荐阅读