Refresh individual table cells without refreshing whole page - php

I have a table with lots of cells that have little php scripts in them that search a text document called foo.txt for a snippit of numbers. The code really isn't needed to understand my problem but just in case:
<?php
$input = "3.000000";
$file = file_get_contents("foo.txt");
$pos = strrpos($file, $input);
if($pos !== false){
$start = $pos + strlen($input);
$end = strpos($file, "00", $start);
$data = substr($file, $start, $end - $start);
$dataprocessed = round($data, 2, PHP_ROUND_HALF_DOWN);
echo $dataprocessed;
}else{
echo "Error";
}
?>
From that i would get a number like "34.23" which is correct. The problem is that foo.txt changes/gets overwritten every minute, changing that "34.23", but the webpage wont display the new data unless the whole page is refreshed. I want to somehow have it so that the new/overwritten data is displayed in a tag without refreshing the entire page every minute. I have experience in HTML/XHTML, PHP, limited experience in JavaScript/JQuery, and have been reading posts and tutorials on AJAX but cant quite get it to work. Im open to creative solutions and any solution. Thanks so much in advance!

You can use setInterval and $.load() to use AJAX to reload parts of your page every couple of seconds:
$(function(){
setInterval(function(){
$('div#table-container').load('website_url.php?randval=' + Math.random() + ' div#table-container table');
},10000);
});
Every 10 seconds, this will load website_url.php via AJAX and grab just the div#table-container table portion and insert into the current page by replacing what is currently inside div#table-container
the ?randval=' + Math.random() is a workaround to solve an IE6 caching issue, if you are worried about IE compatibility.
http://api.jquery.com/load/

