Get all contents of stream socket with fgets() in blocking mode - php

In order to complete the handshaking for Websockets in ssl, the socket must be read in blocking mode. Using stream sockets, communication is done from the php backend with the (javascript) client using fwrite() and fgets(). In blocking mode, fgets() will wait until the next line comes in, and grab one line. Once the socket connection is made, the client sends the PHP some headers so that the handshake can be completed. The problem is, I can't think of a way to find where the end of the headers are, since the order depends on the browser being used.
I used this work around for chrome (since the sec-websocket-extensions line is the last header sent)
stream_set_blocking($lsSocketNew, true);
$lcHeader = "";
while($lcLine = fgets($lsSocketNew)){
$lcHeader .= $lcLine;
if(strstr($lcLine, "Sec-WebSocket-Extensions")){
break;
}
}
but this doesn't work in other browsers like firefox, where this header is the first one sent. :P
(I think fread() is supposed to do what I am looking for -- in blocking mode it is supposed to get "everything" on the socket when it comes in... but when I tried fread instead, it was returning a blank string. :P stream_get_contents() was the same )

Although I can't give you a PHP advice, there is a couple of things that you may want to consider:
I. What kind of "everything" are you looking for? There are no message borders in TCP so "everything in the stream" is equivalent to "random ordered amount of data". Unfortunately, you aren't going to magically read all HTTP headers and stop there.
II. Given point I, you have to find something that separates HTTP headers from an HTTP body. This is actually rather simple, because the headers end with a blank line. So, just read the data until you receive CRLF CRLF*. In PHP you will most probably see CRLF as \n, though this can depend on the OS.
III. If you're implementing websockets, using fgets is questionable, because the rest of the protocol (after HTTP handshake) is binary. You may want to use dedicated PHP's sockets module and socket_recv instead of fread. I can't say how these two functions differ, but socket_* functions are just a wrapper around BSD sockets which are implemented in a wide variety of languages. Since they're mostly language agnostic, you will find more support and tutorials in the internet.
* Per the HTTP standard:
CR = <US-ASCII CR, carriage return (13)>
LF = <US-ASCII LF, linefeed (10)>

Related

Trapping line of code that emits first character

Suddenly, an application isn't any longer able to output ZIP files. An inspection revealed the cause: The first character of the ZIP is a blank, which breaks the ZIP format spec.
To track down this problem, I enabled CStatementTracer, which prints each line of executed code to a log file. Didn't help. [Remark: declare(ticks=1); doesn't seem to trap each line of executed code]
I then set an output handler like so:
function callback( $buffer ) {
$deb = print_r( debug_backtrace(), TRUE );
file_put_contents( './statementTrager.log', $deb );
return $buffer;
}
ob_start("callback", 1 );
Unfortunately, this handler isn't called at all.
Q: Does a generic / canonical solution exists, which identifies the file / line of PHP-code, which emits the first character.
A solution, that finds the loc whatever other code gets executed.
Remarks:
Not even a single PHP file is closed using ?>
Meanwhile I found the suspicious like of code: A blank in front of a starting
Still, I'd like to get hints regarding a programmatic solution. Preferrably a solution written in pure PHP.
https://linux.die.net/man/1/strace is probably the most reliable tool to find out where the output comes from. Assuming you are on Linux. There must be similar tools for other platforms.
Although it will not give you the line of the php code, you can analyse the context of system calls made before and after the offensive character was sent. Usually it is enough to identify where the problem originates.
It is quite time consuming process though. Should be used as the last resort.

PHP unread_bytes work in PHP 5.3 but not in PHP 5.4

I have a problem with a connection to a telnet-server using PHP sockets. I've a finished telnet class, but on my other server did that class not work because of the stream_get_meta_data unread_bytes value. Does PHP have changed that in Version 5.4? I can't find what about this change.
The code that i use:
$buff = '';
while (!feof($this->socket)) {
$buff .= fread($this->socket, 1024);
$stream_meta_data = stream_get_meta_data($this->socket);
if ($stream_meta_data['unread_bytes'] <= 0)
break;
}
Can anyone help me or say me, what can i change?
You didn't clearly state what your code snippet is supposed to do:
read bytes until the socket connection is shut down, or
read bytes that are available at the moment, on a live connection.
But your comment feof() dont work correctly suggests that you're after 2., since a feof() check would be sufficient for 1.; cf. the comment from Wez to the "Not a bug" unread_bytes always 0:
unread_bytes is the number of bytes remaining in PHPs buffering layer
after the last read.
If you have consumed all data from the buffer
on a prior read, unread_bytes will remain at zero until you next read
a chunk of data from the network.
So, unread_bytes should not be
used to determine if more data is pending; you should use either:
feof() to detect end of file.
Don't forget that you
can use non-blocking mode here. PHP 4.3 has a new function
called stream_select() which behaves like socket_select() from the
sockets extension, but works on all files returned by fopen() and
fsockopen(). You can use it to test which files are ready for
reading/writing and also specify a timeout.
So, if you want 2., you can use stream_select() or socket_select().

Send SMS containing 'æøå' with AT commands

