1

I am using phpBB as a forum platform. I'm using a Mutualised Linux server with PHP Version 5.6.31 and MySQL(i) 5.7.19-log.

And I've found a bug that doesn't happen on others servers, since some phpbb team members as some friend of mine couldnt reproduce the problem. But there is more people with the same problem.

For people that want to check by themselves: Basically with a fresh install of phpBB 3.2.1, we can go to ACP - Forums - Your first category - Your first forum. There we confirmed that the option "Enable quick reply" is marked as "No" Then we go to ACP - Posting - Messages - Post Settings and click on "Submit and enable quick reply in all forums". After that we go again to the "your first forum" to check the "Enable quick reply" and its still as "No". And it should be "Yes".

I've try to DEBUG and on the .php file that have the function that will create the SQL query that will be sent to database, I've put: print(1 << 6); and it gives me 64. So I've put too: print($bit); and it gives me 6. So the code (1 << $bit) that is on the php should be correct, and should give me 64 BUT if I put: print(1 << $bit); it gives me 32!

I've put the 3 prints:

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

And the result was: 64 6 32

Wtf?! Why the hell when we've an variable with 6 as value, it assumes as 5?!, or it assumes as the 6th position the representation of a byte?

Anyone have any idea why this is happening? Maybe PHP versin bug? Or can any type of configuration mess with this?

Let me explain better.

In /includes/constants.php we can find: define('FORUM_FLAG_QUICK_REPLY', 64); That value will be use to create the $bit value.

And on /includes/acp/acp_board.php we've a function that will create the $bit variable:

$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));
}

This _enable_bitfield_column_flag_ function is what will create the sql code. And the log(FORUM_FLAG_QUICK_REPLY, 2) = Log2(64) = 6. So that's why the $bit is 6.

And in includes/functions_admin.php we've:

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);
}

We can see here the sql code being created by php code. And finally on /phpbb/db/driver/driver.php we've:

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

And before that line I've put the 3 prints, and the values were 64 6 32... and it doesnt make sense, why print $bit gives 6 and 1 << $bit gives 32...

Thanks in advance!

11
  • 2
    you're not saying where $bit comes from, but I suspect it is the result of some calculation which is not an integer but a float (5.999999999999 or something) which, although round()able to 6, might be agressively converted to 5. 3v4l.org/oAOlS Commented Sep 16, 2017 at 14:51
  • 2
    The explanation provided by @Calimero sounds right. Even more, I can prove it is right: 3v4l.org/AvU0D. Calimero, develop it to an answer. Commented Sep 16, 2017 at 15:05
  • Let me explain better. In /includes/constants.php we can find: define('FORUM_FLAG_QUICK_REPLY', 64); That value will be use to create the $bit value. And on /includes/acp/acp_board.php we've a function that will create the $bit variable: $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)); } Commented Sep 16, 2017 at 15:12
  • This enable_bitfield_column_flag function is what will create the sql code. And the log(FORUM_FLAG_QUICK_REPLY, 2) = Log2(64) = 6. So that's why the $bit is 6. And in includes/functions_admin.php we've: 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); } Commented Sep 16, 2017 at 15:13
  • We can see here the sql code being created by php code. And finally on /phpbb/db/driver/driver.php we've: return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); and before that line I've put the 3 prints, and the values were 64 6 32... and it doesnt make sense, why print $bit gives 6 and 1 << $bit gives 32... Commented Sep 16, 2017 at 15:13

1 Answer 1

1

Based on our exchanges in comment, and assuming $bit is indeed log2(64), I ran some tests and proved my initial idea :

$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

demo here : https://3v4l.org/Zogme

In this demo, all php versions tested appear to cast the result to 6 when converting to integer type (as it is the case with bitwise shifting operators such as <<, which works with integer arguments), but that's not guaranteed.

Float/double values are not really safe to work with, better round() it explicitly to a proper integer just to be sure and avoid the bug you are seeing.

$bit = round($bit);

Kudos goes to @axiac for fact-checking and pushing me to write this as an answer. Let me know if I can improve it further.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I've edited the log code: enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', round(log(FORUM_FLAG_QUICK_REPLY, 2))); adding the round(). And it worked! ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.