AJAX Long Polling – Simple Example With PHP MySQL

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 long polling, we essentially set an AJAX request to repeat itself:

  • var poll = () => {
  • fetch("SCRIPT.PHP", { method:"POST", body:DATA })
  • .then(res => res.text())
  • .then((txt) => { /* DO SOMETHING */ poll(); })
  • .catch((err) => { 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!

ⓘ I have included a zip file with all the example source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

QUICK SLIDES

 

TABLE OF CONTENTS

Download & Notes Long Polling Useful Bits & Links
The End

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • Create a database and import 1-score.sql.
  • Change the database settings in 2-score.php to your own.
  • Launch 3-score.html in your browser – Captain Obvious, AJAX calls will only work with http://, not file://.
  • Insert a dummy score into the score table, watch how AJAX long-polling update the page.
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, 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

All right, let us now get into an example of AJAX long polling a live game score using PHP MySQL.

 

STEP 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=latin1;

ALTER TABLE `score`
  ADD PRIMARY KEY (`time`);

For this example, we will just use a simple table to hold the game scores.

Field Description
time Time at which the score is recorded. The primary key, defaults to the current time.
home The score for the home team.
away The score for the away team.

 

 

STEP 2) SERVER-SIDE PHP

2-score.php
<?php
// (A) TIME LIMIT & ABORT
set_time_limit(30); // SET THE APPROPRIATE TIME LIMIT
ignore_user_abort(false); // STOP WHEN LONG POLLING BREAKS
 
// (B) DATABASE SETTINGS - CHANGE THESE TO YOUR OWN!
define("DB_HOST", "localhost");
define("DB_NAME", "test");
define("DB_CHAR", "utf8");
define("DB_USER", "root");
define("DB_PASS", "");
 
// (C) DATABASE CLASS
class DB {
  // (C1) CONSTRUCTOR - CONNECT TO DATABASE
  protected $pdo = null;
  protected $stmt = null;
  function __construct () {
    try {
      $this->pdo = new PDO(
        "mysql:host=".DB_HOST.";charset=".DB_CHAR.";dbname=".DB_NAME,
        DB_USER, DB_PASS
      );
    } catch (Exception $ex) { exit($ex->getMessage()); }
  }
 
  // (C2) DESTRUCTOR - CLOSE CONNECTION
  function __destruct () {
    if ($this->stmt !== null) { $this->stmt = null; }
    if ($this->pdo !== null) { $this->pdo = null; }
  }
 
  // (C3) 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(PDO::FETCH_ASSOC);
  }
}
$DB = new DB();
 
// (D) LOOP - CHECK FOR SCORE UPDATES
// WILL KEEP LOOPING UNTIL A SCORE UPDATE OR TIMEOUT
if (isset($_POST["last"])) { while (true) {
  $score = $DB->getScore();
  if (isset($score["unix"]) && $score["unix"] > $_POST["last"]) {
    echo json_encode($score);
    break;
  }
  sleep(1); // NOT TO BREAK THE SERVER. SHORT PAUSE BEFORE NEXT CHECK.
}}

The PHP script looks complicated, but keep calm and look carefully:

  • The user will send $_POST["last"] over, a Unix timestamp of the last score update they got.
  • Then, we fetch the latest score from the database.
  • Lastly, compare the database’s timestamp against the user’s timestamp
    • Send the update to the user if they have an outdated score.
    • Or continue to loop and check until there is a score update.

 

 

STEP 3) CLIENT-SIDE JAVASCRIPT & HTML

3-score.html
<!-- (A) HTML SCOREBOARD -->
<div id="scoreboard"></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);
 
  // (C2) FETCH
  console.log("Fetch run");
  fetch("2-score.php", { method:"POST", body:data })
  .then((res) => { return res.json(); })
 
  // (C3) UPDATE ON SERVER RESPONSE
  .then((data) => {
    // HTML DISPLAY
    let sb = document.getElementById("scoreboard");
    sb.innerHTML = `[${data.time}] ${data.home} - ${data.away}`;
 
    // NEXT ROUND
    last = data.unix;
    poll();
  }) 
 
  // (C4) CATCH ERROR - LOOP ON TIMEOUT
  .catch((err) => { poll(); });
}
 
// (D) GO!
window.addEventListener("DOMContentLoaded", 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) Dummy HTML “scoreboard” to display the scores.
  • (B) var last is used to hold the Unix timestamp of the current score update.
  • (C) We send last to the server, check for score updates.
  • (C3 & C4) Notice how it loops itself to keep on getting “live updates”.

 

 

STEP 4) TESTING

Go ahead, launch 3-score.html in the browser. Then insert new scores into the database and see how it updates in near real-time.

 

USEFUL BITS & LINKS

That’s all for this guide, and here is a small section on some extras and links that may be useful to you.

 

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 socket, we only create 1 instance of the server script to handle 1000 connections.

So yeah. Long polling may be a shortcut fix for servers that are not too busy, but it is a far cry as 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 how to do it, here’s a push tutorial on good old Google Developer.

 

 

BETTER EXAMPLES (WITH WEB SOCKETS)

 

INFOGRAPHIC CHEAT SHEET

How To Do AJAX Long Polling (click to enlarge)

 

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!

2 thoughts on “AJAX Long Polling – Simple Example With PHP MySQL”

  1. This worked great for what you designed it for, however, how does on display multiple rows rather than one?

    I want to show the last status of each user, let’s say there are 10 users total, each have a variety of status updates, but I just want to display the last status per unique user?

Leave a Comment

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