I'm connecting trough an API to Steam and get the SteamID from it for authentication purposes.
When I get my user_id from the API it gives me 76561198118533739 and when I check it on https://www.binaryhexconverter.com/decimal-to-hex-converter, the proper hex value is the result (1100001096efa6b).
But, when I use the PHP function dechex it gives me the wrong value. How can I get the correct value to use?
Example:
<?php
echo dechex(76561198118533739); // 7fffffff
?>
PHP has no error reporting for this function, it should have given an error for integer overflow, but no such luck.. 7fffffff is the largest signed 32-bit integer, which is as close as this function will get on 32bit platforms. to properly convert this number to hex on a 32bit system, use a arbitrary precision library like bcmath or GMP to calculate the hex value, here's 1 of those posted in the comments by "joost at bingopaleis dot com"
function dec2hex($number)
{
$hexvalues = array('0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F');
$hexval = '';
while($number != '0')
{
$hexval = $hexvalues[bcmod($number,'16')].$hexval;
$number = bcdiv($number,'16',0);
}
return $hexval;
}
it requires the bcmath extension to work.
also keep in mind that the number is too large to store as a number on 32bit systems, so you need to store it as a string.
dec2hex("76561198118533739"); // "1100001096efa6b"
if bcmath is not available, maybe it's time to upgrade your servers to 64bit?
This differencie is because your php platform use 32 bit but the numer you test need 64 bit long (http://php.net/manual/en/function.dechex.php) - the binary online calculator give right answer. You can check how much "bit" you have using echo PHP_INT_SIZE*8;
Related
I currently have a Decimal that is coming through as: 4294960896
This is then converted to Binary with this function:
decbin('4294960896')
Which equals: 11111111111111111110011100000000
I then need to take that binary and convert it to the 32bit signed version which should be '-6400'
I can't seem to find any built in functions that support 32bit signed output.
The hexadecimal representation of the number 4294960896 is FFFFE700h. This should be interpreted as 32 bit signed long.
The functions that support such tasks are pack and unpack.
$i64 = 4294960896;
$i32 = unpack('l',pack('V',$i64))[1];
//int(-6400)
I used
$i64 = unpack('L',pack('l',$decimal))[1];
$t = base_convert($i64,10,2);
$r = str_pad($t,32,'0', STR_PAD_LEFT);
It seemed more logical to use L and l formats for (un)packing, to keep it machine independent. Wrote a lot of tests though, to be sure it works.
I'm integrating a PHP application with an API that uses permissions in the form of 0x00000008, 0x20000000, etc. where each of these represents a given permission. Their API returned an integer. In PHP, how do I interpret something like 0x20000000 into an integer so I can utilize bitwise operators?
Another dev told me he thought these numbers were hex annotation, but googling that in PHP I'm finding limited results. What kind of numbers are these and how can I take an integer set of permissions and using bitwise operators determine if the user can 0x00000008.
As stated in the php documentation, much like what happens in the C language, this format is recognized in php as a native integer (in hexadecimal notation).
<?php
echo 0xDEADBEEF; // outputs 3735928559
Demo : https://3v4l.org/g1ggf
Ref : http://php.net/manual/en/language.types.integer.php#language.types.integer.syntax
Thus you could perform on them any bitwise operation since they are plain integers, with respect to the size of the registers on your server's processor (nowadays you are likely working on a 64-bit architecture, just saying in case it applies, you can confirm it with phpinfo() and through other means in doubt).
echo 0x00000001<<3; // 1*2*2*2, outputs 8
Demo : https://3v4l.org/AKv7H
Ref : http://php.net/manual/en/language.operators.bitwise.php
As suggested by #iainn and #SaltyPotato in their respective answer and comment, since you are reading the data from an API you might have to deal with these values obtained as strings instead of native integers. To overcome this you would just have to go through the hexdec function to convert them before use.
Ref : http://php.net/manual/en/function.hexdec.php
Since you are receiving it from an API php will interpret it as a string
echo hexdec('0x00000008');
returns the integer 8
This should work.
I have been trying to unserialize on a 32-bit server an object that was serialized on a 64-bit server. I have isolated my problem to an integer in the object. Here is a small reproduction of the problem.
On a 64-bit machine:
$i = serialize('20110510134021'); //i:20110510134021;
On a 32-bit machine:
$i = unserialize('i:20110510134021;');
Gives the error
Notice: unserialize(): Error at offset 0 of 16 bytes
Now I understand that those serialization method shouldn't be used for cross system data transmition. However, we are merely trying to migrate the data to another system, not use it actively for transfers. This is a one time thing.
I would think that this might be due to integer overflow, but even on the 32-bit server I can do something like
$i = 20110510134021;
echo $i;
And it will work fine. I'm guessing PHP integer types scale to some double type or something like that. But why doesn't it do that when it unserializes?
How can I unserialize those objects? If I can't, is there any way to convert them to something else? Finally, has anyone written a deserialize method in PHP itself? Or has details on the protocol? I could use that and have a custom case for those integers.
Thanks.
Note: I do not have access to the original data, only the serialized result.
The max integer on 32 bit system is 4294967296;
$i = 20110510134021; works because PHP converts the variable to double.
So replace i with d
$i = unserialize('d:20110510134021;');
If you run this script, you will see the correct represenation of the variable on the system you are running (d: on 32 bit system, i: on 64 bit system):
$int = 20110510134021;
var_dump(serialize($int));
The simple solution is if you know that there is a chance that data serialized on 64 bit will be unserialized on 32 bit machine is to cast it to (double) before serializing.
Then it will be unserialized as a double, giving you more bits per integer than a standard 4-byte per integer (32 bits)
Once unserialized just work with that number as a double. In 99% of the cases this is a good solution. There is still a chance that for a very large number the number of bits allocated to the 'real' part on the number to a double on a 32 bit machine will not be enough. I think it's 56 bits, so the maximum integer is still significantly larger that the 32bits for the int type.
How about:
$serialized = 'i:20110510134021';
if (preg_match('/i\:([\d]+)/', $serialized, $match))
{
$unserialized = $match[1];
}
I am trying to port a piece of code from perl to php. The perl code snippet is part of akamai's video on demand link generation script. The script generates seed based on the location / URL of the video file (which will always be constant for a single URL). And then it is used in generating serial ID for stream (which is basically a random number between 1 and 2000 using the seed). Here is the perl code.$seed=6718;
srand($seed);
print(int(rand(1999)) + 1); // return 442 every time And the converted PHP code is:$seed=6718;
srand($seed);
echo(rand(0, 1999) + 1); //returns 155 every time
Does php rand behaves differently than perl one?
Yes. You can't depend on their algorithms being the same. For perl, which rand is used depends on what platform your perl was built for.
You may have more luck using a particular algorithm; for instance, Mersenne Twister looks to be available for both PHP and Perl.
Update: trying it produces different results, so that one at least won't do the trick.
Update 2: From the perl numbers you show, your perl is using the drand48 library; I don't know whether that's available for PHP at all, and google isn't helping.
[clippy]It looks like your trying to hash a number, maybe you want to use a hash function?[/clippy]
Hash functions are designed to take an input and produce a consistently repeatable value, that is in appearance random. As a bonus they often have cross language implementations.
Using srand() with rand() to get what is basically a hash value is a fairly bad idea. Different languages use different algorithms, some just use system libraries. Changing (or upgrading) the OS, standard C library, or language can result in wildly different results.
Using SHA1 to get a number between 1 and 2000 is a bit overkill, but you can at least be sure that you could port the code to nearly any language and still get the same result.
use Digest::SHA1;
# get a integer hash value from $in between $min (inclusive) and $max (exclusive)
sub get_int_hash {
my ($in, $min, $max) = #_;
# calculate the SHA1 of $in, note $in is converted to a string.
my $sha = Digest::SHA1->new;
$sha->add( "$in" );
my $digest = $sha->hexdigest;
# use the last 7 characters of the digest (28 bits) for an effective range of 0 - 268,435,455.
my $value = hex substr $digest, -7;
# scale and shift the value to the desired range.
my $out = int( $value / 0x10000000 * ( $max - $min ) ) + $min;
return $out;
}
print get_int_hash(6718, 1, 2000); #this should print 812 for any SHA1 implementation.
Just seeing this snippet of code it is impossible to say if it is the same.
At first you need to knew that even a random generator like the rand() function is not really random. It calculates a new value with a mathematical formula from the previous number. With the srand() function you can set the start value.
Calling srand() with the same argument each time means that the program always returns the same numbers in the same order.
If you really want random numbers, in Perl you should remove the initialization of srand(). Because Perl automatically sets srand() to a better (random) value when you first call the rand() function.
If your program really wants random numbers, then it should also be okay for PHP. But even in PHP i would look if srand() is automatically set and set to a more random value.
If your program don't work with random numbers and instead really want a stream of numbers that is always the same, then the snipet of code are probably not identical. Even if you do the same initialization with srand() it could be that PHP uses another formula to calculate the next "random" number.
So you need to look at your surrounding code if you code really wants random numbers, if yes you can use this code. But even then you should look for a better initialization for srand().
I have a simple function that I'm using but for some reason the number doesn't calculate correctly as it would in a calculator. I think it has something to do with the numbers being too large, or something to do with 64 bit. Is there any way I can convert them so that they would work correctly?
$sSteamComID = 76561197990369545;
$steamBase = 76561197960265728;
function convertToSteamID($sSteamComID) {
$sServer = bcmod($sSteamComID, '2') == '0' ? '0' : '1';
$sCommID = bcsub($sSteamComID, $sServer);
$sCommID = bcsub($sCommID, $steamBase);
$sAuth = bcdiv($sCommID, '2');
echo "$sServer:$sAuth";
}
convertToSteamID($sSteamComID);
This function outputs 0:15051912 on a server when it should be printing 1:15051908
The missing global $steamBase was the problem, as already mentioned in a comment. (Tip: turn on E_NOTICE during development.) However, I'd like to address your question:
I think it has something to do with
the numbers being too large, or
something to do with 64 bit. Is there
any way I can convert them so that
they would work correctly?
PHP integers are signed and platform-dependent. Using 64-bit numbers will not work if you are on a 32-bit host.
So your concern is valid. But even on a 64-bit system:
$x = 9223372036854775808; // highest bit (64th) set
var_dump($x);
--> float(9.2233720368548E+18)
Note that PHP's BC Math routines operate on strings, not integers. Thus, you should be storing your big numbers as strings.
This will work around the potential problem of integers being converted to floats, which will happen even on your 64-bit environment if you are using large, unsigned integers.