依旧是无可救药的一天……在开始正文之前请容我小小的吐槽一下。

CTF吧,真的是个巨坑。

一开始选的web和misc,结果选这个方向的人太多找不到其他方向的人组队……形势所迫,只好自己看看能不能全栈或者换个方向下手。一开始想试试pwn,结果pwn要求有逆向基础,又想去试试逆向,结果逆向又要求有汇编语言基础,好巧不巧的是汇编语言的书籍刚好给人借走了……好了,毫无疑问这也是个坑,不过汇编早晚都得学,倒也不是什么大问题。但是现在又只能暂时转向web了,无奈,先从之前的SQL注入入手吧。但是没有MySQL基础去学注入实在是看天书,那去学学MySQL?巧了,MySQL要求PHP基础,PHP又要求HTML/CSS基础(所幸上学期已经学过前端三件套了),于是乎,又得先从PHP开始学起,还有一大堆协议等着,又是个巨坑……

实在是……受不了一点

好了,闲话到此打住,先来归纳一下今天学习PHP的一些笔记吧,姑且当做我的碎碎念好了。

那么,正文开始。


我参考的书是《PHP和MySQL Web开发》,同时参考了部分菜鸟驿站的内容PHP 教程 | 菜鸟教程 (runoob.com)。有兴趣的可以自行查看,适合快速预习。

开始之前

首先我们先对PHP做一个大概的综述,方便更好的理解这门语言。

在开发一个网站时,一般都是先用HTML搭建起一个大致的框架,然后用CSS美化网页属性,最后用JavaScript实现一些更复杂的用户交互功能。但是,学会这些基本上只能搭建一个静态网页,也就是说,用户不能与网站产生任何互动(也许JS除外?),每一次网页的更新都必须依靠与重写其底层的HTML代码。那么我们要如何搭建起一个动态页面来实现更加丰富的网页功能呢?答案是使用PHP。

PHP是一个服务器端脚本代码,它能接收网页传递给服务器的数据,并在后端处理数据并将其发送到网页来实现内容的更新。最经典的操作就是处理表单,比如,处理一个在线购物的购物车订单。

PHP的学习其实并不难(至少书上是这么说的),如果你有过C/C++、Python等其他编程语言基础,要上手PHP其实挺快的。PHP存在大量的函数和语句功能和C相同,基本上就是一通百通的道理(果然C是万物之母)。这里主要介绍一些PHP语言特有的属性,和C雷同的地方就略过了,也就是说,阅读这篇文章已经默认了你已经有了一定的C语言基础,不过要求也没那么高,只要掌握一些最基本的C语法就可以上手。

那么介绍到此为止,我们开始讲解PHP的语法。

万物源头之hello world

这里在书中给出了一个HTML制作的静态订单网站搭配PHP进行讲解,但是很遗憾我没有这本书的电子书资源,而且我也不想手撸一个HTML网页,所以这里我选择介绍菜鸟教程的内容。

在编程中,每每开始学习一门新语言,先输出一个hello world是传统,比如C的printf("Hello, world");。那么,在PHP中我们要怎么发扬传统呢?下面是我们编写的第一个PHP语句。

<?php
echo "Hello, world";
?>

这里就有许多需要讲解的地方了。

PHP语句的格式

如你所见,在执行输出函数的主体外,套着一个< ?php … ?>,以小于号开始,以大于号结束。这是PHP代码块的标志,即使是在PHP文件中,在标志外的代码仍然会被识别为HTML,只有代码块内的PHP语言才能被正确解释。所以,所有的PHP语句都必须在标志内编写。

值得一提的是这种风格有它自己的名字,叫做XML风格,是最为推荐也是最通用的风格。简短风格则是可以省开头的‘php’,但是不推荐。

echo是什么?

在PHP中一般使用echo来回显内容,使用方法如上。在echo后接你想要回显的值,如果是字符串需要加上双引号,且末尾用分号表示语句结束(这一点很像C语言)。

当然用print也能实现同样的功能,区别在于echo无返回值且速度更快,而print会返回1且不支持输出多条语句。在使用echo和print时,可以加括号也可以不加括号,因为echo和print都不是真正的函数。

