how make binary varibale with specific structure - php - php

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.

Related

how to create a row of digits based on a string in php [duplicate]

In php is there a way to give a unique hash from a string, but that the hash was made up from numbers only?
example:
return md5(234); // returns 098f6bcd4621d373cade4e832627b4f6
but I need
return numhash(234); // returns 00978902923102372190
(20 numbers only)
the problem here is that I want the hashing to be short.
edit:
OK let me explain the back story here.
I have a site that has a ID for every registered person, also I need a ID for the person to use and exchange (hence it can't be too long), so far the ID numbering has been 00001, 00002, 00003 etc...
this makes some people look more important
this reveals application info that I don't want to reveal.
To fix point 1 and 2 I need to "hide" the number while keeping it unique.
Edit + SOLUTION:
Numeric hash function based on the code by https://stackoverflow.com/a/23679870/175071
/**
* Return a number only hash
* https://stackoverflow.com/a/23679870/175071
* #param $str
* #param null $len
* #return number
*/
public function numHash($str, $len=null)
{
$binhash = md5($str, true);
$numhash = unpack('N2', $binhash);
$hash = $numhash[1] . $numhash[2];
if($len && is_int($len)) {
$hash = substr($hash, 0, $len);
}
return $hash;
}
// Usage
numHash(234, 20); // always returns 6814430791721596451
An MD5 or SHA1 hash in PHP returns a hexadecimal number, so all you need to do is convert bases. PHP has a function that can do this for you:
$bignum = hexdec( md5("test") );
or
$bignum = hexdec( sha1("test") );
PHP Manual for hexdec
Since you want a limited size number, you could then use modular division to put it in a range you want.
$smallnum = $bignum % [put your upper bound here]
EDIT
As noted by Artefacto in the comments, using this approach will result in a number beyond the maximum size of an Integer in PHP, and the result after modular division will always be 0. However, taking a substring of the hash that contains the first 16 characters doesn't have this problem. Revised version for calculating the initial large number:
$bignum = hexdec( substr(sha1("test"), 0, 15) );
You can try crc32(). See the documentation at: http://php.net/manual/en/function.crc32.php
$checksum = crc32("The quick brown fox jumped over the lazy dog.");
printf("%u\n", $checksum); // prints 2191738434
With that said, crc should only be used to validate the integrity of data.
There are some good answers but for me the approaches seem silly.
They first force php to create a Hex number, then convert this back (hexdec) in a BigInteger and then cut it down to a number of letters... this is much work!
Instead why not
Read the hash as binary:
$binhash = md5('[input value]', true);
then using
$numhash = unpack('N2', $binhash); //- or 'V2' for little endian
to cast this as two INTs ($numhash is an array of two elements). Now you can reduce the number of bits in the number simply using an AND operation. e.g:
$result = $numhash[1] & 0x000FFFFF; //- to get numbers between 0 and 1048575
But be warned of collisions! Reducing the number means increasing the probability of two different [input value] with the same output.
I think that the much better way would be the use of "ID-Crypting" with a Bijectiv function. So no collisions could happen! For the simplest kind just use an Affine_cipher
Example with max input value range from 0 to 25:
function numcrypt($a)
{
return ($a * 15) % 26;
}
function unnumcrypt($a)
{
return ($a * 7) % 26;
}
Output:
numcrypt(1) : 15
numcrypt(2) : 4
numcrypt(3) : 19
unnumcrypt(15) : 1
unnumcrypt(4) : 2
unnumcrypt(19) : 3
e.g.
$id = unnumcrypt($_GET('userid'));
... do something with the ID ...
echo ' go ';
of course this is not secure, but if no one knows the method used for your encryption then there are no security reasons then this way is faster and collision safe.
The problem of cut off the hash are the collisions, to avoid it try:
return hexdec(crc32("Hello World"));
The crc32():
Generates the cyclic redundancy checksum polynomial of 32-bit lengths
of the str. This is usually used to validate the integrity of data
being transmitted.
That give us an integer of 32 bit, negative in 32 bits installation, or positive in the 64 bits. This integer could be store like an ID in a database. This don´t have collision problems, because it fits into 32bits variable, once you convert it to decimal with the hexdec() function.
First of all, md5 is basically compromised, so you shouldn't be using it for anything but non-critical hashing.
PHP5 has the hash() function, see http://www.php.net/manual/en/function.hash.php.
Setting the last parameter to true will give you a string of binary data. Alternatively, you could split the resulting hexadecimal hash into pieces of 2 characters and convert them to integers individually, but I'd expect that to be much slower.
Try hashid.
It hash a number into format you can define. The formats include how many character, and what character included.
Example:
$hashids->encode(1);
Will return "28630" depends on your format,
Just use my manual hash method below:
Divide the number (e.g. 6 digit) by prime values, 3,5,7.
And get the first 6 values that are in the decimal places as the ID to be used. Do a check on uniqueness before actual creation of the ID, if a collision exists, increase the last digit by +1 until a non collision.
E.g. 123456 gives you 771428
123457 gives you 780952
123458 gives you 790476.

Exceed PHP binary limit

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)

