Order of execution of PHP scripts or how to block repeated execution

The question is, if during the first running copy of the script (it has already created the lock.txt file), run it again, then the second copy will be executed only after 1 finishes its work. Roughly speaking, echo will be displayed 6 times. And I expected that if I run the script again and it sees a file with a lock, then it exits with die.

1) Tell me, why is this happening?
2) Is it possible to stop the execution of the second running copy, and not wait for it to be executed again.

Launching on Denwere

PHP Version 5.3.3

In FF 6.0.2 – buggy, Opera 11.51 – buggy. In IE 8 it works.

Output: Use IE if necessary 🙂


Answer 1, authority 100%

This lock is not secure. The fact is that if an error occurs in the script, or if the script is killed from the outside, the file will not be deleted and all subsequent launches will be unsuccessful. In order to avoid this, you need to use flock(). The algorithm is something like this:

$lockFile = __FILE__.'.lock';
$hasFile = file_exists($lockFile);
$lockFp = fopen($lockFile, 'w');
//     ,     
if (!flock($lockFp, LOCK_EX | LOCK_NB)) {
    die('Sorry, one more script is running.');
}
//     ,    ,
//     
if ($hasFile) {
    echo 'The previous running has been completed with an error.';
}
//   ,  lock 
//         
register_shutdown_function(function() use ($lockFp, $lockFile) {
    flock($lockFp, LOCK_UN);
    unlink($lockFile);
});
//    ,     
//    ,      

As for running long-running scripts, there are two full-fledged ways:

  1. Fork/run another script in a separate process, and end the current one.
  2. When using PHP-FPM, call the fastcgi_finish_request() function. Then the request will complete correctly, and the script will continue to work for as long as necessary.

The option of explicitly sending the Content-Length header is not very good, because:

  1. Only suitable if php is running through apache’s mod_php. so-called. with nginx, this trick will no longer work.
  2. In some browsers the connection will not be closed and as a result the page loading icon will spin until the script is finally terminated (or until the user presses the Stop button)

Answer 2, authority 25%

So, I checked) It’s really the same situation: FF hangs, the rest goes well. Alteration (look at the result in log.txt):

<?
//  
if(file_exists("lock.txt"))
  die("copy");
function log123($msg) {
  if (!$f = fopen('log.txt', 'a+')) return false;
  @fputs($f, date('H:i:s > ').$msg."\r\n"));
  @fclose($f);
  return true;
  }
header('Content-Length: 1');
header('Connection: close;');
echo ' ';
@flush();
@ob_flush();
//
@file_put_contents("lock.txt", "");
for($i=0; $i<3; $i++) {
    log123("test"); //   ,  
    sleep(5);
}
// 
@unlink("lock.txt");
?>

Answer 3

require_once()/include_once() won’t help here?

In your case, it seems that he does NOT create a file at all, or because mod_rewrite is looking for the wrong file.
It’s hard to say: it’s normal, the code is correct, it seems

Testing is simple: comment out unlink().
If it starts after that, then what I wrote happens, and if it crashes, the problem is in sleep under Windows.