array_search() 是 PHP 中非常基础且常用的一个数组处理函数。但在 Web 安全(尤其是代码审计和 CTF)中,它因为默认的弱类型比较机制,经常成为漏洞的突破口。
1. 函数基本定义
array_search() 的作用是在数组中搜索给定的值,如果找到则返回首个匹配的键名 (Key) ,如果没找到则返回 false。
官方语法签名:
php
array_search(mixed $needle, array $haystack, bool $strict = false): int|string|false
它接收三个参数(前两个必填,第三个选填):
$needle(搜索的值): 你想要在数组中查找的目标值。$haystack(被搜索的数组): 你要在哪个数组里面找。$strict(严格模式):这是最关键的安全考点!- 默认值是
false:此时函数使用松散比较 (==)。也就是说,它只比较值,不比较数据类型。 - 如果设置为
true:此时函数使用严格比较 (===)。它不仅要求值相等,还要求数据类型完全一致。
- 默认值是
在 PHP 中,数组的"键"(key)既可以是整数(索引),也可以是字符串 。也就是说,索引数组的下标(0、1、2...)本身就是键。PHP 手册里统一称它们为"键"(key),而不是分开叫"索引"和"键名"。
php
// 索引数组 ------ 键是整数
$arr1 = ['苹果', '香蕉', '橙子'];
$key = array_search('香蕉', $arr1);
echo $key; // 输出 1(整数键,也就是我们常说的下标)
// 关联数组 ------ 键是字符串
$arr2 = ['a' => '苹果', 'b' => '香蕉', 'c' => '橙子'];
$key = array_search('香蕉', $arr2);
echo $key; // 输出 'b'(字符串键)
// 混合数组
$arr3 = [10, 'name' => 'Tom', 20];
$key = array_search('Tom', $arr3);
echo $key; // 输出 'name'
再看看array_search的其它用法:
php
//重复值-只返回第一个匹配键
$arr = [1,2,3,2];
$key = array_search(2,$arr); //返回 1(索引1)
//严格比较模式(strict=true)
$arr = [1,'1',2];
$key1 = array_search(1,$arr); //返回 0(索引0)
$key2 = array_search(1,$arr,true); //返回 0(索引0)
$key3 = array_search('1',$arr,true); //返回 1(索引1)
//搜索失败返回false
$arr = ['a', 'b', 'c'];
$key = array_search('d', $arr); // false
//警惕返回0导致的逻辑错误
$arr = ['apple', 'banana'];
$index = array_search('apple', $arr); // 0
if (!$index) { // 错误:0 被当作 false
echo "未找到"; // 错误地输出"未找到"
}
// 正确写法:
if ($index === false) {
echo "未找到";
}
扩展技巧
获取所有匹配值的键
如果数组中有重复值,而你想得到所有匹配的键,请使用:
php
$arr = ['a','b','a','c'];
$needle = 'a';
$keys = array_keys($arr, $needle, true); // [0,2]
PHP 8.0 弱类型大改版(影响 CTF 和老系统审计)
这是近几年代码审计中最重大的变化。在 PHP 8.0 之前和之后,array_search() 在松散模式下的表现有着天壤之别。
- PHP 7.x 及更早版本(经典的数字与字符串比较坑): 在老版本 PHP 中,当数字与非数字字符串进行
==比较时,PHP 会把字符串强制转换为数字0。
php
// 在 PHP 7.4 中
$arr = ['apple', 'banana'];
$key = array_search(0, $arr); // 返回 0 !!
// 因为 0 == 'apple' 变成了 0 == 0,结果为 true
- 你要搜索的值是整数
0。 - 数组中的元素是字符串
'apple'和'banana'。 - 在松散比较下,字符串与整数比较时,PHP 会尝试将字符串转换为数字。
'apple'转换为数字的结果是0(非数字开头字符串转数字得0),'banana'同理。 - 所以
0 == 'apple'成立,array_search()返回第一个匹配的键,即0。
PHP 8.0 及之后版本: PHP 官方终于修正了这个"反人类"的机制。现在,数字和非数字字符串比较时,会先把数字转成字符串。因此 0 == 'apple' 变成了 '0' == 'apple',结果为 false。