I was trying to do some sort of XOR binary crypting algorithm in PHP and so I needed to convert large strings into binary. The problem is that PHP seems to be very limited in terms of binary calculation / storage as a string of six letters only, once converted, exceeds the PHP INT limit.
That means unpacking a big string to binary just gives a unusable number. I tried to do the string unpacking by splitting the string into packs of 4 letters and then unpacking them, but then I've got troubles with the repacking where it gives random characters instead of the original ones.
How can I do the unpacking of very long strings, and then store them either in a string (made only of 0s and 1s) or in a big array (where each value is either a 0 or 1, the key indicating the location of this bit) ?
have you tried the GMP library? Man page GMP
quick test code:
<?php
$gmpValue1 = gmp_init("1562767628166296698262", 10); // note: using base 10 (decimal)
$gmpValue2 = gmp_init("2163623626362663286446", 10);
$gmpValue3 = gmp_xor($gmpValue1, $gmpValue2);
echo gmp_strval($gmpValue3, 10) . "\n"; // note: using base 10 (decimal)
Related
I want to convert byte array to UINT64 using PHP.
I can do this easily in C# but I want to do this in PHP.
Here is C# code.
bytes = Encoding.UTF8.GetBytes(hashed);
BitConverter.ToUInt64(bytes, 0);
I want to convert this to PHP.
I tried to use pack() function but this does not works.
Let's say this is a byte array.
$bytes = [101,102,54,55,99,55,56,49];
pack("J*","101","102","54","55","99","55","56","49");
This shows a warning.
epack(): 7 arguments unused on line
How can I fix this?
The major issue here (if I understand it correctly) is you're using PHP numbers to represent a byte array however unpack requires an input string. If you keep the array as is then PHP seems to just convert the numbers to strings meaning a 101 will be '101' which in turn is 3 bytes, which breaks the whole thing down.
You need to first convert the numbers to bytes. A byte is essentially as an unsigned char so you could first pack your array into unsigned chars and then unpack them:
$bytes = [101,102,54,55,99,55,56,49];
$unpacked = unpack("J", pack('C*', ...$bytes));
echo current($unpacked);
Explanation:
C is the pack code for unsigned char and * indicates that you need to use all array entries. This will generate a string of characters based on the array. You can then unpack this string using J (if you know for a fact that the bytes were generated in a big endian byte order) or P if you know the bytes were generated in little endian order or Q if you want to use the machine order. If the bytes were generated in the same machine then Q would probably be a better choice than J otherwise you need to know the endianess.
Example: http://sandbox.onlinephpfunctions.com/code/5cba2c29522f7b9f9a0748b99fac768012e759ce
Note: This is my personal understanding of what is happening so anyone with better pack/unpack knowledge can let me know if I got things wrong.
I'm getting into compression algorithms and my native language is PHP, and I can understand that PHP is a language that you wouldn't normally make a big algorithm in, but I was wondering if it was possible. (of course it's possible - more so efficient and powerful)
The first type of algorithm I'd attempt to make is a simple adaptive algorithm, by taking in the most used bytes (chars) and converting them into binary types, (ex: a = 0001, b = 0010, c = 0011) - tho there is no real way to do that in PHP that I am familiar with, before this I was using simple ASCII conversions like a = chr(33), b = chr(34) that would get the least valued ASCII values use them as the smallest -> largest operators for the compression definitions.
So what I am asking is that if there's a way to assign binary values to a variable instead of it being represented as ASCII, if I go:
$string_after_compression = 000100100011;
#split it by 4 bits per = 0001 | 0010 | 0011
That would be interpreted as an int - therefore making an over-large int therefore most likely running out of available ram with a simple sentence, then if I try to store the value in a string instead, that removes the point of compressing as it's just making a string like:
$string_after_compression = "000100100011";
#split it by 4 bits per = "0001" . "0010" . "0011";
-----
This question is a bit confusing but the aim is: Is there a way to assign a PHP variable using a PHP intigers
Example solution:
$binary_var = (binary) 0001;
To work with binary in PHP, your data type of choice is a string. Because strings are mere byte arrays:
$bytes = '';
There's no simple base 2 notation for binary in PHP (0100101), usually the next best option to work with binary is hex notation:
$bytes = "\x42"; // 0100 0010
You'll need to convert between base 2 and base 16 notation back and forth in your head, but once you get used to that it's typically easier to follow and work with than long strings of 1s and 0s.
To test or manipulate binary data you'll want to get used to the binary operators:
if (($bytes[3] & "\x02") === "\x02") {
// the second bit of the forth byte in the sequence is set (0000 0010)
}
$bytes[6] |= "\x02"; // setting the second bit of the seventh byte
I want to cmmunicate with a udp tracker and send a connect request to it.
for this i must at first create a 16-bytes variable in php and sends it to the tracker.
request variable structure:
put it first 64-bit 0x41727101980 and 32-bit with 0.
generate a 32-bit unsigned integer as random and then add generated number to end of the variable.
finally, the size of my variable should be 128-bit equal to 16-bytes.
I use this way:
$a = time();
$connect_request = 0x41727101980;
$connect_request .= 0x00000000;
$connect_request .= $a;
var_dump($connect_request);
but result is:
string '449748612544001413719239' (length=24)
this is 24-byte not 16-byte.
what I must do now ??
What you have there are numbers.
Try this:
$connect_request = pack("N*",0x417,0x27101980,0,time());
If you have PHP 5.6 then you can use pack("JN*", 0x41727101980, 0, time()), allowing for direct 64-bit number use, but otherwise you will need to manually split the big number into two smaller numbers (each 32-bit, hence the second 0x... having eight hexits).
This will pack the inputs into a string of your desired length, in this case 128-bit, or 24 bytes.
I've been playing around with large numbers in PHP and was just wondering what module/process it uses to calculate the large numbers, and why it isn't used for all PHP numeric functions.
Hope this explains it a little better
My PHP_INT_MAX is 2147483647 (31 bits)
But, I figured out can create a 1017 bit number, by using:
$largenumber = pow(142,142);
This number is 310 digits long so I wont paste it in here ...
But then if I then try convert it to binary:
decbin($largenumber);
I get 1111111111111111111111111111111 (31 bits ... PHP_INT_MAX)
So, if the pow() function can handle this large number, why can't the decbin() function handle it?
From the official PHP documentation on pow:
base raised to the power of exp. If both arguments are non-negative
integers and the result can be represented as an integer, the result
will be returned with integer type, otherwise it will be returned as a
float.
$largenumber = pow(142,142);
var_dump($largenumber); //float(INF)
pow returns a float, which decbin tries to convert to an int and where you exceed the maximum integer value.
I've used unpack to convert most of the data types I have in a binary file that I'm parsing with little problems. I have no idea how to work with a big endian 64-bit signed long. I think this data type is stored using 2's complement. The application of the data file I'm reading is a java app so I assume it's 2's complement. I don't need to work with it as a number but simply work with it as a string.
Java 64-bit integers are indeed stored natively as "network-order" (big endian, i.e. start with the most significant byte) 8-byte 2's complement format. So typically you take byte at a time, shift left by 8, repeat. Byte values can be thought of as unsigned (while result is signed), but with left-shifting this should not matter.
So: first you just created equivalent 64-bit int from bytes, and display from there. No point in using short cuts; while it is possible, you just end up with more complicated and less efficient code.
32-bit PHP will only have signed 32-bit integers, thus as far as I know, there's no way to natively unpack the data.
The following code should be able to read a big endian, two's complement 64-bit integer:
<?php
function read_int64($fp)
{
$hex = unpack('H16a', fread($fp, 8));
$hex = '0x'.$hex['a'];
$n = gmp_init($hex);
if (gmp_testbit($n, 63))
{
$n = gmp_xor($n, '0xffffffffffffffff'); // flip the bits
$n = gmp_neg(gmp_add($n, 1)); // add one and negate
}
return gmp_strval($n);
}
?>
It returns the integer as a string. It can be used like:
$fp = fopen('test.bin', 'rb');
echo read_int64($fp)."\n";
fclose($fp);
(Edit: Updated code to call fewer GMP functions.)