A byte buffer in PHP?

I am working with a project which uses a custom TCP protocol. I have everything down the line, except for one thing: The protocol requires 4 bites before the message, that determine the length of the package. In NodeJS, this is done via:
var b = new Buffer(4);
b.writeUInt32BE(data.length, 0);
But is there such a way in PHP also? I was considering using pack() - but I have no experience with this function. I also need to read a package of the same format, so I also need to be able to obtain the integer from the first 4 bites too.
Using pack is the correct way to go in PHP and here is an example of how to use it to return the information you require:
<?php
$string = 'hello world';
$bytes = pack ( 'N', strlen ( $string ) ); // unsigned 32 bit big endian byte order
?>
To parse the first 4 raw bytes back into a number, this is assuming the a variable named $rawBytes contains the data read from the tcp packet.
<?php
$decoded = unpack ( 'N', substr ( $rawBytes, 0, 4 ); );
$length = end ( $decoded );
?>
One unfortunate gotcha within PHP is that the binary only understands 32bit signed integers on Windows machines and on 32bit Linux/Macintosh/Unix machines.
−2,147,483,648 to 2,147,483,647
64bit PHP binaries running on Linux/Macintosh/Unix machines have the maximum integer value of a signed 64bit integer.
−9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
But using 64bit binary on a Windows machine still has an integer size of a 32bit signed integer.
Anything outside of the integer bounds will be cast to a floating point number.

Converting two integers into a long in PHP

I've got two integers and I need to convert them into a long. I'm totally lost on how to do this. The two integers that I need to convert are:
INT 1: 60850985
INT 2: 59150141
I need a method that converts two integers into a long. If you can post one, that'd be great.
When I say converting to a long, I'm wondering how you would do the equivalent of (long) from java in PHP
Let me be completely clear here:
I'm receiving two ints from the client, then I need to convert them to a long, then the single long is to be used again as a single int.
In essence, I need to take two ints and convert them into a single int. An example of how this is done in java would be:
long $intA = (long) readInt();
long $intB = (long) readInt();
return ($intA << 32) + $intB;
PHP stores numbers as integers or floats, where the size of the integer is platform dependent (but usally 32 bit, signed). If you need to represent a larger number you should use the BC Math functions.
Using BCM adding two numbers is like:
$a = '60850985';
$b = '59150141';
echo bcadd($a, $b);
or multiplying:
$a = '60850985';
$b = '59150141';
echo bcmul($a, $b);
EDIT:
If you want to get, how it should look as a 64-bit signed integer in 1-complement (if there is an overflow), then you have to do some manual conversion to cast the value inside the -2^63 .. 2^63-1 range:
For nonnegative values you can for example first cast it to 0 .. 2^64-1:
$long = bcmod($value, bcpow('2','64'));
Then if it's larger than 2^63-1 then subtract 2^63 from it, and then subtract this value from -2^63.
For negative values, first add 2^64, until the value is positive, then do the above steps.
But the above steps are only needed if you want to check how the string number looks if there was an overflow. Usually you don't need this, and probably you don't even need to use BCM as your numbers will easily fit inside PHP's signed 32-bit integer datatype (for which no casting is needed, conversion is automatical):
$a = '123'; // $a is a string
echo $a + 1; // will write 124, $a gets converted into int
You can force conversion if you want though:
$a = $a+0;
or
$a = (int)$a;
EDIT 2:
You can still use BCM functions to do the math:
$long = bcadd($low, bcmul($high, bcpow('2','32')))
// this essentially means:
// $long = $low + $high * 2^32
// which is
// $long = $low + $high << 32
Then, if the result is larger than 2^63-1 you can do some additional BCM calculations, described above to convert the unsigned integer into a signed one.
I used regular addition:
$int1 = 60850985;
$int2 = 59150141;
$result = $int1 + $int2;//120001126
Here's a quote from the PHP manual:
The size of an integer is platform-dependent, although a maximum value
of about two billion is the usual value (that's 32 bits signed).
64-bit platforms usually have a maximum value of about 9E18. PHP does
not support unsigned integers. Integer size can be determined using
the constant PHP_INT_SIZE, and maximum value using the constant
PHP_INT_MAX since PHP 4.4.0 and PHP 5.0.5.
If you want to deal with large numbers use GMP ( http://www.php.net/manual/en/book.gmp.php ) or BCMath ( http://www.php.net/manual/en/book.bc.php ).
To elaborate on what AgentConundrum said, there isn't a need to cast an integer to a long in PHP. PHP is a dynamic language which means that generally, for operations on fundamental types, there is no need for casting (unless it is for some explicit purpose - i.e. a float to an integer), as PHP handles it for you.

How can you parse a Java 64-bit long from a binary file into a PHP string?

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.)

Categories