PHP XOR operation two numbers - php

I am trying to xor two values which are like below:
Variable 1 : 6463334891
Variable 2 : 1000212390
When i did xor with these values in php it gives me wrong answer.
It should give me "7426059853"
This is my code
$numericValue = (int)$numericValue;
$privateKey = (int)$privateKey;
echo "Type of variable 1 ".gettype($numericValue)."<br />";
echo "Type of variable 2 ".gettype($privateKey)."<br />";
$xor_val = (int)$numericValue ^ (int)$privateKey;
echo "XOR Value :".$xor_val."<br />";

Just a total stab into the dark...
You're doing this:
echo "6463334891" ^ "1000212390";
When you want to be doing this:
echo 6463334891 ^ 1000212390;
XOR is an operation on bytes. The byte representation of the integer 6463334891 and the string "6463334891" are very different. Hence this operation will result in very different values depending on whether the operands are strings or integers. If you get your numbers in string form, cast them to an int first:
echo (int)$var1 ^ (int)$var2;

That is because you re hitting the MAXIMUM INTEGER LIMIT which is 2147483647
From the PHP Docs...
The maximum value depends on the system. 32 bit systems have a maximum
signed integer range of -2147483648 to 2147483647. So for example on
such a system, intval('1000000000000') will return 2147483647. The
maximum signed integer value for 64 bit systems is
9223372036854775807.
Thus to handle such big integers you need to make use of an extension like (GMP) GNU Multiple Precision
<?php
$v1="6463334891";
$v2="1000212390";
$a = gmp_init($v1);
$b = gmp_init($v2);
echo gmp_intval($a) ^ gmp_intval($b); //"prints" 7426059853
Else , Switch to a 64-bit system.

my solution to maintain the value of big integers is to convert them to binary (with base_convert cause decbin doesnt work) and then make the xor for every bit, to finally convert the string to decimal.
function binxor($w1,$w2)
{
$x=base_convert($w1, 10, 2);
$y=base_convert($w2, 10, 2);
// adjust so both have same lenght
if (strlen($y)<strlen($x)) $y=str_repeat(0,strlen($x)-strlen($y)).$y;
if (strlen($x)<strlen($y)) $x=str_repeat(0,strlen($y)-strlen($x)).$x;
$x=str_split($x);$y=str_split($y);
$z="";
for ($k=0;$k<sizeof($x);$k++)
{
// xor bit a bit
$z.=(int)($x[$k])^(int)($y[$k]);
}
return base_convert($z,2,10);
}
Also, to adjust large numbers to 32 bits
bindec(decbin($number))
because decbin cuts the number to 32 automatically.

Related

Why PHP round my number when I use json_encode?

