Shift Bit Operation on PHP with Wrong Values? - php

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!

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.

Related

PHP value comparison wrong despite correct typing [duplicate]

This question already has answers here:
Compare floats in php
(17 answers)
Closed 4 years ago.
This piece of code:
$total=$o->cart->getTotalSum();
$subTotal=$o->cart->getSubTotal();
if(floatval($r['sum_total']) != floatval($total) ||
floatval($r['sum_sub']) != floatval($subTotal)) {
echo 'Differs on #' . $r['id'];
echo 'Total: ' . $total . ' / ' . $r['sum_total'];
echo 'Sub: ' . $subTotal . ' / ' . $r['sum_sub'];
}
Gives me this output:
Differs on #697
Total: 19.6 / 19.6
Sub: 19.6 / 19.6
Why? How is that even possible?
I make sure that all values compared are of type float, so no strings could have slipped in.
I must be missing something.
My apologies for not providing really reproducible code, but i wouldn't know how in this case.
If you do it like this they should be the same. But note that a characteristic of floating-point values is that calculations which
seem to result in the same value do not need to actually be identical.
So if $a is a literal .17 and $b arrives there through a calculation
it can well be that they are different, albeit both display the same
value.
Usually you never compare floating-point values for equality like
this, you need to use a smallest acceptable difference:
if (abs(($a-$b)/$b) < 0.00001) { echo "same"; } Something like that.
I think someone else had the exact same problem.
https://stackoverflow.com/a/3148991/2725502

How does python converts mysql binary(16)

I have two apps one written in php and one in python and both of them use the same mysql database.
For the public id of the entries in some of the tables I use binary(16) fields(I can't change this, it must remain this way).
The question is how does python does the conversion of this binary field?
Let's take one of the entries as an example.
When I get it in php(from the db) the value of the public id is °•WiCÄ‘õ0Iò|–g, the same value is shown in SequelPro. But php myAdmin does a hex function over binary fields and shows 0bb09557691443c491f53049f27c9667. Now I managed in php to convert the binary to the value showed in php myAdmin and it works for all the entries but I've just noticed that python does another conversion. When I get the entry used in this example via python the public id is owwweye1rjnvt3i1d0ib18x3.
What I need to achieve is to convert in php what I get from MySql: °•WiCÄ‘õ0Iò|–g to what python sees: owwweye1rjnvt3i1d0ib18x3. The php app makes calls on the python one(not developed by me) and thus the id needs to be in the same format for a successfull call.
Any suggestions are welcomed. Thanks.
EDIT: If i send °•WiCÄ‘õ0Iò|–g from php to python and print it rigth away I get: °•WiCÄ‘õ0Iò|–g
Finally I've sorted this out.
Seems that python converts to base36 not hex as I've wrongly supposed.
I've tried to simply base_convert 0bb09557691443c491f53049f27c9667 from 16 to 36 but I've got owwweye1rk04k4cskkw4s08s. Not really what I needed but still a great step further as it started to look like owwweye1rjnvt3i1d0ib18x3.
This difference I supposed to appear because of the large values to be converted(loss of precision), so I've further researched and found the bellow function, written by Clifford dot ct at gmail dot com on the php.net website:
<?php
function str_baseconvert($str, $frombase=10, $tobase=36) {
$str = trim($str);
if (intval($frombase) != 10) {
$len = strlen($str);
$q = 0;
for ($i=0; $i<$len; $i++) {
$r = base_convert($str[$i], $frombase, 10);
$q = bcadd(bcmul($q, $frombase), $r);
}
}
else $q = $str;
if (intval($tobase) != 10) {
$s = '';
while (bccomp($q, '0', 0) > 0) {
$r = intval(bcmod($q, $tobase));
$s = base_convert($r, 10, $tobase) . $s;
$q = bcdiv($q, $tobase, 0);
}
}
else $s = $q;
return $s;
}
?>
I don't think others will come across this issue very often, but still if it happens hope they'll find this instead of burning their brains out like I did :))))

Workaround for suhosin.mt_srand.ignore to consistently shuffle an array in PHP?

