Increment hex value (little endian?) in PHP - php

In an incoming UDP packet I have the hex value b70500. This is actually a sequence number (1463). I need to increment this value before sending it back to the server in the same format (b80500).
How can I, in PHP, increment the value by one?
Using the code suggested here I was able to convert the hex value to an integer and increment it by one:
$original_hex = 'b70500'; // 1463
$original_int = unpack("H*", strrev(pack("H*", $original_hex))); // 0005b7
$incremented_int = hexdec($original_int[1]) + 1; // 1464
$incremented_hex = ? // Expected result: b80500
... But I have no idea how to convert it back into hex. Perhaps there is a more efficient method?

hexdec() and dechex(). You do not have to unpack the value.
$incremented = dechex(hexdec('b70500') + 1);

It's not pretty and I bet there are more efficient ways of doing this, but it works:
function increment_hex($hex) {
$original_hex = $hex;
$original_int = unpack("H*", strrev(pack("H*", $original_hex)));
$incremented_int = hexdec($original_int[1]) + 1;
$incremented_hex = dechex($incremented_int);
$padded_hex = str_pad($incremented_hex, 6, '0', STR_PAD_LEFT);
$reversed_hex = unpack("H*", strrev(pack("H*", $padded_hex)));
return $reversed_hex[1];
}
echo "result: " . increment_hex('b70500') . "\n";
result: b80500

Related

Convert a full string (represented in exponential format) back in number in PHP

I've been searching for converting my exponential number string into an exact number.
So, I've an exponential number stored as string in MySQL. I want to convert back this string in the exact number.
But It seems the number is quite big and crosses the boundary and provide me wrong data.
While I tried following code in various format but result is not in proper format.
policy_number = "2.9992020830803E+18";
number_format($policy_number, 0,'.','');
// Output
2999202083080300032
(float) $policy_number;
// Output
2.9992020830803E+18
sscanf($policy_number, "%f")[0];
// Output
2.9992020830803E+18
floatval($policy_number);
// Output
2.9992020830803E+18
gmp_init("2.9992020830803E+18");
gmp_strval($policy_number);
// Output
0
"2.9992020830803E+18" + 0;
// Output
2.9992020830803E+18
Please show me the right way to convert it.
Updated
I agree with Ed Cottrell that your problem is how you are storing your data in the db. However, if this is a project where you are already looking at a large set of data that is already stored as an exponent then this function I wrote should work for you. It should work for positive and negative bases and exponents. It basically mimics the way you would do the operation by hand.
I was not able to figure out a way to do it using math functions. If someone knows how to do it better please post. In the meantime, I had fun writing this.
Hope it helps you out!
function getRealNumber($number){
//Parse the base and exponent.
preg_match('/^(.*?)E[\-|\+](.*?)$/', $number, $data);
$base = $data[1];
$exp = $data[2];
//Test to see if the base is negative.
if(preg_match('/\-/', $base)){
$base = str_replace('-', '', $base);
$isNegative = TRUE;
}
//Capture the offset of the decimal point.
preg_match('/\./', $base, $position, PREG_OFFSET_CAPTURE);
$offset = $position[0][1]; //This is the offset of the decimal point.
$string = str_replace('.', '', $base); //Get numbers without decimal.
$length = strlen($string); //Get the length of string.
//Test to see if we are adding zeros to the end or beginning of string.
if(preg_match('/E\+/', $number)){
//Let's move the decimal.
if($length > ($exp + $offset)){
$string = substr_replace($string, '.', ($exp + $offset), 0);
} else {
$string = $string . str_repeat('0', $exp - ($length - $offset));
}
}elseif(preg_match('/E\-/', $number)){
//Calculate the number of zeros needed to add and append them.
if($offset > $exp){
$string = substr_replace($string, '.', $offset, 0);
} else {
$string = '0.' . str_repeat('0', $exp - $offset) . $string;
}
}
//Add the negative sign if we need to.
if(!$isNegative){
return $string;
} else {
return '-' . $string;
}
}
$policy_number = "2.9992020830803E+18";
echo getRealNumber($policy_number);
//Will output 2999202083080300000

php convert decimal to hexadecimal

