深入理解ajax系列第八篇
前面的话
在以前,网站的用户与后端交互的主要方式是通过HTML表单的使用。表单的引入在1993年,由于其简单性和易用性,直到电子商务出现之前一直保持着重要位置。理解表单提交,对于更深入地理解ajax是有好处的。下面将详细介绍表单形式的交互
建立表单
表单处理是一个多线程。首先创建一个表单,以供用户输入详细的请求信息。接着,输入的数据被发送到网页服务器,在服务器里这些数据得到编译和错误检测。如果PHP代码标识出一个或多个需要重要输入的字段,则带有相关错误信息的表单会重新显示。当精确的输入信息满足代码的需要时,代码会采取一些调用数据库的行为,如输入购物的细节
[注意]关于HTML表单元素的详细信息移步至此
要建立一个表单,至少需要以下几个元素:一个form元素、一个指定GET或POST方法的提交类型、一个或多个输入字段,以及表单数据提交的目的地址URL
<form action="http://www.w3school.com.cn/demo/welcome.php">
<span>Name:</span>
<input name="name"><br>
<span>Email:</span>
<input name="email"><br>
<input type="submit">
</form>
表单处理
PHP 超全局变量 $_GET 和 $_POST 用于收集表单数据(form-data)
GET 和 POST 都创建数组(例如,array( key => value, key2 => value2, key3 => value3, ...))。此数组包含键/值对,其中的键是表单控件的名称,而值是来自用户的输入数据。
GET 和 POST 被视作 $_GET 和 $_POST。它们是超全局变量,这意味着对它们的访问无需考虑作用域,即无需任何特殊代码,能够从任何函数、类或文件访问它们
$_GET 是通过 URL 参数传递到当前脚本的变量数组
$_POST 是通过 HTTP POST 传递到当前脚本的变量数组
通过 GET 方法从表单发送的信息对任何人都是可见的(所有变量名和值都显示在 URL 中)。GET对所发送信息的数量也有限制。限制在大于2000个字符。不过,由于变量显示在 URL 中,把页面添加到书签中也更为方便
通过 POST 方法从表单发送的信息对其他人是不可见的(所有名称/值会被嵌入 HTTP 请求的主体中),并且对所发送信息的数量也无限制。此外 POST 支持高阶功能,比如在向服务器上传文件时进行 multi-part 二进制输入。不过,由于变量未显示在 URL 中,也就无法将页面添加到书签。一般地,使用 POST 来发送表单数据
【post】
<!-- 提交页 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form method="post" action="http://www.w3school.com.cn/demo/welcome.php">
<span>Name:</span>
<input name="name"><br>
<span>Email:</span>
<input name="email"><br>
<input type="submit">
</form>
</body>
</html>
<!-- 响应页 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
Welcome <?php echo $_POST["name"]; ?><br>
Your email address is: <?php echo $_POST["email"]; ?>
</body>
</html>
【get】
如果不设置form元素的method属性,则默认为get方法
<!-- 提交页 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form action="http://www.w3school.com.cn/demo/welcome_get.php">
<span>Name:</span>
<input name="name"><br>
<span>Email:</span>
<input name="email"><br>
<input type="submit">
</form>
</body>
</html>
<!-- 响应页 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
Welcome <?php echo $_GET["name"]; ?><br>
Your email address is: <?php echo $_GET["email"]; ?>
</body>
</html>
表单安全
上面的代码很简单。不过,最重要的内容被漏掉了。需要对表单数据进行验证,以防止脚本出现漏洞
对 HTML 表单数据进行适当的验证对于防范黑客和垃圾邮件很重要
字段 验证规则
Name 必需。必须包含字母和空格。
E-mail 必需。必须包含有效的电子邮件地址(包含 @ 和 .)
Website 可选。如果选填,则必须包含有效的 URL。
Comment 可选。多行输入字段(文本框)
Gender 必需。必须选择一项。
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> 姓名:
<input type="text" name="name" value="">
<span class="error">* </span>
<br><br>
电邮:
<input type="text" name="email" value="">
<span class="error">* </span>
<br><br>
网址:
<input type="text" name="website" value="">
<span class="error"></span>
<br><br>
<label>
评论:
<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">* </span>
<br><br>
<input type="submit" name="submit" value="提交">
</form>
【$_SERVER["PHP_SELF"]】
$_SERVER["PHP_SELF"] 是一种超全局变量,它返回当前执行脚本的文件名。因此,$_SERVER["PHP_SELF"] 将表单数据发送到页面本身,而不是跳转到另一张页面。这样,用户就能够在表单页面获得错误提示信息
【XSS】
$_SERVER["PHP_SELF"] 变量能够被黑客利用。如果页面使用了PHP_SELF,用户能够输入下划线然后执行跨站点脚本(XSS)
跨站点脚本(Cross-site scripting,XSS)是一种计算机安全漏洞类型,常见于Web应用程序。XSS能够使攻击者向其他用户浏览的网页中输入客户端脚本
假设"test_form.php" 的页面中有如下表单
<form method="post" action="<?php echo $_SERVER["PHP_SELF"];?>">
现在,如果用户进入的是地址栏中正常的URL:"http://www.example.com/test_form.php",上面的代码会转换为:
<form method="post" action="test_form.php">
不过,如果用户在地址栏中键入了如下 URL:
http://www.example.com/test_form.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E
在这种情况下,上面的代码会转换为:
<form method="post" action="test_form.php"/><script>alert('hacked')</script>
这段代码加入了一段脚本和一个提示命令。并且当此页面加载后,就会执行JavaScript代码(用户会看到一个提示框)。这仅仅是一个关于 PHP_SELF 变量如何被利用的简单无害案例
<script>标签内能够添加任何JavaScript代码,黑客能够把用户重定向到另一台服务器上的某个文件,该文件中的恶意代码能够更改全局变量或将表单提交到其他地址以保存用户数据等
【htmlspecialchars()】
如果避免$_SERVER["PHP_SELF"]被利用?通过使用 htmlspecialchars() 函数能够避免$_SERVER["PHP_SELF"]被利用
htmlspecialchars()函数把特殊字符转换为 HTML 实体。这意味着 < 和 > 之类的HTML字符会被替换为 < 和 >。这样可防止攻击者通过在表单中注入HTML或JavaScript代码(跨站点脚本攻击)对代码进行利用
表单代码是这样的:
<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的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变量
<?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;
}
?>
错误信息
在下面的代码中增加了一些新变量:$nameErr、$emailErr、$genderErr以及$websiteErr。这些错误变量会保存被请求字段的错误消息。还为每个$_POST变量添加了一个if else语句。这条语句通过PHP的empty()函数检查$_POST变量是否为空。如果为空,则错误消息会存储于不同的错误变量中。如果不为空,则通过test_input()函数发送用户输入数据
<?php
// 定义变量并设置为空值
$nameErr = $emailErr = $genderErr = $websiteErr = "";
$name = $email = $gender = $comment = $website = ""; if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["name"])) {
$nameErr = "Name is required";
} else {
$name = test_input($_POST["name"]);
} if (empty($_POST["email"])) {
$emailErr = "Email is required";
} 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 = "Gender is required";
} else {
$gender = test_input($_POST["gender"]);
}
}
?>
在 HTML 表单中,在每个被请求字段后面增加了一点脚本。如果需要,会生成恰当的错误消息(如果用户未填写必填字段就试图提交表单)
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> Name: <input type="text" name="name">
<span class="error">* <?php echo $nameErr;?></span>
<br><br>
E-mail:
<input type="text" name="email">
<span class="error">* <?php echo $emailErr;?></span>
<br><br>
Website:
<input type="text" name="website">
<span class="error"><?php echo $websiteErr;?></span>
<br><br>
<label>Comment: <textarea name="comment" rows="5" cols="40"></textarea>
<br><br>
Gender:
<input type="radio" name="gender" value="female">Female
<input type="radio" name="gender" value="male">Male
<span class="error">* <?php echo $genderErr;?></span>
<br><br>
<input type="submit" name="submit" value="Submit"> </form>
表单验证
验证规则中,"Name", "E-mail" 以及 "Gender" 字段是必需的。这些字段不能为空且必须在 HTML 表单中填写
【验证名字】
以下代码检查name字段是否包含字母和空格。如果name字段无效,则存储一条错误消息
$name = test_input($_POST["name"]);
if (!preg_match("/^[a-zA-Z ]*$/",$name)) {
$nameErr = "只允许字母和空格!";
}
【验证 E-mail】
以下代码展检查e-mail地址语法是否有效。如果无效则存储一条错误消息
$email = test_input($_POST["email"]);
if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$email)) {
$emailErr = "无效的 email 格式!";
}
【验证 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";
}
保留值
如果需要在用户点击提交按钮后在输入字段中显示值,我们在以下输入字段的value属性中增加了一小段 PHP 脚本:name、email 以及 website。在 comment 文本框字段中,把脚本放到了 <textarea> 与 </textarea> 之间。这些脚本输出$name、$email、$website 和 $comment 变量的值
然后,还需要显示选中了哪个单选按钮。对此,必须操作 checked 属性(而非单选按钮的 value 属性)
Name: <input type="text" name="name" value="<?php echo $name;?>"> E-mail: <input type="text" name="email" value="<?php echo $email;?>"> Website: <input type="text" name="website" value="<?php echo $website;?>"> Comment: <textarea name="comment" rows="5" cols="40"><?php echo $comment;?></textarea> Gender: <input type="radio" name="gender"
<?php if (isset($gender) && $gender=="female") echo "checked";?>
value="female">Female
<input type="radio" name="gender"
<?php if (isset($gender) && $gender=="male") echo "checked";?>
value="male">Male
表单发送
HTML网页的<form>元素能够以四种格式,向服务器发送数据
使用POST方法,将enctype属性设为application/x-www-form-urlencoded,这是默认方法
<form action="register.php" method="post" onsubmit="AJAXSubmit(this); return false;"></form>
使用POST方法,将enctype属性设为text/plain
<form action="register.php" method="post" enctype="text/plain" onsubmit="AJAXSubmit(this); return false;"></form>
使用POST方法,将enctype属性设为multipart/form-data
<form action="register.php" method="post" enctype="multipart/form-data" onsubmit="AJAXSubmit(this); return false;"></form>
使用GET方法,enctype属性将被忽略
<form action="register.php" method="get" onsubmit="AJAXSubmit(this); return false;"></form>
某个表单有两个字段,分别是foo和baz,其中foo字段的值等于bar,baz字段的值是一个分为两行的字符串。上面四种方法,都可以将这个表单发送到服务器
第一种方法是默认方法,POST发送,Encoding type为application/x-www-form-urlencoded
Content-Type: application/x-www-form-urlencoded
foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
第二种方法是POST发送,Encoding type为text/plain
Content-Type: text/plain foo=bar
baz=The first line.
The second line.
第三种方法是POST发送,Encoding type为multipart/form-data
Content-Type: multipart/form-data; boundary=---------------------------314911788813839 -----------------------------314911788813839
Content-Disposition: form-data; name="foo" bar
-----------------------------314911788813839
Content-Disposition: form-data; name="baz" The first line.
The second line. -----------------------------314911788813839--
第四种方法是GET请求
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line
完整代码
<!DOCTYPE HTML>
<html>
<head>
<style>
.error {color: #FF0000;}
</style>
</head>
<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("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$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;
}
?> <p><span class="error">* 必需的字段</span></p>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
姓名:<input type="text" name="name" value="<?php echo $name;?>">
<span class="error">* <?php echo $nameErr;?></span>
<br><br>
电邮:<input type="text" name="email" value="<?php echo $email;?>">
<span class="error">* <?php echo $emailErr;?></span>
<br><br>
网址:<input type="text" name="website" value="<?php echo $website;?>">
<span class="error"><?php echo $websiteErr;?></span>
<br><br>
评论:<textarea name="comment" rows="5" cols="40"><?php echo $comment;?></textarea>
<br><br>
性别:
<input type="radio" name="gender"
<?php if (isset($gender) && $gender=="female") echo "checked";?>
value="female">女性
<input type="radio" name="gender"
<?php if (isset($gender) && $gender=="male") echo "checked";?>
value="male">男性 <span class="error">* <?php echo $genderErr;?></span>
<br><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
深入理解ajax系列第八篇的更多相关文章
- 深入理解ajax系列第八篇——表单提交
前面的话 在以前,网站的用户与后端交互的主要方式是通过HTML表单的使用.表单的引入在1993年,由于其简单性和易用性,直到电子商务出现之前一直保持着重要位置.理解表单提交,对于更深入地理解ajax是 ...
- 深入理解ajax系列第四篇——请求实例
前面的话 在使用ajax的过程中,常用的请求方式是GET和POST两种.本文将以实例的形式来详细说明这两种请求方式 GET GET是最常见的请求类型,最常用于向服务器查询某些信息.必要时,可以将查询字 ...
- 深入理解ajax系列第三篇——响应解码
前面的话 我们接收到的响应主体类型可以是多种形式的,包括字符串String.ArrayBuffer对象.二进制Blob对象.JSON对象.javascirpt文件及表示XML文档的Document对象 ...
- 深入理解ajax系列第七篇——传递JSON
前面的话 虽然ajax全称是asynchronous javascript and XML.但目前使用ajax技术时,传递JSON已经成为事实上的标准.因为相较于XML而言,JSON简单且方便.本文将 ...
- 深入理解ajax系列第七篇
前面的话 虽然ajax全称是asynchronous javascript and XML.但目前使用ajax技术时,传递JSON已经成为事实上的标准.因为相较于XML而言,JSON简单且方便.本文将 ...
- 深入理解ajax系列第三篇
前面的话 我们接收到的响应主体类型可以是多种形式的,包括字符串String.ArrayBuffer对象.二进制Blob对象.JSON对象.javascirpt文件及表示XML文档的Document对象 ...
- 深入理解ajax系列第四篇——FormData
前面的话 现代Web应用中频繁使用的一项功能就是表单数据的序列化,XMLHttpRequest 2级为此定义了FormData类型.FormData为序列化表单以及创建与表单格式相同的数据提供了便利. ...
- 深入理解ajax系列第四篇
前面的话 现代Web应用中频繁使用的一项功能就是表单数据的序列化,XMLHttpRequest 2级为此定义了FormData类型.FormData为序列化表单以及创建与表单格式相同的数据提供了便利. ...
- 深入理解ajax系列第三篇——头部信息
前面的话 每个HTTP请求和响应都会带有相应的头部信息,其中有的对开发人员有用.XHR对象提供了操作头部信息的方法.本文将详细介绍HTTP的头部信息 默认信息 默认情况下,在发送XHR请求的同时,还会 ...
随机推荐
- 14、BigInteger类简介
BigInteger类概述 BigInteger类可以让超过Integer范围的数据进行运算,通常在对数字计算比较大的行业中应用的多一些. package com.sutaoyu.usually_cl ...
- PyText
Facebook开源了自家工程师们一直在用的NLP建模框架PyText.这个框架,每天要为Facebook旗下各种应用处理超过10亿次NLP任务,Facebook AI的工业级NLP开源框架.(简化部 ...
- aarch64_p1
PEGTL-devel-1.3.1-2.fc26.aarch64.rpm 2017-02-14 08:00 63K fedora Mirroring Project PackageKit-1.1.6- ...
- clog,cout,cerr 输出机制
clog:控制输出,使其输出到一个缓冲区,这个缓冲区关联着定义在 <cstdio> 的 stderr. cerr:强制输出刷新,没有缓冲区. cout:控制输出,使其输出到一个缓冲区,这个 ...
- Ubuntu 18.04安装MongoDB 4.0(社区版)
Ubuntu 18.04(虚拟机VirtualBox上),MongoDB 4.0, 听室友说,23点有世界杯决赛呢!可是,孤要写博文的啊!以记录这忙乱的下午和晚间成功安装了一个软件到Linux上.—— ...
- 【前端vue开发】vue项目使用sass less扩展语言所要安装的依赖
1.创建一个基于 webpack 模板的新项目 $ vue init webpack myvue 2.在当前目录下,安装依赖 $ cd myvue $ npm install 3.安装sass的依赖包 ...
- SNMP相关命令
SNMP的相关命令使用方法: snmpdelta 一直监视SNMP变量中的变化 linux:~ # snmpdelta -c public -v 1 -Cs -CT localhost IF-MIB: ...
- Tomcat底层实现
package myserver; import java.io.IOException;import java.net.ServerSocket;import java.net.Socket; pu ...
- WDK10+VS2015 驱动环境搭建
其实做驱动或者说底层安全的最大问题就是没有合适的资料去参考,网上很难找到想要的信息.比如搭建驱动环境我以前一直用的都是WDK7.1基于控制台去编译的,之前尝试过搭建WDK10+VS2015的组合环境, ...
- return to dl_resolve无需leak内存实现利用
之前在drop看过一篇文章,是西电的Bigtang师傅写的,这里来学习一下姿势做一些笔记. 0x01 基础知识 Linux ELF文件存在两个很重要的表,一个是got表(.got.plt)一个是plt ...