PHP Conference Japan 2024

strcmp

(PHP 4, PHP 5, PHP 7, PHP 8)

strcmp二进制安全的字符串比较

描述

strcmp(字符串 $string1, 字符串 $string2): 整数

请注意,此比较区分大小写。

参数

string1

第一个字符串。

string2

第二个字符串。

返回值

如果 string1 小于 string2,则返回 -1;如果 string1 大于 string2,则返回 1;如果它们相等,则返回 0

变更日志

版本 描述
8.2.0 此函数现在返回 -11,而以前返回负数或正数。

示例

示例 #1 strcmp() 示例

<?php
$var1
= "Hello";
$var2 = "hello";
if (
strcmp($var1, $var2) !== 0) {
echo
'$var1 在区分大小写的字符串比较中不等于 $var2';
}
?>

参见

  • strcasecmp() - 二进制安全的区分大小写的字符串比较
  • preg_match() - 执行正则表达式匹配
  • substr_compare() - 从偏移量开始,最多比较 length 个字符的两个字符串的二进制安全比较
  • strncmp() - 前 n 个字符的二进制安全的字符串比较
  • strstr() - 查找字符串的第一次出现
  • substr() - 返回字符串的一部分

添加注释

用户贡献的注释 16 条注释

116
jendoj at gmail dot com
12 年前
如果您依赖 strcmp 进行安全的字符串比较,则两个参数都必须是字符串,否则结果将非常不可预测。
例如,您可能会得到意外的 0,或返回 NULL、-2、2、3 和 -3 的值。

strcmp("5", 5) => 0
strcmp("15", 0xf) => 0
strcmp(61529519452809720693702583126814, 61529519452809720000000000000000) => 0
strcmp(NULL, false) => 0
strcmp(NULL, "") => 0
strcmp(NULL, 0) => -1
strcmp(false, -1) => -2
strcmp("15", NULL) => 2
strcmp(NULL, "foo") => -3
strcmp("foo", NULL) => 3
strcmp("foo", false) => 3
strcmp("foo", 0) => 1
strcmp("foo", 5) => 1
strcmp("foo", array()) => NULL + PHP 警告
strcmp("foo", new stdClass) => NULL + PHP 警告
strcmp(function(){}, "") => NULL + PHP 警告
59
lehal2 at hotmail dot com
11 年前
我希望这能让你清楚地了解 strcmp 在内部是如何工作的。

<?php
$str1
= "b";
echo
ord($str1); //98
echo "<br/>";
$str2 = "t";
echo
ord($str2); //116
echo "<br/>";
echo
ord($str1)-ord($str2);//-18
$str1 = "bear";
$str2 = "tear";
$str3 = "";
echo
"<pre>";
echo
strcmp($str1, $str2); // -18
echo "<br/>";
echo
strcmp($str2, $str1); //18
echo "<br/>";
echo
strcmp($str2, $str2); //0
echo "<br/>";
echo
strcmp($str2, $str3); //4
echo "<br/>";
echo
strcmp($str3, $str2); //-4
echo "<br/>";
echo
strcmp($str3, $str3); // 0
echo "</pre>";
?>
33
Rob Wiesler
15 年前
一个重要的警告 - 从反引号操作检索的字符串可能以零结尾(C 样式),因此将不等于 PHP 中正常的非零结尾字符串(大致为 Pascal 样式)。解决方法是将每个 `` 对或 shell_exec() 函数用 trim() 函数括起来。其他调用 shell 的函数也可能出现此问题;我没有费心去检查。

在 Debian Lenny(以及 RHEL 5,差异很小)上,我得到了这个

====PHP====
<?php
$sz
= `pwd`;
$ps = "/var/www";

echo
"以零结尾的字符串:<br />sz = ".$sz."<br />str_split(sz) = "; print_r(str_split($sz));
echo
"<br /><br />";

echo
"Pascal风格的字符串:<br />ps = ".$ps."<br />str_split(ps) = "; print_r(str_split($ps));
echo
"<br /><br />";

echo
"正常的比较结果:<br />";
echo
"sz == ps = ".($sz == $ps ? "true" : "false")."<br />";
echo
"strcmp(sz,ps) = ".strcmp($sz,$ps);
echo
"<br /><br />";

echo
"使用trim()处理过的以零结尾字符串的比较结果:<br />";
echo
"trim(sz) = ".trim($sz)."<br />";
echo
"str_split(trim(sz)) = "; print_r(str_split(trim($sz))); echo "<br />";
echo
"trim(sz) == ps = ".(trim($sz) == $ps ? "true" : "false")."<br />";
echo
"strcmp(trim(sz),ps) = ".strcmp(trim($sz),$ps);
?>

