Intereting Posts
PHP сравнивает строку с акцентами и без акцентов PHP form submit – преобразование в jQuery .Ajax как преобразовать японский английский характер нормальному английскому персонажу? Скажите SELinux предоставить Apache для доступа к файлам PHP вне корневого документа Обрезка блока текста до ближайшего слова, когда достигается определенный предел символов? Как выделить изменения / различия в одном текстовом абзаце другого? PHP Markdown XSS Sanitizer Просмотр Yiic Grid, всегда дающий живое, не является функцией Как полностью интегрировать XMPP на веб-сайт с зарегистрированными пользователями Как создать объект в родительском классе, разделяемом его дочерними классами? phpinfo сообщает о некорректной версии pcre Проверка даты php Разделение данных PHP / MySQL на 3 столбца Получение ошибки: NotReadableException в строке AbstractDecoder.php 302 HTML-форма PHP post для самостоятельной проверки или отправки на новую страницу

Как предотвратить запуск скрипта PHP более одного раза?

В настоящее время я пытался предотвратить onlytask.php сценария onlytask.php более одного раза:

 $fp = fopen("/tmp/"."onlyme.lock", "a+"); if (flock($fp, LOCK_EX | LOCK_NB)) { echo "task started\n"; // while (true) { // do something lengthy sleep(10); } // flock($fp, LOCK_UN); } else { echo "task already running\n"; } fclose($fp); 

и есть работа cron для выполнения вышеупомянутого скрипта каждую минуту:

 * * * * * php /usr/local/src/onlytask.php 

Это работает некоторое время. Через несколько дней, когда я это сделаю:

 ps auxwww | grep onlytask 

Я обнаружил, что есть два экземпляра! Не три или более, не один. Я убил один из экземпляров. Через несколько дней снова повторяются два примера.

Что не так в коде? Существуют ли другие альтернативы для ограничения только одного экземпляра onlytask.php?

ps my /tmp/ папка не очищается. ls -al /tmp/*.lock показывает, что файл блокировки был создан в первый день:

 -rw-r--r-- 1 root root 0 Dec 4 04:03 onlyme.lock 

Solutions Collecting From Web of "Как предотвратить запуск скрипта PHP более одного раза?"

При открытии файла блокировки вы должны использовать флаг x :

 <?php $lock = '/tmp/myscript.lock'; $f = fopen($lock, 'x'); if ($f === false) { die("\nCan't acquire lock\n"); } else { // Do processing while (true) { echo "Working\n"; sleep(2); } fclose($f); unlink($lock); } 

Примечание из руководства по PHP

' x ' – создавать и открывать только для записи; поместите указатель файла в начало файла. Если файл уже существует, вызов fopen () завершится неудачей, возвратив FALSE и создав ошибку уровня E_WARNING. Если файл не существует, попытайтесь его создать. Это эквивалентно определению флагов O_EXCL | O_CREAT для базового открытого (2) системного вызова.

И вот объяснение O_EXCL странице man :

O_EXCL – если O_CREAT и O_EXCL установлены, open () должен завершиться неудачно, если файл существует. Проверка наличия файла и создания файла, если он не существует, должен быть атомарным относительно других потоков, выполняющих open (), именовав то же имя файла в том же каталоге, что и O_EXCL и O_CREAT. Если O_EXCL и O_CREAT установлены, а пути – символическая ссылка, open () завершится с ошибкой и установите errno на [EEXIST], независимо от содержимого символической ссылки. Если O_EXCL установлен и O_CREAT не установлен, результат не определен.

ОБНОВЛЕНИЕ :

Более надежный подход – запустить основной скрипт, который получает блокировку, запускает рабочий сценарий и освобождает блокировку.

 <?php // File: main.php $lock = '/tmp/myscript.lock'; $f = fopen($lock, 'x'); if ($f === false) { die("\nCan't acquire lock\n"); } else { // Spawn worker which does processing (redirect stderr to stdout) $worker = './worker 2>&1'; $output = array(); $retval = 0; exec($worker, $output, $retval); echo "Worker exited with code: $retval\n"; echo "Output:\n"; echo implode("\n", $output) . "\n"; // Cleanup the lock fclose($f); unlink($lock); } 

Здесь идет рабочий. Давайте поднимем фатальную ошибку:

 #!/usr/bin/env php <?php // File: worker (must be executable +x) for ($i = 0; $i < 3; $i++) { echo "Processing $i\n"; if ($i == 2) { // Fake fatal error trigger_error("Oh, fatal error!", E_USER_ERROR); } sleep(1); } 

Вот результат, который я получил:

 galymzhan@atom:~$ php main.php Worker exited with code: 255 Output: Processing 0 Processing 1 Processing 2 PHP Fatal error: Oh, fatal error! in /home/galymzhan/worker on line 8 PHP Stack trace: PHP 1. {main}() /home/galymzhan/worker:0 PHP 2. trigger_error() /home/galymzhan/worker:8 

Главное, что файл блокировки очищается правильно, поэтому вы можете снова запустить main.php без проблем.

Теперь я проверяю, работает ли процесс ps и деформирует скрипт php с помощью сценария bash :

  #!/bin/bash PIDS=`ps aux | grep onlytask.php | grep -v grep` if [ -z "$PIDS" ]; then echo "Starting onlytask.php ..." php /usr/local/src/onlytask.php >> /var/log/onlytask.log & else echo "onlytask.php already running." fi 

и запускать скрипт bash cron каждую минуту.

 <?php $sLock = '/tmp/yourScript.lock'; if( file_exist($sLock) ) { die( 'There is a lock file' ); } file_put_content( $sLock, 1 ); // A lot of code unlink( $sLock ); 

Вы можете добавить дополнительную проверку, написав pid, а затем проверите ее в файле file_exist-statement. Чтобы обеспечить его еще больше, вы можете получить все запущенные приложения с помощью «ps fax» end, проверьте, находится ли этот файл в списке.

попробуйте использовать наличие файла, а не флаг его флока:

 $lockFile = "/tmp/"."onlyme.lock"; if (!file_exists($lockFile)) { touch($lockFile); echo "task started\n"; // // do something lengthy // unlink($lockFile); } else { echo "task already running\n"; } 

Вы можете использовать файлы блокировки, как предполагали некоторые, но то, что вы действительно ищете, это функции PHP Semaphore . Они вроде как блокировки файлов, но разработаны специально для того, что вы делаете, ограничивая доступ к общим ресурсам.

Никогда не используйте unlink для файлов блокировки или других функций, таких как переименование. Это ломает ваш LOCK_EX на Linux. Например, после отмены или переименования файла блокировки любой другой скрипт всегда возвращает true из flock ().

Лучший способ обнаружить предыдущий действительный конец – записать в файл блокировки несколько байтов в конце блокировки, до LOCK_UN для обработки. И после того, как LOCK_EX прочитает несколько байтов из файлов блокировок и обработчика ftruncate.

Важное примечание: все проверено на PHP 5.4.17 на Linux и 5.4.22 на Windows 7.

Пример кода:

set Семафор:

 $handle = fopen($lockFile, 'c+'); if (!is_resource($handle) || !flock($handle, LOCK_EX | LOCK_NB)) { if (is_resource($handle)) { fclose($handle); } $handle = false; echo SEMAPHORE_DENY; exit; } else { $data = fread($handle, 2); if ($data !== 'OK') { $timePreviousEnter = fileatime($lockFile); echo SEMAPHORE_ALLOW_AFTER_FAIL; } else { echo SEMAPHORE_ALLOW; } fseek($handle, 0); ftruncate($handle, 0); } 

оставить семафор (лучший вызов в обработчике останова):

 if (is_resource($handle)) { fwrite($handle, 'OK'); flock($handle, LOCK_UN); fclose($handle); $handle = false; }