Creating buffers in PHP

Asked

Viewed 212 times

4

Staff need to create in PHP a buffer (string) from a data set (array) to send via socket. In this buffer i want all attributes of the set that are stored in it, obey its size.

Example: Whether I will store an integer value of the dataset in buffer, it will have to occupy 4 bytes within that buffer.

Code:

// Cria array
$bMsg3 = array (
    $at1 = 1,  
    $at2 = 2,
    $at3 = 3,
    $at4 = 4,
    $at5 = 5,
    $at6 = 6,
);

    $buffer[$at1]   = 32768;           /* Inteiro  = 4 bytes  */
    $buffer[$at2]   = 'HelloWorld';    /* String   = 10 bytes */
    $buffer[$at3]   = 123456;          /* Inteiro  = 4 bytes  */
    $buffer[$at4]   = 789101;          /* Inteiro  = 4 bytets */
    $buffer[$at5]   = 123852;          /* Float    = 4 bytes  */
    $buffer[$at6]   = 'teste';         /* String   = 5 bytes  */
                                      /* Total: 31 bytes     */

// Converte para string
$str = implode('', $buffer);

print "String: $str";

In that code, I create a array with multiple attributes, and I do the conversion to string and store in variable $str, giving a print in the $str, gets like this:132768HelloWorld123456789101123852teste. In this case the byte size of the string is 39 bytes, while it should be 31 bytes, how could I fix this?

  • 1

    to read a buffer with a certain size you must use fgets($handle, $tamanho_do_buffer)

  • Take a look here: http://php.net/manual/en/function.socket-read.php

  • But if you make the string occupy 4 bytes it will lose information because each letter represents 1 byte and in "stringTeste" will have 11 bytes

  • Note that at1 is an INTEGER and at3 is a FLOAT, both occupy 4 bytes. at2 is a string that occupies 11 bytes. However, by converting this to string, it should have a total of 19 bytes, right? The question is, how to convert the array to string, so that the string occupies 19 bytes? which is the total size of the array attributes.

  • How could it be 31 bytes? you have 5 more bytes of :, that is to say, 31+5 = 36.

  • I just put a better example.

  • But if you compute the bytes of a string, each number counts as 1 character and not as an integer. 132768!='132768'

  • Exactly, this number 132768 is an integer and is different from '132768' which is a string. Because it is integer, it occupies 4 bytes, that is, any integer occupies 4 bytes.

  • 2

    exactly, you said everything, converting everything to string will be string. What you can do is maybe convert everything to binary or hexadecimal. Maybe define a package structure (package frame)

  • Do you have any idea how I could convert into binary and put these binaries in the string? Because I need to put this data inside the string, with their respective sizes.

  • 1

    take a look at the php pack function

  • When the socket receives "42Hello24" how does he decide whether to receive a int, one string and another int ... or 2 int (4, 2) 2 string ("Hell", "o") and two more int??

  • @pmg When I receive this string in the C Program, which has a struct containing the same attributes in the sequence, I will copy the string’s memory block and play on the struct using the function memmove(args). For this reason I want each attribute to respect the size of its type in the string.

  • @Adirkuhn did not find much information about the pack function, could describe how it works in a response?

  • Why don’t you send the normal string and then deal with it in C?

  • It would take a lot more work than the solution I’m looking for, and the processes in the C program should be shorter, the time it takes php to create the message is no problem in my case. One thing personal, would you know why is printing a number 1 at the beginning of the string? q being it starts at 32768.

  • 2

    @Adirkuhn I solved the problem using the Pack function. Thank you very much.

Show 12 more comments

2 answers

4


As I mentioned in the comments the solution of using string to mount the package is wrong, because if you convert a number to string it will be treated as string by PHP then the int(40) that should occupy 4 bytes in memory will take 2 bytes as string '4' and '0'

You can use PHP’s pack / unpack functions to convert the information into byte array. Ai the arrays will have the sizes you are looking for, but you can still see that the array elements are int's and if you put it all together also will not be the result you seek.

<?php

$bMsg3 = array (
    $at1 = 1,  
    $at2 = 2,
    $at3 = 3,
    $at4 = 4,
    $at5 = 5,
    $at6 = 6,
);

    $bMsg3[$at1]   = 32768;           /* Inteiro  = 4 bytes  */
    $bMsg3[$at2]   = 'HelloWorld';    /* String   = 10 bytes */
    $bMsg3[$at3]   = 123456;          /* Inteiro  = 4 bytes  */
    $bMsg3[$at4]   = 789101;          /* Inteiro  = 4 bytets */
    $bMsg3[$at5]   = 123852;          /* Float    = 4 bytes  */
    $bMsg3[$at6]   = 'teste';         /* String   = 5 bytes  */
                                      /* Total: 31 bytes     */