I'm making a SMS sending function for at project i'm working on. The code works just fine, but
when i send the letters 'æ-ø-å-Æ-Ø-Å' it turns to 'f-x-e-F-X-E'.
How do i change the encoding so that I can send these letters?
This is my code:
<?php
include "php_serial.class.php";
$html = $_POST['msg'];
$serial = new phpSerial;
$serial->deviceSet("/dev/cu.HUAWEIMobile-Modem");
$serial->deviceOpen();
$serial->sendMessage("ATZ\n\r");
// Wait and read from the port
var_dump($serial -> readPort());
$serial->sendMessage("ATE0\n\r");
// Wait and read from the port
var_dump($serial -> readPort());
// To write into
$serial->sendMessage("AT+cmgf=1;+cnmi=2,1,0,1,0\n\r");//
$serial->sendMessage("AT+cmgs=\"+45{$_POST['number']}\"\n\r");
$serial->sendMessage("{$html}\n\r");
$serial->sendMessage(chr(26));
//wait for modem to send message
sleep(3);
$read=$serial->readPort();
$serial->deviceClose();
$read = preg_replace('/\s+/', '', $read);
$read = substr($read, -2);
if($read == "OK") {
header("location: index.php?send=1");
} else {
header("location: index.php?send=2");
}
?>
First of all, you must seriously redo your AT command handling to
Read and parse the every single response line given back from the modem until you get a final result code for every single command line invocation, no exceptions whatsoever. See this answer for more details.
For AT+CMGS specifically you also MUST wait for the "\n\r> " response before sending data, see this answer for more details.
Now to answer your question about æøå turning into fxe, this is a classical stripping of the most significant bit of ISO 8859-1 encoding (which I had almost forgotten about). This is probably caused the default character encoding, but since you always should be explicit and set the character encoding you want to use in any case, investigating that further is of no value. The character encoding used for strings to AT commands is controlled by the AT+CSCS command (see this answer for more details), run AT+CSCS=? to get a list of options.
Based on your information you seem to using ISO 8859-1, so running AT+CSCS="8859-1" will stop zeroing the MSB. You might be satisfied with just that, but I strongly recommend using character encoding UTF-8 instead, it is just so vastly superior to 8859-1.
All of that failing I am quite sure that at least one of the GMS or IRA encodings should supports the æøå characters, but then you have to do some very custom translation, those characters will have binary values very different from what is common in text elsewhere.

PHP: Sockets, socket_read() only returns 1st character

I'm new to socket programming, I'm just starting to play around with a multi user server script. The problem comes with reading a socket, if my response is
"A, something or other"
socket_read only gives me "A"
Any idea why this may be occuring?
if (false === ($input = socket_read($clients[$i], 2048, PHP_BINARY_READ))) {
Source: http://pastebin.com/dEvYLUfV
If I'm not mistaken, socket_read only reads what data is currently available, and perhaps your PHP is running faster than your server socket (and is trying to read the data before it's available).
What you should do is add some kind of header to your message, which indicates the length of the expected message. Then, you keep "socket_read"ing until you've read that many bytes.

Read constant UDP stream in php

how do i go about reading data being sent almost constantly to my server.
the protocol is udp. if i try to read in a while(1) loop, i dont get anything. it seems like the read will only echo once all the reading is done. so it waits till the loop is done reading which it will never be. i want the socket_read to echo immediately when it gets the data. here is the code that doesnt work. thanks in advance.
<?php
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($sock, $local, $port) or die('Could not bind to address');
//this is where the reading loop should go.
while(1)
{
echo socket_read($sock,1024);
}
socket_close($sock);
?>
Try calling flush() immediately after that echo statement.
Something like this might help:
do {
echo socket_read($handle,1024);
$status = socket_get_status($handle);
} while($status['unread_bytes']);
OR
while ( $buffer = #socket_read($sock,512,PHP_NORMAL_READ) )
echo $buffer;
The PHP manual entry on socket_read() is a little vague when it comes to how much (if any) internal buffering it's doing. Given that you are passing 1024 in for the length, that specifies that it should return after receiving no more than 1024 bytes of data.
Disclaimer: the following is just speculation, as I have no knowledge of the internal implementation of socket_read().
If the socket_read() function is using its length parameter as a hint for an internal buffer size, you might see bad performance with small UDP packets. For example, if socket_read() waits for 1024 bytes of data regardless of the size of the packets, if you are constantly receiving 60 byte UDP packets it'll take a while for the buffer to fill and the function to return.
(Note: after looking up the "unread_bytes" field mentioned by Tim, it looks like PHP does keep internal buffers, but it makes no mention of how large or small those might be.)
In this case, socket_read() will return larger chunks of data once its buffers fill to reduce processing resource consumption, but at the expense of higher latency. If you need the packets as past as possible, perhaps setting a lower length field would work. That would force socket_read() to return sooner, albeit at the expense of executing your loop more often. Also if you set the length too low, your socket_read()'s might start returning incomplete packets, so you'll have to account for that in your code. (If that matters for your application, of course.)
I needed to call ob_flush();. Never even heard of it before. turns out my problem wasn't the loop, but the fact that php naturally waits till script is done before actually sending the internal buffer to the web browser. calling flush(); followed by ob_flush(); will force php to send whatever buffer it has stored to the browser immediately. This is needed for scripts that will not stop (infinite loops) and want to echo data to the browser. Sometimes flush() doesn't work as it didn't in this case. Hope that helps.

Categories