I have a PHP script which needs to randomise an array with consistent results, so it can present the first few items to the user and they can then pull in more results from the same shuffled set if they want to.
What I'm currently using is this (based on the Fisher Yates algorithm I believe):
function shuffle(&$array, $seed)
{
mt_srand($seed);
for ($a=count($array)-1; $a>0; $a--) {
$b = mt_rand(0, $a);
$temp = $array[$a];
$array[$a] = $array[$b];
$array[$b] = $temp;
}
}
Which works fine on my local installation, but the server it needs to run on has Suhosin installed, which overrides mt_srand, meaning the seed is ignored, the array is just randomly shuffled and the user gets duplicate results.
Everything I've found on Google suggests I need to disable suhosin.mt_srand.ignore (and suhosin.srand.ignore, not sure if the latter is relevant though) so I put the following in .htaccess:
php_flag suhosin.mt_srand.ignore Off
php_flag suhosin.srand.ignore Off
I have no access to php.ini on this server so AFAIK that's the only way I can do it. The problem is that has no effect - phpinfo() still shows both settings as On, whereas I can change other Suhosin settings using .htaccess no problem.
So I suppose what I'm looking for is either a way to actually disable suhosin.mt_srand.ignore (or a reason why it isn't working), or a workaround to seed a random number generator from within PHP. Or will I just have to implement another RNG myself?
Any help would be much appreciated. Thanks!
Using some basic maths and a few tricks you can quite easily create your OWN random function like i have just done :)
Sorry i haven't cleaned it up. It would be much better in a class as you could prevent the need to keep re-seeding it with the previous seed. Don't use a static variable as it limits you to only using 1 seed at a time (or manually keeping track of the seeds yourself). OOP would solve that. Do what you like with the function below, but let me know if you rewrite it.
/**
* returns a decimal between 0 and max_number, requires seeding every time and will ALWAYS return the same decimal for the same seed
* #copyright scott thompson, all rights reserved
* #license MIT (do what you like with this)
* #param string $seed
* #param int $max_number=100 adjust the maximum number range
*/
function random_number($seed, $max_number = 100) {
//make sure there won't be any deadspace where random numbers will never fill
if ($max_number > 0xFFFFFF) {
trigger_error("Max random number was to high. Maximum number of " . 0xFFFFFF . " allowed. Defaulting to maximum number.", E_USER_WARNING);
$max_number = 0xFFFFFF;
}
//hash the seed to ensure enough random(ish) characters each time
$hash = sha1($seed);
//use the first x characters, and convert from hex to base 10 (this is where the random number is obtain)
$rand = base_convert(substr($hash, 0, 6), 16, 10);
//as a decimal percentage (ensures between 0 and max number)
return $rand / 0xFFFFFF * $max_number ;
}
$seed = 'hello';
print ($seed = random_number($seed)) . '<br />'; //66.779748605475
print ($seed = random_number($seed)) . '<br />'; //3.5753311857779
print ($seed = random_number($seed)) . '<br />'; //13.994396567011
print ($seed = random_number($seed)) . '<br />'; //70.344917198713
print ($seed = random_number($seed)) . '<br />'; //4.5583250855401
Hope this helps, scott

Obfuscating string values in PHP source code

I want to protect PHP source code at easy way.
here is a example.
$a = "\x46\122" . chr(578813952>>23) . "" . chr(0105) . "\x2d";
$b = "\x73" . chr(847249408>>23) . "" . chr(0162) . "\x69" . chr(0141) . "" . chr(905969664>>23) . "";
$c = "" . chr(0x53) . "" . chr(0105) . "\x52\x56" . chr(0105) . "\x52" . chr(796917760>>23) . "\x4e" . chr(545259520>>23) . "\x4d" . chr(0x45) . "";
it is.
$a="FREE-";
$b="serial";
$c="SERVER_NAME";
Please help me someone to convert this type of string ??
There is 3 type of encryption.
Type[1] : "\x46\122"
Type[2] : chr(0105)
Type[3] : chr(578813952>>23)
Please help me to create a convert function...from PHP string.
thank you !
------------------------ I update question-------------------
OK... I should change question..
I want to create a function.
function1.
$a = "FREE-";
echo function1($a);
---> output
"\x46\122" . chr(578813952>>23) . "" . chr(0105) . "\x2d";
in this function, Function use 3 type of logic at random.
here is 3 type.
Type[1] : "\x46\122"
Type[2] : chr(0105)
Type[3] : chr(578813952>>23)
Could you help me ....
This is a, frankly, stupid way of "protecting" your code. Hopefully you realize that once the code is delivered to the clients, they can simply undo all of this and extract the values themselves?
Use legal means to protect the code. "here's my code, you are not allowed to share it. If you do, I get $50 kazillion dollars and the Droit de Seigneur with your most beautiful daughter, or an extra 200 kazillion in lieue if they're all ugly".
An iron-clad licensing agreement will be far better protection than any cereal-box decoder-ring wet kleenex method you care to apply ever will be.
For further suggestions why this is a waste of your time:
Asked at 8:36, decoded at 8:44. Eight minutes of protection: https://stackoverflow.com/questions/5456462/what-does-this-php-code-do
Asked at 11:01, decoded at 11:17, and very-well analyzed at 11:47. Hacked, what does this piece of code do?
In the first case, I'm willing to bet the majority of the fastest poster's time was spent writing. So feel confident that however you try to obfuscate your code, it'll take only three or four minutes to undo whatever it is you've done.
How much time are you willing to put into obfuscating your code when it'll take someone only a few minutes to undo what you've done? Could that time have been better spent writing awesome features that your customers would love?
ord will get you a character's ASCII value, using that we can generate the 3 things you want.
Type 1: Use dechex to convert int to hex.
$chr = 's';
$hex = dechex(ord($chr)); // 73
Type 2: Use decoct to convert into to octal.
$chr = 'E';
$oct = decoct(ord($chr)); // 105
Type 3: Use the << (shift left) operator.
$chr = 'e';
$bin = ord($chr)<<23; // 847249408

PHP Advanced Currency Formatting

I was wondering if there is a simple method in PHP to format currency correctly for the following tasks:
If a value is: 4.37 then the output will be $4.37
If a value is: 4.00 then the output will be $4
If a value is: 4.3 or 4.30 then the output will be $4.30
If a value is 0.37 then the output will be 37¢
I'm sure this is quite complicated to do (I'm a beginner in PHP), but if anyone has any suggestions it would be greatly appreciated.
function format_currency($val) {
if ($val < 1) return intval(round($val * 100)) . '¢';
if (fmod($val, 1.0) == 0) return '$' . intval($val);
return '$' . intval($val) . '.' . intval(round((fmod($val,1))*100));
}
// Call it like this
$val = 1.2;
echo 'Your total: ' . format_currency($val);
Although this function will work, it's generally a bad idea to encode dollar amounts in a float.
I know this might be a bit of an overkill but take a look at Zend_Currency, it will take care of many different types of currency for this, it's also simple to use. Do note that you don't have to use the whole framework, just the currency class and the file it requires
http://framework.zend.com/manual/en/zend.currency.html

Categories