您的位置:首页 > 编程语言 > PHP开发

PHP弱类型

2020-02-03 04:36 351 查看

1PHP弱类型

之前我们在PHP代码基础中讲过,PHP是一种弱类型语言,在设置变量的时候不用事先设置数据类型。弱类型的语言对变量的数据类型没有限制,我们可以在任何地时候将变量赋值给任意的其他类型的变量,同时变量也可以转换成任意地其他类型的数据。

PHP中的松散比较”==”给我们提供了利用弱类型漏洞的机会。我们看看官方手册是怎么说的。

“如果比较一个数字和字符串或者比较涉及到数字内容的字符串,
则字符串会被转换为数值并且比较按照数值来进行。
此规则也适用于switch语句。
当用=== 或!== 进行比较时则不进行类型转换,
因为此时类型和数值都要比对。”

很明确的说使用”==”比较时会进行类型转换,如果是数字和字符串作比较,那么字符串会被转成数字类型。(不会将数字转为字符串)。我们继续看官方手册,看看字符串被转换成数值后的结果是怎样:

当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含'.','e' 或'E' 并且其数字值在整型的范围之内(由PHP_INT_MAX 所定义),该字符串将被当成integer来取值。其它所有情况下都被作为float来取值。该字符串的开始部分决定了它的值。如果该字符串以合法的数值开始,则使用该数值。否则其值为0(零)。合法数值由可选的正负号,后面跟着一个或多个数字(可能有小数点),再跟着可选的指数部分。指数部分由'e' 或'E' 后面跟着一个或多个数字构成。

然后官方给了几个例子:

<?php
$foo=1+"10.5";//$fooisfloat(11.5)
$foo=1+"-1.3e3";//$fooisfloat(-1299)
$foo=1+"bob-1.3e3";//$fooisinteger(1)
$foo=1+"bob3";//$fooisinteger(1)
$foo=1+"10SmallPigs";//$fooisinteger(11
)$foo=4+"10.2LittlePiggies";//$fooisfloat(14.2)
$foo="10.0pigs"+1;//$fooisfloat(11)
$foo="10.0pigs"+1.0;//$fooisfloat(11)
?>

我们不妨在官方的基础上具体深入一点:

<?php
$foo=1+"10.5";
//"10.5"含有.,所以“10.5”作为float来取值为10.5,1+10.5=11.5。

$foo=1+"-1.3e3";
//"-1.3e3"中的负号是合法数值,又带了.和e,转换后应该是浮点数类型float,1.3e3是科学计数法,表示1.3乘以10的3次方,就是1300,那么整个算式就是1+(-1300)=1299。虽然结果看起来是int,但是因为中间转换的时候已经是float了,所以最终结果的类型依然是float。

$foo=1+"bob-1.3e3";
//"bob-1.3e3"按官方说法,字符串开始的部分决定了它的值,这里开始部分不是数字,所以这里"bob-1.3e3"的值为0,所以最终算式的结果为1.

$foo=1+"bob3";//同上。

$foo=1+"10SmallPigs";//与上面刚好相反,"10SmallPigs"开始部分是合法数值,所以直接取数值10,最终结果就是11。

$foo=4+"10.2LittlePiggies";//同上,只是10.2是float,最终结果也是float。

$foo="10.0pigs"+1;//同上。

$foo="10.0pigs"+1.0;//同上。
?>

1.1类型转换的弱类型

根据我们深入分析后,可得出一些结论:

<?php
var_dump("abc"== 0);
var_dump("1"== 1);
var_dump("1abc"== 1);
var_dump("abc1"== 0);
var_dump("1a2b3c"== 1);
?>

1.2十六进制转换的弱类型

0x开头代表该值是16进制数,PHP在遇到16进制字符串的时候,会先将其转换成十进制再进行运算,我们直接用0x29a(666)看实例:

<?php
var_dump("0x29a"== "666");
var_dump("0x29a"== 666);
var_dump("0x29a"== 0);
var_dump("0x29a"== "29a");
var_dump("0x29a"== "0x29a");
?>

1.3hash比较的弱类型

hash是一种编码转换算法,有些字符串经hash转化后会存在以0e开头的值,这个在php中会被当成科学计数法。所以只要两个字符串经hash转换后的值都是0e开头的话,这两者比较就为true。

