H2S121: An AJAX / PHP / MySQL live messaging w/ char-by-char paradigm.

<WP.MIC-H2S112> Reverse chron self.notes-dump, from 11/16/22 to a few days prior:

Hu: A socket is also just a file that you write to, which handles the storage, and may not be significantly more efficient. PHP to MySQL might also use a TCP connection, like sockets. MySQL in 2022 is probably significantly more optimized, by about a million orders of magnitude, than even the most advanced sockets, WebSockets. WebSockets in theory, is the best implementation, over time. I’ll take 10% slower, 10x less scalability, to use something that’s more proven.

H4S1: Decision to use MySQL as temp-storage between POST and GET<Turing>:

Hu: If setInterval checks once per second, and the echo on server.php occurs only when a POST is made, then the client-display is either going to miss it, or it will overwrite it, later. I need it to display the latest, and stop there # An interval refresh listener is not the stop as a stop block listener. The post echo, and the setInterval check on the other side, are 2 completely separate events. There is no precedent for a separate script being able to “catch” the output of a server, after a former script # posted to it; only that script can catch a response, within a small enough finite interval. What I need, therefore, given these limitations, is storage. The first event puts something in a storage, and the second event retrieves it. The file is not writing to itself to storage, the echo is ephemeral, and therefore, it’s not storage. Let’s go with the db-implementation for now, and then maybe switch to a base.less-f,write later. We’re back to cli-ser-ser-cli; one ser makes the write, and a separate one, called by client-display.php, makes the read, and echoes it.

H4S2: Decision to use POST, rt GET, in AJAX write to server-UPDATE<Turing>:

Hu: From I can see that my POST request is not in the right format. Look up some formats, but most likely, I’ll need a long string encoder, and decoder on the other end, to make a regular string. Either way, for these messages, I should be using POST.

H3S1: Client-send.php:

<!-- removed minlength="1" from textarea, for now -->
<textarea style="width:400px;min-height:100px;vertical-align: top;" type="text" onkeyup="live_message(), test_message()" id="message" maxlength="250"></textarea>
<input type="submit" name="submit" value="Done">
<p id="peen"></p>
<!-- Write an onkeyup triggered pull of all of element_ID=message, ie the text area
and use an AJAX post to post that to server.php, where the PHP side will "catch" this post-->