echo "<pre>";
var_dump(unpack("C*", pack("i", $bMsg3[$at1])));
var_dump(unpack("C*", $bMsg3[$at2]));
var_dump(unpack("C*", pack("i", $bMsg3[$at3])));
var_dump(unpack("C*", pack("i", $bMsg3[$at4])));
var_dump(unpack("C*", pack("i", $bMsg3[$at5])));
var_dump(unpack("C*", $bMsg3[$at6]));

Upshot:

array(4) {
  [1]=>
  int(0)
  [2]=>
  int(128)
  [3]=>
  int(0)
  [4]=>
  int(0)
}
array(10) {
  [1]=>
  int(72)
  [2]=>
  int(101)
  [3]=>
  int(108)
  [4]=>
  int(108)
  [5]=>
  int(111)
  [6]=>
  int(87)
  [7]=>
  int(111)
  [8]=>
  int(114)
  [9]=>
  int(108)
  [10]=>
  int(100)
}
array(4) {
  [1]=>
  int(64)
  [2]=>
  int(226)
  [3]=>
  int(1)
  [4]=>
  int(0)
}
array(4) {
  [1]=>
  int(109)
  [2]=>
  int(10)
  [3]=>
  int(12)
  [4]=>
  int(0)
}
array(4) {
  [1]=>
  int(204)
  [2]=>
  int(227)
  [3]=>
  int(1)
  [4]=>
  int(0)
}
array(5) {
  [1]=>
  int(116)
  [2]=>
  int(101)
  [3]=>
  int(115)
  [4]=>
  int(116)
  [5]=>
  int(101)
}

So one of the possible solutions is to convert everything to hexa and send this package on the network.

<?php

$bMsg3 = array (
    $at1 = 1,  
    $at2 = 2,
    $at3 = 3,
    $at4 = 4,
    $at5 = 5,
    $at6 = 6,
);

    $bMsg3[$at1]   = 32768;           /* Inteiro  = 4 bytes  */
    $bMsg3[$at2]   = 'HelloWorld';    /* String   = 10 bytes */
    $bMsg3[$at3]   = 123456;          /* Inteiro  = 4 bytes  */
    $bMsg3[$at4]   = 789101;          /* Inteiro  = 4 bytets */
    $bMsg3[$at5]   = 123852;          /* Float    = 4 bytes  */
    $bMsg3[$at6]   = 'teste';         /* String   = 5 bytes  */
                                      /* Total: 31 bytes     */

echo "<pre>";
var_dump(unpack("H*", pack("i", $bMsg3[$at1])));
var_dump(unpack("H*", $bMsg3[$at2]));
var_dump(unpack("H*", pack("i", $bMsg3[$at3])));
var_dump(unpack("H*", pack("i", $bMsg3[$at4])));
var_dump(unpack("H*", pack("i", $bMsg3[$at5])));
var_dump(unpack("H*", $bMsg3[$at6]));

That will result in that, but to send you can join them all in a single string.

array(1) {
  [1]=>
  string(8) "00800000"
}
array(1) {
  [1]=>
  string(20) "48656c6c6f576f726c64"
}
array(1) {
  [1]=>
  string(8) "40e20100"
}
array(1) {
  [1]=>
  string(8) "6d0a0c00"
}
array(1) {
  [1]=>
  string(8) "cce30100"
}
array(1) {
  [1]=>
  string(10) "7465737465"
}

In C the package comes as an unsigned char, so we can have this example here to print the data. (using a small piece of the package)

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(void) {

    unsigned char pacote[] = { 0x00, 0x80, 0x00, 0x00, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x57, 0x6f, 0x72, 0x6c, 0x64 };

    struct pckt {
        int a;
        char b[10];
    };


    struct pckt *meu_pckt = (struct pckt*) pacote;
    char n[11];
    memcpy(n, meu_pckt->b, 10);
    n[10] = '\0';
    printf("%d\n", meu_pckt->a);
    printf("%s\n", n);

    return 0;   
}

Must print:

32768
HelloWorld
  • Here I am using the formats i and f, for integers and floats in the function pack(format,args...), and it worked perfectly. The only problem is that I did not find format for the Strings, you can tell me? Follow the command line: $str = pack("iiifa", $attribute1, $attribute2, $attribute3, $attribute4, $attribute5); NOTE: the last 'a' format takes only the first character of the string.

  • string is nothing more than characters represented by a number of the ascii table. I would choose to use H* as it becomes easier to work on C

  • when I put H* this error: http://pastebin.com/fYpTdfG8

  • unpack("H*", .....);

  • I used a* and it worked, thanks :D

1

I don’t know if it’s a good solution, but it should work.

    $array = array(
        (int)substr($str, 0, 4),
        substr($str, 4, 10),
        (int)substr($str, 10, 4),
        (int)substr($str, 14, 4),
        (float)substr($str, 18, 4),
        substr($str, 22, 5),            
    );
  • 1

    What is this doing?

  • It is converting some values to integer ((int)) and ensuring the variable size $str using the substr defining the initial and final position.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.