PHP学习及练习
一、PHP开发入门
1.PHP概述
PHP最初是由 Rasmus Lerdorf于1994年为了维护个人网页而编写的一个简单程序。这个程序用来显示Rasmus Lerdorf的个人履历以及统计网页流量,因此最初称为个人主页(Personal Home Page)。后来受到GNU的影响,它更名为PHP(Hypertext Preprocessor,超文本预处理器)。
PHP作为服务器端Web程序开发语言,主要有以下两方面原因:
1.PHP是一种服务器端、HTML嵌入式的脚本语言,因此适合Web开发。
2.PHP是B/S(Browser/Server,浏览器/服务器)架构,即服务器启动后,用户可以不使用客户端软件,而是使用浏览器进行访问,这种方式既保持了图形化的用户界面,又大大减少了应用程序的维护量。
PHP的应用领域:
全球有60% 的网站都在使用PHP技术进行开发,包括Facebook、谷歌、百度、新浪等国内外一线互联网公司。PHP正吸引着越来越多的Web开发人员,其应用领域非常广泛,如网站开发、OA办公系统、电子商务、CRM管理系统、ERP系统、手机APP接口及API接口、网页游戏后台、服务器脚本等。
2.PHP开发环境搭建
下载WampServer
安装WampServer
打开WampServer
成功编写第一个php程序!!!!!!
二、PHP编程基础
1.PHP基础知识
PHP的一些知识与语言相同,相同的部分不多赘述
php标记:开始要用一对标记将PHP代码包含起来,以便和HTML代码区分。\
一般用来分别作为开始结束标记
注释:可以使用c语言风格
标识符和关键字如下图:
PHP变量及数据类型:在PHP中,变量是由$和变量名构成的,命名规则与标识符相同,且区分大小写。
boolean(布尔型):该类型只能为true(真)和false(假)且不区分大小写。
例:$bool = true;将true值赋给$bool
integer型(整型):存储整数
float(浮点型):存储实数
string(字符串型):字符串可以由单引号(单引号的这种形式只能转义单引号(')和反斜杠(\)。)、双引号 (可以转移一些字符,也可以解析变量)、定界符(<<<)(在之后用一个标识符表示开始,然后是包含的字符串,最后是同样的标识符结束字符串,并且后面除了分号不能有任何其他字符)
PHP检测数据类型:
函数返回的布尔值true转换成字符串“1”,false转换成空字符串
PHP常见转义字符:

预定义常量:
数据类型转换:
其他类型转换成布尔型:整型0、浮点型0.0、字符串型””与”0”、不包含任何元素的数组、不包含任何成员变量的对象、NULL会被转换成false,其他值会被转化成true。
布尔型转化成整型:true转化成1,false转化成0
字符串类型转化成整型或浮点型:如果字符串是数字序列的字符,则这转换成该数字,否则出现警告
布尔型转化成字符串类型:true转换成”1”,false转换成””。
整型或浮点型转换成字符串类型:字面样式转换
PHP一些基本运算符参考c语言
==与===的区别是==先将操作数转换成相同类型在进行比较,两者值相同则返回true,而===只有值相等并且数据类型相同才返回true
NULL合并运算符:表达式1 ?? 表达式2 ; 意为表达式1的值存在且不为NULL则返回该值,否则返回表达式2的值
组合比较运算符:表达式1 <=> 表达式2; 意为当表达式1小于等于大于表达式2时分别返回-1、0、1
位运算符:
其他运算符:
运算符的优先级:
选择语句,循环语句、跳转语句基本与c语言相通,在此不多赘述了
写了一道题:
2.PHP函数、数组
PHP的函数的定义:
function 函数名(参数名1 [=值1],参数名2 [=值2],参数名3 [=值3],……)
{
函数体
[return 返回值;]
};
[]中的内容可以省略。并且在书写时不带[]
函数的调用:
function 函数名(参数名1 [=值1],参数名2 [=值2],参数名3 [=值3],……)
常用函数:
urlencode() 函数:urlencode() 函数编码URL 字符串函数,此函数便于将字符串编码并将其用于 URL 的请求部分,同时它还便于将变量传递给下一页。
语法:string urlencode ( string $str );
此函数便于将字符串编码并将其用于 URL 的请求部分,同时它还便于将变量传递给下一页。编码 URL 字符串函数。
此函数便于将字符串编码并将其用于 URL 的请求部分,同时它还便于将变量传递给下一页。
serialize() 函数:用于序列化对象或数组,并返回一个字符串。函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。
语法:string serialize ( mixed $value );
__wakeup()函数:__wakeup() 是 PHP 中一个特殊的魔术方法。它在反序列化一个对象时被自动调用,允许开发者在对象从序列化格式还原为可用的 PHP 对象之前对其进行某些特殊处理。这个方法可以接受任意的参数,但在实际使用中,它通常不需要参数。
eval() 函数:eval() 函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。
语法:eval(phpcode);
include ()和 require()函数:在 PHP 中,可以在服务器执行 PHP 文件之前在该文件中插入一个文件的内容。include 和 require 语句用于在执行流中插入写在其他文件中的有用的代码。include 和 require 除了处理错误的方式不同之外,在其他方面都是相同的:require 生成一个致命错误(E_COMPILE_ERROR),在错误发生后脚本会停止执行。include 生成一个警告(E_WARNING),在错误发生后脚本会继续执行。
语法:include ‘filename’; 或者 require ‘filename’;
mb_substr()函数:mb_substr() 函数返回字符串的一部分,substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。
语法:mb_substr( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] )
mb_strpos()函数: — 查找字符串在另一个字符串中首次出现的位置 查找 string 在一个 string 中首次出现的位置。 基于字符数执行一个多字节安全的 strpos () 操作。 第一个字符的位置是 0,第二个字符的位置是 1,以此类推。 要被检查的 string。 在 haystack 中查找这个字符串。 和 strpos () 不同的是,数字的值不会被当做字符的顺序值。
语法:mb_strpos (haystack ,needle );
参数:haystack:要被检查的字符串。needle:要搜索的字符串。
urldecode()函数:urldecode() 方法用于解码 PHP 中的编码字符串。urldecode() 是 PHP 中用于解码编码字符串和 URL 的内置方法。 urldecode() 只能解码由 urlencode() 方法完成的编码字符串和 URL。 此方法的语法是: 其中 URL 是要解码的 URL 或字符串,此方法的返回值是一个字符串
语法:string urldecode ( string $str );
strcmp()函数:函数用于比较两个字符串(区分大小写)。如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
语法:strcmp(string1,stristrcmp()
file_get_contents()函数:在PHP中,file_get_contents() 函数是一个强大的工具,它既可以用于读取本地文件的内容,也可以用于发起 HTTP 请求获取远程资源。
语法:file_get_contents(path,include_path,context,start,max_length);
preg_match()函数: preg_match函数用于执行一个正则表达式匹配。
语法:int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
参数说明:
$pattern: 要搜索的模式,字符串形式。
$subject: 输入字符串。
$matches: 如果提供了参数matches,它将被填充为搜索结果。 $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。
$flags:flags 可以被设置为以下标记值:
PREG_OFFSET_CAPTURE: 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。 注意:这会改变填充到matches参数的数组,使其每个元素成为一个由 第0个元素是匹配到的字符串,第1个元素是该匹配字符串 在目标字符串subject中的偏移量。
offset: 通常,搜索从目标字符串的开始位置开始。可选参数 offset 用于 指定从目标字符串的某个未知开始搜索(单位是字节)。
数组的定义:
1.直接为数组赋值:_$数组名[key]= value ; _
2.使用array语句定义数组:$数组名 = array(key1 => value1 , key2 => value2 ,……);
数组的操作:
输出:var_dump()函数可以输出数组中的每个元素与值的数据类型,print_r()函数可以直接输出数组中的所有元素
删除:用unset语句可以删除整个数组,也可以删除数组中的某一个元素。用法为:unset(数组名);
运算:
举例:
数组的常用语句、函数:
1.list语句:把数组中的值赋给一些变量。
语法:_ list(var1,var2…);_
2.each()函数:返回当前元素的键名和键值,并将内部指针向前移动,该元素的键名和键值会被返回带有四个元素的数组中。两个元素(1 和 Value)包含键值,两个元素(0 和 Key)包含键名。
语法: each(array);
**3.count()函数:**该函数可以统计数组中元素的个数
语法:_int count(array,mode); _
mode为可选参数可选。规定模式。可能的值:
0 - 默认。不对多维数组中的所有元素进行计数
1 - 递归地计数数组中元素的数目(计算多维数组中的所有元素)
4.压入、弹出元素函数:
5.移除重复值:array_unique() 函数移除数组中的重复的值,并返回结果数组。当几个数组元素的值相等时,只保留第一个元素,其他的元素被删除。返回的数组中键名不变。
语法:array_unique(array);
二维数组:
定义:
array (
array (elements…),
array (elements…),
…
)
二维数组的遍历可以通过foreach语句嵌套来遍历二维数组
三、练习(BUUCTF)
1.[极客大挑战 2019]Havefun
进入这一题看到了一只很可爱的猫猫,如果我不是来做题的话,我会看上一整天,傻笑一整天……
这道题页面上啥都没有,就想着看看源代码,进一步发掘有效信息
打开之后是一堆晦涩难懂的内容,这代码确实不想看,感觉都是无效信息
还好我比较谨慎,耐心翻源代码,在页面最下面找到了绿油油的被注释掉的东西,这应该就是关键信息了,这是一段PHP代码,这段代码的意思是用get传参cat到变量…$cat里,输出变量$cat的值,之后是if语句,如果$cat里的值等于dog,那么就输出Syc{cat_cat_cat_cat},大概率是flag。
所以我们在后面get请求去传参dog给cat变量,满足if语句的条件,flag就出现了。
这道题挺适合我这样的小白的,也是做完BaseCTF2024新生赛后自己独立做出来的题目,为自己鼓掌
2.[HCTF 2018]WarmUp
进入页面后这一个滑稽属实绷不住,大晚上的
还是和上一题一样,这个页面没有有效信息,所以我看看源代码,又是这一个绿油油的注释,提示已经很明显了
果然,在后面加上/source.php访问一下果然出现PHP代码了。这串代码看的我比较蒙,我简单理解一下:这段PHP代码先是用class定义emmm的类,之后定义函数checkFile,之后进行If语句,if条件语句是关键,即需要满足if(true && true && true),才会执行include函数,否则输出:https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg,即滑稽图。
满足后面的if(true && true && true)前两个true比较简单,但是最后的true得看这个checkFile函数,这 函数确实难懂,但是我找到了hint.php,这个应该也是关键信息,访问一下后出现了这个,说明flag藏在fffllllaaaagggg里,这道题确实抽象的像极了我的室友,我们始终是在source.php页面下进行操作,目的是利用最后的include函数将flag文件包含出来,从而得到答案
接着分析一下传入hint.php之后出现”flag not here, and flag in ffffllllaaaagggg“,PHP代码是怎么工作的:
这个题目是用class定义了一个名为emmm的类,在该类中有一个静态方法的checkFile用于检查要包含的文件是否在白名单($whitelist)中,白名单是一个关联数组$whitelist。在代码中,白名单允许包含的文件有”source”=>”source.php”和”hint”=>”hint.php”。
第一个if语句:当传入hint.php时进行第一个if语句判断,显然hint.php是字符串,不执行输出”you can’t see it”并返回false。
第二个if语句:之后第二个if语句检查hint.php是否在白名单内,显然它在白名单内,条件通过,继续执行后面的代码。
之后对hint.php执行mb_substr函数,但是函数内一个参数是来自另一个函数mb_strpos的返回值,因此我们先看mb_strpos函数,使用.进行字符连接,即连接了一个问号字符 ‘?’,得到hint.php?在这个新的字符串中查找问号是否存在,那么很明显肯定能找到。那么返回值是”?”首次出现位置的数值,0开始算,即8,所以mb_substr函数的处理是返回从hint.php?的第0个字符到第8个字符,其实还是返回hint.php。来回绕是吧!!!原样进去原样出来,这一步真是字如其名666
第三个if语句:之后进行第三个if语句,显然hint.php还在白名单中,继续执行后面的代码
第四个if语句(包含语句前的内容):将$_page进行URL解码之后重复之前的
如果上述条件都不满足,则输出”you can’t see it”并返回false。
这就是函数的分析,我们只需要传入一个在白名单内的文件名(source.php或者hint.php),并添加上问号,这样可以保证每次找去用于检查的内容都在白名单,返回true。
并且我们当前的source.php一般是在html目录下,往上是www,var,然后到根目录,flag一般就放在根目录下面,这里还有一个hint.php?/或者source.php?/,因此需要返回四层才能到根目录并且flag 是在 ffffllllaaaagggg 里的,所以构造source.php?file=hint.php?/../../../../ffffllllaaaagggg即可得到falg
3.[ACTF2020 新生赛]Include
看到这个题目,它给了tips,点开之后反问我Can you find out the flag?卧艹,这能忍?来吧我已经迫不及待了!!!

正当我举足无措时,看了一下题目[ACTF2020 新生赛]Include,include!!!想到了以前写的笔记,flag大概率是被注释掉了,这里可能是要用到伪协议来显示注释的内容。
所以把file后面的内容换成php://filter/read=convert.base64-encode/resource=flag.php
execute一下,出现一下内容,这显然这就是base64编码内容
解码之后就发现flag就是被注释掉了,拿falg提交完事
4.[NewStarCTF 2023 公开赛道]Begin of PHP
进入到题目里发现这里有一堆PHP代码
分析代码:绕过=Level 1=到=Level 5=就可输出flag,所以接下来就是绕过
显然=Level 1=是md5绕过,之前的笔记有用啦!key1和key2原来的值不强等于而经过md5加密后的值弱相等,之后把$flag1赋值True,这里也可用数组绕过。
所以参照上次写的笔记输入?key1=QNKCDZO&key2=240610708可得如下图所示的内容,说明绕过成功了,笔记是有用的,为自己鼓掌!!!
对于=Level 2=,我们需要POST传参key3,出现了要md5密和sha1加密的内容强比较绕过,查了资料sha1()函数和md5一样,都无法处理数组,如果传入的为数组,会返回NULL,所以就数组绕过呗,试了试,就出现了以下内容,还真成功了,不愧是我。
=Level 4= 的if是用的is_numeric 函数来比较,它是用于检查一个变量是否是数字或数字字符串,,是的话返回1,但是is_numeric()无法解析数组会返回false。所以还是数组绕过,且数组的值大于2023,所以传入key5[]=2024绕过
=Level 5=的if,由is_numeric() 函数不能匹配a-zA-Z0-9可知这里要输入的POST内容不能是字母和数字,并且下一关只有flag5为真才输出flag,所以在这里需要给flag5赋值一个符号就行,给数组也行。
说实话,这道题从=Level 1=到=Level 5=也确实都可以使用数组绕过。
提交flag,游戏结束。
5.[极客大挑战 2019]PHP
进去是一只可爱的猫猫,随着鼠标的移动,那个球也在移动,当球靠近猫猫时,猫猫还在布拉球,真是卡哇伊
页面上没有什么信息,我的思路是先到元素和网页源代码看看有没有什么有用的信息
下面是几个网址,看了一下,都是一堆代码,仔细看也没有关键信息,猜了一下,这大概是页面猫猫的代码吧
即使有高亮部分也是注释或者其他的与题目无关的代码
这道题一开始确实是没有思路,但是页面上的这句话”因为每次猫猫都在我键盘上乱跳,所以我有一个良好的备份网站的习惯“帮我打开了一下思路,查了查网站备份的相关知识
所以我猜测flag应该是藏在了某个文件里了,我是从zip开始尝试的,毕竟zip是压缩包的后缀,比较熟悉的
在这里输入web.zip、website.zip、zipbackup.zip,back.zip都不行
到了www.zip试了一下,结果下载了一个压缩包,说明方向是正确的,网站备份文件就找到了,flag肯定就藏在里面

~~ 真狗,666~~,直接删了。
也找了其他的文件,最后在class.php这里找到了flag。在这个里面我们可以知道如果password不等于100则接下来会执行到die退出程序,如果username不等于admin则会直接绕过flag执行输出”hello my friend~~sorry i can’t give you the flag!“只有username=admin,password=100,才可拿到flag。
仔细分析一下代码:这里一开始是包含flag.php的,然后有一个类,两个私有变量$username,$password。之后构造函数建立了一个一 一对应的关系,wakeup会把username换成guest。所以username在wakeup函数那里就会变为guest就不可能是admin,所以我们的目标是绕过这个wakeup函数。查了一下资料,一般做CTF题目时绕过wakeup的方法就是:先序列化字符串,然后使序列化后字符串中属性的个数大于真实对象中属性的个数,即可绕过wakeup魔术方法。
所以写代码来序列化它一下(因为username=admin,password=100,所以Name里的两个参数分别为’admin’、100)。
序列化的结果如下
因为序列化后字符串中属性的个数大于真实对象中属性的个数,即可绕过wakeup,所以要把
”O:4:”Name”:2:{s:14:”Nameusername”;s:5:”admin”;s:14:”Namepassword”;i:100;}“中”Name”:后面的2改为比2大的数(我用的是3)即可,注意空字符!!!(我在这里卡了半小时才发现问题)。所以修改后的序列化的字符如下:
O:4:”Name”:3:{s:14:”%00Name%00username”;s:5:”admin”;s:14:”%00Name%00password”;i:100;}
其他文件也是要看一眼的,在index.php这里找到了PHP代码,知道了这是通过select来GET传参。
所以,提交
?select=O:4:”Name”:3:{s:14:”%00Name%00username”;s:5:”admin”;s:14:”%00Name%00password”;i:100;}
然后,flag就出来了,提交完事。
这一周先写到这里啦,这一周又是改视频又是密码技术决赛志愿者,太累了,休息一下啦















































































