I am trying to write Python code to PHP. But I couldn't PHP pack format equivalent to Python pack format
Python:
format = "!LLLLQ"
mystr = struct.unpack(format, str)
I am using like this
$mystr = unpack("!LLLLQ", $str); // But its not working
Because there is no ! or Q in PHP pack.
Is there anyway to achieve that?
Format codes for Python: https://docs.python.org/2/library/struct.html
Format codes for PHP: http://www.php.net/manual/en/function.pack.php
Thanks!
The following sequence:
!LLLL
represents 4 unsigned longs (32 bit) in big endian format. In PHP this would be:
NNNN
However, the Q at the end is problematic. It represents an unsigned long long (64 bit). PHP's pack function doesn't offer unsigned long longs ( Correct me if I'm wrong).
If you unpack the 8-byte unsigned long long using two 4-byte unsigned longs (NN format in PHP), then you can bit-shift the first long 32 bits and add that to the second long to recover the 8-byte unsigned long long. In Python,
In [49]: import struct
In [50]: c = 12345678912345678912
In [51]: struct.pack('!Q', c) # this is the packed string
Out[51]: '\xabT\xa9\x8f\x81e$#'
# unpack the string using `NN` in PHP
In [52]: a, b = struct.unpack('!LL', struct.pack('!Q', c))
In [53]: a, b
Out[53]: (2874452367L, 2170889280L)
This bit-shifts the first number by 32-bits then adds it to the second number.
In [54]: (a<<32)+b
Out[54]: 12345678912345678912L
And this shows that the original number c is recovered:
In [55]: assert (a<<32)+b == c
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 have to unpack a struct in PHP which where written into a fifo.
The struct orginal was created by a Qt application and looks like following:
typedef struct {
float32_t fNumberOne;
uint16_t uIntOne; //maybe padding for alignment?
bool_t myOneBitBool;
float32_t fNumberTwo;
} mystruct;
Now, the struct was serialized to write it into a fifo / named-pipe, so that 'the PHP' can read the fifo and unpack() the struct.
If you read the fifo, you will get a string. This string you can substr() to get the (in this example) 4byte for the first float fNumberOne. And if you get your substring you can unpack() this with parameters like "f" for float. This works fine for me.
But, as you can see here there are 1 32bit float, 1 16bit int, our 1 bool that only needs 1bit and another 32bit float.
So my question is, if I get my first float and the first 16bit int correctly (byte 1-4 and 5-6) and, how do I get my bool bit out of this struct string (inside position 7?)? And what does the compiler do with the other 15 bits between the bool and the second float(byte rest of 7 and 8)? Are the next following bits are the second float or are they unused? Or does there help any padding to tell the compiler that he have to use another 32bit container?
Or better, how does the struct-string looks on binary level?
For further information, the compiler is not configured at this settings. It is all at standart settings.
many thanks in advance
If you're using C++11, alignas() might be what you're looking for
I want to send JSON messages from a PHP script to a C# app over a network connection using PHP Sockets.
Usually, for binary protocols, the first 4 bytes of every message must be an integer which represents the length (how many bytes) of the message.
In C# I prefix every message with an integer that tells the length of the message as follow:
byte[] msgBytes = UTF8Encoding.UTF8.GetBytes("A JSON msg");
byte[] prefixBytes = BitConverter.GetBytes(msgBytes.Length);
byte[] msgToSend = new byte[prefixBytes.Length + msgBytes.Length];
Buffer.BlockCopy(prefixBytes, 0, msgToSend, 0, prefixBytes.Length);
Buffer.BlockCopy(msgBytes, 0, msgToSend, prefixBytes.Length, msgBytes.Length);
As I understand, in PHP the function socket_send only accept strings. So, how can I do the same prefixing in PHP 5.x?
Update: I posted a follow-up question on how to process such prefixed data when received from a network socket.
In PHP strings are binary.
So you need to encode the integer length value as the binary representation of an unsigned integer as a 4-char (4 Octets; 32 bits) string. See pack:
# choose the right format according to your byte-order needs:
l signed long (always 32 bit, machine byte order)
L unsigned long (always 32 bit, machine byte order)
N unsigned long (always 32 bit, big endian byte order)
V unsigned long (always 32 bit, little endian byte order)
$string = pack('l', $length);
I guess you could use pack() to convert the number of bytes to a binary string. As you send your data over the network, you probably need to convert using the format "N" (unsigned long, always 32 bit, big endian byte order).
Here's an example:
$s="Hello World";
$length=pack("N",strlen($s));
socket_send($sock,$length.$s,4+strlen($s));
$x = pack("N", $num1).pack("N", $num2).$data;
I am trying to do it with
union unionchal {
struct ast{
unsigned long a;
unsigned long b;
char c[8];
} chal;
unsigned char response[16];
};
ast being the input and response being the output
It is meant to output yp¶ ‚¬þÖHpö€ì_± but gives ¶pyßêÈ)ÖHpöì_
I think it's got something to do with it being big endian byte order
Try using htonl on your integers before placing them into the structure. It will convert them into big-endian order. If you need 64-bit longs, see the discussion about it on SE.
I think it's got something to do with
it being big endian byte order
I also think so. You may use htonl() for example, to change the byte order on little-endian machines, or write your own byte-swapping function (but then you'll have to test yourself what the byte order of the host machine is).
Try using Boost Variant library.
Does anyone know of a class/library/etc. that can simulate 32 bit unsigned integers on a 32 bit platform in PHP?
I'm porting a C lib into PHP and it uses a lot of integers that are greater than the maximum for 32 bit signed int.
Try the BC Math Library, which "supports numbers of any size and precision, represented as strings."
Good luck!
Why can't you write
modulo(a+b,2^32)
or its PHP equivalent for a, b being "unsigned" integers you are trying to "unsigned integer add", similarly for subtract, multiply, divide, ...? You can of course hide this in a function add_unsigned to make the code a bit clearer.
Do you really need it? php will convert to float if you go out of bounds of an int.
http://www.php.net/manual/en/language.types.integer.php
var_dump(PHP_INT_MAX);
$int = PHP_INT_MAX;
var_dump($int + $int);