上次最后学到了超级全局变量,比如:

1
2
3
4
5
6
7
echo $_SERVER['PHP_SELF'];#返回当前执行脚本文件名。

echo $_SERVER['SERVER_ADDR'];#返回主机的IP地址。

echo $_SERVER['SERVER_NAME'];#返回主机名(解析过的)

echo $_SERVER['REMOTE_ADDR'];#返回浏览页面用户的IP地址

然后来看$_REQUEST[]

下面我们和前端结合一下:

1
2
3
4
<form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">
NAME:<input type="text" name="fname">
<input type="submit">
</form>

然后紧接着写php文件

1
2
3
4
5
6
7
8
9
10
<?php
if($_SERVER["REQUEST_METHOD"] == "POST"){
$name = $_REQUEST['fname'];
if (empty($name)){
echo "name is empty";
} else {
echo $name;
}
}
?>

image-20220224182351192

image-20220224182358890

也就是从表中收集信息。

下面看POST传参

直接把我们的表格和PHP后端的REQUEST改为POST即可

前端是

1
<a herf ="test_get.php?subject=PHP&web=W3schools.com">Test $GET</a>

即构造了TEST$GET的按钮,只要点下去就会传左边的URL进去

后端PHP为:

1
2
3
<?php
echo "Study".$_GET['subject']."at".$_GET['web'];
?>#显然就是用GET方法传了两个参数进去。

下面看REGEX也就是PHP的正则表达式

先看

1
2
3
4
5
preg_match()#能够告诉我们匹配到多少个项,比如
<?php
#str="W3Schools";
$pattern="/w3schools/i"#后面的/i表示大小写不敏感,也就是不区分,因为insensitive
echo preg_match($pattern, $str);//输出结果应该为1,因为只有一个w3schools.

下面再看

1
2
3
4
5
6
preg_match_all()#能够告诉我们在一个字符串里匹配了多少次
<?php
$str="The rain in SPAIN falls mainly on the plains.";
$pattern="/ain/i";#设定匹配内容为ain,不区分大小写。
echo preg_match_all($pattern, $str);
?>#这时应该输出4,也就是匹配了4次

再看

1
2
3
4
5
preg_replace()#用来替换,显而易见
<?php
$str="Visit Microsoft!";
$pattern="/microsoft/i";
echo preg_replace($pattern, "W3Schools", $str);#就是将str中的microsoft内容转换为W3Schools。

Outputs “Visit W3Schools!”

有一些特殊的表示

Quantifier Description
n+ Matches any string that contains at least one n
n* Matches any string that contains zero or more occurrences of n
n? Matches any string that contains zero or one occurrences of n
n{x} Matches any string that contains a sequence of X n‘s
n{x,y} Matches any string that contains a sequence of X to Y n‘s
n{x,} Matches any string that contains a sequence of at least X n‘s
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 $。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 ( 和 )。
* 匹配前面的子表达式零次或多次。要匹配 字符,请使用 \
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。
. 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 . 。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 [。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?。(非贪婪模式)
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\‘ 匹配 “\”,而 ‘(‘ 则匹配 “(“。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 \^。
{ 标记限定符表达式的开始。要匹配 {,请使用 {。
\ 指明两项之间的一个选择。要匹配 \ ,请使用 \

如果匹配特殊字符,可以用转义符号。

举个例子。

例:匹配banana

1
2
3
4
5
<?php
$str="banana";
$pattern="ba(na){2}/i";#即将na括起来加上次数2
echo preg_match($pattern, $str);
?>

下面看表单处理

1
2
3
4
5
6
7
8
9
10
11
<html>
<body>

<form action="welcome_get.php" method="get">
Name:<input type="text" name="name"><br>
E-mail:<input type="text" name="e-mail"><br>
<input type="submit">
</form>

</body>
</html>

以上设计了一个简单的提交表单

下面对应其后端 welcome_get.php

1
2
3
4
5
6
7
<html>
<body>

welcome <?php echo $_GET['name'];?>
Your email is :<?php echo $_GET['e-mail'];?>
</body>
</html>

注意,我们这样看起来很简单,因为并没有进行输入WAF,可能会遭到恶意代码注入

下面看输入验证

1
2
对于表单的验证
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

根据$_SERVER的性质,返回正在执行脚本的文件名。

因此,$_SERVER[“PHP_SELF”]将提交的表单数据发送到页面本身,而不是跳转到不同的页面。通过这种方式,用户将在与表单相同的页面上获得错误消息。

然后

1
htmlspecialchars()很重要!

这个函数用来将字符转换为html字符,也就是一种防注入的转换,比如将

1
2
<and>转换为 &lt; and &gt;#即小于号和大于号都有对应的字符
这样防止跨站脚本攻击XSS

下面看一个htmlspecialchars()的例子,先构造一个表单

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

如果我们此时进入 http://www.example.com/test_form.php

上述代码会被翻译成

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

下面进行传参

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

将参数URL解码就是

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

会引起JS执行

如果我们在制作表单时加上

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

之后再传参,解码就会变成

1
<form method="post" action="test_form.php/&quot;&gt;&lt;script&gt;alert('hacked')&lt;/script&gt;">

注意,我们的大于小于号都被转换掉了

将不会执行恶意代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
// define variables and set to empty values
$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;
}
?>

可以做个函数验证一下,如上面。

上面的

1
if ($_SERVER["REQUEST_METHOD"] == "POST")

用来检验是否提交了表单信息,如果提交,开始检验,如果未提交,就表单空白状态不动。

现在来练习一个简单的表单过滤

1
2
3
4
$name = test_input($_POST["name"]);
if (!preg_match("/^[A-Za-z-' ]*$/",$name)) {
$nameErr = "Only letters and white space allowed";
}

中间的过滤就是A到Z和a-z还有单引号,空格,横线,后面的*表示大于等于0次匹配,后面的$表示从结尾匹配,前面的^表示从开头匹配,也就是从头匹配到结尾。