PHP write binary response - php

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.

Related

Get Zipfile as Bytes in php?

Using php, how can I read a zip file and get its bytes, for example something like
$contents = file_get_contents('myzipfile.zip');
echo $contents;
// outputs: 504b 0304 1400 0000 0800 1bae 2f46 20e0
Thank you!
file_get_contents gets the raw bytes, your echo outputs those raw bytes. If you expect to output a hexadecimal notation of the raw byte contents instead, use bin2hex:
echo bin2hex($contents);
If you want that arbitrarily grouped with a space every two bytes, you can do something along these lines:
echo join(' ', str_split(bin2hex($contents), 4));
(Note that this is all rather inefficient, modifying the entire, possibly many megabyte large file in memory. I'm expecting this is just for debugging purposes, so won't go out of my way to write super efficient code.)
file_get_contents() will return the exact contents of the file, so the format depends on the file type.
If you are looking for the byte size of the file you can get any available file information with the core SPL library's fileInfo class:
$info = new SplFileInfo('myzipfile.zip');
$bytes = $info->getSize();

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.

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

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.

MD5 hash discrepancy between Python and PHP?

I'm trying to create a checksum of a binary file (flv/f4v, etc) to verify the contents of the file between the server and client computers. The application that's running on the client computer is python-based, while the server is using PHP.
PHP code is as follows:
$fh = fopen($filepath, 'rb');
$contents = fread($fh, filesize($filepath));
$checksum = md5(base64_encode($contents));
fclose($fh);
Python code is as follows:
def _get_md5(filepath):
fh = open(filepath, 'rb')
md5 = hashlib.md5()
md5.update(f.read().encode('base64'))
checksum = md5.hexdigest()
f.close()
return checksum
on the particular file I'm testing, the PHP and Python md5 hash strings are as follows, respectively:
cfad0d835eb88e5342e843402cc42764
0a96e9cc3bb0354d783dfcb729248ce0
Server is running CentOS, while the client is a MacOSX environment. I would greatly appreciate any help in understanding why the two are generating different hash results, or if it something I overlooked (I am relatively new to Python...). Thank you!
[post mortem: the problem was ultimately the difference between Python and PHP's base64 encoding varieties. MD5 works the same between the two scripting platforms (at least using .hexdigest() in Python).]
I would rather assume that the base64 implementations differ.
EDIT
PHP:
php -r 'var_dump(base64_encode(str_repeat("x", 10)));'
string(16) "eHh4eHh4eHh4eA=="
Python (Note the trailing newline):
>>> ("x" * 10).encode('base64')
'eHh4eHh4eHh4eA==\n'
PHP and python use different base64 flavors:
PHP's base64_encode uses MIME (RFC 2045, see page 24)
Python's base64 module uses RFC 3548.
The problem seems to be that your base-64-encoding the file data, changing the structure of the binary data, in php I belive that it does not base_64 encode the file.
Give this a go:
def md5_file(filename):
//MD5 Object
crc = hashlib.md5()
//File Pointer Object
fp = open(filename, 'rb')
//Loop the File to update the hash checksum
for i in fp:
crc.update(i)
//Close the resource
fp.close()
//Return the hash
return crc.hexdigest()
and within PHP use md5_file and see if that works accordingly.
python taken from: http://www.php2python.com/wiki/function.md5-file/
Python appends a newline '\n' to the string when using .encode, therefore the input strings to the md5 function are different. This issue in the Python bug tracker explains it in detail. See below for the gist of it:
>>> import base64
>>> s='I am a string'
>>> s.encode('base64')
'SSBhbSBhIHN0cmluZw==\n'
>>> base64.b64encode(s)
'SSBhbSBhIHN0cmluZw=='
>>> s.encode('base64')== base64.b64encode(s)+'\n'
True

Categories