Hu: I’m going to read phpWebSocketServer<a-r> by Heinz Schweitzer, which is posted on Github.
H3S1: server/RFC_6455.php:
Hu: Some background: I was happy to have come across # an existing | library that provides a solution to building a totally custom web-server with Web-Sockets, using PHP. This is actually extremely rare, as most of the libraries available on Github for Web-Sockets are written in JS, and it’s incorrect to write a backend-server with JS. Schweitzer has high–quality documentation on his website, which encouraged me to check out his code<a-r>.
Considering that I’m also able to write this code, from scratch, I recognize I’m not dependent on Schweitzer. I’m only willing to check out his code, if it’s well-written enough that the time it takes me to interpret it, and adopt his ideas, is less than it takes me to come up with my own. So far, it seems like to be the case #, so I’m willing to do a deeper dive.
In RFC_6455.php, Schweitzer has some encode/decode functions that are in compliance with 5.2: Base frame protocol, in that spec-sheet by the IETF<a-r>. There’s quite a bit of Ph.D-level cryptography in the RFC spec-sheet, along with references to previous spec-sheets that more deeply define the encoding paradigm; all of this is very dense, and difficult to understand. Hopefully, by reading Schweitzer, we can deduce some further details about the the paradigm.
H4S1: Encoding and decoding the payload:
Hu: The payload # is the message unit that is sent, after a Web.Sockets-conn has already been established. Every msg, and, therefore, every transaction since the 2 starting-transactions, will include this payload, and a pair of en/decode-functions will be run for each payload-send, and payloads can be sent both ways, including simultaneously. Therefore, the following 2 functions, will be the most–called, in any Web.Socket-based,app:
H5S1: function Decode($frame) {
public function Decode($frame) {
// detect ping or pong frame, or fragments
$this->fin = ord($frame[0]) & 128;
$this->opcode = ord($frame[0]) & 15;
$length = ord($frame[1]) & 127;
if ($length == 0) {
$this->opcode = 8;
return '';
}
Hu: Schweitzer defines a function named Decode that takes a variable $frame as an argument. RFC.6455-5,1: In the WebSocket Protocol, data is transmitted using a sequence of frames. To avoid confusing network intermediaries (such as intercepting | proxies) and for security reasons that are further discussed in Section 10.3. Hu: A frame is the data that is sent, or a unit of that data, if that data exceeds the payload of a single | frame. The purpose of this function # is to decode the frame and return # a simple variable, $text, which contains a string that corresponds to the data.
Line 4: <geeksforgeeks.com a-r>: In PHP, this is declared like a variable | declaration (with the ‘$’ sign) even though it is a reserved | keyword. More specifically, $this is a special read-only variable that is not declared anywhere in the code and which represents a value that changes depending on the context of program execution. X.ref-<WP.MIC-H2S35,H3S6.H4S1>
<W3Schools>: The ord() function returns the ASCII value of the first | character of a string. ASCII = American Standard Code for Information Interchange<Wikipedia>
<?php echo ord("h")." ";
echo ord("hello"); ?>
Output: 104 104. Hu: The first line will set a bit that is in both ord($frame[0]) & 128,
H4S2: function Handshake($Socket, $Buffer) {
Hu: This function is called # from /server/webSocketServer.php:<H3S6.H4S5-H5S9> and is fed 2 arguments, which are variables, over there. What Server.php will feed over # is 1) a stream–obj and 2) a data | string, corresponding to an HTTP-req, from the client.
$Lines = explode("\n", $Buffer);
This line will split the data | string, $Buffer, by “\n”, which is supposed to be the new line character in PHP<a-r>into an array of strings # In the ensuing foreach | loop, if any line contains :, a secondary | explode will split the line by that : #, in its first to occurrence, into 2 | elements, and assign the resulting array to $Header. The 2 elements of $Header will be extracted and trimmed independently<a-r>: the strtolower version of $Header[0] will be assigned as a key, in an associative array named $Headers, while the second index, the value, to that key. For example: array(“Host”=>”server.example.com” would be one of the elements, of the assoc_array.
H5S1: } else if (stripos($Line, “get “)
Hu: If the line does not contain : but rather, contains get<manual><bad!>, Schweitzer will trigger a separate set of processings:
preg_match("/GET (.*) HTTP/i", $Buffer, $reqResource);
<php.net>: Searches subject
for a match to the regular expression given in pattern
.
preg_match(
string $pattern,
string $subject,
array &$matches = null,
int $flags = 0,
int $offset = 0
): int|false
<php.net>: 1) pattern: The pattern to search for, as a string. 2) subject The input | string. 3) matches: If matches is provided, then it is filled with the results of search. $matches[0] will contain the text that matched the full pattern, $matches[1] will have the text that matched the first captured parenthesized sub–pattern, and so on. Hu: The $subject, input string, or the search | target, is $Buffer, or what was fread over at # webSocketServer.php, and fed into the Handshake-func, containing the HTTP-req, from client. The pattern is “/GET (.*) HTTP/i”, and the obj that is filled, subsequently, is a declaration $reqResource-var. This obj is filled as an array, with always 2 elements. What is utile to Schweitzer, according to the very | next | line<anthro> is the element at the second index, so we are concerned with, from the docs, “the text that matched the first captured parenthesized sub-pattern“, however, it’s not quite clear, from the string, which text that would be<anthro-fail>. Some testing is needed, from my end. In any case, this $matches[1], or $reqResource[1], for Schweitzer #defd, is assigned to the variable $Headers[‘get’], after trim() is applied: <php.net>: This function returns a string with whitespace stripped from the beginning and end of string. Without the second parameter, trim() will strip these characters: ” ” (ASCII 32 (0x20)), an ordinary space. “\t” (ASCII 9 (0x09)), a tab. “\n” (ASCII 10 (0x0A)), a new line (line feed). “\r” (ASCII 13 (0x0D)), a carriage return. “\0” (ASCII 0 (0x00)), the NUL-byte. “\v” (ASCII 11 (0x0B)), a vertical tab.
H5S2:
foreach (['host', 'origin', 'sec-websocket-key', 'upgrade', 'connection', 'sec-websocket-version'] as $key) {
if (isset($Headers[$key]) === false) {
Next, Schweitzer has a function that will check for the presence # of several keywords, that are expected in an HTTP-req, and returns:
fwrite($Socket, "HTTP/1.1 400 Bad Request", strlen("HTTP/1.1 400 Bad Request"));
Hu: if any are missing. The exact syntactical relationship between the foreach, isset, and conditional, needs to be investigated further.
H3S2: websocketCore.php:
Hu: This file contains functions for 1) setting the HTTP.request-header<setHandshake>, 2) confirming the validity of the HTTP.request-response, from server<getHandshake>3) encoding a message for sending, across the protocol<encodeForServer>, 4) decoding a message, from the server<decodeFromServer>, and additional functions, that I have not decoded yet #
H4S1: get/set handshake:
H5S1: Building client.HTTP-header<anthro!>:
<WP.MIC-H2S81><righteous.road-start!>
return implode("\r\n", $req) . "\r\n\r\n";
Hu: Mmkek, so Schweitzer’s setHandshake function returns a string comprised of the joined | elements of an indexed | array, $req, and we can see from the lines that added | elements to req that each element is a string, and that each line corresponds to a line of an HTTP header<RFC-2616>
H5S2: Building.server.HTTP-header: Hu: Update, Websocketcore.php lacks this functionality; H5S2-again<fbno>: getHandshake:
$Lines = explode("\n", $Buffer);
Hu: The 3rd execution | line of the getHandshake function, which is called by _construct, after the fwrite.HTTP-req is sent, to validate the output # of fread, explodes the output, from fread, into: <php.net> explode: returns an array of strings, each of which is a substring of string
formed by splitting it on boundaries formed by the string | separator
.
explode(string $separator, string $string, int $limit = PHP_INT_MAX): array
Hu: After exploding, Schweitzer uses a series of for loops to str-parse<WP.MIC-H2S64> each string, in the array of strings #, to confirm that the connection is active #
H4S2: writeSocket:
final function writeSocket($message) {
if ($this->connected) {
fwrite($this->socketMaster, $this->encodeForServer($message));
}
}
Hu: This function takes # an argument, $message, and passes it to encodeForServer(), which will return an encoded version of this message as a string. The key | function in this function # is fwrite:
H5S1: fwrite<intermezzo, ch-40>
<php.net>: fwrite() writes the contents of data
to the file | stream pointed to by stream
.
fwrite(resource $stream, string $data, ?int $length = null): int|false
H6S1: Arguments: 1) stream: A file system | pointer resource that is typically created using fopen(). 2) data: The string that is to be written. 3) length: If length is an int, writing will stop after length bytes have been written or the end of data is reached, whichever comes first. Hu: Not sure what “write” means for php-here #, but the specification that write is going into a file | stream seems to indicate that it does not actually edit a static | file. <php.net>: fwrite() returns the number of bytes written, or false
on failure. Intermezzo.fin-v,1
The first argument taken by fwrite is $this->socketmaster, which is previously defined inside of function _construct, which is not | called in this function:
$this->socketMaster = stream_socket_client("$prot$Address$Port", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $context);
H6S2: stream_socket_client
<WP.MIC-H2S75,H3S2.H4S1><php.net>: Open Internet or Unix domain socket connection. Wikipedia: A Unix domain socket aka UDS or IPC socket (inter-process communication socket) is a data communications endpoint for exchanging data between processes executing on the same host operating system<a-r> Hu: Here, we are using an Internet socket | connection. // Paused 11/3/22, the code is too sloppy for me to continue making sense of the arguments into stream_socket_client.
Sample code from <php.net>:
<?php
$fp = stream_socket_client("tcp://www.example.com:80", $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($fp, "GET / HTTP/1.0\r\nHost: www.example.com\r\nAccept: */*\r\n\r\n");
while (!feof($fp)) {
echo fgets($fp, 1024);
}
fclose($fp);
}
?>
Hu: PHP.net is the only | truly | credible | source we have here, so we will be holding on to their words with the weight of gold # It uses 2 key functions also used by Schweitzer<anthro!> but in a much | condensed | format: fwrite, and stream_socket_client.
H6S3: Both Schweitzer and sample code<php.net> use fwrite, directly, to send the HTTP-request<consilience.100%, Watson*><fbno>. The file | stream, pointed to by stream, that is written to is, for <php.net>, the stream | object created by assigning the value of the output of the stream_socket_client built-in to a variable, now an obj # For Schweitzer, the stream | object for his HTTP.f-write # is $this->socketMaster, which was also assigned the value, of the prior stream_socket_client function call. It would be fallacious to say that stream_socket_client “opens” a connection, since that’s the job of the HTTP-request sent by fwrite, so perhaps it’s better to say, more precisely, that it defines a destination for the HTTP-request to be sent. Q: How does the URL, defined by Schweitzer<fml-incoming> as $prot$Address$port, which, without looking, is a tri-variable he self-assembles for just constructing a URL, with the correct domain, scheme<ie tcp://, ws://, or http://>, and port number, correspond, in his application, with the file that contains # the answer to the HTTP-request?
H7S1: For our hard-coded solution, it looks like # the condensed | code from <php.net> will suffice<WP.MIC-H2S84> H7S2: Testing the preceding code<php.net>:
Ran this page, actually loaded the page for example.com, which is an IANA-managed
reserved domain; IANA = Internet Assigned Numbers Authority. However, entering tcp://www.example.com:80 in the Brave browser, converts that string into a Google search.
Hu: The first line of the code establishes a stream | object; if $fp, the stream-obj, is false, which is what the function stream_socket_client returns, if the attempt to create this resource fails, then an error is returned. Otherwise, the condition executes the else lines, first to send an HTTP request into $fp, with a GET request specifying / and the example.com domain as the host. As long as <feof:>end-of-file on a file pointer<$fp># has not be reached, the loop will echo, <fgets>line by line, from the file pointer<$fp>, returning a string each time; presumably, what is retrieved, from the file pointer, is an HTML-file, since what was ultimately displayed, when this page is run, is the same webpage, as is on example.com:
HTTP/1.0 200 OK
Age: 363844
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Fri, 04 Nov 2022 08:35:28 GMT
Etag: "3147526947+ident"
Expires: Fri, 11 Nov 2022 08:35:28 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (nyb/1D07)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256
Connection: close
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
?>
Hu: We can see, at the top of the returned code is the standard HTTP-response, with response code 200=OK, followed by a line-by-line HTML, from example.com. Although we received HTTP-information back, we were listening on a tcp port, indicating that there is not mutual exclusivity between the 2 protocols<Turing> Note that the code continues to run, even if all arguments, except for the $address, are removed from stream_socket_client 11/4/22
H4S3: Sending the HTTP-request:
fwrite($this->socketMaster, $this->setHandshake($Address, $app));
Hu: This line, from the obscurely | titled _construct function, listed first in the code, is the one, that actually sends the HTTP-request, which will establish the Web.Sockets-conn. Again, as in the fwrite in H4S2 #, 2 arguments are required: the stream-obj, established by the earlier stream_socket_client function call; this generates a stream | resource that consists of multiple parameters, and all of this, as a package, can be processed by fwrite. Rather than passing a string that is the result of # an imploded | string from encodeForServer, it passes a string that is the result of a string from setHandshake. Indeed, both calls to fwrite, the only ones that the client ever needs to do, pass strings, to the same | target.
H4S4: Reading the HTTP-response:
Hu: The line for reading the HTTP-response, from the server, immediately follows the fwrite in _construct:
$buff = fread($this->socketMaster, 1024);
H5S1: After assigning the response # to the obj–var named $buff, Schweitzer calls his predefined getHandshake-func to validate the response, and returns false, in the _construct function, which I’ve deduced now<anthro-3>to be responsible for constructing the handshake on the client–side; more so than this, it is the function that will be called first, since the first HTTP-send is from the client side, so the involvement of the server, in this part, can be seen as a pseudo.func-call, within this function, for Schweitzer. The maximum of 1024 bytes, should be more.than-enough for the read.
H4S5: Selection of Scheme:
Feed to #<WP.MIC-H2S90>
H4S6: Selection of port:
Feed to #<WP.MIC-H2S89>
H4S7: The stream object:
Hu: Both the Schweitzer and<php.net> codes get quite a bit of mileage # out of the stream-obj, generated by stream_socket_client, which<php.net> calls $fp, and Schweitzer, within the class, $this->socketMaster. Both sides run fwrite to this obj, and either fread, or fget, to retrieve a response. If this obj contains false<Turing>, then checking it, conditionally, can also generate an error | response.
H4S8: Currently unknown: How to generate, or where to find, the $address that needs to be specified<Turing> in the argument used to create the stream-obj by stream_socket_client:
H5S1: First question, most fundamental, when we are connecting to a port<Turing> on our own server, is whether this port already exists, on our computer, or as a consequence of WAMP-install, or whether we have to somehow generate it. H5S2: If we don’t have to generate it, then finding this address is within the domain of the client–code. H5S3: If we do have to generate it, then this is within the domain of a server<WP.MIC-H2S75>
H5S4: Does Schweitzer specify, somewhere, that he’s actively generating an address, prescriptively, that becomes the stream.obj-address, the client uses, from the server side?
H5S5: PHP contains a complementary function, stream_socket_server, that allows a server to “create an Internet or Unix domain server socket”, in contrast to opening a connection, from the client.
H5S6: OK, so in server/webSocketServer.php, Schweitzer does stream_socket_server<anthro>, and 3 other thematic stream_socket functions, which we will review below in H3S6. We will also review # php’s server-side stream_socket functions in<WP.MIC-H2S75>, including the 4 used by Schweitzer H6S1: stream_socket_server in H2S75.H3S2-H4S2, H6S2: stream_socket_accept in H4S5, H6S3: stream_socket_get_name in H4S8, and H6S4: stream_socket_shutdown in H4S4.
H3S3: Client.side-code:
H4S1: Which server-file is specified in the client.side-HTTP,header:
H4S2: How a connection is established:
Hu: In /phpClient/testWithPHPSockets.php, which is Schweitzer’s PHP.client-test,page, a new obj of class-websocketPhp, which is defined in /phpClient/websocketPhp.php, with the arguments $Address, which is pulled from ‘../include/adressPort.inc.php’ as ‘ws://localhost:8095’:
$talk = new websocketPhp($Address.'/php');
Hu: I don’t quite understand the syntax of this obj-instantiation, possibly due to lack of deeper PHP-know. However, if I can ascertain that the origin used by Schweitzer is ‘ws://localhost:8095’, then I might be done pulling relevant information, from /phpClient #
H4S3: How a function call is made to encode an out-going message:
H3S4: Architecture:
Hu: Schweitzer has 2 separate client libraries, one built with PHP-only, and the other, primarily with the JS.built-in,Web.Socket-funcs. According to the read-me in /server<a-r>, these 2 libraries can be run independently<Watson-80%>.
H4S1: PHP-client setup:
Hu: Most likely, I’ll sidestep JS entirely for this project #; websocketCore.php<H3S2> is Schweitzer’s “base-class” for the PHP.front-end<fbno>, and implements the HTTP-requests, and the base data.ex-funcs. I should be able to get everything I need, from his project, just from this file, which H5S1: contains no includes<80% 11/3/22>.
H3S5: General review:
H4S1: Schweitzer’s code is not max-red:
Hu: Max.red-code contains only what is necessary, to complete or check an action, by logically minimizing the sufficient–components<Turing>. Schweitzer’s code is quite manual, in that he will check all the data that he is fed, without any well-considered meta | frames that can reduce, potentially by adding higher order conditionals. Over scaling #, his code will not be viable.
H4S2: Schweitzer’s class and function dependency architecture does not streamline cross-calling:
Hu: Schweitzer should have put more thought into designing his class and function dependency hierarchy; on this level, it looks like he copied an existing JS-library, which tend to be, at no fault to the lang-itself, poorly designed at this level as well. It’s quite possible, that he spent very little time on high.level-planning, and was too busy figuring out str-parse functions work #
H4S3: Schweitzer overcodes, because he doesn’t understand the concept of an MVP, and this deprives future users of pedagogical value:
H5S1: Some of the settings that Schweitzer establishes by default, including their constants, were meant to be discovered by users organically, which also indicates, that he doesn’t understand their action. This is a thematic problem in all American-software, and is endemic of the “one click solution” mentality # There’s a difference between performing a task, and getting rid of it.
H3S6: /server/webSocketServer.php:
Hu: This file requires /server/RFC_6455.php, located in the same folder, and uses the RFC_6455 trait, from that file:
H4S1: Use:
<W3>The use
keyword has two purposes: it tells a class to inherit a trait and it gives an alias to a namespace.
H4S2: $context = stream_context_create();
Hu: Based on the variable name, it’s clear that Schweitzer is, at least to an extent, adhering to the php-docs<convention!>. This line occurs in the 5th functional line of the body of # the first method in the webSocketServer class, which Schweitzer defines, from the outset. He proceeds to set context options to this $context resource-obj; all of the options set related to the ssl | wrapper, which we don’t need to worry about, at least yet, since we are building on localhost #
H4S3<fbno>: stream_socket_server:
$socket = stream_socket_server(“$usingSSL$Address:$Port”, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context);
Hu: Shortly after stream_context_create, in the first method in this class, named _construct, reminiscent of, at least in name, to a function of the same name in websocketCore.php<WP.MIC-H2S75> $Address takes one of the arguments taken by the parent _construct function, so it’s not clear, at this point, what the address is, or where it came from, in any function-calls # Likewise, the source of $Port is a bit unclear. H5S1: STREAM_SERVER_BIND<tips.n-tricks!><php.net, stream-constants>: Tells a stream created with stream_socket_server() to bind to the specified target. Server sockets should always include this flag. H5S2: STREAM_SERVER_LISTEN<php.net>: Tells a stream created with stream_socket_server() and bound using the STREAM_SERVER_BIND flag to start listening on the socket. Connection-orientated | transports (such as TCP) must use this flag, otherwise the server socket will not be enabled. Using this flag for connect-less transports (such as UDP) is an error. $context is pulled from the earlier H4S2, but again, we are ignoring this for now.
H5S1: Following stream_socket_server, the _construct function terminates, without much additional fanfare. Schweitzer assigns the value in the $socket variable to a couple of class items. No immediate processing is done, for example, to process any incoming HTTP-reqs.
H5S2: Calls of _construct in webSocketServer.php: N/A
H5S3: Calls of _construct elsewhere in codebase<fbno>: //
H4S4: isSecure:
Hu: A user-generated function, by Schweitzer:
private function isSecure(&$Address, &$port) {
$secure = false;
$arr = explode('://', $Address);
if (count($arr) > 1) {
if (strncasecmp($arr[0], 'ssl', 3) == 0 || strncasecmp($arr[0], 'wss', 3) == 0) {
$Address = $arr[1];
$secure = true;
$port = '443'; // default
} else {
$Address = $arr[1]; // just the host
$port = '80'; // default
}
}
/*
* ***********************************************
* extract port from $Address if given
* ***********************************************
*/
$arr = explode(':', $Address);
if (count($arr) > 1) {
$Address = $arr[0];
$port = $arr[1]; // overwrite default
}
return $secure;
}
Hu: underneath _construct, Schweitzer has a function that updates $port to 80, if ‘ssl’ or ‘wss’ are not found in the first 3-chars of $Address<Turing>, and $port to 443, if found. The first action line in the function defines a local | variable named $secure, that is also what is returned # by this function, and a default | value of false. In the next line, $Address, one of the arguments:
H5S1: &$ in function declaration:
Hu: According to a Stack.Over-flow consensus<rare!>, declaring a variable with the & prefix establishes a reference to the original | variable, such that any updates to that variable in the function, will also modify the variable, in its extra.function-existence, as opposed to making a local | copy of that variable | argument<Turing> This also confirms that $Address, and $port, are being drawn from somewhere.
H5S2: $arr = explode(‘://’, $Address);
Hu: The explode function will split $Address by the preceding separator, :// #, for as many instances of ://, but this should only be 1 in a valid | URL #
H5S3: if (count($arr) > 1) {
Hu: The count function will # count the # of elements in the $arr array; the minimum is 1, if $Address is not empty. If there is an instance of ://, and preceding text, there there will be 2 split strings, in the array, and this line will trigger true #
H5S4: if (strncasecmp($arr[0], ‘ssl’, 3) == 0 || strncasecmp($arr[0], ‘wss’, 3) == 0) {
Hu: Activated if H5S3 rings true, this line will compare the first 3 characters of the string element in index 0 position, of $arr, so the string before the first instance of ‘://” separator, with ‘ssl’, and separately, the same parameter #, with ‘wss’. If either one is equal, then this entire line triggers true #
H5S5: The next 3 lines, if H5S4 triggers true, will establish $Address as only the second | element in $arr, thereby stripping this $Address of the scheme<WP.MIC-H2S90>; moreover, the $secure variable, from the first action line, will be switched to true, and $port set to ‘443’. If H5S4 triggers false, $Address is set to $arr[1] anyways, and the port is set to ’80’.
H5S6: $arr = explode(‘:’, $Address);
Hu: The next line, Schweitzer denotes with a big | comment “extract port from $Address if given”. If a port setting is found #, he will overwrite the $port, previously set, with the original | port setting, in &$Address, and subsequently, strip $Address of its port setting, by setting its value equal to $arr[0], ->here<fbno>
At this point in the function, $Address will contain only the domain | name #
H4S5: $clientSocket = stream_socket_accept($Socket);
Hu: A buried line # in a bloated function, immediate after IsSecure, that takes no arguments<dubious!> and logs “Starting server”, but does not make a call to _construct. While a variable $a is true, and this variable is set to false never<suspect.at-best!>, stream_select, which accepts arrays of streams and waits for them to change status, and Schweitzer has this set to 1 | second. If this function returns -0, indicating no change, then something something, log, “Ping Clients”, but nothing significant, protocol-wise<80% 11/5/22>, so I will disregard stream_select for now, in my implementation. Subsequently,
H5S1: foreach ($socketArrayRead as $Socket) {
Hu: Previously, just in the while loop of this same function #,
$socketArrayRead = $this->Sockets;
I have no idea what the value is, that is being assigned to $socketArrayRead; however, since foreach is the operator #, we know that $socketArrayRead<anthro>is an array<Turing>, and $Socket is an element, in that array. The nomenclature, as a final clue, suggests that these are created | streams, such as those returned # by stream_socket_server<Turing> Anyways, Schweitzer is looping through this array of created | streams, and applying some actions, to each | of them #
H5S2: $SocketID = intval($Socket);
Schweitzer creates a variable $SocketID using intval, returning the integer value of $Socket, so, the resource #<flare/HTTP.client-test,int.server-2.php><fbno>
H5S3: if ($Socket === $this->socketMaster) {
Previously, $this->socketMaster was assigned the value of $socket, the output of the sole stream_socket_server, of this file. So Schweitzer is checking to see if this particular $Socket matches that one, and if so:
H5S4: $clientSocket = stream_socket_accept($Socket);
Hu: The first line in this if execution, which Schweitzer terms “new client”. H6S1:
stream_socket_accept(resource $socket, ?float $timeout = null, string &$peer_name = null): resource|false
<php.net>: Accept a connection on a socket previously created by stream_socket_server(). Returns a stream to the accepted socket connection or false
on failure. Hu: It looks like # the accepted socket connection becomes an obj, and a stream can be returned unto it<Biblical!><fbno> Davis<a-r>: In 1 Timothy 1:16, the substantive is (eternal) life, and it is the object of the preposition “unto,” where “unto” denotes the relation between believing on Jesus and eternal | life. Hu: The order of events, in this entire operation, has been unclear, and I’m not sure what the prompt is to trigger stream_socket_accept.
H5S5: if (!is_resource($clientSocket)) {
This next line uses is_resource to check whether $clientSocket is assigned a resource; presumably, the stream returned by stream_socket_accept is also a resource, and it was returned unto $clientSocket<anthro-2>. This line also provides a template for checking if any action was had, by the running of s_r_accept.
I implemented this into my initial test<WP.MIC-H2S88,H3S3.H4S4>
H5S6: $ipport = stream_socket_get_name($clientSocket, true);
I tried this on my local machine and received ‘[::1]:443’ as the output. <WP.MIC-H2S75,H3S2.H4S8>Schweitzer proceeds to process this $ipport variable with a function, defined in RFC_6455, as extractIPort, presumably, and it returns,
(object) ['ip' => $inIP, 'port' => ''];
H5S7: $this->Log(“New client connecting from $ipport on socket #$SocketID\r\n”);
H5S8: continue; // done so far for this new client
<php.net>: continue
is used within looping structures to skip the rest of the current loop iteration and continue execution at the condition evaluation and then the beginning of the next iteration.
H5S9: if ($this->Handshake($Socket, $dataBuffer) === false) {
Hu: This line comes after a previous mention of handshake; it seems like the later parts of this function have some interpreter ordering | issues<WP.MIC-H2S61> This conditional triggers continue if the Handshake<H3S1-H4S2>function, in RFC-6455, returns false.
H6S1: $Socket argument:
We are still under the jurisdiction # of the foreach loop<H5S1>, so this $Socket, is one of the array of sockets, previously defined.
H6S2: $dataBuffer:
$dataBuffer = fread($Socket, $this->bufferLength);
Earlier, before $dataBuffer is fed to Handshake(), it is defined, in fread of $Socket at a specified length of 40960, for Schweitzer, which will read up to this length # from the file pointer referenced by stream, which, in this case, is $Socket. At this point, $dataBuffer should contain # the read | string data from the $Socket stream-obj<WP.MIC-H2S80,H3S4>
H4S5: /server/runSocketServer.php: $server = new websocketServer($option[‘adress’], $logger, $option[‘certFile’], $option[‘pkFile’]);
Hu: According to Heinz over email, this line, in the other file, runs the _construct function in webSocketServer.php<tips-tricks>
References:
https://github.com/napengam/phpWebSocketServer/blob/master/server/RFC_6455.php
https://hgsweb.de/phpwebsocketDoc/book/index.php
https://www.rfc-editor.org/rfc/rfc6455
https://www.w3schools.com/php/phptryit.asp?filename=tryphp_func_string_ord
https://www.w3schools.com/charsets/ref_html_ascii.asp
https://en.wikipedia.org/wiki/ASCII
https://www.cs.uah.edu/~rcoleman/Common/Basics/ASCIICharSet.html
https://www.php.net/manual/en/function.implode.php
https://www.rfc-editor.org/rfc/rfc2616
https://www.php.net/manual/en/function.fwrite.php
https://www.php.net/manual/en/function.stream-socket-client.php
https://en.wikipedia.org/wiki/Unix_domain_socket
https://www.php.net/manual/en/function.explode.php
https://stackoverflow.com/questions/3957584/how-does-the-operator-work-in-a-php-function
https://www.php.net/manual/en/function.stream-socket-accept.php
Ruth Davis: https://baruchhousepublishing.com/unto-as-a-nonce-word-and-why-we-should-keep-unto-in-the-bible/
https://www.php.net/manual/en/control-structures.continue.php
https://www.php.net/manual/en/function.nl2br.php
https://www.php.net/manual/en/function.trim.php
https://www.php.net/manual/en/function.preg-match.php
Issues:
How is port set in _construct in /server/webSocketServer?