3

I've been looking for a way to prevent running a php script simultaneously. So I found a way (on this site) to prevent this. This is where I came with (test file).

Link to found solution on stackoverflow: How to prevent PHP script running more than once?

test.php

echo "started: ".microtime()."<br>";

$lock = $_SERVER['DOCUMENT_ROOT'].'/tmp/test.lock';
$f = fopen($lock, 'x');
if($f === false){
    die("\nCan't aquire lock\n");
}else{
    // Do processing
  echo "Working: ".microtime()."<br>";
    sleep(5);

    echo "Still working: ".microtime()."<br>";
    sleep(5);

    echo "Ready: ".microtime()."<br>";
    fclose($f);
    unlink($lock);      
}

When running this script for the first time, the output will be like this:

started: 0.87157000 1389879936
Working: 0.87532100 1389879936
Still working: 0.87542000 1389879941
Ready: 0.87551800 1389879946

Now when I run the same script in the same browser simultaneously, both will be executed, however the second one is executed after the first one. So not simultaneously, but twice. I didn't expect that because it should die if the test.lock file already exists.

So running the script in the same browsers with two tabs, this is the result:

tab1:

started: 0.87157000 1389879936
Working: 0.87532100 1389879936
Still working: 0.87542000 1389879941
Ready: 0.87551800 1389879946

tab2:

started: 0.92684500 1389879946
Working: 0.92911700 1389879946
Still working: 0.92920300 1389879951
Ready: 0.92930400 1389879956

As you can see, the script in the 2e tab is started when the script in the first tab is finished. Isn't that weared?

When I do this with different browsers, the script started as second is terminated, so it works.

browser 1:

started: 0.62890800 1389880056
Working: 0.63861900 1389880056
Still working: 0.63878800 1389880061
Ready: 0.63893300 1389880066

Browser 2:

started: 0.10137700 1389880058

Warning: fopen(/home/users/domain/tmp/test.lock) [function.fopen]: failed to open stream: File exists in /home/users/domain/test.php on line 8
Can't aquire lock

The question

I'm now able to prevent executing the script simultaneous, but how to prevent the second script in the same browser of being executed after the first script is finished!

Community
  • 1
  • 1
Timo002
  • 3,138
  • 4
  • 40
  • 65
  • well, for example just create a permanent file instead of a lock file. – Lexib0y Jan 16 '14 at 13:56
  • @Lexib0y: It must be able to run the script a second time, If I want to. But the browser must be stopped for running it if it runs already. And now the browser waits until another tab is ready. I must just stop and not wait! – Timo002 Jan 16 '14 at 14:02
  • What if you close the lock file at the beginning of the else statement? – NotABlueWhale Jan 16 '14 at 14:05
  • Then you must catch the error (error handling) and let the script wait for some time and retry. To be safe, do limit the amount of retries. – Lexib0y Jan 16 '14 at 14:06

1 Answers1

1

I'm guessing that two tabs in the same browser count as the same client, the browser will use the same session. And the server will answer requests from the same session sequentially. That is why you can be logged into the same service with multiple tabs. (E.g. have several tabs open in stackoverflow)

Requests from a different session (browser) may be processed simultaneously. I guess this depends on your server.

You can't really prevent the script from being executed twice with a simple lock-file. You can only prevent simultaneous execution, as you have demonstrated.

If you wanted to prevent the same client from executing a script too often you'd need to keep track of the last time they executed the script. (possibly in a cookie / database)

Loopo
  • 2,204
  • 2
  • 28
  • 45
  • I agree with your theory, looks like it's something I have to live with. Maybe setting a timestamp in the database when the script is ready en not letting it run again within 1 minute after it has finished. – Timo002 Jan 16 '14 at 14:13
  • 1
    well, you could do something like not deleting your lockfile unless a certain amount of time has passed since your created it, using filemtime or stat. ie. don't delete the lockfile at the end of the script. At the start of the script if now() - timestamp < limit -> exit, else touch your lockfile with current time and run – Loopo Jan 16 '14 at 20:39
  • I know this is an old post. The only thing I found different in the two tabs was the `$GLOBALS['REQUEST_TIME']` variable. It is the timestamp of when the script started. I don't know if that's helpful in anyway, but it does allow the script to differentiate two initiating instances. – Branndon Jun 30 '17 at 19:47