I’m playing a bit around with push notifications, and want to update a page whenever there’s a change in the database.
I have this from http://www.screenr.com/SNH:
<?php
$filename = dirname(__FILE__).'/data.php';
$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$currentmodif = filemtime($filename);
while ($currentmodif <= $lastmodif) {
usleep(10000);
clearstatcache();
$currentmodif = filemtime($filename);
}
$response = array();
$response['msg'] = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);
?>
My data.php is a script getting data from a JSON file:
<script>function itnews_overview() {
$.getJSON('/ajax.php?type=itnews_overview', function(data) {
$.each(data.data, function(option, type) {
$('.bjqs').append('<li><span class="date">'+ type.submitted +'<br />'+ type.time +'</span><h2>' + type.title + '</h2><p>' + type.content + '</p></li>');
});
});
}
</script>
<script>
itnews_overview();
</script>
<div id="news">
<ul class="bjqs"></ul>
</div>
UPDATE: Code from index.php:
<script type="text/javascript">
var timestamp = null;
function waitForMsg() {
$.ajax({
type: "GET",
url: "getData.php?timestamp=" + timestamp,
async: true,
cache: false,
success: function(data) {
var json = eval('(' + data + ')');
if(json['msg'] != "") {
$(".news").html(json['msg']);
}
timestamp = json['timestamp'];
setTimeout('waitForMsg()',1000);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
setTimeout('waitForMsg()',15000);
}
});
}
$(document).ready(function(){
waitForMsg();
});
</script>
As this file isn’t saved when I add something to the database, filemtime won’t work — is there another way I can check if new rows has been added to the table?
UPDATE: Trying to solve this with SSE.
I have two files, index.php and send_sse.php (inspiration from http://www.developerdrive.com/2012/03/pushing-updates-to-the-web-page-with-html5-server-sent-events/)
index.php:
<div id="serverData">Content</div>
<script type="text/javascript">
//check for browser support
if(typeof(EventSource)!=="undefined") {
//create an object, passing it the name and location of the server side script
var eSource = new EventSource("send_sse.php");
//detect message receipt
eSource.onmessage = function(event) {
//write the received data to the page
document.getElementById("serverData").innerHTML = event.data;
};
}
else {
document.getElementById("serverData").innerHTML="Whoops! Your browser doesn't receive server-sent events.";
}
</script>
send_sse.php:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$url = "content.json";
$str = file_get_contents($url);
$data = json_decode($str, TRUE);
//generate random number for demonstration
//echo the new number
echo "data: " . json_encode($data);
ob_flush();
?>
This, however, doesn’t seem to work, which is probably because SSE needs plain text data. I just can’t figure out how to do that and then wrap that content in a couple of HTML tags.
UPDATE: Okay, so now it’s sort of working with SSE, thanks to VDP. I have the following:
$sql= "SELECT title, content, submitted FROM `flex_itnews` where valid = 1 order by submitted desc";
$query= mysql_query($sql);
setlocale(LC_ALL, 'da_DK');
while($result = mysql_fetch_array($query)){
echo "data: <li><span class='date'>". strftime('%e. %B', strtotime($result['submitted'])) ."<br />kl. ". strftime('%H.%M', strtotime($result['submitted'])) ."</span><h2>" . $result['title']. "</h2><p>" . $result['content'] ."</p></li>\n";
}
However, when I add anything new, it just echoes data: data: data. If I refresh the page, it displays correctly.
UPDATE: Using livequery plugin:
<script>
var source = new EventSource('data2.php');
source.onmessage = function (event) {
$('.bjqs').html(event.data);
};
$('#news').livequery(function(){
$(this).bjqs({
'animation' : 'slide',
'showMarkers' : false,
'showControls' : false,
'rotationSpeed': 100,
'width' : 1800,
'height' : 160
});
});
</script>
UPDATE: Trying to use delegate()
<script>
$("body").delegate(".news", "click", function(){
$("#news").bjqs({
'animation' : 'slide',
'showMarkers' : false,
'showControls' : false,
'rotationSpeed': 100,
'width' : 1800,
'height' : 160
});
var source = new EventSource('data2.php');
source.onmessage = function (event) {
$('.bjqs').append(event.data);
};
});
</script>
Yes! There are multiple (better) ways:
I’ve posted another answer with examples about it before
I listed several transport methods. websockets being the ideal (because it’s the only 2 way communication between server and client), SSE being my second choice. You won’t need the
$.getJSONmethod. The overall idea will be the same.On the server side (php in your case) you query your database for changes. You return the data as JSON (
json_encode(data)can do that). On the client side you decode the JSON (JSON.parse(data)can do that). With the data you received you update your page.Just the polling like you where doing causes more overhead because you are doing lots of request to the server.
SSE is more “I want to subscribe to a stream” and “I want to stop listening”. => less overhead
Websockets is more: “I set up a connection. I talk server listens. Server talks client listens” A full duplex connection. => least overhead
SSE Code example
The page the client goes to (for example index.html or index.php)
It’s just a normal html page containing this javascript:
The ‘data.php’ page:
So you only need those 2 pages.
UPDATE:
I had only seen your comments not the updates.. sorry 😉
if you use
.delegate()you shouldn’t use body but try a selector as high up the tree as possible (.bjqsin your case).In you’re case you don’t even need live,delegate,on or all that! Just apply the bjqs again afther the content is updated.
This will give you issues too because you are constantly re-initializing bjqs and it isn’t written to handle dynamically updating content. What you can do is send only data (with php) if there is new data. Check if the call returns empty, if not update: