php reading from sockets - php

I need to communicate with service by sending and getting xml through socket.
...
$fp = fsockopen("...", "..,", $errno, $errstr);
fwrite($fp, $xml);
echo stream_get_contents($fp);
but it's take too long to get output by stream_get_contents()
on the other hand fpassthru() prints output immediately but than script stuck for a few seconds before ending.
Is there any way to get data from socket?
PS: I can't use fread() because of not knowing the length of the response

You could go with fread - if you don't know the length of the response, just check for EOF in a loop:
while (!feof($handle)) {
$xml .= fread($handle, 8192);
}
fclose($handle);
fread() - reading stops (non-exhaustive list) if one of following conditions are met:
length bytes have been read
EOF (end of file) is reached

Related

How to show all output from fread socket unix in PHP?

I try show output from socket but the return is showed cut.
<?php
$socket = '/var/run/qemu-server/121.serial1';
$sock = stream_socket_client('unix://'.$socket, $errno, $errstr);
fwrite($sock, $argv[1] . "\r\n");
$data = '';
while ($buffer = fread($sock, 8128)) $data .= $buffer;
echo $data;
fclose($sock);
?>
I need this output:
{"VMid":"121","Command":"ls /","Output":"bin\nboot\ndev\netc\nhome\nlib\nlib32\nlib64\nlibx32\nlost+found\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nsnap\nsrv\nswap.img\nsys\ntmp\nusr\nvar\n"}
But it only returns:
{"VMid":"121","Command":"ls /","Output"
I tried "stream_set_read_buffer", "file_get_contents" and no success.
I presume here that the server has not had time to fully respond by the time you are polling. You can quickly test this theory by putting a sleep() after you send the instruction (fwrite) before you poll (fread). That's a test solution, not final (as you never know how long to "sleep" for).
What you need for sockets generally are a continuous poll (while loop that basically never ends, but under control so you can pause / exit etc), and continuous buffer read/write (append new content to a buffer; when you either reach the end of expected message OR you read the number of bytes you expect* remove that content from the front of the buffer and leave the remainder for next loop. You can, of course, bomb out at this point if you have everything you need and close the socket or return to polling later.
A common trick is to set the first two/four bytes of the message to the length of the payload, then the payload. So you constantly would poll for those two/four bytes and then read the content based of that. Probably not possible with another system like QEMU, so you'll need to look instead for...? EOL/NL etc?

byte position: file_get_contents vs fopen

I need some data from a specific byte in range in a binary file.
(concatenated jpegs, don't ask...)
So I have a offset and length data from an external API.
(I would guess that those are byte positions)
What works is the following:
$fileData = file_get_contents($binaryFile);
$imageData = substr($fileData, $offset, $length);
But i would rather not load the full file into memory and therefor tried fopen:
$handle = fopen($binaryFile, 'rb');
fseek($handle, $offset);
$imageData = fgets($handle, $length);
But that doesn't work. The data chunk is no valid image data.
So i assume i got the position wrong with fopen.
Any ideas on how the positions differ in substr vs fopen?
You wrote
The data chunk is no valid image data
"image data" - but in your code you call fgets() to read that data. That's wrong, as image is binary data, not a text file, so you don't want it read it by lines (docs):
fgets — Gets line from file pointer
This means fgets() would stop reading from file once it finds what it considers line end marker, which usually means stopping earlier and reading less than $length as there's pretty low chance such byte is not in the binary sequence.
So fgets() wrong method to use and this is the main issue. Instead you should pick less smart fread() (which does not know about lines and stuff, and just reads what you told). Finally you should fclose() the handle when you done. And naturally you should always check for errors, starting from fopen():
if ($handle = fopen($binaryFile, 'rb')) {
if (fseek($handle, $offset) === 0) {
$imageData = fread($handle, $length);
if ($imageData === false) {
// error handling - failed to read the data
}
} else {
// error handling - seek failed
}
fclose($handle);
} else {
// error handling - can't open file
}
So always use right tool for the task, and if you are unsure what given method/function does, there's always not-that-bad documentation to peek.
You can use file_get_contents, too. See this simple line:
imageData = file_get_contents($binaryFile, null, null, 0, $length);
And here the documentation of file_get_contents.

PHP fread file pointer position

I wanted to know how fread function moves the file pointer inside the file.
lets consider the following scenario:
<?php
$file=fopen(binary.txt,rb);
fread($file,0x594);
function(fread($file,0x1a8), ....); // some function w/ first argument as fread O/P
?>
brief overview of the code:
it will open a binary file in read only mode. I wanted to know if my understanding is correct or not:
The first invocation of the fread function will move the file pointer to position 0x594.
Since the position of the first byte in the binary file is considered 0, and fread function is reading 0x594 bytes, so what will be the new position of file pointer?
0x593 or 0x594?
The second fread function will start reading from the previous file pointer position. So, everytime, there is an invocation of fread function, the position of file pointer is preserved?
Which means, in a sequence of fread function invocations, each fread function starts reading bytes from the position of the file pointer set by the previous fread function?
in this case, it will start reading bytes from position, 0x594 to (0x594+0x1a8) or 0x73c ?
thanks.
You can investigate this yourself, using ftell(). The current position of the file pointer is an inherent part of the file infrastructure, and PHP is simply riding on top of libc/glibc's implementation of fopen/fread/etc...
However, consider this:
$fh = fopen('somefile.txt', 'r');
the file pointer will now be a position zero, because no data has been read.
$data = fread($fh, 500);
file pointer will now be at position 500, because it's read positions 0->499 (500 bytes) as part of the previous fread call.
$data = fread($fh, 0); // makes no sense to read 0 bytes, but hey...
still at position 500
$data = fread($fh, 1); // now at 501
$data = fread($fh, 2); // now at 503
etc...
Basically, use ftell() to check for yourself. ftell() is used to retrieve the CURRENT LOCATION of the filepointer, so you can use remember where you are. You can then use rewind(), fseek(), etc... to move the pointer all over, then jump right back to where you were without losing place:
$old_loc = ftell($fh); // 503
fseek($fh, 9999);
fseek($fh, 20000); // jump around a bit
fseek($fh, $old_loc); // back to 503, ready to resume reading where we left off.

Not getting entire response from popen

Hi I'm running a process with popen;-
$handle = popen('python scriptos.py', "r");
while (!feof($handle)) {
$data = fgets($handle);
echo "> ".$data;
}
And I'm only getting 3 lines from a process that returns 5 lines. I run this exact command in CLi and I will get more response. It's as if it stops reading early (it can take time to complete and updates the next 2 lines whilst working, it's a progress indicator).
Am I doing anything wrong? Is proc_open more suitable (i've started seeing if I can try that).
The two missing lines are probably being written to STDERR, and popen() only returns a pointer for STDOUT.
You can either get a pointer for STDERR using proc_open(), or change the popen() line to
$handle = popen('python scriptos.py 2>&1', "r");
to redirect STDERR to STDOUT, so they are included in your output.

PHP fread hangs when using SSL

I'm using fsockopen to connect to an OpenVAS manager and send XML. The code I am using is:
$connection = fsockopen('ssl://'.$server_data['host'], $server_data['port']);
stream_set_timeout($connection, 5);
fwrite($connection, $xml);
while ($chunk = fread($connection, 2048)) {
$response .= $chunk;
}
However after reading the first two chunks of data, PHP hangs on fread and doesn't time out after 5 seconds. I have tried using stream_get_contents, which gives the same result, BUT if I only use one fread, it works ok, just that I want to read everything, regardless of length.
I am guessing, it is an issue with OpenVAS, which doesn't end the stream the way PHP expects it to, but that's a shot in the dark. How do I read the stream?
I believe that fread is hanging up because on that last chunk, it is expecting 2048 bytes of information and is probably getting less that that, so it waits until it times out.
You could try to refactor your code like this:
$bytes_to_read = 2048;
while ($chunk = fread($connection, $bytes_to_read)) {
$response .= $chunk;
$status = socket_get_status ($connection);
$bytes_to_read = $status["unread_bytes"];
}
That way, you'll read everything in two chunks.... I haven't tested this code, but I remember having a similar issue a while ago and fixing it with something like this.
Hope it helps!

Categories