https://www.youtube.com/watch?
v=rQ46mQjLVyI
https://code-boxx.com/ajax-long-polling-php-mysql/
AJAX Long Polling In PHP MySQL
(Simple Example)
Last Updated: November 14, 2023
Welcome to a tutorial on how to do AJAX long polling. So you want
to run a real-time application, but web sockets are too complicated?
Or maybe you have heard of this long polling thing from somewhere
and wondering what it does?
To do AJAX long polling, set an AJAX function to repeat itself:
var poll = () => {
fetch("SCRIPT.PHP")
.then(res => res.text())
.then(txt => { /* DO SOMETHING */ poll(); })
.catch(err => poll());
};
poll();
This is extremely useful for processes that require “live updates” –
Live chat, live game scores, live news, etc… Let us walk through a
simple example of long-polling a game score update in this guide,
read on!
TABLE OF CONTENTS
Download & Notes
PHP MYSQL Long Polling
Extras
The End
DOWNLOAD & NOTES
Here is the download link to the example code, so you don’t have to
copy-paste everything.
Source code on GitHub Gist
(https://gist.github.com/code-boxx/263bbd7d94efad49a8ee4f68dbe4e09f)
Just click on “download zip” or do a git clone. I have released it
under the MIT license, so feel free to build on top of it or use it in
your own project.
AJAX LONG POLLING WITH PHP MYSQL
All right, let us now get into an example of AJAX long polling a live
game score using PHP MySQL.
PART 1) GAME SCORE TABLE
1-score.sql
CREATE TABLE `score` (
`time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`home` int(3) NOT NULL,
`away` int(3) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `score`
ADD PRIMARY KEY (`time`);
For a start, this simple table will store the game scores.
time Time at which the score is recorded. Primary key
and defaults to the current time.
home The score for the home team.
away The score for the away team.
PART 2) SERVER-SIDE PHP
2-score.php
<?php
class Score {
// (A) CONSTRUCTOR - CONNECT TO DATABASE
protected $pdo = null;
protected $stmt = null;
function __construct () {
$this->pdo = new PDO(
"mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB
_CHARSET,
DB_USER, DB_PASSWORD, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
}
// (B) DESTRUCTOR - CLOSE CONNECTION
function __destruct () {
if ($this->stmt !== null) { $this->stmt = null; }
if ($this->pdo !== null) { $this->pdo = null; }
}
// (C) GET LATEST SCORE
function getScore () {
$this->stmt = $this->pdo->prepare(
"SELECT *, UNIX_TIMESTAMP(`time`) AS `unix`
FROM `score` ORDER BY `time` DESC LIMIT 1"
);
$this->stmt->execute();
return $this->stmt->fetch();
}
}
// (D) DATABASE SETTINGS - CHANGE THESE TO YOUR OWN!
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHARSET", "utf8mb4");
define("DB_USER", "root");
define("DB_PASSWORD", "");
// (E) CHECK FOR SCORE UPDATES
if (isset($_POST["last"])) {
// (E1) SET TIME LIMIT
set_time_limit(30); // set an appropriate time limit
ignore_user_abort(false); // stop when long polling
breaks
// (E2) LOOP UNTIL THERE ARE UPDATES OR TIMEOUT
$_SCORE = new Score();
while (true) {
$score = $_SCORE->getScore();
if (isset($score["unix"]) && $score["unix"] >
$_POST["last"]) {
echo json_encode($score);
break;
}
sleep(1); // short pause to not break server
}
}
The PHP script looks complicated, but keep calm and look carefully:
(A, B, E2) When $_SCORE = new Score() is created,
the constructor will connect to the database. The
destructor closes the connection.
(D) Remember to change the database settings to your
own.
(E) The HTML page will send $_POST["last"] over, a
Unix timestamp of the last score update it got.
(E1, E2, C) This part then fetches the latest score from
the database in a loop. Respond only when there is an
updated score.
PART 3) CLIENT-SIDE HTML JAVASCRIPT
<!-- (A) HTML SCOREBOARD -->
<div id="sTime"></div>
<div id="sBoard">
<div id="sHome"></div>
<div id="sAway"></div>
<div id="sHomeT">Home</div>
<div id="sAwayT">Away</div>
</div>
<script>
// (B) LAST UPDATED TIMESTAMP
var last = 0;
// (C) AJAX LONG POLL
function poll () {
// (C1) FORM DATA
let data = new FormData();
data.append("last", last);
console.log("Fetch run", last);
// (C2) FETCH UPDATE ON SERVER RESPONSE
fetch("2-score.php", { method:"POST", body:data })
.then(res => res.json())
.then(data => {
// (C2-1) UPDATE HTML DISPLAY
document.getElementById("sTime").innerHTML =
data.time;
document.getElementById("sHome").innerHTML =
data.home;
document.getElementById("sAway").innerHTML =
data.away;
// (C2-2) NEXT ROUND
last = data.unix;
poll();
})
// (C3) CATCH ERROR - LOOP ON TIMEOUT
.catch(err => poll());
}
// (D) GO!
window.onload = poll;
</script>
As in the introduction, this does an AJAX request that is set to loop
itself infinitely to check for updates from the server.
A. HTML “scoreboard” to display the scores.
<div id="sTime"> The time when the score
update is received.
<div id="sHome"> Home team score.
<div id="sAway"> Away team score.
B. var last is used to hold the Unix timestamp of the
current score update.
C. poll() Will send last to the server to check for score
updates.
(C2 & C3) Notice how it loops itself endlessly to keep on
getting “live updates”.
EXTRAS
That’s all for this guide, and here is a small section on some extras
and links that may be useful to you.
CHANGING THE TIMEOUT LIMIT FOR FETCH
// (A) NEW ABORT CONTROLLER - 5 SECONDS
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(),
5000);
// (B) FETCH WITH ABORT CONTROLLER
fetch(url, { signal: controller.signal })
.then(res => res.text())
.then(txt => { ... });
Please take note that at the time of writing, the timeout
limit for fetch() depends on the browser.
Chrome seems to be 300 seconds and Firefox is 90
seconds.
The “official way” to set the timeout for fetch() is
seeming an AbortController. Credits to this post
on Stack Overflow.
(https://stackoverflow.com/questions/46946380/fetch-api-
request-timeout)
LIMITATIONS – LONG POLLING VS WEB SOCKET
Congratulations code ninja, you have mastered the arts of long
polling. But there is one thing you need to understand – It is not a
replacement for web sockets… Not even close. In a nutshell:
An instance of the PHP server script will run for every
client connection. If there are 1000 connections, the
server will spawn 1000 instances.
But when it comes to web sockets, we only create 1
instance of the server script to serve 1000 connections.
So yeah. Long polling may be a shortcut fix for servers that are not
too busy, but it is a far cry from a true solution for a real-time
system. Go invest some of your time in learning web sockets if you
are interested.
PUSH NOTIFICATIONS
Also, times have changed. We no longer live in the Stone Age of
the Internet, and there is something called “push notification”. Yep,
this makes a lot more sense when pushing out updates and news.
Check out the links below for more examples of push and
WebSockets.
LINKS & REFERENCES
PHP Push Notifications – Code Boxx
Add push notifications to a web app – Google Developer
PHP Live Chat – Code Boxx
NodeJS Live Chat – Code Boxx
THE END
Thank you for reading, and we have come to the end of this guide. I
hope that it has helped you with your project, and if you want to
share anything with this guide, please feel free to comment below.
Good luck and happy coding!
WEB SOCKETS AS A SERVICE
1. Pusher
2. Ably
3.