2012-01-31 10 views
9

Sto provando a scrivere uno script PHP che voglio assicurarmi che abbia una sola istanza in esecuzione in un dato momento. Tutto questo parlare di diversi modi di bloccaggio, di condizioni di gara, ecc. Ecc. Ecc. Mi sta dando i brividi.Blocco PHP/assicurandosi che un determinato script sia in esecuzione una sola volta in qualsiasi momento

Sono confuso sul fatto che i file di lock sono la strada da percorrere, o semafori, o utilizzando le serrature MySQL, o ecc ecc ecc

qualcuno può dirmi:

a) Cosa è il corretto modo per implementare questo?

E

b) punto me un'implementazione di PHP (o qualcosa di facile da porta a PHP?)

+2

è lo script in esecuzione in un server web, o riga di comando? –

+0

Se è davvero importante ... web server. –

+1

probabilmente un blocco mysql, in tal caso, quindi lo script può abortire e pronunciare "alread in use". usare flock e simili bloccherebbe lo script da Apache stesso e probabilmente causerebbe 500 errori interni e quant'altro. –

risposta

0

Si può andare per la soluzione che si adatta meglio il vostro progetto, i due semplici modi per raggiungere tale sono il blocco dei file o il blocco del database.

Per le implementazioni di blocco dei file, controllare http://us2.php.net/flock

Se si utilizza già un database, creare una tabella, generare token di conosciuto per lo script, messo lì, e basta toglierlo dopo la fine dello script. Per evitare problemi sugli errori, puoi utilizzare i tempi di scadenza.

+0

Sei sicuro che questo sia un modo sicuro per gestirlo? I commenti su PHP.net hanno diverse voci che indicano che potrebbe introdurre condizioni di gara. –

1
// borrow from 2 anwsers on stackoverflow 
function IsProcessRunning($pid) { 
    return shell_exec("ps aux | grep " . $pid . " | wc -l") > 2; 
} 

function AmIRunning($process_file) { 
    // Check I am running from the command line 
    if (PHP_SAPI != 'cli') { 
     error('Run me from the command line'); 
     exit; 
    } 

    // Check if I'm already running and kill myself off if I am 
    $pid_running = false; 
    $pid = 0; 
    if (file_exists($process_file)) { 
     $data = file($process_file); 
     foreach ($data as $pid) { 
      $pid = (int)$pid; 
      if ($pid > 0 && IsProcessRunning($pid)) { 
       $pid_running = $pid; 
       break; 
      } 
     } 
    } 
    if ($pid_running && $pid_running != getmypid()) { 
     if (file_exists($process_file)) { 
      file_put_contents($process_file, $pid); 
     } 
     info('I am already running as pid ' . $pid . ' so stopping now'); 
     return true; 
    } else { 
     // Make sure file has just me in it 
     file_put_contents($process_file, getmypid()); 
     info('Written pid with id '.getmypid()); 
     return false; 
    } 
} 

/* 
* Make sure there is only one instance running at a time 
*/ 
$lockdir = '/data/lock'; 
$script_name = basename(__FILE__, '.php'); 
// The file to store our process file 
$process_file = $lockdir . DS . $script_name . '.pid'; 

$am_i_running = AmIRunning($process_file); 
if ($am_i_running) { 
    exit; 
} 
0

Nel caso in cui si sta utilizzando PHP su Linux e penso che il modo più pratico è:

<?php 
if(shell_exec('ps aux | grep '.__FILE__.' | wc -l')>3){ 
    exit('already running...'); 
} 
?> 

Un altro modo per farlo con flag di file e richiamare l'uscita, la richiamata di uscita assicurerà che il flag del file sarà resettato a 0 in ogni caso di esecuzione php l errori.

<?php 
function exitProcess(){ 
    if(file_get_contents('inprocess.txt')!='0'){ 
    file_put_contents('inprocess.txt','0'); 
    } 
} 

if(file_get_contents('inprocess.txt')=='1'){ 
    exit(); 
} 

file_put_contents('inprocess.txt','1'); 
register_shutdown_function('exitProcess'); 

/** 
execute stuff 
**/ 
?> 
0

Un modo è quello di utilizzare la funzione php gregge con un file fittizio, che agirà come un cane da guardia.

Sulla all'inizio del nostro lavoro, se il file di sollevare un LOCK_EX bandiera, di uscita, o aspettare, può essere fatto.

Php documentazione gregge: http://php.net/manual/en/function.flock.php

Per questo esempio, un file denominato lock.txt deve essere creato prima.

Esempio 1, se un altro processo gemello è in esecuzione, uscirà correttamente, senza riprovare, fornendo un messaggio di stato.

Genera lo stato di errore, se il file lock.txt non è raggiungibile.

<?php 

$fp = fopen("lock.txt", "r+"); 

if (!flock($fp, LOCK_EX|LOCK_NB, $blocked)) { 
    if ($blocked) { 

     // another process holds the lock 
     echo "Couldn't get the lock! Other script in run!\n"; 

    } 
    else { 
     // couldn't lock for another reason, e.g. no such file 
     echo "Error! Nothing done."; 
    } 
} 
else { 
    // lock obtained 
    ftruncate($fp, 0); // truncate file 

    // Your job here 
    echo "Job running!\n"; 

    // Leave a breathe 
    sleep(3); 

    fflush($fp);   // flush output before releasing the lock 
    flock($fp, LOCK_UN); // release the lock 

} 

fclose($fp); // Empty memory 

Esempio 2, ci vuole il processo di aspettare, per un'esecuzione dopo la coda, se del caso:

<?php 

$fp = fopen("lock.txt", "r+"); 

if (flock($fp, LOCK_EX)) { // acquire an exclusive lock 
    ftruncate($fp, 0);  // truncate file 

    // Your job here 
    echo "Job running!\n"; 

    // Leave a breathe 
    sleep(3); 

    fflush($fp);   // flush output before releasing the lock 
    flock($fp, LOCK_UN); // release the lock 
} 

fclose($fp); 

E 'anche fattibile con fopen in modalità x, creando e cancellando un file al termine dello script.

Creare e aprire solo per scrittura; posiziona il puntatore del file all'inizio del file . Se il file esiste già, i fopen() chiamano fallirà restituendo FALSE

http://php.net/manual/en/function.fopen.php

Problemi correlati