But, everything screwed up. My VPS server could not manage to handle the traffic with long polling. So, I changed the system to websockets with the help of Node.JS.
AJAX Long Polling is an interesting topic to learn, but do not use it in productional websites unless you have unlimited hosting resources.
I found a smarter solution for connecting PHP and Node.JS for real-time communication. You can see it here.
Need to create a real-time application with Javascript and PHP? Actually, there are some different ways to client-side to interact with the server in real time.
Short Polling and SSE are not good to use for a website. You may use long polling or Web Sockets. Long polling is supported by the most of web browsers while web sockets do not support old browsers. However, long polling needs more CPU capacity than web sockets. Many websites such as Facebook, etc. use long polling. I will be showing you how to create a long polling script with PHP. Examples at the end will describe you advanced long-polling.
This article is divided into following sub-topics.
The following image describes the concept of Long-Polling.
First, we have to send an ajax request from the browser to the server to accomplish our target. I assume that you have basic knowledge of using Ajax with Javascript. If you like, you can follow my tutorial on that topic to learn more.
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// when everything goes fine...
}
};
xhttp.open("GET", "long-polling.php", true);
xhttp.send();
What the above code does...
First of all, you should have a good knowledge of using following statements, functions, and tricks. Let's go through those kinds of stuff.
<?php
while(true) {
echo 'yes'; // this will be executed unlimited times
}
There should be a way to go out from the infinite loop and send a response to the client. In the script below, I have shown 3 different ways to break loops.
<?php
while(true) {
// escape from the infinite loop
break;
// escape from multiple loops
for ($i = 0; $i < 10000; $i ) {
if ($foundAnUpdate) {
break 2; // escapes from the for loop & the infinite loop
}
}
// output a message and terminate the script
if ($foundAnUpdate) {
exit(json_encode[
'status' => 'success'
]);
}
}
<?php
session_write_close();
ignore_user_abort(true);
set_time_limit(0);
while(true) {
// here goes the loop
sleep(1);
}
I have created two examples for you. You can download a .zip file of both examples at the end of this sub-topic.
First, I will create index.html which is the client-side file. It sends an ajax request to long-polling.php which is an Ajax Request Handler.
<html>
<head>
<title>Listen to File Update</title>
</head>
<body>
<script type="text/javascript">
function poll() {
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
if (this.status === 200) {
try {
var json = JSON.parse(this.responseText);
} catch {
poll();return;
}
if (json.status !== true) {
alert(json.error);return;
}
var div = document.createElement("DIV");
document.body.appendChild(div);
div.innerHTML = 'time: ' json.time ', content: ' json.content;
poll();
} else {
poll();
}
}
}
ajax.open('GET', 'long-polling.php', true);
ajax.send();
}
poll();
</script>
</body>
</html>
<?php
session_write_close();
ignore_user_abort(false);
set_time_limit(40);
try {
// lastUpdate cookie saves the file update time which was sent to the browser
if (!isset($_COOKIE['lastUpdate'])) {
setcookie('lastUpdate', 0);
$_COOKIE['lastUpdate'] = 0;
}
$lastUpdate = $_COOKIE['lastUpdate'];
$file = 'file.txt';
if (!file_exists($file)) {
throw new Exception('file.txt Does not exist');
}
while (true) {
$fileModifyTime = filemtime($file);
if ($fileModifyTime === false) {
throw new Exception('Could not read last modification time');
}
// if the last modification time of the file is greater than the last update sent to the browser...
if ($fileModifyTime > $lastUpdate) {
setcookie('lastUpdate', $fileModifyTime);
// get file contents
$fileRead = file_get_contents($file);
exit(json_encode([
'status' => true,
'time' => $fileModifyTime,
'content' => $fileRead
]));
}
// to clear cache
clearstatcache();
// to sleep
sleep(1);
}
} catch (Exception $e) {
exit(
json_encode(
array (
'status' => false,
'error' => $e -> getMessage()
)
)
);
}
This example is based on a cookie. In the first request, it creates a cookie named lastUpdate and sends it to the client's browser. This cookie saves the last file modification time of file.txt that was sent to the browser.
In the next request, it loops until the actual modification time of file.txt is greater than the lastUpdate cookie. If yes, it sends a JSON response to the browser. Javascript code in ajax request creates new <div> and adds some content to it.
Here we only create a cookie to save the user id. Timestamps and other data are saved in the database.
I recommend you to download the .zip file and try it yourself. I have explained the code line by line with comments.
In index.html only the onreadystatechange function is changed.
function poll() {
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
if (this.status === 200) {
try {
var json = JSON.parse(this.responseText);
} catch {
poll();return;
}
if (json.status !== true) {
alert(json.error);return;
}
var data = json.data;
for (var i = 0, len = data.length; i < len; i ) {
var x = data[i];
var div = document.createElement("DIV");
document.body.appendChild(div);
div.innerHTML = 'time: ' x.time ', content: ' x.content;
}
poll();
} else {
poll();
}
}
}
ajax.open('GET', 'long-polling.php', true);
ajax.send();
}
poll();
<?php
session_write_close();
ignore_user_abort(false);
set_time_limit(40);
try {
// connect to the db ($mysqli)
include_once '../config.php';
if (empty($_COOKIE['user'])) {
$user = rand(0,10000000);
// send to the browser
setcookie('user', $user);
// save in global variable
$_COOKIE['user'] = $user;
// add user to the database
$mysqli -> query("INSERT INTO db_user_data VALUES ($user, 0)");
// first request does not do anything than creating the cookie
exit();
}
// get the user value
$user = $_COOKIE['user'];
while (true) {
// select new rows
$result = $mysqli -> query("SELECT t.id, t.content, t.time FROM db_updating_table t INNER JOIN db_user_data ud ON ud.last_sent_id < t.id WHERE ud.user = $user ORDER BY t.id");
if ($result && $result -> num_rows) {
$output = [];
$lastId = 0;
foreach ($result as $row) {
$output[] = [
'content' => $row['content'],
'time' => $row['time']];
$lastId = $row['id'];
}
$mysqli -> query("UPDATE db_user_data SET last_sent_id = $lastId WHERE user = $user");
echo json_encode([
'status' => true,
'data' => $output
]);
exit;
}
// db queries are heavy. So 2 seconds
sleep(2);
}
} catch (Exception $e) {
exit(
json_encode(
array (
'status' => false,
'error' => $e -> getMessage()
)
)
);
}
<?php
include_once '../config.php';
$content = !empty($_GET['content']) ? $_GET['content'] : 'No Message Defined';
$time = time();
$mysqli -> query("INSERT INTO db_updating_table (content,time) VALUES ('$content', $time)");
Querying the database continuously needs a powerful server. If you have one, there's nothing wrong with doing this.
This zip has both above examples. To use the second example, first, import the .sql file to your MYSQL database and then change config.php with your hostname, username, password and the database.
I have shown you how to use long polling different ways. I hope you enjoyed this tutorial. If you have any question, suggestion or feedback, comment below. Thanks for reading.