I need execute json_encode() and convert my original number from:
50610101800060384093800100001010000000056199999999
to
"50610101800060384093800100001010000000056199999999"
But it return
5.061010180006E+49
I tried this:
ini_set('precision', 30); //With 1, 30, 50, 100, 1000
ini_set('serialize_precision', -1);
'content' => json_encode($params, JSON_NUMERIC_CHECK)
but doesn't work. Can you help me?
50610101800060384093800100001010000000056199999999 exceeds the value of the maximum integer in PHP and so it is promoted to a float and expressed in scientific notation. The float result may be problematic for various reasons as the Manual explains in warning about floating point precision.
If you wish to express the value as if it were an integer you must encapsulate it in a string. That string you may add zero to it but when you do so the result in scientific notation will refer to a float, as follows:
<?php
$s = "50610101800060384093800100001010000000056199999999";
echo $s,"\n";
$x = $s + 0;
echo $x, "\n",is_float($x);
See here.
For more info in re PHP and floats, see here.
On the other hand, if there were an array of numbers whose digits corresponded to the numerical display in the OP's post, you could write code as follows:
<?php
$a = [5,0,6,1,0,1,0,1,8,0,0,0,6,0,3,8,4,0,9,3,8,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,5,6,1,9,9,9,9,9,9,9,9];
foreach($a as $e) {
$e = (string) $e;
}
$foo = join($a);
var_dump($foo);
$foo = bcadd($foo, 1);
var_dump($foo);
See live code.
The reason this example works is because each array value is converted to a numerical string and then the individual elements are joined to form one very long numerical string. BC Math is an extension in PHP which supports arbitrary precision. In this case, the bcadd() function adds one to the numerical string which results in the display of an incremented numerical string value.
Try This [https://3v4l.org/biNJG][1]
If you want this output "50610101800060384093800100001010000000056199999999"
you may want to pass this Value as string after encoding the value to JSON using json_encode
An integer data type is a non-decimal number between -2,147,483,648 and 2,147,483,647.
Rules for integers:
An integer must have at least one digit
An integer must not have a decimal point
An integer can be either positive or negative
Integers can be specified in three formats: decimal (10-based), hexadecimal (16-based - prefixed with 0x) or octal (8-based - prefixed with 0)

Convert IEEE754 to hex in PHP

For a project I need to read in information from MQTT. The payload is filled with protobuf information, that needs to be converted.
For a certain value I receive 5.6904566139035E-28 as float. Using http://www.exploringbinary.com/floating-point-converter/ I can convert this when I tick single and raw hexadecimal value, then I receive 12345678, the value I should have (I know what is sent).
But now I need to do that conversion in PHP. I haven't any idea how this could be done. After some reading I figured out it is a Floating Point, but how to convert this like done on that website.
Is there someone that can help me with this!
Thanks a lot!
With the quite cryptic pack and unpack functions, it can be done in a one-liner:
function rawSingleHex($num) {
return strrev(unpack('h*', pack('f', $num))[1]);
}
This "packs" the number as its binary representation, then "unpacks" it in an array with one element: the binary representation in hexadecimal format. This format has the digits in the reversed order, so the function reverses that in the final result.
Call it by passing the floating point number:
echo rawSingleHex(5.6904566139035E-28);
Output:
12345678
Without pack/pack
(this was my original answer, but with the first option being available, this is not the advised way to proceed)
The binary format is explained in Wikipedia's article on the Single-precision floating-point format.
Here is a PHP function that implements the described procedure:
function rawSingleHex($num) {
if ($num == 0) return '00000000';
// set sign bit, and add another, higher one, which will be stripped later
$sign = $num < 0 ? 0x300 : 0x200;
$significant = abs($num);
$exponent = floor(log($significant, 2));
// get 24 most significant binary bits before the comma:
$significant = round($significant / pow(2, $exponent-23));
// exponent has exponent-bias format:
$exponent += 127;
// format: 1 sign bit + 8 exponent bits + 23 significant bits,
// without left-most "1" of significant
$bin = substr(decbin($sign + $exponent), 1) .
substr(decbin($significant), 1);
// assert that result has correct number of bits:
if (strlen($bin) !== 32) {
return "unexpected error";
}
// convert binary representation to hex, with exactly 8 digits
return str_pad(dechex(bindec($bin)), 8, "0", STR_PAD_LEFT);
}
It outputs the same as in the first solution.

rand(0,$var) returns zero when $var is really big

When I run the code below:
<?
echo rand(0, 0xfffffffffffffbff);
echo rand(0, 0xfffffffffffffc00);
echo rand(0, $something_bigger_than_0xfffffffffffffbff);
I got something like:
-828
0
0
(the 2nd and 3rd number will always be zero)
mt_rand() has the same behavior.
so, why zero?
rand() function takes two integers as its arguments. Integers usually have the maximum range of 2^32. The supplied argument, when converted to integers, will be larger than this, hence causing an integer overflow.
This is actually documented behavior. From the PHP manual documentation:
When converting from float to integer, the number will be rounded
towards zero.
If the float is beyond the boundaries of integer (usually +/- 2.15e+9
= 2^31 on 32-bit platforms and +/- 9.22e+18 = 2^63 on 64-bit platforms), the result is undefined, since the float doesn't have
enough precision to give an exact integer result. No warning, not even
a notice will be issued when this happens!
You need to pass integer value to the rand() as the above $a = 0xfffffffffffffbff; is a double but not an integer value, the double value 0xfffffffffffffbff will be cast to an integer and eventually you will be getting a zero.
An illustration for your understanding.
<?php
$a = 0xfffffffffffffbff;
echo gettype($a); //"prints" double
if(is_int($a))
{
echo "Yes";
}
else
{
echo "Nope.. casting that to int results in..".intval($a)."<br>";
}
echo rand(0, $a);
OUTPUT :
double
Nope.. casting that to int results in..0
0

How do I truncate a decimal in PHP?

I know of the PHP function floor() but that doesn't work how I want it to in negative numbers.
This is how floor works
floor( 1234.567); // 1234
floor(-1234.567); // -1235
This is what I WANT
truncate( 1234.567); // 1234
truncate(-1234.567); // -1234
Is there a PHP function that will return -1234?
I know I could do this but I'm hoping for a single built-in function
$num = -1234.567;
echo $num >= 0 ? floor($num) : ceil($num);
Yes intval
intval(1234.567);
intval(-1234.567);
Truncate floats with specific precision:
echo bcdiv(2.56789, 1, 1); // 2.5
echo bcdiv(2.56789, 1, 3); // 2.567
echo bcdiv(-2.56789, 1, 1); // -2.5
echo bcdiv(-2.56789, 1, 3); // -2.567
This method solve the problem with round() function.
Also you can use typecasting (no need to use functions),
(int) 1234.567; // 1234
(int) -1234.567; // -1234
http://php.net/manual/en/language.types.type-juggling.php
You can see the difference between intval and (int) typecasting from here.
another hack is using prefix ~~ :
echo ~~1234.567; // 1234
echo ~~-1234.567; // 1234
it's simpler and faster
Tilde ~ is bitwise NOT operator in PHP and Javascript
Double tilde(~) is a quick way to cast variable as integer, where it is called 'two tildes' to indicate a form of double negation.
It removes everything after the decimal point because the bitwise operators implicitly convert their operands to signed 32-bit integers. This works whether the operands are (floating-point) numbers or strings, and the result is a number
reference:
https://en.wikipedia.org/wiki/Double_tilde
What does ~~ ("double tilde") do in Javascript?
you can use intval(number); but if your number bigger than 2147483648 (and your machine/os is x64) all bigs will be truncated to 2147483648. So you can use
if($number < 0 )
$res = round($number);
else
$res = floor($number);
echo $res;
You can shift the decimal to the desired place, intval, and shift back:
function truncate($number, $precision = 0) {
// warning: precision is limited by the size of the int type
$shift = pow(10, $precision);
return intval($number * $shift)/$shift;
}
Note the warning about size of int -- this is because $number is potentially being multiplied by a large number ($shift) which could make the resulting number too large to be stored as an integer type. Possibly converting to floating point might be better.
You could get fancy with a $base parameter, and sending that to intval(...).
Could (should) also get fancy with error/bounds checking.
An alternative approach would be to treat number as a string, find the decimal point and do a substring at the appropriate place after the decimal based on the desired precision. Relatively speaking, that won't be fast.

PHP: Signed Binary Strings

I'm having a problem with converting binary strings to signed integers
If you call decbin('-40'), php will output 1111111111111111111111111111111111111111111111111111111111011000
But if you call bindec(decbin('-40')), it will output 1.84467440737E+19 (or something similar, which is obviously not -40) because it "sees the most significant bit as another order of magnitude rather than as the sign bit" - php manual
Is there a way to convert a binary 64 bit binary string (much like the one output by decbin) string into a signed integer?
From the documentation, you cannot use bindec
bindec() interprets all binary_string values as unsigned integers. This is because bindec() sees the most significant bit as another order of magnitude rather than as the sign bit.
base_convert appears to ignore signing altogether.
If you know that your incoming string will always be 64 bit binary and you are not on a 32 bit system, it's quite easy to write a custom function.
Check if the string is 64 characters long.
Check if the most significant bit is a 1.
Flip all bits
Add 1
Negate
Here's a quick one I knocked together.
function bindec2($bin)
{
if (strlen($bin) == 64 && $bin[0] == '1') {
for ($i = 0; $i < 64; $i++) {
$bin[$i] = $bin[$i] == '1' ? '0' : '1';
}
return (bindec($bin) + 1) * -1;
}
return bindec($bin);
}
Use pack and unpack to convert between int and binary string.
// 'i' means signed integer
var_dump(unpack('i', pack('i', '-40'))); // gives you -40

Categories