【问题标题】:PHP string '==' returns false on same stringsPHP 字符串 '==' 在相同的字符串上返回 false
【发布时间】:2015-07-31 16:52:51
【问题描述】:

我有检查用户 cookie 的代码:

echo 'prev: ' . $prevCookie;
echo 'curr: ' . $currentCookie;
if ((string) $prevCookie == (string)$currentCookie) {
  echo 'same cookies';
} else {
  echo 'different cookies';
}

在大约 0.1% 的情况下,我得到以下关注:

// prev: xxx
// curr: xxx
// different cookies

这些事情是怎么发生的?

PS。字符串被修剪,没有多余的空格。

更新

我可以为您提供存储在 db 中的真实值,但它们是相同的: (直接),(有机),YandexCPC 等。如果我能以某种方式复制它会很容易。

【问题讨论】:

  • echo strlen($prevCookie);echo strlen($currentCookie); 产生相同的结果吗?
  • 执行var_dump($prevCookie)var_dump($currentCookie) 并将结果发布到您的问题中
  • 0.1% 的时间字符串不相同。
  • @jww 使用 MD5 可能另一个 cookie 值生成相同的哈希值!
  • @survex 看起来似乎相等的两个字符串有一些不可见的不同之处,它可能是前导或后缀空格,或者任何地方的\0。有些符号可能不会打印或打印时不会被注意到,这将导致两个字符串在逻辑上不同但看起来相同。

标签: php cookies


【解决方案1】:

有时在调试时 ide 会显示相同的值,但例如,如果您在函数内比较全局值并且您没有声明结果将不会是相同的示例

不工作

function compare($p){
  return $p == $z;
}

会工作

function compare($p){
global $z;
return $p == $z;
}

【讨论】:

    【解决方案2】:

    我的猜测是你的字符串有一些不可见的字符。

    考虑以下几点:

    $a = "abc";
    $b = "abc\0";
    echo (int)( $a == $b );
    

    这将回显0

    但是,如果您回显$a$b,您将看到 "abc"


    另一种可能性可能是您正在使用 fopen() 而不使用 b 选项来读取/写入文件。

    Windows 具有将\r\n 转换为\r\n 的功能。

    当您回读时,它带有 Windows 的行尾。

    比较时,值不同,因为\r(在内存/cookie 中)与\r\n(从文件中读取)不同。

    当您将其输出到浏览器时,它会显示为abc。浏览器会忽略输出中的空格(可通过 CSS 更改)。


    另一件事可能是隐式数字转换。

    考虑以下代码:

    echo '1000000000000000000000000000000000000000000000000' == '1.0E+48';
    

    这将回显1。在这里查看:http://sandbox.onlinephpfunctions.com/code/1debf1a505793e3d0fde3b174c26e1f1454ea1e2

    使用=== 可以解决这个问题。

    可能会发生类似的事情。但这显示了相反的情况(比较不相等的 2 个不同的字符串,返回 true)。


    来源和环境本身是未知的。

    这些值是如何获得的也是未知的。

    未知数太多了……

    【讨论】:

    • 我觉得差不多了!现在我已经重现了这个错误,明天我将部署更改。您认为逃避此类问题的最佳方法是什么?
    • @survex 在比较之前使用trim() 过滤cookie。此函数从字符串的开头和结尾删除最常见的不可见符号。
    • @survex 有很多未知数。我不知道之前存储的$prevCookie 在哪里。我不知道$currentCookie 里面有什么。但最好是trim() 并使用str_replace("\0",'',$cookie)。另外,请改用===
    • @IsmaelMiguel 在将两个变量显式转换为(string) 时无需强制进行类型比较。
    • @Havenard sandbox.onlinephpfunctions.com/code/… --> 这证明你错了。尝试运行这个:echo '1000000000000000000000000000000000000000000000000' == '1.0E+48';(应该输出1)。
    【解决方案3】:

    使用strcmp(区分大小写)或strcasecmp(不区分大小写)。

    对于字符串比较,在大多数语言中,直接比较字符串并不是一个好的解决方案。

    echo 'prev: ' . $prevCookie;
    echo 'curr: ' . $currentCookie;
    if (strcmp($prevCookie,$currentCookie) === 0) {
      echo 'same cookies';
    } else {
      echo 'different cookies';
    }
    

    【讨论】:

    • 我看不出使用strcmp() 与使用== 相比会产生什么不同的行为。
    • 如果函数存在意味着等于==会检查变量是否相同,而不是相同的值。
    • 据我所知,比较它们没有错。要避免的是使用if ($string) 检查字符串是否为空,因为解释器会将其理解为if ((bool)$string),如果字符串不为空,但等于"0""0000",它将评估为false.
    • @Havenard 还有其他危险。尝试运行这个:echo '1000000000000000000000000000000000000000000000000' == '1.0E+48';(它会回显1,但它应该什么都不回显)。字符串'1000000000000000000000000000000000000000000000000' 将转换为整数1.0E+48,而字符串'1.0E+48' 将转换为相同的精确值。使用===strcmp() 可以解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多