【问题标题】:Shift Bit Operation on PHP with Wrong Values?使用错误值对 PHP 进行移位操作?
【发布时间】:2017-09-16 14:46:06
【问题描述】:

我正在使用 phpBB 作为论坛平台。我正在使用带有 PHP 版本 5.6.31 和 MySQL(i) 5.7.19-log 的 Mutualised Linux 服务器。

我发现了一个在其他服务器上不会发生的错误,因为一些 phpbb 团队成员作为我的一些朋友无法重现该问题。但是有更多人遇到同样的问题。

对于想要自己检查的人: 基本上用全新安装的 phpBB 3.2.1,我们可以去 ACP - 论坛 - 你的第一个类别 - 你的第一个论坛。 在那里,我们确认“启用快速回复”选项被标记为“否” 然后我们去 ACP - 发帖 - 消息 - 发帖设置并点击“提交并在所有论坛中启用快速回复”。 之后我们再次去“你的第一个论坛”检查“启用快速回复”,它仍然是“否”。 它应该是“是”。

我尝试调试并在具有创建将发送到数据库的 SQL 查询的函数的 .php 文件上,我放了: 打印(1

我已经打印了 3 张照片:

print(1 << 6);
print($bit);
print(1 << $bit);

结果是:64 6 32

靠?!为什么当我们有一个以 6 为值的变量时,它假定为 5?!,或者它假定为第 6 位表示一个字节?

有人知道为什么会这样吗?也许是 PHP 版本错误?或者任何类型的配置都可以解决这个问题?

让我解释得更好。

/includes/constants.php 我们可以找到: define('FORUM_FLAG_QUICK_REPLY', 64); 该值将用于创建 $bit 值。

/includes/acp/acp_board.php 我们有一个函数可以创建 $bit 变量:

$config->set($config_name, $config_value);
if ($config_name == 'allow_quick_reply' && isset($_POST['allow_quick_reply_enable']))
{
    enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', log(FORUM_FLAG_QUICK_REPLY, 2));
}

这个 _enable_bitfield_column_flag_ 函数将创建 sql 代码。 并且日志(FORUM_FLAG_QUICK_REPLY,2)= Log2(64)= 6。 所以这就是 $bit 是 6 的原因。

includes/functions_admin.php 中,我们有:

function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '')
{
    global $db;
    $sql = 'UPDATE ' . $table_name . '
        SET ' . $column_name . ' = ' . $db->sql_bit_or($column_name, $flag) . '
        ' . $sql_more;
    $db->sql_query($sql);
}

我们可以在这里看到由 php 代码创建的 sql 代码。 最后在 /phpbb/db/driver/driver.php 我们已经:

return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');

在那一行之前,我已经打印了 3 个,值是 64 6 32... 这没有意义,为什么 print $bit 给出 6 和 1

提前致谢!

【问题讨论】:

  • 你不是说 $bit 来自哪里,但我怀疑它是一些计算的结果,它不是整数而是浮点数(5.999999999999 或其他东西),虽然 round() 能够6,可能会主动转换为 5。3v4l.org/oAOlS
  • @Calimero 提供的解释听起来不错。更重要的是,我可以证明它是正确的:3v4l.org/AvU0D。 Calimero,把它发展成一个答案。
  • 让我解释得更好。在 /includes/constants.php 我们可以找到:define('FORUM_FLAG_QUICK_REPLY', 64); 该值将用于创建 $bit 值。在 /includes/acp/acp_board.php 我们有一个函数将创建 $bit 变量:$config-&gt;set($config_name, $config_value); if ($config_name == 'allow_quick_reply' &amp;&amp; isset($_POST['allow_quick_reply_enable'])) { enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', log(FORUM_FLAG_QUICK_REPLY, 2)); }
  • 这个 enable_bitfield_column_flag 函数将创建 sql 代码。而 log(FORUM_FLAG_QUICK_REPLY, 2) = Log2(64) = 6。这就是 $bit 为 6 的原因。在 includes/functions_admin.php 中,我们有: function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '') { global $db; $sql = 'UPDATE ' . $table_name . ' SET ' . $column_name . ' = ' . $db-&gt;sql_bit_or($column_name, $flag) . ' ' . $sql_more; $db-&gt;sql_query($sql); }
  • 我们可以在这里看到由php代码创建的sql代码。最后在 /phpbb/db/driver/driver.php 我们有:return $column_name . ' | ' . (1 &lt;&lt; $bit) . (($compare) ? ' ' . $compare : ''); 在该行之前我放了 3 个打印件,值为 64 6 32... 和这没有意义,为什么 print $bit 给出 6 和 1

标签: php mysqli bitwise-operators bit-shift phpbb3


【解决方案1】:

根据我们在评论中的交流,假设 $bit 确实是log2(64),我进行了一些测试并证明了我最初的想法:

$bit = log(64,2);
echo gettype(6)."\n"; //  integer
echo gettype($bit)."\n"; //  double
echo (int)$bit."\n"; // prints 6, but might as well have been 5
echo round($bit)."\n"; // prints 6

在这里演示:https://3v4l.org/Zogme

在这个演示中,所有测试的 php 版本在转换为整数类型时似乎都将结果转换为 6(就像&lt;&lt; 等按位移位运算符一样,它适用于整数参数),但这并不能保证.

使用浮点/双精度值并不是很安全,最好将它明确地舍入到一个适当的整数,以确保避免您看到的错误。

$bit = round($bit);

感谢@axiac 进行事实检查并推动我写下这个作为答案。让我知道我是否可以进一步改进它。

【讨论】:

  • 谢谢,我已经编辑了日志代码:enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', round(log(FORUM_FLAG_QUICK_REPLY, 2))); 添加了 round()。它奏效了! ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-10
  • 2010-10-24
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多