<script> function live_message() {
	var xhttp = new XMLHttpRequest();
xhttp.open("POST", "server.php", true);
var message = "message=" + document.getElementById("message").value;
<!-- document.write(message); -->
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
function test_message() {
	document.getElementById("peen").innerHTML = document.getElementById("message").value;
<!-- http://flare/client-send.php -->
<!-- dependencies:
	onkeyup-test.php worked(11/15 archive)
<!-- tests 
	20:21 11/16/22:
		setRequestHeader is working<80% 11/16>, message= sent as key, only value is written.
			Test passed: in coordination with server.php. 
		When a second char is typed, the entire msg is written to the db. 
			Test passed.
		When a period is typed, that punctuation is also added. 'ff.'
			Test passed. 
		Spaces, and chars after spaces, are stored fidelously:
			Test passed: ff. f
	Added document.write(message); to test message variable string validity. 
		Test passed: document.write appears on screen, with "message=[char]", where char
		is the first char input into textarea="message". 
	document.getElementById("peen").innerHTML = "peen", triggered in a function
	by onkeyup = function()
	Test passed:
		<p id="peen"> element displays "peen" in innerHTML, upon first keystroke, up. 
	Test failed: 
		document.getElementById("peen").innerHTML = document.getElementById("message").innerHTML;
		Nothing appears, upon onkeyup. 
			document.getElementById("peen").innerHTML = document.getElementById("message").value;
			Used .value rather .innerHTML to represent the value of current input, in text field. See refs:
<!-- refs:
	- https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_element_innerhtml
	- Confirms, should be a string: https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_element_innerhtml_p 

H3S2: Server.php:

<?php /* write a db-write, with the check being, that a write is being shown
in phpmyAdmin */
require 'C:\wamp64\www\flare\my.sql-inc\db.conn-inc.php';
echo 'Line<br>';
if(isset($_POST['message'])) {
	echo $_POST['message']; 
	echo 'test';
$sql = "UPDATE socket_conn SET test_return='{$_POST["message"]}' WHERE ID='1'";
echo $conn->error; ?>
<!-- http://flare/server.php -->
<!-- internal lib:
	'{$_POST["message"]}' --> 
<!-- test log: 
	$sql UPDATE works with a hard-coded string upon refresh: 11/16/22 20:20
	$_POST from client-send.php is WORKING, successful write to db upon 
	single char-write. -->

H3S3: Server-read.php:

<?php // write a db-select

require 'C:\wamp64\www\flare\my.sql-inc\db.conn-inc.php';

$sql = "SELECT test_return FROM socket_conn WHERE ID='1'"; 
$result = $conn->query($sql); 
$row = $result->fetch_assoc();
// var_dump($row);
echo $row["test_return"]; 
echo $conn->error; 
<!-- http://flare/server-read.php -->
<!-- test log: -->

H3S4: Client-display.php:

<p><button type="button" onclick="retrieve_more_msg()">Retrieve-msg</button>
| <button type="button" onclick="clear_msg()">Clear</button></p>
<p id="msg"></p>
function retrieve_msg() {
    const xmlhttp = new XMLHttpRequest();
    xmlhttp.onload = function() {
      document.getElementById("msg").innerHTML = this.responseText;
  xmlhttp.open("GET", "server-read.php");
<!-- There is no clear interval yet, so the effect of clear_msg is not permanent -->
function clear_msg() {
	document.getElementById("msg").innerHTML = 'no more msg';
function retrieve_more_msg(){
<!-- The millisecond interval is set to video consensus 30 frames/sec>
setInterval(retrieve_msg, 33);
<!-- http://flare/client-display.php -->
<!-- tests

H3S5: db-conn-inc.php:

$servername = "localhost";
$username = "root";
$password = "";
$dbname = "flare-db";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
	die("Connection failed: " . $conn->connect_error);
	} else {
	// echo "Connection successful!";

// echo 'test';

<!-- http://flare/my.sql-inc/db.conn-inc.php -->

<!-- test-log 
1:24 AM 10/30/22:
	URL test, db-conn test; created new db, swapped in db-name. 
		Connection successful! displayed, when this URL is visited. 

H3S6: Video walkthrough:

H3S7: Across the internet<Williams, a-r #p-f><fbno> considerations:


Some feedback for improvement and research:

  1. You should look at the “debounce” concept, there are some library implementations for JS, like in lodash. Debounce helps to reduce the amount of POST calls you make to the server, so for example rather than making a server call every keyup, you make no more than 1 call per some number of miliseconds.  Most of the time something like 200-300 milliseconds is typical from what I’ve seen. This reduces the load on the database, as UPDATE queries are rather expensive and will clear out any caches… remember that browsers/JS is single threaded, so having a heavy event loop will slow down the browser while they are typign, so the debounce helps to use less resources all around, client and server.
  2. around 14:30 in the video you talk about that making calls every 33 ms to GET the data is scalable because it happens only on the user’s local machine. However this is not true, the client is making a call across the internet to the server every 33 milliseconds (which is about as fast as the internet gets round trip, so you might even be making a new request before the first one even finishes), and with more users this will mean multiples of connections and GET queries the server has to handle every 33 milliseconds, which is a lot, and the database will quickly run out of connections/memory/etc since each connection used requires memory. (and you’re not using connection pooling on the PHP server).
  3. the client doing the GET will continue to make these calls for as long as the window is open, so even users who just leave their computer open to the page will still be making calls even if there is no data change, or even if that spot on the browser is visible to the user (e.g. it’s making calls even if the user doesn’t care.).. to make this more scalable, whenever an app is doing polling, developers typically use some kind of exponential backoff… e.g. it polls for data, then 30 ms it polls again, if there was no data change, it might poll 300ms next time, then 1s, then 3s, etc. up to some limit. until there is some data change, then it resets down to polling faster… this will also help to ensure that you only are making one request at a time, not sending a new request for data before one comes back.


Will read more carefully, but my initial response: I have considered the GET 30/s issue. In my local implementation, and keep in mind, what you are seeing in this video, is all happening on localhost, and my local MySQL in WAMP, so there’s no internet yet. I’m assuming you are talking about hypothetical future scenario, in which this GET will occur across the internet, either to a TURN server, or peer to peer. == Solution: when the web server has an update, that update is pushed; this can be done with WebSockets, POST, or a db-write to the user’s local db. Once the data is in the user’s local-db via one of these methods #, the user will continue the GET polling, to his local db, so the implementation remains unchanged, only what is updating the local-db. Will read your other words later, but this seems to be the main point at the moment. == In general, polling never has to be done across the internet, since all writes can occur as they happen, and so all writes can occur, in this format, into a storage, and the read-polls occur locally, to that storage, to produce the live update. I did this without sockets, but even with sockets, this should be the implementation. (edited) 


Leave a Reply

Your email address will not be published. Required fields are marked *