I've this while loop here:
$payment_timeout = time() + 300;
while ( time() < $payment_timeout ) {
if (is_valid()) {
continue;
}
break;
}
This loop get's called via an AJAX function. The plan is to wait until a customer paid something. To check this, I've build a is_valid() function which does a check against the database to check if the order was paid.
The problem is that in this case my database will crash because of the amount of requests. So I'm looking for a way to execute the check every 10 seconds or so and the other times just do the continue.
Is there a way to do this?
You can do a "long-polling" with javascript.
It is very simple: a javascript function that runs every X seconds (in your case 10) and do a call to the server.
From this post Using setInterval() to do simplistic continuous polling you can do:
// This function is called every 10000 milliseconds (10 seconds)
function refresh() {
// make Ajax call here, inside the callback call:
// call itself again after 10 seconds
setTimeout(refresh, 10000);
}
// if you want to wait 10 seconds for the first call
setTimeout(refresh, 10000);
// or if you want to call immediately the first time
refresh();
If you want to stop the calls after 5 minutes, you just have to set a counter variable and check it in the refresh function.
Something like (pseuso code):
IF YOUR_COUNTER < 5 MINUTES THEN
CALL REFRESH AGAIN
at the end of the refresh function.
Below is a simple generic implementation of a polling mechanism in Javascript, working with variable endpoint, intervals, durations, and callback.
The assumption is that you remove the while loop from the PHP code, and make sure you send back a valid JSON response. In the callback parameter I've given below the assumption is that PHP sends back json_encode(['paid' => true]).
// interval & duration in seconds
function poll(endpoint, interval, duration, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', endpoint);
xhr.onload = function() {
var message;
try {
message = JSON.parse(xhr.response);
} catch(err) {
// malformed json
}
if (duration >= 0 && callback(message) !== false) {
setTimeout(function() {
poll(interval, duration - interval, callback);
}, interval * 1000);
}
};
xhr.send();
}
// usage
var endpoint = '/your-validity-check.php',
interval = 10, // every 10 seconds
duration = 5 * 60, // for 5 minutes
callback = function(response) {
var date = new Date();
console.log(response.paid);
// return false to abort the polling when we know the purchase is paid
if (response.paid) {
window.alert('Thank you for your purchase!');
return false;
}
};
poll(endpoint, interval, duration, callback);
NB: XHR = XMLHttpRequest; what #Giacomo shows is not long-polling, long-polling is a client-server technique which involves keeping connection requests open.
I'm using now a setInterval() function to check:
let interval = setInterval( function () {
//If max time of 5 minutes exceeded (5 * 60000) I leave the interval
if ( new Date().getTime() - startTime > 300000 ) {
clearInterval( interval );
}
//Here I'm doing my AJAX request to check the payment status
}, 5000 ); //<- Execute every 5 seconds
This works great for me and is simple
Related
I have an a.php page containing a variable x = 10;
and a page b.php which contains var y = 10;
my question is can i add x + y and write the result in b.php? knowing that the ajax code is in a.php
<?php
if (isset($_POST['y']) && isset($_POST['x']) ) {
$y = 50;
$x=$_POST['x'];
echo $x+$y ;
}
?>
<script type="text/javascript">
$('button').on('click' , function(){
$.post('b.php' , { x:10, y:10 } , function(data){
$('div').html(data);
} );
} );
</script>
in first sight i think that you should use java script ajax on your a.php for sending data to page b.php but that is not enough so for getting you result a+b=something you need to use something called java script concurrence and those technique allow you to listen for a period of time on the existence of a so i will try to give you the solution o some steps :
Step 1: you've done your ajax sending data
step 2: you need to go check on the java script concurrence you have set interval and set timeout so use one of them but you will need to use set interval cause it will be more efficient
step 3 :use a Php condition called !empty()to check each period of time with the set Interval that a don't equal the default value if it's equal to that default value you should use clear Interval since keeping the execution of set Interval doesn't have any meaning and you will consume of the load of your page and your page will run slower
step 4: you've done with everything and you can do your operation.
i will let a short code for set Interval and you can find them on w3schools with execution example
var myVar;
function myFunction() {
myVar = setInterval(alertFunc, 3000);
}
function alertFunc() {
alert("Hello!");
}
for the clearInterval
var myVar = setInterval(myTimer, 1000);
function myTimer() {
var d = new Date();
var t = d.toLocaleTimeString();
document.getElementById("demo").innerHTML = t;
}
function myStopFunction() {
clearInterval(myVar);
}
We are using the following countdown function on our bidding site.
setInterval(function(){
$(".countdown").each(function(){
var seconds = $(this).data('seconds');
if(seconds > 0) {
second = seconds - 1;
$(this).data('seconds', second)
var date = new Date(null);
date.setSeconds(second);
$(this).html(date.toISOString().substr(11, 8))
}
else
{
$(this).html("Finished");
alert('finished');
}
});
}, 1000);
we pass the number of seconds where we want the counter to appear (sometimes more than once on our page:
echo "<div id=\"".$auctionid."\" class=\"countdown\" data-seconds=\"".$diff."\"></div>";
So far it should be clear an it works. Now we have a situation where when someone bids somewhere on the site - the time left for auction is prolonged for 15 seconds, which is written to mysql.
$diff variable is calculated from mysql end time, and it's passed to jQuery on page load.
The question is how to check the mysql time for that auction and sync it in jQuery counter? We had the idea to maybe check every 5 seconds and after it reaches zero to make sure it's over? Any suggestions?
It should look nice to the user.
EDIT:
This is what we have so far:
$(".countdown").each(function() {
var countdown = $(this);
var auctionid = $(this).attr('id');
var interval = setInterval(function() {
var seconds = countdown.data("seconds");
if( seconds > 0 ) {
var second = --seconds;
var date = new Date(null);
date.setSeconds(second);
countdown.data("seconds", second).html(date.toISOString().substr(11, 8))
} else {
// countdown.html("Finished <img src=\"loading.gif\" class=\"tempload\">");
startUpdateingTimeFromDatabase(auctionid);
countdown.html("Finished");
clearInterval(interval);
}
}, 1000);
});
function startUpdateingTimeFromDatabase(auctionid) {
$.getJSON("timer.php?auctionid="+auctionid, function(response) {
// console.log(response.seconds);
$(".countdown#"+auctionid).data("seconds", response.seconds);
if( response.seconds > 0 ) {
// setTimeout(startUpdateingTimeFromDatabase(auctionid), 1000);
} else {
}
});
}
This simply isn't doing what we need it to do. We need to update the seconds (query startUpdateingTimeFromDatabase) every time it reaches zero. Now I think there are two approaches. First is simply return seconds via startUpdateingTimeFromDatabase function and then do everything in the main function, second is update the div via startUpdateingTimeFromDatabase. I think first will be better but I simply can't find a way to do it properly.
Any help is appreciated. Thanks.
You store the seconds left in the elements data. So why not fetch the remaining time maybe via ajax and just pass the new seconds to the elements? Within the next interval run all times will be updated.
Something like this:
$.get("yourGetRemainingTimeScript.php", {auctionId: 1}, function(response) {
$(".countdown").data("seconds", response.seconds);
});
How you check and get the remaining time is up to you. You can set the time for all everywhere again.
$(".countdown").data("seconds", 1337);
Another hint from my side: don't loop all elements with each in the setInterval. Create the intervals inside the loop once. Then your script doesn't need to search every second again over and over for the elements.
And clear the interval when it's finished.
$(".countdown").each(function() {
var countdown = $(this);
var interval = setInterval(function() {
// do your stuff ...
// when finished stop the interval
if( finished ) {
clearInterval(interval);
}
}, 1000);
});
Full working example.
I have this code which change value on click
$.post('test.php', {val:value}, function (data) {
var value = document.getElementById('value');
val.value = value;
}
I need to change value on time(for example on 10 sec) how i can do that with Ajax?
If I understand your question correctly, you need to call the server (i.e. "poll") and get the latest value based on a set time interval. If that is the case, you should look at the setInterval() function and have it call your update method. For example:
function update() {
$.post('test.php', {val:value}, function (data) {
var value = document.getElementById('value');
val.value = value;
}
}
// Call every 10 seconds
var seconds = 10;
var int = setInterval(update, seconds * 1000);
Be aware that this sort of polling, especially on Apache (my guess since you tagged PHP) can quickly use up your max connections if you have a lot of traffic and effectively DDOS your own web server.
So since you said after 10 seconds:
You want to use the setTimeout function, after the delay specified in miliseconds
function postValue() {
$.post('test.php', {val:value}, function (data) {
var value = document.getElementById('value');
val.value = value;
}
}
Now we set the click handler to call the postValue function after a timeout of 10 seconds
var seconds = 10;
$('#button').click(function(){
setTimeout(postValue, seconds * 1000)
});
I'm having a problem with an ajax call.
I have some code set up to run a function every 2 seconds which looks to see if the content has been updated or not with WordPress ajax, does some work with php, then updates a database:
window.setInterval( "updateContent()", 2000 );
function updateContent(){
if($('#needcontent').hasClass('yes')){
CONTENT.updateContent( 'monitor' , ids );
}
}
$(function() {
CONTENT= {
updateContent: function(callback, data){
data = {
action: 'myplugin_do_ajax',
callback: callback,
data: data
};
$.post(ajaxurl, data, function(response){
switch(data.callback){
case 'monitor' :
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Do nothing because no content was found, let the Interval run again
}
break;
}
}
}
}
The problem I'm finding is that sometimes the content is quite large, and ends up locking the table while php updates the database. The ajax call runs once, runs into a database lock, and doens't return anything until the database is unlocked again. The database could be locked for a 10 second period, resulting in 1 run and 4 not-run calls.
UPDATE:
It's not the database locking, it's the php function taking longer than 2 seconds to return, causing the Interval to loop again and again without a response.
What's happening is those 4 not-run ajax calls then begin to fire one right after the other like they are trying to catch up or something.
I've tried increasing the Interval time to 10 seconds, but that doesn't solve the problem because if the database is locked for 11 seconds it'll still fire twice.
I've tried using global variables in Javascript (yuck) to stop the Interval from calling the function, but that doesn't seem to work either.
UPDATE 2:
I answered my own question below to what worked for me.
try this:
window.updateCheck= window.setInterval( "updateContent()", 2000 );
function updateContent(){
if($('#needcontent').hasClass('yes')){
CONTENT.updateContent( 'monitor' , ids );
clearInterval(window.updateCheck);
}
}
$(function() {
CONTENT= {
updateContent: function(callback, data){
data = {
action: 'myplugin_do_ajax',
callback: callback,
data: data
};
if(window.ajaxCall) window.ajaxCall.abort();
window.ajaxCall= $.post(ajaxurl, data, function(response){
window.updateCheck= window.setInterval( "updateContent()", 2000 );
switch(data.callback){
case 'monitor' :
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Do nothing because no content was found, let the Interval run again
}
break;
}
}
}
}
what we did here was to put the interval in a global variable, and also the ajax call ($.post() call actually), then when the conditions of updating is checked, we stop the interval, kill all the other active or queued request and send the ajax request to the server.
while the request is being sent to the server the update checks are stopped, then as soon as the server responds to the request we start the update check again!
charlietfl's comment on my OP got me thinking about the difference between setInterval and setTimeout, and I realized that:
a) setInterval would continuously run, regardless if a result is returned or not. In my case, using ajax, the function was being call asynchronously so the setInterval wouldn't care if a result was returned.
b) If I changed the code to use setTimeout, I could control the outcome more.
This is what I did.
Firstly, remove the setInterval function completely, it's not needed.
Then I changed my switch case to this:
case 'monitor' :
var monitor = false;
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Run the monitor after a 2 second timeout.
var ids = j('.contentDiv').attr('id');
window.setTimeout(CONTENT.updateContent( 'monitor' , ids ) , 2000);
}
break;
Assume that you are doing a banking application. If users are logged into your site, how to detect their inactivity and ask them to log out if they remain inactive for a period of time? Inactive here means they have either switch to other tabs, or not touching the browser application.
I guess think I can do this by registering every mouse movement or keyboard movement when users are doing on EVERY page of my application. But the code would be very ugly and hard to maintain. Is there other more elegant ways of doing this?
This is the code I use. It is not mine, but I did modify it to it's 'perfection'.
// Add the following into your HEAD section
var timer = 0;
function set_interval() {
// the interval 'timer' is set as soon as the page loads
timer = setInterval("auto_logout()", 10000);
// the figure '10000' above indicates how many milliseconds the timer be set to.
// Eg: to set it to 5 mins, calculate 5min = 5x60 = 300 sec = 300,000 millisec.
// So set it to 300000
}
function reset_interval() {
//resets the timer. The timer is reset on each of the below events:
// 1. mousemove 2. mouseclick 3. key press 4. scroliing
//first step: clear the existing timer
if (timer != 0) {
clearInterval(timer);
timer = 0;
// second step: implement the timer again
timer = setInterval("auto_logout()", 10000);
// completed the reset of the timer
}
}
function auto_logout() {
// this function will redirect the user to the logout script
window.location = "your_logout_script.php";
}
// Add the following attributes into your BODY tag
onload="set_interval()"
onmousemove="reset_interval()"
onclick="reset_interval()"
onkeypress="reset_interval()"
onscroll="reset_interval()"
Good luck.
If the user is requesting new pages/data from your server on a regular basis, then adjusting the session timeout in PHP should work for this (assuming you are using PHP sessions).
If the concern is that they could be sitting on one page for a good length of time with no trips to the server (e.g. filling out a long form), and you want to distinguish between this and the user simply switching to another window, you could do something like use javascript to request some data using XMLHTTPRequest every five minutes or so to keep the session alive. You could use the window.focus and window.onblur events in javascript to stop and restart this mechanism (I think there are some differences for IE, there is a good explanation here).
A very easy and effective way of doing this is by placing something like this in your HTML HEAD section:
<META HTTP-EQUIV="refresh" CONTENT="1800;URL=logout.php?timeout">
Replace the logout.php?timeout with the appropriate script .. In the example above, if ?timeout is in the query string, I show them a login page with information indicating that they've been logged out due to inactivity.
Replace 1800 with the time in seconds that you wish to allow them to stay inactive before automatically logging them out. Set this to the same time that you have your session expiration set to.
Edit - Another easy mechanism to implement is to have a session variable called last_time, or last_activity, or something along those lines, and set it to a timestamp everytime there is activity. In most of my stuff, I have a general include file that I do this in. In the same file, you could check to ensure that it's within the constraints that you've set forth for an active session. If it's been too long -- just do a 300 redirect to the logout page and display the appropriate inactivity message there.
Good luck!
Ian
We can improve our codes to jquery now
idleTime = 0;
$(document).ready(function() {
var idleInterval = setInterval("timerIncrement()", 60000); // 1 minute //60000
$(this).mousemove(function(e) {
idleTime = 0;
});
$(this).keypress(function(e) {
idleTime = 0;
});
});
function timerIncrement() {
idleTime = idleTime + 1;
if (idleTime >= 5) {
window.location = $('#base_url').val() + 'home/logout_user';
}
}
You can do it more elegantly with underscore and jquery javascript libraries-
$('body').on("click mousemove keyup", _.debounce(function(){
// logout user here
}, 1800000)) // 30 minutes inactivity
It depends how they are "logged in" in the first place. Doesn't the session expiration on the server do this for you? If you really want to do it manually then you could use some javascript in a setTimeout, but thats ugly
Usually the session lifetime is used to determine whether a user is logged in or not. So you could set a flag in the session that represents this state. And if it’s missing (either the user didn’t log in yet or the session timed out), he is considered as not logged in.
You can have a bit of javascript that checks the server every x minutes to see when the user's last activity was. Shouldn't be more than a few lines of code. I would also add a meta refresh if the user has javascript disabled.
I took the timestamp 'now' and check on each click if the delay is less than 3000 seconds or more than billions of seconds, which means that the user just logged in, if it's not it will redirect to logout
var time = 0;
$(document).on('click', function() {
var now = Date.now() / 1000 | 0;
if (now - time < 3000 || now - time > 1480000000) {
time = now;
} else {
window.location.replace("http://url");
}
})
put in header of your java script page.. if you want to avoid the backend calls
Below is the snip-let under script tag :
<script>
var idleTime = 0;
function func(){
console.log(idleTime);
$(this).keypress(function(e) {
idleTime = 0;
});
$(this).click(function(e) {
idleTime = 0;
});
timerIncrement();
}
function timerIncrement() {
console.log("timerIncrement");
console.log(idleTime);
idleTime = idleTime + 1;
if (idleTime >= 1) {
console.log(window.location);
logoutcall(); //API call
window.location = window.location.origin+"/riskoffice_UI/Login";
}
}
setInterval(func,1800000) //Runs the "func" function every second
</script>
Update : localStorage can be use to keep idle time for the application with multiple tabs are opened.
// Check browser support
if (typeof(Storage) !== "undefined") {
// Store an item to localStorage
localStorage.setItem("timeIdle", "0");
console.log(localStorage.getItem("idleTime"));
// Retrieve the added item
} else {
//display this message if browser does not support localStorage
console.log("Sorry, your browser does not support Web Storage.");
}
function func(){
$(this).keypress(function(e) {
localStorage.setItem("timeIdle", "0");
});
$(this).click(function(e) {
localStorage.setItem("timeIdle", "0");
});
timerIncrement();
}
function timerIncrement() {
var timeIdle = localStorage.getItem("timeIdle");
timeIdle = parseInt(timeIdle) + 1;
if (timeIdle >= 1) {
logoutCall();
window.location = window.location.origin+"/riskoffice-ui/Login";
}
localStorage.setItem("timeIdle", timeIdle.toString());
}
setInterval(func,1800000); //Runs the "func" function every second