====输出====
以零结尾的字符串
sz = /var/www
str_split(sz) = Array ( [0] => / [1] => v [2] => a [3] => r [4] => / [5] => w [6] => w [7] => w [8] => )

Pascal风格的字符串
ps = /var/www
str_split(ps) = Array ( [0] => / [1] => v [2] => a [3] => r [4] => / [5] => w [6] => w [7] => w )

正常的比较结果
sz == ps = false
strcmp(sz,ps) = 1

使用trim()处理过的以零结尾字符串的比较结果
trim(sz) = /var/www
str_split(trim(sz)) = Array ( [0] => / [1] => v [2] => a [3] => r [4] => / [5] => w [6] => w [7] => w )
trim(sz) == ps = true
strcmp(trim(sz),ps) = 0
4
kgun ! mail ! com
5年前
如果你希望始终获得-1、0或1的结果,就像JS的indexOf()一样。

<?php
function cmp(string $str1, string $str2): int {
return (
$str1 > $str2) - ($str1 < $str2);
}

$str1 = 'a';
$str2 = 'z';
var_dump(cmp($str1, $str2), strcmp($str1, $str2));

//=> int(-1) int(-25) int(-25)

$str1 = 'a';
$str2 = '1';
var_dump(cmp($str1, $str2), strcmp($str1, $str2));
//=> int(1) int(48) int(48)
?>
18
frewuill at merlin-corp dot com
24年前
确保你正在比较的字符串不包含特殊字符,比如'\n'或类似的字符。
7
luizvid at gmail dot com
9年前
如果两个字符串不相同,strcmp返回-1或1,
如果相同则返回0,除了比较一个字符串和一个空字符串(<?php $a = ""; ?>)时,它返回字符串的长度。

例如
<?php
$a
= "foo"; // 长度为3
$b = ""; // 空字符串
$c = "barbar"; // 长度为6

echo strcmp($a, $a); // 输出0
echo strcmp($a, $c); // 输出1
echo strcmp($c, $a); // 输出-1
echo strcmp($a, $b); // 输出3
echo strcmp($b, $a); // 输出-3
echo strcmp($c, $b); // 输出6
echo strcmp($b, $c); // 输出-6
?>
2
erik at eldata dot se
3年前
strcmp和strcasecmp在处理多字节(UTF8)字符串时效果不佳,并且没有mb_strcmp或mb_strcasecmp - 相反,请查看功能强大的Collator类及其compare方法(在上面搜索Collator)- 不仅支持UTF8,还支持不同的国家语言排序规则(排序顺序)。

自然排序也受支持,使用setAttribute将Collator::NUMERIC_COLLATION设置为Collator::ON。
8
hrodicus at gmail dot com
13年前
注意5.2和5.3版本的差异

echo (int)strcmp('pending',array());
在PHP 5.2.16(可能在5.3之前的所有版本中)中将输出-1
但在PHP 5.3.3中将输出0

当然,在字符串比较中,你永远不需要使用数组作为参数。
5
jcanals at totsoft dot com
20年前
关于西班牙语言环境的一些说明。我读到一些说明说“CH”、“RR”或“LL”在西班牙语中必须被视为单个字母。这并不完全正确。“CH”、“RR”和“LL”在过去(很多年前)被视为单个字母,为此你必须使用“传统排序”。如今,学院使用现代排序,并建议不再将“CH”、“RR”和“LL”视为单个字母。它们必须被视为两个独立的字母,并以此方式进行排序和比较。

你只需要查看西班牙官方语言词典,你就可以看到那里多年来没有“CH”、“LL”或“RR”的独立部分……例如,以CH开头的单词必须在以CG开头的单词之后,在以CI开头的单词之前。
8
chris at unix-ninja dot com
11 年前
由于有些人可能不清楚,请注意此函数还有另一个可能的返回值。

strcmp()在失败时将返回NULL。

这具有在使用等于比较(==)时等同于匹配的副作用。
相反,你可能希望使用相同比较(===)来测试匹配,这应该不会捕获NULL返回值。

---------------------
示例
---------------------

$variable1 = array();
$ans === strcmp($variable1, $variable2);

这将阻止$ans返回匹配;

在比较用户输入时请谨慎使用strcmp(),因为它可能对你的代码产生潜在的安全影响。
4
mikael1 at mail dot ru
5年前
1) 如果两个字符串具有相同的开头部分,则会从两个字符串中截断这些部分。
2) 比较结果字符串,可能有两种结果
a) 如果结果字符串之一为空字符串,则返回非空字符串的长度(符号取决于你传递给函数的参数顺序)
b) 在任何其他情况下,只比较第一个字符的数值。无论数值差异有多大,结果都是+1或-1。

