1

I have this script that performs a database query 2 minutes after the page has loaded. I can't use the sleep() function because it just doesn't let the page load correctly.

I found this piece of code:

$now = time();
while ($now + 120 > time()) {
    // do nothing
}

//other actions here

but it just doesn't load the page. How can I do that? Thank you in advance!

EDIT: I want to reward the user after watching a video for two minutes. If the user closes the page early nothing will be executed.

user3857732
  • 11
  • 1
  • 4
  • 2
    why not just use a cron job? – Funk Forty Niner Oct 07 '15 at 16:10
  • because I need the timer to start after the user has loaded the page – user3857732 Oct 07 '15 at 16:12
  • 1
    This is not a good idea to hold a scrip for certain amount of time. – RNK Oct 07 '15 at 16:12
  • 2
    you can't. php script basically single-threaded. You'd have to fire off some OTHER script to do the delay/querying. Anything you do in the main script will simply force the user to be dead in the water for 2 minutes. Maybe a JS timer to do an ajax call, triggering the query, but still... – Marc B Oct 07 '15 at 16:13
  • exactly ^ you should show them some type of activity: *"Please wait, loading..."* – Funk Forty Niner Oct 07 '15 at 16:13
  • ah Marc broke my comment arrow – Funk Forty Niner Oct 07 '15 at 16:14
  • You should rather describe why you want this, what's your goal, because it doesn't make a sense. There's more ways to achieve this, but unless we know, what exactly you want to do, we can't pick the best one. – David Ferenczy Rogožan Oct 07 '15 at 16:16
  • What your code snippet is a type of `Spin Lock`, it's effectively not much different than the `sleep` function so it won't help you. Your code will delay the page from loading for 2 minutes. You should make a async call after the page loads and the 2 minutes have passed. – Matt Urtnowski Oct 07 '15 at 16:19

3 Answers3

4

Assuming you need the query results returned to the page, Why not make an async call. Let the page load, wait two minutes in javascript, then use ajax to hit your php server and pull the query results.

Use setTimeout https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout

Then make an Ajax request with

http://api.jquery.com/jquery.ajax/

Or

https://developer.mozilla.org/en-US/docs/AJAX

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest

Also depending on your app and what the query is, consider caching the query results for next time. However, this is dependent on what your application does.


If you don't need query results on your page, see Run PHP Task Asynchronously


The correct way to implement this using strictly server side only, given the context of your new edit, would be to use a video streaming service that upon successfully streaming the entire video (without the user dropping out early or pausing), runs a post operation script that credits the user. However, this is a more complex to setup then the other proposed methods if you are unfamiliar with video streaming services. I would air on the side of using an implementation you find easy and are most comfortable with given your security needs, costs, consequences of hackery.

Community
  • 1
  • 1
Matt Urtnowski
  • 2,556
  • 1
  • 18
  • 36
  • You can't say this is the best approach unless you know, what's he's trying to achieve. If an user closes the page after 1 minute, it won't be ever executed. It may or may not be a problem. – David Ferenczy Rogožan Oct 07 '15 at 16:24
  • My answer assumes he needs the query results returned to the page. He if doesn't need results, consider this http://stackoverflow.com/questions/858883/run-php-task-asynchronously – Matt Urtnowski Oct 07 '15 at 16:27
  • Yeah, if the user closes the page the code must not execute. – user3857732 Oct 07 '15 at 16:31
  • If it is a requirement that if the user closes the page before the 2 minutes are up the query is not run, you should use the ajax request sent from the browser. – Matt Urtnowski Oct 07 '15 at 16:34
  • Yeah, but with jquery the parameters and the php file url are visible. This means that the user can give itself credits. – user3857732 Oct 07 '15 at 16:36
  • You may need to use session information and tokens to help prevent this. Similar too csrf tokens. That way their isn't a static link they can hit for credit, instead each request is sent with a generated token you can check to ensure the page they are coming from matches what you expect. This token expires after use or time. – Matt Urtnowski Oct 07 '15 at 16:39
  • Yeah, that is what I was going to do – user3857732 Oct 07 '15 at 16:43
  • You can also check the time at which the token was generated to ensure it is not being used early. – Matt Urtnowski Oct 07 '15 at 16:46
  • So this is not the way to implement it definitely. If you set a timer to 2 minutes to execute an AJAX call, you can add whatever tokens you want, user can just change the interval of timer using Developer tools in a browser and he'll get credits after a few seconds. Everything what's in a browser belongs to the user and he do whatever he wants with it. **This should be implemented server-side.** – David Ferenczy Rogožan Oct 07 '15 at 16:52
  • As I previous stated, you can check the time at which the token as generated. At some point the browser is going to need to communicate back to the server, either to setup a websocket, to make an ajax request, or make a page navigation. – Matt Urtnowski Oct 07 '15 at 16:54
  • But why to do it hard way (without 100 % result), if you can do it easy way? Implementing token checks etc. What if user reloads the page or goes to another page and it resets the timer? You would need to implement another mechanism to solve this. And than you'll find another issue. If you would do it server-side, you just implement the business logic you need without any security checks and hacks. – David Ferenczy Rogožan Oct 07 '15 at 17:09
0

Create a PHP script, which will update user's credits. Schedule the execution of this script for example every 1 minute using Cron.

This script goes through all active users and updates credits of each user. Then it ends.

Conditions when it should update the credits are up to you. I guess you'll check if 2 minutes elapsed from some previous activity and if yes, you'll update the credits. Otherwise you will do nothing.

It could look like this:

$users = getActiveUsers();
$currentTime = time();

// go through all active users
foreach ($users as $user) {
    // if conditions are met, give some credits to the user
    if ($currentTime - $user->lastActivityOn >= 120) {
        $user->credit += 1;
        $user->save();
    }
}

This script will run very small amount of time, depending on a number of users it can be a few milliseconds to a few seconds, and will be executed every minute. It's very simple and it's a common way how similar tasks are implemented.

It shouldn't be implemented on a client, because you can't trust the client. You would pay a lot of effort to implement various security checks and mechanisms and they won't be 100 % secure most probably. On the other side server-side solution is completely secure by design without any effort.

David Ferenczy Rogožan
  • 23,966
  • 9
  • 79
  • 68
-2

You can use usleep fonction in php

wait 2 seconds usleep(20000); http://php.net/manual/en/function.usleep.php

time is in microseconds

Px2
  • 1