I am extracting a serial from a digital certificate using the built-in OpenSSL library, however, I am having trouble converting this number to hex with precision.
The extracted number is originally in decimal but I need to have it in hex.
The number I am trying to convert is: 114483222461061018757513232564608398004
Here is what I've tried:
dechex() did not work, it returns: 7fffffffffffffff
The closest I could get was this function from the php.net page but it does not convert the whole number on part of it.
function dec2hex($dec) {
$hex = ($dec == 0 ? '0' : '');
while ($dec > 0) {
$hex = dechex($dec - floor($dec / 16) * 16) . $hex;
$dec = floor($dec / 16);
}
return $hex;
}
echo dec2hex('114483222461061018757513232564608398004');
//Result: 5620aaa80d50fc000000000000000000
Here is what I am expecting:
Decimal number: 114483222461061018757513232564608398004
Expected hex: 5620AAA80D50FD70496983E2A39972B4
I can see the correction conversion here:
https://www.mathsisfun.com/binary-decimal-hexadecimal-converter.html
I need a PHP solution.
The problem is that The largest number that can be converted is ... 4294967295 - hence why it's not working for you.
This answer worked for me during a quick test, assuming you have bcmath installed on your server, and you can obtain the number as a string to start with. If you can't, i.e. it begins life as numeric variable, you'll immediately reach PHP's float limit.
// Credit: joost at bingopaleis dot com
// Input: A decimal number as a String.
// Output: The equivalent hexadecimal number as a String.
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;
}
Example:
$number = '114483222461061018757513232564608398004'; // Important: already a string!
var_dump(dec2hex($number)); // string(32) "5620AAA80D50FD70496983E2A39972B4"
Ensure you pass a string into that function, not a numeric variable. In the example you provided in the question, it looks like you can obtain the number as a string initially, so should work if you have bc installed.
Answered by lafor.
How to convert a huge integer to hex in php?
function bcdechex($dec)
{
$hex = '';
do {
$last = bcmod($dec, 16);
$hex = dechex($last).$hex;
$dec = bcdiv(bcsub($dec, $last), 16);
} while($dec>0);
return $hex;
}
Example:
$decimal = '114483222461061018757513232564608398004';
echo "Hex decimal : ".bcdechex($decimal);
This is a big integer, so you need to use a big-integer library like GMP:
echo gmp_strval('114483222461061018757513232564608398004', 16);
// output: 5620aaa80d50fd70496983e2a39972b4
Try this 100% working for any number
<?php
$dec = '114483222461061018757513232564608398004';
// init hex array
$hex = array();
while ($dec)
{
// get modulus // based on docs both params are string
$modulus = bcmod($dec, '16');
// convert to hex and prepend to array
array_unshift($hex, dechex($modulus));
// update decimal number
$dec = bcdiv(bcsub($dec, $modulus), 16);
}
// array elements to string
echo implode('', $hex);
?>

Using number_format to get decimals

I got a few values I want to sum up and check agains another number like this:
$a = '15';
$b = '5,50';
$c = '-10';
$to_pay = '10,50';
$formated_total = number_format(($a+$b+($c)), 2, ',', ' ');
$this->assertEquals($to_pay, $formated_total);
the asser part is a selenium function I am using so dont think about that, it's just supposed to check if the 2 values are the same. Now the result I get is:
- Expected
+ Actual
-'10,50'
+'10,00'
Why am I losing the value from the decimals?
You should not use "," as decimal point it's not excel. In PHP you need to use DOT
Change your numbers to:
$a = '15';
$b = '5.50';
$c = '-10';
$to_pay = '10.50';
or even better solution would be treat them as numbers not as strings
Change your numbers to:
$a = 15;
$b = 5.50;
$c = -10;
$to_pay = 10.50;
In that way you would get error if you tried using , instead of .
You can also simplify this line:
$formated_total = number_format(($a+$b+($c)), 2, ',', ' ');
to
$formated_total = number_format($a+$b+$c, 2, ',', ' ');
You may be curious why the result is 10. It's because during casting it to number php parser checks in 5,50 the number at the begining which is 5 and ignores the rest.
From manual:
If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero).
Because comma is not a valid decimal point. You need to "convert" $b and $to_pay values to use dots.

Summing string in php, converted to integer

