Convert a binary string to float in php - php

I get through Modbus some 4-Byte Float Values.
I get this 4 bytes in an array:
Array ( [0] => 67 [1] => 105 [2] => 25 [3] => 154 )
After some Bitconversion I made this:
1000011011010010001100110011010
when putting this binary string into a online converter such as
https://www.binaryconvert.com/result_float.html?hexadecimal=4369199A
I get the value of 2.331E2 which is correct (233.1).
However I fail to convert this binary in a PHP float variable. I tried to point the address to a float variable, but did not succeed.
How can I convert this binary string or the array above into a php float?
Added:
The pointer Idea was stupid, since php does not let me define the type of variable. So I tried a different approach using unpack to a float type. But it does not work either:
// This represents a 4 byte float read from modbus
$array=array(67,105,25,154);
$array=array_reverse($array);
print_r($array);
for ($i=0;$i<count($array);$i++) {
$t+=pow(2,$i*8)*$array[$i];
}
echo '<br>Binary: '.decbin($t). ' - This would be the correct Binary for 233.1';
echo '<br>float: ';
print_r(unpack('f',$t));
This code results in:
Array ( [0] => 154 [1] => 25 [2] => 105 [3] => 67 )
Binary: 1000011011010010001100110011010 - This would be the correct Binary for 233.1
float: Array ( [1] => 6.5189725839687E-10 )
No chance to get my 233.1 :(

I know I come with a possible answer a little bit later but maybe others found useful.
The conversion is a little bit complicated, I worked few hours on it to include in my application.
Firstly I created a function to get value of the Mantissa, then calculated a float number. I didn't created function for the calculation of the exponent and sign.
This example is valid for positive float numbers, for more details read this:
HOW REAL (FLOATING POINT) AND 32-BIT DATA IS ENCODED IN MODBUS RTU MESSAGES
And the script:
$array=array(67,105,25,154);
$result = pow(2,(((($array[0] * 256 + $array[1]) & 32640) >> 7)-127)) * calcMantissa((($array[1] & 127) << 16) + ($array[2] << 8) + $array[3]+1);
echo $result . "\n";
function calcMantissa($nb) {
$retValue = 1;
for ($i = 0; $i < 22; $i++) {
$retValue = $retValue + (($nb & (1 << (22 - $i))) > 0) / (pow(2,($i+1))) ;
}
return $retValue;
}
which gave the following result:
233.10000610352

Related

Unpack hex-encoded binary data in PHP

We're collecting data from a partner's IoT devices and the data comes encoded in a hex string like 1C000000010028 which contains binary data:
Byte 0 bit 0 Boolean
Byte 0 bit 1 Boolean
Byte 0 bit 2 Boolean
Byte 0 bit 3 Boolean
Byte 0 bits 4-7 UInt4
Bytes 1-2 bits 0-15 UInt16
Byte 3 bits 0-7 UInt8
Bytes 4-5 bits 0-15 UInt16
Byte 6 bits 0-7 UInt8
I have never worked with this kind of data and am wondering how to decode / unpack this in PHP. I was guessing that https://www.php.net/manual/de/function.unpack.php would be my friend but I just don't get it. Any help would be much appreciated, thanks!
They say that the input is a hex string like '1C000000010028'.
$code = '1C000000010028';
To use unpack() the data must be a string with binaryData. You can convert it with hex2bin.
$binaryData = hex2bin($code);
// "\x1c\x00\x00\x00\x01\x00\x28"
Now you could use unpack.
$arr = unpack('Cbyte_0/vUInt16_0/Cbyte_1/vUInt16_1/Cbyte_2',$binaryData);
/*
$arr = array (
'byte_0' => 28,
'UInt16_0' => 0,
'byte_1' => 0,
'UInt16_1' => 1,
'byte_2' => 40,
)
*/
Individual data types such as Boolean and UInt4 are not included in the pack/unpack formats. To get this data you have to work with the bit operators.
Just one example of this:
$byte_0bit2 = (bool)($arr['byte_0'] & 0b00000100);
This can lead to further questions, the answers of which can be found here on Stackoverflow.

PHP Converting Hex string to Byte Array - converting VB.Net to PHP

I'm writing a PHP website that is accessing an encrypted MySQL database. The database is currently a back end to a VB.Net Windows forms program. This is all working fine, but I want to the PHP website to access some of the data and be able to decrypt/encrypt it. The fields are encrypted using Blowfish code originally written by David Ireland in VB6 and converted by Todd Acheson with a few tweaks from myself.
With the PHP Blowfish examples I've seen, the $iv is set at random, but I need it to be set to the same as that created in VB, so I'm attempting to convert the VB code to PHP.
I've started converting the code line by line, and from a technical perspective, it seems OK, but testing the first part of it doesn't provide the same results as with VB
Setting the key:
Dim aKey() as Byte = cv_BytesFromHex(MySecretKey)
Public Function cv_BytesFromHex(ByVal sInputHex As String) As Object
' Returns array of bytes from hex string in big-endian order
' E.g. sHex="FEDC80" will return array {&HFE, &HDC, &H80}
Dim i As Long
Dim M As Long
Dim aBytes() As Byte
If Len(sInputHex) Mod 2 <> 0 Then
sInputHex = "0" & sInputHex
End If
M = Len(sInputHex) \ 2
ReDim aBytes(M - 1)
For i = 0 To M - 1
Dim x = "&H" & Mid(sInputHex, i * 2 + 1, 2)
Debug.Print(x + " " + Val(x).ToString)
aBytes(i) = Val(x)
Next
cv_BytesFromHex = aBytes 'CopyArray(aBytes)
Return cv_BytesFromHex
End Function
Converting this function to PHP5.
public function cv_BytesFromHex($inputstring)
{
// Returns array of bytes from hex string in big-endian order
// e.g. shex="fedc80" will return array {&hfe, &hdc, &h80}
$i=0;
$m=0;
if (strlen($inputstring)/2 <> (int)(strlen($inputstring)/2)) {
$inputstring = "0".$inputstring;
}
$m = strlen($inputstring)/2;
echo 'Length '.strlen($inputstring).' = '.$m." elements</br>";
$abytes=array_fill(0,$m-1,0) ;
for ($i=0; $i<=$m-1;$i++) {
$raw=substr($inputstring, $i * 2 , 2);
$hexed=hexdec($raw);
echo 'Raw ='.$raw.' = '.$hexed.'</br>';
$abytes[$i]=$hexed;
}
return $abytes;
}
Testing with the key "1check".
VB output:
&H1C 28
&Hhe 0
&Hck 12
PHP output:
Length 6 = 3 elements
Raw =1c = 28
Raw =he = 14
Raw =ck = 12
So.. in this example, "1C" and "ck" give me the same values, but "he" doesn't
another example:
key =10stack
vb
&H01 1
&H0s 0
&Hta 0
&Hck 12
php
Length 8 = 4 elements
Raw =01 = 1
Raw =0s = 0
Raw =ta = 10
Raw =ck = 12
This one works:
key =1234wxyz
vb
&H12 18
&H34 52
&Hwx 0
&Hyz 0
php
Raw =12 = 18
Raw =34 = 52
Raw =wx = 0
Raw =yz = 0
Does anyone know why?
so, there is no errors here. h is ignored by hexdec and only e is decoded. cause...
https://en.wikipedia.org/wiki/Hexadecimal there is no h :)
and in VBA Val function returns 0, cause he is not valid hex-combination
<?php
function myHex($str)
{
if ($str === dechex(hexdec($str))) {
return hexdec($str);
}
return 0;
}
var_dump(myHex("he")); // returns 0

PHP program to accept user input and terminate when entered zero

I came across this program on http://www.programmr.com . And the question is
Complete the program to print the sum of negative numbers, positive even numbers, positive odd numbers from a list of numbers entered by the user. The list terminates when the number entered is zero . And my code is,
$nums = array();
while(trim(fgets(STDIN)) != 0){
array_push($nums,trim(fgets(STDIN)));
}
I know the code is incomplete but what im trying to do is to push the inputs to the array and then calculate the sum. When I print_r($nums) the array it gives me this,
Array
(
[0] => 34
[1] => 32
[2] => 45
[3] => 0
)
And my input is,
12
34
12
32
12
45
12
0
0
It pushes the alternative elements i dont know whats happening with this. Please help me , thanks in advance.
You are calling fgets(STDIN) twice in your code, i have adjusted it a bit so the array part is working. The rest of the assignment i let you figure that part out ;) Hint: Use modulus operator.
$nums = array();
do {
$number = (int) trim(fgets(STDIN));
array_push($nums,$number);
} while ($number !== 0);
print_r($nums);
Also if you are using PHP5.6 or higher you can use short array syntax like so:
$nums = [];
And
$nums[] = $number;

