How to deal with binary data in php (not binary string)? - php

I wrote a C++ program which send POST data to php. My data is 123456 in binary, which is 0x0001e240.
My php file reads like
$f=fopen("php://input", "r");
if (!$f) die ("cannot open");
$data = fread($f, 4);
echo $data;
In my receiving program (in C++), I can see the echoed data is exactly 0x0001e240, so I believe php did accept a pure binary thing and saved into $data.
However, I want to get 123456 in php. I tried functions like bindec, hexdec, and so on but none of them works. How can I get the number from $data.
Also, do I need to care about endians in php? I am working locally now with windows environment but I will finally put my codes onto cloud.
Edit
$f=fopen("test.bin", "rb");
if (!$f) die ("cannot open");
$data = fread($f, 4);
echo $data;
where test.bin is a bin file which contains 0x0001e240. It seems that I got a string in $data which is composited with ASCII of 0x00, 0x01, 0xe2, and 0x40. How can I make them into a number value?

You can use unpack:
$num = unpack('n', $data);
Use an uppercase letter for an unsigned integer, and a v (or V) for little-endian. Yes, you have to worry about endianness. Just find out what it is and stick with it.

Related

Unexpected output with zlib_encode()

I'm trying to encode a chunk of binary data with PHP in the same way zlib's compress2() function does it. However, using zlib_encode(), I get the wrong encoded output. I know this because I have a C program that does it (correctly). When I compare the output (using a hex editor) of the C program against that of the PHP script below, I notice it doesn't match at all.
My question I guess is, does this really compress in the same way zlib's compress2() function does?
<?php
$filename = 'C:\data.bin';
$in = fopen($filename, 'rb');
$data = fread($in, filesize($filename));
fclose($in);
$data_dec = zlib_decode($data);
$data_enc = zlib_encode($data_dec, ZLIB_ENCODING_DEFLATE, 9);
?>
The compression level is correct, so it should match with the C program's encoded output. Is there a bug somewhere perhaps.. ?
Yes, zlib_encode() (with the default arguments), and uncompress() are compatible, and compress2() and zlib_decode() are compatible.
The way to check is not to compare compressed output. Check by decompressing with uncompress() and zlib_decode(). There is no reason to expect that the compressed output will be the same, and it does not need to be. All that matters is that it can be losslessly decompressed on the other end.

Why would 00 in data break UTF-16 encode / OpenSSL?

I'm working on a PHP login that takes an ID and logs them in elsewhere after the user is already authenticated. It works for every single ID except three of them, and they all have something in common: They all start with two zeros (e.g.: 0012).
I'm wondering if a double zero holds a special place in the encoding, like a delimiter? Or something to do with OpenSSL? It only breaks on those three. Doesn't matter if I treat the data as a string or an integer, it breaks both ways. Any ideas?
Code (modified slightly):
$fp = fopen("/OpenSSL-Win64/bin/myrsakey.pem", "r");
$priv_key = fread($fp, 8192) or die("File not found.");
fclose($fp);
$pkeyid = openssl_get_privatekey($priv_key);
$data = '0012'; // THIS DOESN'T WORK
$data = '0123'; // THIS DOES WORK
$data = '1234'; // THIS ALSO WORKS
$data = mb_convert_encoding($data, "UTF-16LE");
openssl_sign($data, $signature, $pkeyid, OPENSSL_ALGO_SHA1);
openssl_free_key($pkeyid);
Why would 00 in data break UTF-16 encode / OpenSSL?
The problem is not with OpenSSL. OpenSSL just works with data - it does not care about encodings. It might be related to openssl_sign. But its hard to tell at the moment.
Your problem is likely related to mb_convert_encoding. However, you never stated what the actual problem was.
How does it not work? Does it not work when verifying the signature on a Linux system? Did you check for the presence (or absence) of a Byte Order Mark (BOM)? That's a real problem, especially when working with Java.

Generating different content when creating picture on different machines

I want to create a picture from a passed binary string:
$fileName = uniqid().".".$imgType;
$fileName = "../tmp/".$fileName;
$f = fopen($fileName,'wb');
$picture = mb_convert_encoding($picture, "UUENCODE", "UTF-8");
fwrite($f, $picture);
fclose($f);
This works quite well on one machine with PHP 5.3.10-1ubuntu3.4. The picture is created properly. If try it on a different machine with PHP 5.3.19 the output is very strange. E.g. if you open the file with less then you will find \0 instead of desired ^# characters.
Why does this happen?
The binary string is part of a post request from a website using HTML5 Formdata encoded in both cases with UTF-8.
$picture = convert_uudecode($picture);

Fixed Length Record I/O in PHP

I have read a fixed length Record from the file Using php. I have given the code below.
$f = fopen('data.txt', 'rb');
while (!feof($f)) {
// read one segment of 52 bytes
if ($s = fread($f, 52)) {
// unpack the binary structure into an associative array
print_r(unpack('ieid/ieage/a20name/a20city', $s));
}
}
fclose($f);
Now i need to know How to write the Fixed Length record to the file. I searched in many web sites but still i didn't get the correct answer . How can i write the fixed Length record to the binary / text file ?

PHP write binary response

In php is there a way to write binary data to the response stream,
like the equivalent of (c# asp)
System.IO.BinaryWriter Binary = new System.IO.BinaryWriter(Response.OutputStream);
Binary.Write((System.Int32)1);//01000000
Binary.Write((System.Int32)1020);//FC030000
Binary.Close();
I would then like to be able read the response in a c# application, like
System.Net.HttpWebRequest Request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create("URI");
System.IO.BinaryReader Binary = new System.IO.BinaryReader(Request.GetResponse().GetResponseStream());
System.Int32 i = Binary.ReadInt32();//1
i = Binary.ReadInt32();//1020
Binary.Close();
In PHP, strings and byte arrays are one and the same. Use pack to create a byte array (string) that you can then write. Once I realized that, life got easier.
$my_byte_array = pack("LL", 0x01000000, 0xFC030000);
$fp = fopen("somefile.txt", "w");
fwrite($fp, $my_byte_array);
// or just echo to stdout
echo $my_byte_array;
Usually, I use chr();
echo chr(255); // Returns one byte, value 0xFF
http://php.net/manual/en/function.chr.php
This is the same answer I posted to this, similar, question.
Assuming that array $binary is a previously constructed array bytes (like monochrome bitmap pixels in my case) that you want written to the disk in this exact order, the below code worked for me on an AMD 1055t running ubuntu server 10.04 LTS.
I iterated over every kind of answer I could find on the Net, checking the output (I used either shed or vi, like in this answer) to confirm the results.
<?php
$fp = fopen($base.".bin", "w");
$binout=Array();
for($idx=0; $idx < $stop; $idx=$idx+2 ){
if( array_key_exists($idx,$binary) )
fwrite($fp,pack( "n", $binary[$idx]<<8 | $binary[$idx+1]));
else {
echo "index $idx not found in array \$binary[], wtf?\n";
}
}
fclose($fp);
echo "Filename $base.bin had ".filesize($base.".bin")." bytes written\n";
?>
You probably want the pack function -- it gives you a decent amount of control over how you want your values structured as well, i.e., 16 bits or 32 bits at a time, little-endian versus big-endian, etc.

Categories