Trying to use a simple "versioning" system for some hashes, I do the following:
$last_version = '009';
$increment = '001';
$result = $last_version + $increment;
var_dump($result);
I would expect: string(010) but I get int(10) and before I jump into if's and str-pad, I was wondering if there's any other way of conserving the desired format?
Using + automatically casts the variables into the appropriate number type (in this case an int, however different string formats can be casted to float).
If you want to keep the desired 0 left-padding, you can use sprintf() to format the result, as such:
$result = sprintf('%03d', $last_version + $increment);
The format specifier %03d specifies that you want an integer-string (d) with a length of 3 left-padded with the character 0.
More information about PHP's Type Juggling logic can be found in the PHP Documentation: Type Juggling
$last_version = '009';
$increment = '001';
$result = $last_version + $increment;
$result = (string) $result ;
var_dump($result) ;
When you try to perform math operations with strings, they are cast to approprite type. In this case to int. But you can cast integer back to string in the above example.
You cannot add strings (it's as simple as that). That's why PHP implicitly converts both strings to integers (this is called dynamic typing).
To format your number, you could to the following:
$last_version = '009';
$increment = '001';
$result = $last_version + $increment; // = 10
$result = sprintf("%03d", $result) // = "010"
When you use +, PHP will automatically cast the string to integers, thus the int(10 result you are seeing. You will not be able to add strings in this manner. So you best best would be to just keep the version as integer ans string pad like this:
$last_version = 9;
$increment = 1;
$pad_length = 3;
$pad_string = '0';
$result = $last_version + increment; // or simply $last_version++; if increment will always be 1
$string_result = str_pad((string)$result, $pad_length, $pad_string, STR_PAD_LEFT);

Convert a string containing a number in scientific notation to a double in PHP

I need help converting a string that contains a number in scientific notation to a double.
Example strings:
"1.8281e-009"
"2.3562e-007"
"0.911348"
I was thinking about just breaking the number into the number on the left and the exponent and than just do the math to generate the number; but is there a better/standard way to do this?
PHP is typeless dynamically typed, meaning it has to parse values to determine their types (recent versions of PHP have type declarations).
In your case, you may simply perform a numerical operation to force PHP to consider the values as numbers (and it understands the scientific notation x.yE-z).
Try for instance
foreach (array("1.8281e-009","2.3562e-007","0.911348") as $a)
{
echo "String $a: Number: " . ($a + 1) . "\n";
}
just adding 1 (you could also subtract zero) will make the strings become numbers, with the right amount of decimals.
Result:
String 1.8281e-009: Number: 1.0000000018281
String 2.3562e-007: Number: 1.00000023562
String 0.911348: Number: 1.911348
You might also cast the result using (float)
$real = (float) "3.141592e-007";
$f = (float) "1.8281e-009";
var_dump($f); // float(1.8281E-9)
Following line of code can help you to display bigint value,
$token= sprintf("%.0f",$scienticNotationNum );
refer with this link.
$float = sprintf('%f', $scientific_notation);
$integer = sprintf('%d', $scientific_notation);
if ($float == $integer)
{
// this is a whole number, so remove all decimals
$output = $integer;
}
else
{
// remove trailing zeroes from the decimal portion
$output = rtrim($float,'0');
$output = rtrim($output,'.');
}
I found a post that used number_format to convert the value from a float scientific notation number to a non-scientific notation number:
Example from the post:
$big_integer = 1202400000;
$formatted_int = number_format($big_integer, 0, '.', '');
echo $formatted_int; //outputs 1202400000 as expected
Use number_format() and rtrim() functions together. Eg
//eg $sciNotation = 2.3649E-8
$number = number_format($sciNotation, 10); //Use $dec_point large enough
echo rtrim($number, '0'); //Remove trailing zeros
I created a function, with more functions (pun not intended)
function decimalNotation($num){
$parts = explode('E', $num);
if(count($parts) != 2){
return $num;
}
$exp = abs(end($parts)) + 3;
$decimal = number_format($num, $exp);
$decimal = rtrim($decimal, '0');
return rtrim($decimal, '.');
}
function decimal_notation($float) {
$parts = explode('E', $float);
if(count($parts) === 2){
$exp = abs(end($parts)) + strlen($parts[0]);
$decimal = number_format($float, $exp);
return rtrim($decimal, '.0');
}
else{
return $float;
}
}
work with 0.000077240388
I tried the +1,-1,/1 solution but that was not sufficient without rounding the number afterwards using round($a,4) or similar

Categories