Reverting a bitwise/binary number to an array of values?

I have a a list of data that has a value attached to it that constantly gets doubled as it goes up:
0 = value 0
1 = value 1
2 = value 2
4 = value 3
8 = value 4
16 = value 5
32 = value 6
64 = value 7
128 = value 8
256 = value 9
512 = value 10
I have also been given the number x
say x = 76.
Visually, I can see that value 7 (64), value 4 (8), and value 3 (4) all sum up to 76.
What I need to be able to do, is take x, run it through a function, and return an array of the values.
I've tried looping through all the numbers in reverse and taking off what value has been used, but i got confused with lots of if statements.
Is there a built in PHP function to do this? Or am I looking at it the wrong way?
Thanks
May be you are looking for this-
function getArray($x){
$ar = array();
for($i = 0 ; $i < 16; $i++){
if( ($x&(1<<$i)) != 0 ){
array_push($ar, (1<<$i));
// if you need positions; you should use it instead of above line
//array_push($ar, ($i+1));
}
}
return $ar;
}
print_r( getArray(76) );
Output:
Array (
[0] => 4
[1] => 8
[2] => 64
)
The alternate output will be (if you use array_push($ar, ($i+1));)-
Array
(
[0] => 3
[1] => 4
[2] => 7
)
Explanation:
In binary 76 presents 00000000 01001100 in 16 bit. I ran a loop from Least Significant Bit (LSB) to Most Significant Bit (MSB) (0-16). In each loop, I'm generating a new number which contains only i'th bit as 1 and rest of the bits are 0. To generate it I used shifting operator (1 << i) which is actually 2^i. Now I did a bit wise AND operation between x and the new number. If this operation returns any nonzero number that means i'th bit of x is 1 and I'm pushing that position/value inside the array. Finally I'm returning that arry.

How to convert byte array to integer in php?

I have seen a code that converts integer into byte array. Below is the code on How to convert integer to byte array in php 3 (How to convert integer to byte array in php):
<?php
$i = 123456;
$ar = unpack("C*", pack("L", $i));
print_r($ar);
?>
The above code will output:
//output:
Array
(
[1] => 64
[2] => 226
[3] => 1
[4] => 0
)
But my problem right now is how to reverse this process. Meaning converting from byte array into integer. In the case above, the output will be 123456
Can anybody help me with this. I would be a great help. Thanks ahead.
Why not treat it like the math problem it is?
$i = ($ar[3]<<24) + ($ar[2]<<16) + ($ar[1]<<8) + $ar[0];
Since L is four bytes long, you know the number of elements of the array. Therefore you can simply perform the operation is reverse:
$ar = [64,226,1,0];
$i = unpack("L",pack("C*",$ar[3],$ar[2],$ar[1],$ar[0]));
In order to get a signed 4-byte value in PHP you need to do this:
$temp = ($ar[0]<<24) + ($ar[1]<<16) + ($ar[2]<<8) + $ar[3];
if($temp >= 2147483648)
$temp -= 4294967296;

Categories