0

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?

Mr. Jo
  • 4,946
  • 6
  • 41
  • 100
  • 2
    Are you looking for the [sleep()](https://www.php.net/manual/en/function.sleep.php) function? Please use with care. You could for instance initiate an AJAX call every 10 seconds. – KIKO Software Aug 12 '19 at 23:10
  • 1
    what about in the opposite way: using the observer pattern. When the database changes you send the change to all listeners. – Giacomo M Aug 12 '19 at 23:11
  • @KIKOSoftware Oh this might be an idea!!! – Mr. Jo Aug 12 '19 at 23:11
  • @GiacomoM I'm not if PHP can do this because PHP don't has websockets. I had this topic some time ago. – Mr. Jo Aug 12 '19 at 23:12
  • @Mr.Jo check this post for example https://stackoverflow.com/questions/14512182/how-to-create-websockets-server-in-php – Giacomo M Aug 12 '19 at 23:14
  • Another solution: a javascript timeouted function that runs every 10 secs and call the PHP function. its better than using sleep on the server – Giacomo M Aug 12 '19 at 23:15
  • @GiacomoM If I understand this correctly, I need to setup my own websocket server which handles this functionallity? – Mr. Jo Aug 12 '19 at 23:15
  • 1
    @Mr.Jo you don't need websockets to do simple interval-based polling with XHR (via Javascript) – webketje Aug 12 '19 at 23:16
  • @Tyblitz what is that? Never heard this before. – Mr. Jo Aug 12 '19 at 23:17
  • 1
    check this post https://stackoverflow.com/questions/8682622/using-setinterval-to-do-simplistic-continuous-polling – Giacomo M Aug 12 '19 at 23:20
  • @GiacomoM I like this but I'm confused haha. So this is a self executing loop right? How can I execute it now every 10 seconds for until 5 minutes? Because in the case of the answer, the loop get's finished after some time but it could be possible that my request is a bit slower and fails. So I can't use it 100 % like the answer from there. It needs to be like an execute for at least 5 minutes with a 10 seconds AJAX inside and a way to exit the timeout if the AJAX returns true. Otherwise the loop will end when the time is over. – Mr. Jo Aug 12 '19 at 23:23
  • 1
    @Mr.Jo please check my answer below, I think it adresses (almost, if not all) the concerns you mentioned here. – webketje Aug 13 '19 at 14:13
  • @Tyblitz Thanks for your answer. I've found another, simpler solution. I'm using a setInterval function which I can exit with clearInterval() if I'm getting a response. I'll post my answer below in the afternoon (Germany) – Mr. Jo Aug 14 '19 at 10:18

3 Answers3

1

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.

Giacomo M
  • 4,450
  • 7
  • 28
  • 57
1

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.

webketje
  • 10,376
  • 3
  • 25
  • 54
0

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

Mr. Jo
  • 4,946
  • 6
  • 41
  • 100