if you id your table cells in a uniform fashion like:
<tr>
<td id ="a1"></td>
<td id ="a2"></td>
<tr>
<tr>
<td id ="b1"></td>
<td id ="b2"></td>
<tr>
then have an ajax call set up on an interval to a php page, thats server chages in JSON format like: [{'cell': 'a1', 'value': '34.7}];
you could replace them with calls like:
for (item in results) {
$("#" + item.cell).val(item.value);
}
The only thing left after that is keeping a serial# for the data. Every time it changes, it gets a new serial number. So when the client askes for changes, it presents a serial number, and you can update it. The next time that client askes it should present the newest serial number. That way you aren't constantly sending all changes to every client.

I would use AJAX with the setInterval to check if changes are to be made (comet) nd for the tagging get the number of column and line and use a nth-child() modifier with jquery example:
$(table#example tr:nth-child(2) td:nth-child(5)).html('my new html answer');
// meaning 2nd row 5th column
To obtain the nth child values, possibly useful, you would use
$(this).index()+1 because nth-child is not 0 based

Related

Showing progress bar while fetching data [duplicate]

I have this while loop, that basically loops through a lot of records in a database, and inserts the data in another:
$q = $con1->query($users1) or die(print_r($con2->errorInfo(),1));
while($row = $q->fetch(PDO::FETCH_ASSOC)){
$q = $con2->prepare($users2);
$q->execute(array($row['id'], $row['username'])) or die(print_r($con2-errorInfo(),1));
}
(The script has been shortened for easy reading - the correct one has a much longer array)
I would like to do this more graphical, and show a progress bar on how far it has went, instead of just seeing a page loading for a few minutes (there are ~20.000 rows in this one - I have tables with much more data)
I get that you could get the total number from the old database, and I could also easily put the current number into a variable like this:
$q = $con1->query($users1) or die(print_r($con2->errorInfo(),1));
$i = 0;
while($row = $q->fetch(PDO::FETCH_ASSOC)){
$q = $con2->prepare($users2);
$q->execute(array($row['id'], $row['username'])) or die(print_r($con2-errorInfo(),1));
$i++;
}
But now I need to actually fetch $i and display it - or something like it.
How is this "easily" done?
The code for the progress bar can either be in the same document as the while loop, or in another if easier.
You can do a "master" file that does an ajax to this first file to run a single query. You could get all the entry id's in this master file, and then pass it as a parameter to the second file that does a single query. Store these ids in a javascript array.
Create a function that does this, and when the first ajax is done, move to the second element of the id array, and do another ajax with a second parameter. That's how magento imports are done by the way :)
If you need further explanations, let me know, I tried my best to explain, but may have not been perfectly clear.
// you generate this javascript array using php.
// let's say you have all the ids that have to be processed in $Ids php array.
Ids = [<?php echo implode(',', $Ids); ?>];
function doAjax(i) {
$.ajax({ // using jquery for simplicity
'url': "ajax.php?id=" + Ids[i],
}).done(function(){
if ( i >= 0 ) {
// at the point you know you're at ((Ids.length-i)/(Ids.length) * 100) percent of the script
// so you can do something like this:
// $('.progressbar').css('width', ((Ids.length-i)/(Ids.length) * 100) + '%');
doAjax(i-1);
}
});
}
doAjax(Ids.length); // starting from the last entry
So, just to explain what this does. It starts by declaring a global javascript array that has all the ids that will need to be changed.
Then I declare a recursive ajax function, this way we can make sure that only one ajax runs at any single time (so the server doesn't blow up), and we can have a fairly accurate progress. This ajax function does the following:
Sends a request to ajax.php?id=xxx - where xxx is one of the ids in the javascript array.
In the file, we get the id ($_GET['id']), you take it from the old database, and insert it in the new one. This is only for one entry.
when the ajax is done, it goes to the done() function. Since we start the doAjax() function with the last element, we do the next iteration doAjax(i-1). Since we're going backwards in the array, we check if the key is positive. If it's not, the script will stop.
That's about it.
You can't. The php is first interpreted by the server and then send to the user as HTML-Code.
The only possibility would be creating a html-page and call the php-script with AJAX.

Progress bar while running while loop

I have this while loop, that basically loops through a lot of records in a database, and inserts the data in another:
$q = $con1->query($users1) or die(print_r($con2->errorInfo(),1));
while($row = $q->fetch(PDO::FETCH_ASSOC)){
$q = $con2->prepare($users2);
$q->execute(array($row['id'], $row['username'])) or die(print_r($con2-errorInfo(),1));
}
(The script has been shortened for easy reading - the correct one has a much longer array)
I would like to do this more graphical, and show a progress bar on how far it has went, instead of just seeing a page loading for a few minutes (there are ~20.000 rows in this one - I have tables with much more data)
I get that you could get the total number from the old database, and I could also easily put the current number into a variable like this:
$q = $con1->query($users1) or die(print_r($con2->errorInfo(),1));
$i = 0;
while($row = $q->fetch(PDO::FETCH_ASSOC)){
$q = $con2->prepare($users2);
$q->execute(array($row['id'], $row['username'])) or die(print_r($con2-errorInfo(),1));
$i++;
}
But now I need to actually fetch $i and display it - or something like it.
How is this "easily" done?
The code for the progress bar can either be in the same document as the while loop, or in another if easier.
You can do a "master" file that does an ajax to this first file to run a single query. You could get all the entry id's in this master file, and then pass it as a parameter to the second file that does a single query. Store these ids in a javascript array.
Create a function that does this, and when the first ajax is done, move to the second element of the id array, and do another ajax with a second parameter. That's how magento imports are done by the way :)
If you need further explanations, let me know, I tried my best to explain, but may have not been perfectly clear.
// you generate this javascript array using php.
// let's say you have all the ids that have to be processed in $Ids php array.
Ids = [<?php echo implode(',', $Ids); ?>];
function doAjax(i) {
$.ajax({ // using jquery for simplicity
'url': "ajax.php?id=" + Ids[i],
}).done(function(){
if ( i >= 0 ) {
// at the point you know you're at ((Ids.length-i)/(Ids.length) * 100) percent of the script
// so you can do something like this:
// $('.progressbar').css('width', ((Ids.length-i)/(Ids.length) * 100) + '%');
doAjax(i-1);
}
});
}
doAjax(Ids.length); // starting from the last entry
So, just to explain what this does. It starts by declaring a global javascript array that has all the ids that will need to be changed.
Then I declare a recursive ajax function, this way we can make sure that only one ajax runs at any single time (so the server doesn't blow up), and we can have a fairly accurate progress. This ajax function does the following:
Sends a request to ajax.php?id=xxx - where xxx is one of the ids in the javascript array.
In the file, we get the id ($_GET['id']), you take it from the old database, and insert it in the new one. This is only for one entry.
when the ajax is done, it goes to the done() function. Since we start the doAjax() function with the last element, we do the next iteration doAjax(i-1). Since we're going backwards in the array, we check if the key is positive. If it's not, the script will stop.
That's about it.
You can't. The php is first interpreted by the server and then send to the user as HTML-Code.
The only possibility would be creating a html-page and call the php-script with AJAX.

Can i make a number appear on my page then have it increase by x every z seconds

Take this number "#1"
Make it turn to a "#2" in 5 seconds
Then to a "#3" in 5 seconds
Is this possible, or how do i accomplish this?
Because PHP executes on the server and only sends the resulting output to the browser, we can't use only PHP to update it.
Easiest method would be to use JavaScript's setTimeout method.
function update() {
var counter = document.getElementById("counter");
counter.innerText = counter.innerText*1 + 1;
setTimeout(update, 1000);
}
<body onload="update()">
<div id="counter">0</div>
</body>
The update function gets called once on the body's load and then it calls itself after 1000ms to make a 1 second counter. Note: I have to multiply the innerText by 1 to convert a string to a number so it will add instead of concatenating.
Another way of doing this, although I don't know why you'd want to do it this way (but it uses PHP.. lol) is to refresh the page with an updated query string parameter.
<?PHP
$newcount = 0;
if(isset($_GET['count'])) {
$newcount = $_GET['count'] + 1;
echo $newcount;
}
echo "<meta http-equiv='refresh' content=\"1;URL='a.php?count={$newcount}'\">";
?>
Here I get the current value of the counter and add 1 using PHP and then echo a meta refresh tag to, after 1 second, refresh the page with the updated count value in the query string. Next time the page loads, it'll read that value, add one, refresh with the new value, etc. This is just to show you another way, I would not recommend doing this in your application!

using jquery + <audio> w/ php/mysql to loop playback times

I've got a page with an iframe. The iframe is using jquery.scrollTo to detect the audio playback time and keep the contents, lyrics for example, linked to the right point in the audio.
Each line of text is being pulled from a mysql table. What I'm trying to do is to allow the user to click on a line in the <iframe> and have the audio in the parent page play at that point. Here's the code that grabs the times, which exists after the jquery that handles the other audio functions:
<?php
include 'mysqlt.php';
$entries=mysql_query("SELECT * FROM `database`.`table`") or die(mysql_error());
while ($ent = mysql_fetch_object($entries)) {
$segment = $ent->index;
$starttime = $ent->time;
$nextline = $ent->time2;
$length = ($nextline - $starttime); ?>
That same information is also duplicated in the iframe source page along with the individual lines of lyrics. The jquery that uses this info follows:
$("#iframe_id").contents().find("#button_in_iframe<?php echo $segment;?>").bind("click", function(){
audioplayer.currentTime = <?php echo $time;?>;
audioplayer.play();
}
<?php } ?>
This second part loops, echoed once for each each potential line in the iframe that can be clicked. #button_in_iframe<?php echo $segment;?> ends up as something like #button_in_iframe23 for the 23rd line.
I've got jquery loaded up in both the parent and the iframe. As far as I can tell, the syntax is what it should be. If I remove this bit of code, everything works normally. if it's in there, the basic audio functions on the normal controls I have set stop working. So this is not only not working, but it's causing everything else associated with the audio tag's controls to stop working as well. I know that any small error in the audio controls' jquery is enough to make it stop working, but in this case I'm not sure where the problem is.
Thanks in advance for any insights anyone might be able to offer.
update:
I've got it so it no longer crashes the audio tag. Now it's more an issue of the iframe's item not triggering an event. Here's the code now:
$('#iframe_id').contents().find("button.loop2").bind("click", function() {
alert ("test");
});
I'm not getting any console errors except for a Google Maps imbedded in the page in another location. When i click the <button> with class loop2 in the iframe, all of which exist, nothing's happening. That seems to be the root of the problem as it was earlier.
I figured out how to do it. I've set the loop on the parent to read as follows:
play<?php echo $segment; ?> = function(){
sfx.currentTime = sounds.getCueById(id).startTime;
sfx.play();
};
Then in the iframe's page, I've told each button to call parent.play<?php echo $segment;?>();
I'm not sure why finding the tags in the iframe didn't work, but no matter. This get's the job done.
Thanks, shanabus, for all the suggestions.
Would it work to use media cues?
Example:
var sfx = new Audio('sfx.wav');
var sounds = a.addTextTrack('metadata');
// add sounds we care about
sounds.addCue(new TextTrackCue('dog bark', 12.783, 13.612, '', '', '', true));
sounds.addCue(new TextTrackCue('kitten mew', 13.612, 15.091, '', '', '', true));
function playSound(id) {
sfx.currentTime = sounds.getCueById(id).startTime;
sfx.play();
}
You can find a better definition of the spec half way down the page here - http://dev.w3.org/html5/spec/Overview.html
So in your case, maybe something like:
$("#iframe_id").contents().find("#button_in_iframe<?php echo $segment;?>").bind("click", function(){
sounds.addCue(new TextTrackCue('<?php echo $segment; ?>', <?php echo $starttime; ?>, <?php echo ($starttime + $length); ?>, '', '', '', true));
var id = '<?php echo $segment; ?>';
sfx.currentTime = sounds.getCueById(id).startTime;
sfx.play();
}
Or maybe separate your logic into two loops. One for building the cues, then one for building/binding the click events.
Hope this helps!

Measuring online time on website

I would like to measure how much time a user spends on my website. It's needed for a community site where you can say: "User X has been spending 1397 minutes here."
After reading some documents about this, I know that there is no perfect way to achieve this. You can't measure the exact time. But I'm looking for an approach which gives a good approximation.
How could you do this? My ideas:
1) Adding 30 seconds to the online time counter on every page view.
2) On every page view, save the current timestamp. On the next view, add the difference between the saved timestamp and the current timestamp to the online time counter.
I use PHP and MySQL if this does matter.
I hope you can help me. Thanks in advance!
This is probably pointless.... what if the user has three tabs open and is "visiting" your site while actually working on the other two tabs? Do you want to count that?
Two factors are working against you -
You can only collect point-in-time statistics (page views), and there's no reasonable way to detect what happened between those points;
Even then, you'd be counting browser window time, not user time; users can easily have multiple tabs open on multiple browser instances simultaneously.
I suspect your best approximation is attributing some average amount of attention time per click and then multiplying. But then you might just as well measure clicks.
Why not just measure what actually can be measured?: referrals, page views, click-throughs, etc.
Collecting and advertising these kinds of numbers is completely in line with the rest of the world of web metrics.
Besides—if someone were to bring up a web page and then, say, go on a two week holiday, how best to account for it?
What you could do is check if a user is active on the page and then send an ajax request to your server every X seconds (would 60 secs be fine?) that a user is active or not on the page.
Then you can use the second method you have mentioned to calculate the time difference between two 'active' timestamps that are not separated by more than one or two intervals. Adding these would give the time spent by the user on your site.
google analytics includes a very powerful event logging/tracking mechanism you can customize and tap into get really good measurements of user behavior - I'd look into that
A very simple solution is to use a hidden iframe that loads a php web page periodically. The loaded web page logs the start time (if it doesn't exist) and the stop time. When the person leaves the page you are left with the time the person first came to the site and the last time they were there. In this case, the timestamp is updated every 3 seconds.
I use files to hold the log information. The filename I use consists of month-day-year ipaddress.htm
Example iframe php code. Put this in yourwebsite/yourAnalyticsiFrameCode.php:
<?php
// get the IP address of the sender
$clientIpAddress=$_SERVER['REMOTE_ADDR'];
$folder = "yourAnalyticsDataFolder";
// Combine the IP address with the current date.
$clientFileRecord=$folder."/".date('d-M-Y')." ".$clientIpAddress;
$startTimeDate = "";
// check to see if the folder to store analytics exists
if (!file_exists($folder))
{
if (!mkdir($folder))
return; // error - just bail
}
if (file_exists($clientFileRecord) )
{
//read the contents of the clientFileRedord
$lines = file($clientFileRecord);
$count = 0;
// Loop through our array, show HTML source as HTML source; and line numbers too.
foreach ($lines as $line_num => $line)
{
echo($line);
if ($count == 0)
$startTimeDate = rtrim( $line );
$count++;
}
}
if ($startTimeDate == "")
$startTimeDate = date('H:i:s d-M-Y');
$endTimeDate = date('H:i:s d-M-Y');
// write the start and stop times back out to the file
$file = fopen($clientFileRecord,"w");
fwrite($file,$startTimeDate."\n".$endTimeDate);
fclose($file);
?>
The javascript to periodically reload the iframe in the main web page.:
<!-- Javascript to reload the analytics code -->
<script>
window.setInterval("reloadIFrame();", 3000);
function reloadIFrame() {
document.getElementById('AnalyticsID').src = document.getElementById('AnalyticsID').src
// document.frames["AnalyticsID"].location.reload();
}
</script>
The iframe in the main web page looks like this:
<iframe id="AnalyticsID" name="AnalyticsID" src="http://yourwebsite/yourAnalyticsiFrameCode.php" width="1"
height="1" frameborder="0" style="visibility:hidden;display:none">
</iframe>
A very simple way to display the time stamp files:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
</head>
<body>
Analytics results
<br>
<?php
$folder = "yourAnalyticsDataFolder";
$files1 = scandir($folder);
// Loop through the files
foreach ($files1 as $fn)
{
echo ($fn."<br>\n");
$lines = file($folder."/".$fn);
foreach ($lines as $line_num => $line)
{
echo(" ".$line."<br>\n");
}
echo ("<br>\n <br>");
}
?>
</body>
</html>
You get a results page like this:
22-Mar-2015 104.37.100.30
18:09:03 22-Mar-2015
19:18:53 22-Mar-2015
22-Mar-2015 142.162.20.133
18:10:06 22-Mar-2015
18:10:21 22-Mar-2015
I think client side JavaScript analytics is the solution for this.
You have the google analitycs, piwik, and there also commercials tools in JS that do exactly that.

Categories