I run a server on a shared hosted space (Aruba) with LAMP configuration, with two separate sets of PHP pages, one for the administrator and one for several clients (imagine a quiz game where the administrator submits questions).
I want to achieve this behaviour:
To achieve this, I thought of different solutions:
setInterval()
) for the presence of this file and, depending on the creation time of the file (or an equivalent timestamp read from the file name or file content) the client will start a countdown (setTimeout()
) for the time remaining to when the new page has to be fired, to make sure that all clients eventually trigger at the same time (tenth of second)I tried the second solution (to manage the reading of trigger file on client-side) both in PHP and in Javascript, but they both fail when there is more than a client connected:
XMLHttpRequest.status
incorrectly returns 404
even when the trigger file is there) - I even created separate trigger files for the different clients, to make sure there are no concurrency conflicts.Any hints on why XMLHttpRequest.status
occasionally fails, or advice on a better way of achieving this behaviour?
Thank you in advance.
Have you considered long polling? See https://github.com/panique/php-long-polling for an example of how to do this with PHP. This will not scale well because of the number of apache and php processes that would have to stay active, but would be fine for a few clients. If you need it to scale then I would consider switching server technologies to something like hack (like PHP; see http://hacklang.org/) or node which is great at this kind of thing.
EDIT: I didn't understand the question fully in my original answer. Here is my refined answer:
With the current limitations you are under, I see only one way of achieving a simultaneous server response. First, you will need to implement HTML5 SSE (server side events). When your server is ready to send a message to the clients, trigger an SSE to be sent to each client. This event does not need to send any data so there's no need for clients being contacted simultaneously. The event tells the clients to execute an ajax call to your php ajaxHandler.
During each ajax call from the client, your server will check your database for the value of 'waitingClients' in some table you created. If the value is 0, set the value to 1. If the value is greater than 0, increment the waitingClients value by 1. After each ajax call increments the database value, the individual ajax calls are then suspended in a while loop until 'waitingClients' is equal to the value of 'totalClients'. I recommend that you create some kind of entry in your database that records the number of active clients. This makes your 'totalClients' value more dynamic.
You may run into problems with the ajax calls timing out after 30 seconds. Since you're only returning database values, I doubt that you'll run into this problem unless something happens with a client's connection hanging.
Here is some example code (untested):
HTML
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="jquery-1.9.1.min.js"></script>
<script src="ajaxTest.js"></script>
</head>
<body>
<div id="server_message">Waiting for server response</div>
</body>
</html>
Ajax:
$(function() {
var message = $('#server_message');
$.ajax({
url: 'yourAjaxHandler.php',
type: 'POST',
data: {
getAnswer: true
},
success: function(response) {
console.log(response);
message.text(response);
}
})
});
PHP Ajax handler
<?php
$host = 'db host address';
$dbname = 'your database name';
$username = 'your username';
$password = 'your password';
$conn = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
// Define expected number of total clients. I would recommend having clients log an entry into the database upon initial login/connection.
// This would make tallying the number of clients more dynamic. Otherwise you will always need 4 clients connected
$totalClients = 4;
if (isset($_REQUEST['getAnswer'])) {
$qry = 'SELECT waitingClients from some_table';
$waitingClients = $conn->query($qry);
if ($waitingClients === 0) {
// Create waitingClients in database if it doesn't exist. Otherwise, increment value to 1
$qry = "UPDATE some_table set waitingClients = 1";
$conn->exec($qry);
} else {
// Increment waitingClients
$qry = "UPDATE some_table set waitingClients = waitingClients + 1";
$conn->exec($qry);
}
while ($waitingClients <= $totalClients) {
// The while loop will keep the ajax call active for all clients
// Keep querying database until waitingClients value in DB matches the number of totalClients
$qry = 'SELECT waitingClients from some_table';
$waitingClients = $conn->query($qry);
}
// Set the value of waitingClients back to 0
$qry = "UPDATE some_table SET waitingClients = 0";
$conn->exec($qry);
// Return your server message to the clients
echo json_encode("Your server message"); // You could also store your server message in the database
}