<?php
$str
= array('','a','afox','foxa');
$size = count($str);

echo
'<pre>';
for(
$i=0; $i<$size; $i++)
{
for(
$j=$i+1; $j<$size; $j++)
{
echo
'<br>('.$str[$i].','.$str[$j].') = '.strcmp($str[$i], $str[$j]);
echo
'<br>('.$str[$j].','.$str[$i] .') = '.strcmp($str[$j], $str[$i]);
}
}
echo
'</pre>';
?>

在 Apache/2.4.37 (Win32) OpenSSL/1.1.1 PHP/7.2.12 中产生以下结果

(,a) = -1 //与空字符串比较会产生非空字符串的长度
(a,) = 1 // 同上
(,afox) = -4 // 同上
(afox,) = 4 // 同上
(,foxa) = -4 // 同上
(foxa,) = 4 // 同上
(a,afox) = -3 // 两个字符串中相同的开头部分(“a”)被截断。然后将剩余的“fox”与另一个参数中的剩余空字符串进行比较。产生非空字符串的长度。与以上所有示例相同。
(afox,a) = 3 // 同上
(a,foxa) = -1 // 没有要截断的内容。只需比较第一个字母的数值
(foxa,a) = 1 // 同上
(afox,foxa) = -1 // 同上
(foxa,afox) = 1 // 同上
3
匿名用户
22 年前
总之,strcmp() 不一定像在 'C' 语言环境中那样使用每个字符的 ASCII 代码顺序,而是解析每个字符串以匹配特定语言的字符实体(例如西班牙语中的 'ch' 或捷克语中的 'dz'),然后比较其排序顺序。当两个字符实体具有相同的排序顺序(例如德语中的 'ss' 和 '?')时,strcmp() 会根据其代码进行比较,或被 strcasecmp() 视为相等。
然后考虑 LC_COLLATE 语言环境设置:只有当 LC_COLLATE=C 或 LC_ALL=C 时,strcmp() 才会按字符代码比较字符串。
通常,大多数语言环境定义以下顺序
控制字符、空格、标点符号和下划线、数字、字母(拉丁字母中先小写后大写;或阿拉伯字母中先结尾、中间、然后是孤立的、开头的)、符号、其他……
使用 strcasecmp() 时,字母子类会被忽略,并将所有形式的字母视为相等。
还要注意,某些语言环境在处理带重音字符时表现不同:有些认为它们与无重音字符是相同的字母(具有较小的排序顺序,例如法语、意大利语、西班牙语),有些认为它们是具有独立排序顺序的不同字母(例如在 C 语言环境中或北欧语言中)。
最后,排序字符串不是考虑单个字符,而是考虑构成单个字母的字符组
- 例如,西班牙语中的“ch”或“CH”,它始终在所有以 'c' 或 'C' 开头的其他字符串之后,包括“cz”,但在 'd' 或 'D' 之前;
- 德语中的 'ss' 和 '?';
- 一些使用拉丁字母书写的中欧语言中的 'dz'、'DZ' 和 'Dz'……
- 语言环境的 UTF-8、UTF-16(Unicode)、S-JIS、Big5、ISO2022 字符编码(语言环境名称中的后缀)首先将字符解码为 UCS4/ISO10646 代码位置,然后应用由主要语言环境指示的语言规则……
因此,在考虑“字符”时要格外小心,因为它可能只表示一个在字符串排序算法中没有意义的编码字节:“cholera”这个西班牙语字符串的第一个字符是“ch”,而不是“c”!
1
[email protected]
15 年前
[email protected] 的注释做个简短的补充:md5() 是一个哈希函数,因此可能会发生(尽管不太可能)两个不同字符串的 md5() 校验和相等(哈希冲突)……
1
[email protected]
7 年前
漏洞(在 PHP >=5.3 中)

<?php
if (strcmp($_POST['password'], 'sekret') == 0) {
echo
"Welcome, authorized user!\n";
} else {
echo
"Go away, imposter.\n";
}
?>

$ curl -d password=sekret http://andersk.scripts.mit.edu/strcmp.php
欢迎,授权用户!

$ curl -d password=wrong http://andersk.scripts.mit.edu/strcmp.php
走开,冒牌货。

$ curl -d password[]=wrong http://andersk.scripts.mit.edu/strcmp.php
欢迎,授权用户!

此示例的来源:https://www.quora.com/Why-is-PHP-hated-by-so-many-developers
-4
[email protected]
18 年前
如果要根据语言环境排序字符串,请使用 strcoll。
To Top