php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #52374 socket_read(): PHP_NORMAL_READ against user defined string
Submitted: 2010-07-19 02:20 UTC Modified: 2010-07-19 03:04 UTC
Votes:2
Avg. Score:4.5 ± 0.5
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:2 (100.0%)
From: bastard dot internets at gmail dot com Assigned:
Status: Open Package: Sockets related
PHP Version: 5.3.2 OS: any
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2010-07-19 02:20 UTC] bastard dot internets at gmail dot com
Description:
------------
With the assumption that the PHP_NORMAL_READ flag can be used to basically read in line-by-line, can a 4th optional function argument be added to allow users to define what exactly denotes an end of line for their chosen protocol?  If this 4th parameter is not passed by the user, socket_read() could default to it's current behavior.

With PHP_NORMAL_READ set, socket_read() now stops and returns on any of the first "\r", "\n", and presumably "\0" characters found.  Because protocols would more often use a different character or character chains to denote end of line - such as HTTP's "\r\n" - allowing the user to pass in "\r\n" to tell socket_read() where to stop and return would help save extra code to correctly handle message parsing, or having to confirm and discard any useless character socket_read() grabs next.

Also, the current behavior of socket_read() is to consume and return that "end of line" character, which is good.  If the above is implemented, the function should also consume and return everything up to and and including that user defined string, to avoid infinite loops.

Test script:
---------------
// read in line-by-line, echoing the first ord and last ord of each line just to show my point

$conn = socket_accept($s_socket);
socket_set_nonblock($conn) OR
	trigger_error("Failed to set non-blocking for accepted connection!", E_USER_ERROR);
for($current_line = ''; 1;) {
	$current_line = socket_read($conn, 4096, PHP_NORMAL_READ);
	if ($current_line == '') {
		break;
		}
	echo "[Start ord at pos 0: ".ord($current_line[0])."; End ord at pos ".(strlen($current_line) - 1).": ".ord($current_line[strlen($current_line) - 1])."]: $current_line\n";
	}


Expected result:
----------------
With the optional 4th function parameter, the read behavior could be controlled by the user.  For example if a client connected with an HTTP request, socket_read($conn, 4096, PHP_NORMAL_READ, "\r\n") would return the current header.  The next iteration of socket_read() would return the next header.  And, if socket_read() returned only "\r\n", this would denote end of headers section.

Actual result:
--------------
The test script above shows the undesirable behavior if using something like HTTP to connect to this server.  Line 'echo "[Start ord at pos...' produces an extra line each time.  This is because socket_read() stopped and returned at the first encounter of "\r" in each header line, and on the next read, stopped and returned at the first encounter of "\n", which was the very next character in the header line.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-07-19 03:04 UTC] bastard dot internets at gmail dot com
Note: on the echo line, you may want to replace the end '$current_line\n' with '".trim($current_line)."\n";'.  Because of all the extra line breaks and carriage returns echoed directly from the read text, the original example might output a bit oddly.
 [2010-09-14 18:20 UTC] recycling dot sp dot am at gmail dot com
In most text protocols, the end of line is written "\r\n" (See http, POP3,...). Consequently, it requires two consecutive calls using socket_read() to handle answers from these protocol. The latter call is only done to bypass the '\n'.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Sun Nov 17 12:01:34 2019 UTC