常用hash算法有md5和sha1两种,我们寻找一些特殊的字符串,用这两个算法进行举例说明:

<?php
$a = md5("240610708");
$b = md5("QNKCDZO");
echo $a."<br>".$b."<br>";
var_dump($a == $b);
echo "<br>";
$x = sha1("aaroZmOk");
$y = sha1("aaK1STfY");
echo $x."<br>".$y."<br>";
var_dump($x == $y);
echo "<br>";
var_dump($a==$x&&$b==$y);
?>


这里要注意的是,要让php将0e开头的识别为科学记数法,0e的后面必须全是数字。

<?php
var_dump("0e12345678" == "0e9876543210123456789");
var_dump("0e123abc" == "0e123456789");
var_dump("0e123abc" == 0);
?>

1.4小数点精度的弱类型

PHP在特定精度的情况下,也会出现弱类型的问题。

<?php
var_dump("0.9999999999999999" == 1); //小数点后16位;
var_dump("0.99999999999999999" == 1);//小数点后16位以上;
?>

1.5PHP内置函数参数的弱类型

内置函数的弱类型指的就是传递给函数的变量不是函数语法规定的数据类型,这时候就会引发漏洞。

1.md5()

PHP手册中的md5()函数的描述是string md5 ( string $str [, bool $raw_output = false ] ),md5()中的需要是一个string类型的参数。但是当你传递一个array时,md5()不会报错,只是会无法正确地求出array的md5值,这样就会导致任意2个array的md5值都会相等。

<?php
$array1 = array("abc" => "xyz","xyz" => "abc");
$array2 = array("abc", "xyz", "chengdu", "gxa");
var_dump(md5($array1) == md5($array2));
var_dump(md5($array1) == var_dump($array2));
var_dump(md5($array1) == $array2);
?>


2.strcmp()
strcmp()函数在PHP官方手册中的描述是int strcmp ( string $str1 , string $str2 ),需要给strcmp()传递2个string类型的参数。如果str1小于str2,返回-1,相等返回0,否则返回1。strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算,然后根据运算结果来决定返回值。

如果传入给出strcmp()的参数是数组呢?

<?php
$a=array('1','2','3');
var_dump(strcmp($a,'123'));
?>


返回为null,相当于返回false。所以一般遇到这种问题可以构造数组形式绕过,比如pass[]=xxx。

3.switch()

如果switch在进行case是数字类型的判断时,switch会将其中的参数转换为int类型。

<?php
$i = $_GET['a'];
switch ($i) {
case 0:
echo "this is 0";
break;
case 1:
echo "this is 1";
break;
case 2:
echo "this is 2";
break;}
?>


4.in_array()

在PHP手册中,in_array()函数的解释是bool in_array ( mixed $needle , array $haystack [, bool strict=FALSE]),如果strict参数没有提供,那么inarray就会使用松散比较来判断strict = FALSE ] ),如果strict参数没有提供,那么in_array就会使用松散比较来判断strict=FALSE]),如果strict参数没有提供,那么ina​rray就会使用松散比较来判断needle是否在$haystack中。当strince的值为true时,in_array()会比较needls的类型和haystack中的类型是否相同。

<?php
$array=array(0,1,2,'3');
var_dump(in_array('abc', $array));
var_dump(in_array('1bc', $array));
var_dump(in_array('3cd', $array));
?>


可以看到上面的情况返回的都是true,因为’abc’会转换为0,’1bc’转换为1。’3cd’转换为3,但是在数组里面没有数字3,只有字符串3,所以返回false。

5.array_search()

原理同上in_array(),官方手册说:mixed array_search( mixed $needle , array $haystack [, bool $strict = false ] ),大海捞针,在大海(haystack)中搜索针(needle 参数)。第三个参数可选,默认为false。

<?php
$array=array(0,1,"2");
var_dump(array_search("abc",$array));
var_dump(array_search("1abc",$array));
var_dump(array_search("2abc",$array));
?>

  • 点赞
  • 收藏
  • 分享
  • 文章举报
熊猫在路上 发布了10 篇原创文章 · 获赞 1 · 访问量 326 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: