<? //Проверяем на блокировку if(file_exists("lock.txt")) die("Существует"); else echo "не существует"; //Блокируем $h = fopen("lock.txt","w"); fclose($h); for($i=0; $i<3; $i++) { echo "test"; sleep(10); } //Удаляем блокировку unlink("lock.txt"); ?> 


The question is if the first running copy of the script (he has already created the file lock.txt), run it again, 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 re-run the script and it sees the file with the lock, then it goes on die.

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


Run on Denwere
PHP Version 5.3.3

In FF 6.0.2 - buggy, Opera 11.51 - buggy. In IE 8, it works.
Conclusion: If necessary, use IE browser :-)

  • one
    At a minimum, fopen($name, "w") does not create a file. Use "w +" or file_put_contents($name, '') . - Sh4dow pm
  • I adore when novice developers write something and if something is not working right away they invent all sorts of dreads for themselves :) <br> Learn to understand what you are writing, at least check if the file is created ... - Zowie
  • one
    @ Sh4dow> 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it. > 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it. > 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it. > 'w +' Open for reading and writing; The file is zoomed. If the file doesn’t exist, attempt to create it - korwru
  • Or am I confused for 5 years, or "w +" is no different from "rw" O_O - Sh4dow

3 answers 3

Such a lock is not reliable. 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 must use flock () . The algorithm is about the following:

 $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 the launch of long-running scripts, there are two complete ways here:

  1. Fork / run another script in a separate process and terminate 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 as long as necessary.

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

  1. Only suitable if php works via apache's mod_php. T.N. with nginx, this trick is no longer rolling.
  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 completed (or until the user clicks the Stop button)

    So, I checked) This is really the same situation: FF is hanging, the rest is normal. Alteration (see 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"); ?> 
    • Something I like less and less like mazilla and more and more like chrome ^^ - Zowie
    • Something is also buggy and does not work. In sleep, try to put more time, and then 1 script to the start of the second one may stop its work :) And when there is more time, it displays test 6 times. - korwru
    • Checked, yes. I pick it up. Actually, it is ridiculous that the third + requests work out as expected - immediately die with the cry of "copy". Why did I post it - I thought the second one just glitched, and he so constantly o_O I don’t like the option to use it for launching at all?) @Korwru, I can make a dirty hack specifically for FF, but I need sockets. Interested?) - Sh4dow
    • @ Sh4dow no, no need). - korwru
    • one
      And actually this hack was decided, I dug up that script ... Silly fox = (The point is this (if (empty ($ _ GET ['confirm']))) {// send a request to yourself with confirm = 1 exit;} - Sh4dow

    require_once () / include_once () will not save here?

    In your case, the impression is that he does NOT create a file at all or, because of the work of mod_rewrite, is looking for the wrong file. Hard to say: OK, the code is correct, it seems to be

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

    • If you comment out the line unlink ("lock.txt"); then when you restart ... it still waits until 1 copy is executed, and then dies by die ("Exists"); <br /> 1) The file is looking for one. <br /> 2) mod_rewrite has nothing to do with it. < br /> For some reason, the second copy simply becomes in the "queue" and waits for the completion of the 1st copy. I will try to try the inclode, maybe it will work through it. - korwru
    • @korwru, firefox?) - Sh4dow
    • And where does firefox come from? O_o - Zowie
    • one
      And despite the fact that he has some kind of shaman glitch. Request to address - one and no more. I ditched a lot of time to debug the daemon (just launching streams from the browser), I dug in the registry, in about:config , in its files, put the plugins, mozilla.org wool. And then opened in IE and launched 5 threads without problems. It was decided, as I recall, by sending "Content-Length: 0; Connection: close" - Sh4dow
    • I also had a terrible story - everything for some reason hung, the point is that there was just input with id, no form tag, etc., in general, the whole thing was that the whole JS lay in the dresser and about every minute before each page load hung, while in IE6 even worked ... <br> The decision surprised even more instead of <input> made <div> <input> </ div> ... <br> And frarachka shaman's glitch in the chosen 100% ^^ - Zowie