一、PHP标准语言格式
PHP语言标记:
<?php // PHP 的开始标记,表示从此标记开始,进入PHP 模式。
phpinfo(); // PHP 代码
// PHP 的结束标记,表示从开始标记到结束标记,之间的内容是PHP 模式
// 之后的内容依然被PHP 解释引擎认为是纯文本字符串。
?>
PHP用通俗的话来讲它是比较随意的一个语言,在PHP文件中,里面可以掺杂着HTML和JavaScript进行混编。
PHP的开始标记为:<?php 结束标记为:?> ,分号;代表一句话代码结束。//代表注释,//后面的内容不会被执行。而在这标记之外的内容,它们会被当作字符输出到浏览器中。例如:

可以看到上面的sad sad sad内容我们并没有做任何处理,它们直接输出到浏览器中。
对于网络安全来讲,如果在一个在线网站上找到了phpinfo页面,说明存在敏感信息泄露漏洞。
二、字+字符串混搭运算
后面的内容我们用一些小练习来进行解释:
<?php
$a = 10;
$b = "20test";
echo $a + $b;
?>

在PHP中,+ 运算符是算术加法运算符,具有明确的数值上下文要求。当操作数类型不一致时,PHP会触发隐式类型转换,其底层遵循字符串向数值转换的既定规则。加法运算迫使字符串只认开头的数字部分,其余后缀被丢弃,然后两个纯数字完成求和。这是动态类型语言中常见的“弱类型”特性。
三、可变变量
<?php
$user = "hack123";
$admin = "密码123456";
echo $$user;
?>

先计算内层变量 $user,得到字符串值 "hack123"。将 "hack123" 作为新的变量名,去查找名为 $hack123 的变量。因为从未给 $hack123 赋值,查找失败,所以会报错。
可以用数学方面这样理解:∵$user=hack123 ∴$$user=$($user)=$hack123。但因为没有定义$hack123的值,所以它认不出谁是$hack123,然后导致报错。
<?php
$name = "flag";
$flag = "this_is_secret_flag";
$$name = "hacker_get_flag";
echo $flag;
?>

这是一个写入操作,直接修改了名为 flag 的变量。
因为有$name=flag 所以$$name=$flag,但最后写入的是$$name=”hacker_get_flag”;
所以$flag=hacker_get_flag
可变变量为什么会产生变量覆盖漏洞?
如果程序从用户输入(如 $_GET, $_POST, $_COOKIE)中获取数据,并直接或间接地用于创建可变变量,攻击者就可以通过控制输入来覆盖程序中的任意变量。简单的来说当用户可控的数据被不当地用作可变变量的名称时,攻击者可以覆盖任何已存在的变量,从而破坏程序的逻辑或数据。
四、布尔转换黑名单值
<?php
$arr = [false, 0, 0.0, "", "0", [], NULL, "abc", 99, 3.14];
foreach($arr as $v){
if($v){
echo var_dump($v)." → 真<br>";
}else{
echo var_dump($v)." → 假<br>";
}
}
?>

10种不同数据类型的数组,然后用 foreach 遍历每个元素,在 if 判断中验证它们自动转换后的布尔值是真还是假,并通过 var_dump() 输出每个值的原始类型和内容,以此直观展示 PHP 的假值列表和类型自动转换规则。
在布尔上下文中,常见的以下 7 种情况会被转换为false:
|
类型 |
值 |
示例 |
|
布尔 |
false 本身 |
if(false) → 假 |
|
整数 |
0 |
if(0) → 假 |
|
浮点数 |
0.0 或 -0.0 |
if(0.0) → 假 |
|
字符串 |
""(空字符串) |
if("") → 假 |
|
字符串 |
"0"(字符0) |
if("0") → 假 |
|
数组 |
[](空数组) |
if([]) → 假 |
|
NULL |
NULL |
if(NULL) → 假 |
除此以外的所有值,都是 true(真值)。
五、单引号/双引号/定界符
<?php
$name = "xiu";
$str1 = 'hello $name ,\\'test\\'';
echo $str1;