关于空格

可以看到,echo前自动加上了一段缩进。

但是需要声明的是,不同于Python,PHP和HTML一样对空格和缩进不敏感。也就是说,PHP解释器会自动删掉语句间的空格和缩进,这些对语句的执行没有影响。但我们还是推荐在编程时使用缩进和空格,因为这可以提高代码可读性。

关于注释

PHP的注释有几种形式,基本是C和Python的大糅合。你可以使用//或者/**/来进行注释,也可以使用Python风格的#来注释,这些注释都不会被执行。

来添加一个动态内容吧

上面我们用PHP实现了计算机界的祖传手艺,但这还是静态的啊,和我们一开始说好的不一样啊。所以我们现在尝试用PHP实现一个动态内容,我们将调用date()函数,来显示当前的时间。

<?php
echo "<p>The time is";
echo date('H:i, jS F Y');
echo "</p>";
?>
/*
以下代码是等价的
<?php
echo "<p>The time is".date('H:i, jS F Y')."</p>";
?>
*/

小朋友,你是否有很多问号?别急,让我们来逐步探索它背后的真相。

date()函数?!

在这个代码中,我们是这样调用date()函数的date('H:i, jS F Y')。很明显,我们向函数传递了一个格式化字符串变量。这个变量中,H代表小时,i是分钟,j代表该月的日期,s表示顺序后缀(在这里也就是‘th’),F代表月份,Y则是年份。

如果你发现运行代码给出的时间与现在不一致,大概率是你没有调整时区,如何设置时区,请自行上网询问度娘。

为什么等价?

在PHP中,(.)是连接操作符,通过使用 . ,我们可以连接起不同的语句和变量,将他们一起输出。

怎么还有奇怪的<p>?

学过HTML的小朋友都知道,这个是段落的标志。没错,PHP会自动渲染HTML语言并把它显示在网页上,配合的相当不错。

如何访问表单变量

好了,前面我们提到PHP最常用来做的事就是实现订单,那么我们要如何操作呢?

为了详细解释这个知识点,我不得不花了两分钟去网上找到了这本书的电子版资源……(太痛苦了),然后把表单的HTML代码粘贴如下。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body><!--总之注意body部分-->
<form action="processorder.php"method="post"><!--注意action的取值指向了一个php文件-->
<table border="0">
<tr bgcolor="#cccccc">
<td width="150">Item</td>
<td width="15">Quantity</td>
</tr>
<tr>
<td>Tires</td>
<td align="center"><input type="text"name="tireqty"size="3"
maxlength="3"/></td><!--注意这个文本框的名字!!-->
</tr>
<tr>
<td>Oil</td>
<td align="center"><input type="text"name="oilqty"size="3"
maxlength="3"/></td><!--注意这个文本框的名字!!-->
</tr>
<tr>
<td>Spark Plugs</td>
<td align="center"><input type="text"name="sparkqty"size="3"
maxlength="3"/></td><!--注意这个文本框的名字!!-->
</tr>
<tr>
<td colspan="2"align="center"><input type="submit"value="Submit Order"/></td>
</tr>
</table>
</form>
</body>

</html>

最后我们得到了一个小小的可爱的订单。

很可爱吧

显然,这个表单的目的是接收用户输入的值,然后将其提交给processorder.php文件(也就是表单的action属性指向的那个)。那么,我们要如何用PHP文件处理接受的值呢?

闲话少说,上代码!

<?php
$tireqty=$_POST['tireqty'];
$oilqty=$_POST['oilqty'];
$sparkqty=$_POST['sparkqty'];
?>

打住,这里又出现了新情况,让我们细细道来。

关于奇怪的$

在PHP中,我们一般要在声明的变量前加$,不仅如此,在使用变量时也必须要加上$来告诉服务器这是个变量而非什么奇奇怪怪的东西。除此之外,还需要强调的一点是,PHP是一门弱类型语言,即不需要专门指定变量的类型而交给服务器自动匹配,与之相反的则是C语言的强类型。