单引号字符串中的变量不会被解析,特殊字符只有反斜杠 \\ 用于转义单引号 \\' 和反斜杠本身 \\\\。
<?php
$name = "xiu";
$str2 = "hello {$name},\\"test\\"";
echo $str2;
?>

双引号字符串中的变量会被解析。{$name} 是一种明确告诉PHP解析器这是一个变量的写法,尤其在变量名紧挨着其他字符时很有用。
<?php
$title = "php渗透练习";
$html = <<<HTML
<h1>yemianbiaoti: {$title}</h1>
<script>
console.log("定界符无需转义单双引号!");
</script>
HTML;
echo $html;
?>

输出一段HTML,其中 <h1> 标签内显示了 "PHP渗透练习"。<<<HTML 表示开始一个名为 "HTML" 的多行字符串,HTML; 表示结束。这种语法让你能方便地输出大段 HTML/JavaScript 代码,且无需转义引号,{$title} 会被替换为变量的值。
1. 输出变量时`{$name}`大括号作用是什么?不加会出现什么问题?
作用:明确界定变量名的边界。
问题:如果不加大括号,PHP会尽可能多地吞并字符作为变量名。例如 "hello $name123",PHP会认为变量是 $name123 而不是 $name,导致找不到变量而报错。大括号可以避免这种歧义。
2. 大段混合HTML、JS代码时,优先用哪种字符串格式?
首选$变量 = <<<标记名
文本内容(可以包含变量 {$变量名})
标记名;
或
$变量 = <<<'标记名' 注意:标记名用单引号包裹
文本内容(变量不会被解析)
标记名;
<<<HTML的行为类似于双引号,可以解析变量,并且内部的双引号、单引号都无需转义,非常适合输出大段的、包含大量引号和换行符的HTML/JS代码,可读性最好。
单引号:性能最好,不解析变量,只转义 \\' 和 \\\\。
双引号:性能次之,解析变量,转义多种特殊字符(如 \\n, \\t, \\" 等)。
定界符:适合多行文本,行为类似双引号或单引号。
大括号语法: 明确变量边界,提高代码可读性和健壮性。
六、魔术常量
<?php
echo "当前文件完整路径:".__FILE__."<br>";
echo "当前代码行号:".__LINE__."<br>";
echo "PHP版本:".PHP_VERSION."<br>";
echo "操作系统:".PHP_OS."<br>";
echo "目录分隔符:".DIRECTORY_SEPARATOR;
?>

风险:暴露网站根目录,攻击者可以得知网站文件在服务器上的绝对路径(如 /var/www/html/project/app/controller/index.php)。
网站对外暴露 __FILE__ 路径会造成巨大的安全风险。这属于信息泄露漏洞。
辅助其他攻击:这个路径信息可以与其他漏洞(如SQL注入、文件包含、本地文件包含 LFI)结合使用,帮助攻击者更精确地定位和读取敏感文件(如配置文件config.php,包含数据库密码等)。
社会工程学:暴露了开发框架、目录结构,为后续更深入的攻击提供了信息基础。
魔术常量:__FILE__, __LINE__, __DIR__ 等,它们会随着代码位置的变化而变化,提供上下文信息。
预定义常量:PHP_VERSION, PHP_OS, DIRECTORY_SEPARATOR 等,提供了PHP环境和操作系统的信息。
安全风险:永远不要在线上环境直接输出这些敏感信息。phpinfo() 函数更是信息泄露的"重灾区",生产环境务必禁用。
七、== 与 ===
<?php
var_dump("123abc" == 123);
var_dump("123abc" === 123);
var_dump("0" == false);
var_dump("0" === false);
var_dump([] == false);
var_dump(NULL == "");
var_dump(NULL === "");
?>

==:松散比较。比较前会进行类型转换。
"123abc" 转数字是 123,所以 123 == 123 为 true。
"0" 转布尔是 false,所以 false == false 为 true。
空数组 [] 转布尔是 false,所以 false == false 为 true。
NULL 转字符串是空字符串 "",所以 "" == "" 为 true。
===:严格比较。要求值和类型都完全相同。
"123abc" 是字符串,123 是整数,类型不同,为 false。
"0" 是字符串,false 是布尔,类型不同,为 false。
NULL 和空字符串类型不同,为 false。
例如:if ($_POST['password'] == $db_password)。
如果数据库中的密码是纯数字,比如 0。
攻击者可以提交password=0,两者都为数字0,通过验证。
更经典的例子是,如果使用 == 比较,攻击者提交一个空数组 [],它可能被转换为 NULL 或 0,从而绕过。
== 与 ===: 在涉及用户输入比较(尤其是密码、权限判断)时,必须使用 ===,确保值和类型都匹配,防止因类型转换导致的安全绕过。
松散比较规则: 要熟悉常见类型在 == 下的转换结果,特别是字符串与数字、布尔值、NULL之间的比较。
八、反引号与@
<?php
$cmd = "ipconfig";
echo "<pre>".`$cmd`."</pre>";
?>

PHP 中的反引号(`)是一个执行运算符,用于执行系统命令并获取其输出,其功能等同于 shell_exec()。
<?php
echo $undefined_var;
?>

<?php
echo @$undefined_var;
?>

1. 直接将用户输入放入反引号``中会产生什么漏洞?
会产生命令注入漏洞。如果用户输入 ; rm -rf / 或 | whoami,PHP会执行这些恶意命令。
2. 开发者使用@屏蔽报错会给渗透测试带来什么阻碍?
隐藏调试信息:渗透测试人员通常依赖报错信息来了解数据库结构、文件路径、变量名称等。@ 屏蔽了这些信息,增加了信息收集的难度。
隐蔽漏洞:屏蔽错误可能会掩盖一些明显的错误,如SQL查询失败、文件包含失败等,使攻击者难以定位漏洞点。
阻碍判断:攻击者无法通过修改参数触发报错来判断代码执行流程,需要花费更多时间和精力进行"黑盒"测试。
反引号:是 shell_exec() 函数的别名,用于执行系统命令,是命令执行漏洞的直接载体。
错误抑制符 @:可以屏蔽该行代码可能产生的所有错误、警告、通知。在生产环境中过度使用会严重阻碍调试和漏洞排查。
安全编码:不要将用户输入直接传递给反引号或任何系统执行函数(如 system(), exec() 等)。必须使用 escapeshellarg() 或 escapeshellcmd() 进行严格过滤或采用白名单方式。
九、switch和break
<?php
$week = 7;
switch($week){
case 1: echo "周一"; break;
case 2: echo "周二"; break;
case 7: echo "周日"; break;
default: echo "非法星期";
}
?>

$week是1-7的随机数,程序会正常输出对应的星期几,如果不在范围内则输出"非法星期"。

<?php
$week = 7;
switch($week){
case 1: echo "周一"; break;
case 2: echo "周二"; break;
case 7: echo "周日"; break;
default: echo "非法星期";
}
?>

程序会执行 case 1 的代码块(输出"周一"),然后继续穿透执行case 2直到遇到 break或switch结束。
1.switch缺少break会产生什么逻辑漏洞?
逻辑错误:程序可能执行多个case分支,导致输出或操作不符合预期。
权限绕过:在权限判断的switch 中,如果忘记写break,可能导致普通用户"穿透"到管理员的case。
2.break的作用:终止switch语句的执行,防止"穿透"到下一个case。
3.穿透(Fall-through):在某些特殊场景下,可以利用穿透特性来简化代码(比如多个case执行相同的操作),但在大多数情况下,忘记加break是逻辑错误的来源。
十、循环
While循环:
<?php
$i = 1;
while ($i <= 100) {
if ($i == 80) {
break; // 到80终止循环
}
if ($i % 17 == 0) {
$i++; // 注意:跳过时也要递增,防止死循环
continue; // 跳过17的倍数
}
echo $i . " ";
$i++;
}
?>

for循环:
<?php
for ($i = 1; $i <= 100; $i++) {
if ($i == 80) {
break;
}
if ($i % 17 == 0) {
continue;
}
echo $i . " ";
}
?>

continue: 跳过当前循环的剩余代码,进入下一次循环。注意在while循环中,如果continue 前忘记递增 $i,会导致死循环。
break:完全终止并跳出当前的循环结构。
取模运算符%:用于判断是否能被17整除。
循环控制:break和continue可以精细控制循环的执行流程。
while与for:while 更灵活,但需要手动维护循环变量;for结构紧凑,适合知道循环次数的场景。
十一、索引数组、关联数组创建、增删改查
<?php
$class = ["a","b","c"];
$student = [
"name" => "cxy",
"age" => 26,
"score" => 90.9,
"sex" => true
];
$student["score"] = 98.0;
$student["skill"] = "Web渗透";
echo "只取值:";
foreach ($student as $value) {
echo $value . " ";
}
echo "<br>";
echo "同时取键和值:";
foreach ($student as $key => $value){
echo "[$key] => $value";
}
echo "<br>";
?>

索引数组:键是自动递增的数字(从0开始)。
关联数组:键是自定义的字符串。
增/改:直接使用 $array[key] = value 即可,如果键不存在则新增,存在则修改。
删:使用 unset($array[key])。
foreach:是最常用的遍历数组方式。
foreach ($array as $value) 只获取值。
foreach ($array as $key => $value) 同时获取键和值。
数组类型:PHP 的数组实际上是一个有序映射,可以同时充当索引数组和关联数组。
增删改查:操作非常简单直接,是PHP灵活性的体现。
遍历:foreach 是处理数组的首选方式,它内部维护了指针,不需要手动控制。
十二、总结
PHP 标记与信息泄露:PHP 标记外的内容会直接输出到浏览器,phpinfo() 或输出魔术常量(__FILE__、__DIR__ 等)会暴露路径和配置信息,属于敏感信息泄露漏洞,生产环境务必关闭错误显示并禁用 phpinfo。
弱类型与类型转换:字+字符串运算、松散比较(==)等场景下的隐式类型转换,可能导致逻辑判断错误或绕过身份验证。始终使用严格比较(===),并避免在安全敏感处依赖隐式转换。
可变变量与变量覆盖:可变变量($$)若结合用户输入,可直接造成变量覆盖漏洞,攻击者可篡改程序状态。严禁将用户可控数据用于动态变量名。
布尔真假值:理解 PHP 的假值列表(false, 0, 0.0, "", "0", [], NULL),避免在条件判断中因类型转换产生意外结果。尤其注意 "0" 为假值,但 "0.0" 为真值。
字符串定界与注入:定界符(<<<)适合输出大段 HTML,但需注意变量注入的风险。输出到页面时应对变量进行 htmlspecialchars() 转义,防止 XSS。
魔术常量与预定义常量:__FILE__、PHP_VERSION 等可泄露服务器路径、PHP 版本等信息,生产环境禁止直接输出。可通过配置 php.ini 禁用相关输出。
反引号命令注入:反引号等同于 shell_exec(),直接执行系统命令,若拼接用户输入将导致命令注入,是最危险的安全漏洞之一。杜绝使用反引号执行外部输入,需要执行系统命令时应使用 escapeshellcmd() 或白名单。
错误抑制符 @:@ 会屏蔽错误信息,虽然可以隐藏调试信息,但也会掩盖真实漏洞,建议仅用于预期可控的错误场景,生产环境应配合日志记录。
switch 穿透与逻辑错误:忘记 break 会导致 case 穿透,可能造成权限绕过或逻辑漏洞,每个 case 末尾务必添加 break,除非有意利用穿透特性。
循环控制与死循环:while 循环中 continue 前必须递增计数器,否则导致死循环;break 要及时退出循环,防止无限执行。
数组与数据操作:PHP 数组灵活强大,是 Web 开发常用数据结构,但要注意在对数组进行增删改查时,避免因未验证数据来源导致的逻辑漏洞(如未过滤的键名可被利用)。
网硕互联帮助中心


![打卡信奥刷题(3488)用C++实现信奥题 P10725 [GESP202406 八级] 最远点对-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/08/20260804010041-6a7139b908d5e-220x150.png)


评论前必须登录!
注册