关于声明变量,需要注意的是PHP区分变量大小写(但不区分函数的大小写),且变量名只能以下划线和字母开头,由下划线、字母和数字组成。

PHP有以下数据类型:

  • String 字符串
  • Integer 整数
  • Float 浮点数
  • Boolean 布尔值
  • Array 数组
  • Object 对象
  • NULL 空
  • Resource 资源(一种特殊变量,保存了到外部资源的一个引用,比如MySQL)

关于奇怪的_POST

我们注意到有$_POST['tireqty'],这东西很厉害,可是要怎么去理解它呢。

我们最开始的设想是用PHP去处理用户提交的表单信息,且其中一个文本框的名字就叫做’tireqty’。显然,这个代码的作用就是访问’tireqty’文本框的内容。_POST是一个数组,它包含了HTTP通过POST提交的所有数据,也就是文本框的method被设置为POST的情况。除此之外,我们还有_GET_REQUEST。前者用于处理以GET形式提交的数据,而后者则用来处理POST和GET提交的数据总和。一般情况下,数据都可以通过_REQUEST来获得。

我们把通过这种方法获得的数组称为超级全局数组

类似的超级全局数组还有以下几种:

  • $GLOBALS,可以访问所有全局变量
  • $_SERVER,服务器环境变量数组
  • $_COOKIE,cookie变量数组
  • $_FILES,文件上传相关的变量数组
  • $_REQUEST,所有用户输入的变量数组,包括$_POST、$_GET、$_COOKIE所包含的输入内容(但是不包含$FILES)
  • $_ENV,环境变量数组

题外话:GET与POST

网页向服务器提交数据通常有两种方法,一种是将数据直接附加在链接后面发送给服务器,即GET。例如https://adam8en.github.io?id=1就是向网页传递了一个id=1的数据。而POST数据则是将数据单独发出去,具体细节可以用burp suit抓包查看,通常不涉及到复杂的操作时用hackbar就可以很好的使用POST发送数据。

如何回显收到的数据

一般来说,使用我们前文提到的输出hello world的方法就可以回显表单中提交的数据,即:

echo $tireqty.'tires<br />';

但是我们并不推荐这种方式,因为我们没有对用户输入的数据进行检验,这可能会导致恶意用户输入恶意语句而引发安全性问题(终于有点安全的知识了),你应该对数据进行过滤,这里我们先使用另一种方法,即调用htmlspecialchars()函数。

echo htmlspecialchars($tireqty).'tires<br />';

这样做也可以获得可视化结果,且更加安全。如果你现在在浏览器中载入这个脚本,正常来说就可以看到回显的内容。

然而如果你真的这么做了而且和我一样都是小白,那么你大概率看到的不是正常的结果,而是PHP文件的源代码……

因为你没有给自己的主机配置服务器,从而网页不知道该如何去解析PHP代码。至于如何去配置服务器……抱歉,你这个问题我还真不知道lol。

变量和字面量

经历过一些不愉快的小插曲后,我们再次回到例题本身。有关echo htmlspecialchars($tireqty).'tires<br />';这一行代码本身,关于(.)的字符串连接符我们已经讲过,而后面所跟的单引号却又是另一个重点。

在PHP中,双引号和单引号存在区别。其实这一点在C语言中也有类似的情况,在C中单引号常量被视为字符常量,哪怕单引号中包含的字符不止一个;而双引号下的常量则被解释为字符串,末尾默认有一个’\0’占位符存在。而在PHP中,使用双引号会被认为是字符串,此时PHP会解析双引号中的变量,而单引号则会被纯粹的当做是一个字面量,换句话说PHP会直接输出变量名而不会对其进行解析。

例如下面这一串代码

<?php
$web_url='adam8en.github.io';
echo "$web_url";
echo '$web_url';
?>

可以预见到的是,用双引号包裹的变量将会echo出变量的值,而下面的单引号变量则只会打印出变量名。

在日常使用中,单引号的运行速度比双引号更快,因为单引号不需要经过解析步骤。

声明和使用常量

上面我们介绍了如何定义和给变量赋值,那么我们要如何定义常量呢?

在C语言中,我们一般使用#define定义常量。比如:

#define BIRTHDAY 77

在实际编程中,我们就可以用常量’BIRTHDAY’来代替整数77。

在PHP中,我们仍然需要使用define去定义常量,但是使用方式有所不同,具体形式如下:

define('BIRTHDAY',77);

这时我们就定义了一个新常量。

除了我们自己定义的常量外,PHP还自己定义了许多常量,我们可以用函数phpinfo()来查看。

注意函数phpinfo(),今后在安全方面我们还会遇到它。

就到这里

好了,通过表单这个例子我们阐述了大部分PHP语言不同于C语言的新特性,接下来我会快速介绍一些PHP和C语言类似的语法知识点,并简单的指出他们之间的细微不同(如果有的话),一些我认为不重要的知识点可能会被我略过(比如转换变量类型的函数),现在让我们快起来吧。

变量作用域

和C语言类似,分为局部作用域、全局作用域、静态作用域、本地作用域,唯一不同的超级全局作用域在前文中已经有过具体介绍。

使用操作符

PHP也可以直接使用四则运算符合取余符号来对变量进行操作。如果对字符串使用操作符,PHP会尝试把字符串转化为数字。比如把带‘e’或‘E’的字符串视为使用了科学计数法,并将其转化为相应的浮点数。除此之外,PHP还会在字符串开头处寻找数字作为字符串的值,否则把字符串视为0。(C语言会直接报错)

字符串操作符

PHP可以直接实现字符串的加法,通过连接符(.)来实现。

$fname="Adam";
$lname="Ben";
$name=$fname." ".$lname;
//别问我为什么没有遵循XML风格,好麻烦

递减和递增操作符

PHP允许使用诸如++的形式去递增变量的值,和C相同。

引用操作符

PHP可以通过“&”来引用变量的值。它的用法和效果类似于C语言的指针,但是它实际上并不是指针,只是一个别名。

$a=5;
$b=$a;//b等于5,相当于生成了一个a的副本
$a=7//此时b仍为5
/**********************/
$a=5;
$b=&$a;
$a=7;//此时b也为7

如果想要破坏掉变量之间的引用关系,使用unset()函数重置。

比较操作符

除了==等于操作符外,PHP还有===恒等操作符。区别在于前者只判断数值是否相等,而后者要求类型也要一致。

比如0和’0’,在==下是相等的,而===是不等的。因为前者是整数,后者是字符串。

逻辑操作符

除了和C相同的&& || !操作符外,PHP还支持类Python的and or逻辑操作符,但是优先级比前面的略低。PHP还支持xor异或操作符。

位操作符

这一部分PHP和C完全相同。

其他操作符

操作符new->分别用来初始化类的实例和访问类的成员。看起来有点像C++的分配内存符和C的访问结构指针变量操作符。

PHP和C都支持三元操作符condition ? value if true : value if false

错误抑制符

错误抑制符@可以对任何表达式使用,它将抑制可能产生的警告而使程序不中断运行。例如:

$a=@(50/0);

执行操作符

执行操作符是一对反向双引号``,它的作用是把反双引号中间的内容当成服务器端的命令来执行。比如在windows端:

$out=`dir c:`;
echo '<pre>'.$out.'<pre>';

这串代码会得到一个目录列表保存在out中,然后在浏览器上显示。

数组操作符

PHP也支持用[]访问数组元素,除此之外还有其他操作符。比如可以用+来连接两个数组。

类型操作符

PHP只有一个类型操作符instanceof,用于判断一个对象是否是指定的类。

其他

剩下的诸如if、while、for、switch1等代码块均与C规则相同,不一一介绍了。唯一注意的地方是除了使用C经典的花括号控制结构外,还可以使用PHP特色的控制方法。

if ($a==0){
//C风格
echo 'TEST';
exit;
}
/*这两种方法是等价的*/
if ($a==0) :
//PHP风格
echo "TEST";
exit;
endif;

小结

这一章我们快速的入门了PHP的知识,如果你已经有过C语言的基础,相信这个过程并不难。

再学一点PHP,直到能入门MySQL为止(勿忘初心)。

300411