Ecco come l'ho risolto per ora, usando un file.
Procedura
- Ottieni l'IP del client ed esegui l'hashing (per impedire la lettura dei file).
- Apri il file IP e scansiona ogni riga
- Confronta l'ora del record corrente con l'ora corrente
- Se la differenza è maggiore del timeout impostato, vai a 5., altrimenti 7.
- Se l'IP corrisponde al client, crea un record aggiornato, altrimenti
- elimina record.
- Se l'IP corrisponde al client, fornisci il messaggio di errore, altrimenti copia il record.
Codice di esempio
<?php
$sIPHash = md5($_SERVER[REMOTE_ADDR]);
$iSecDelay = 10;
$sPath = "bucket.cache";
$bReqAllow = false;
$iWait = -1;
$sContent = "";
if ($nFileHandle = fopen($sPath, "c+")) {
flock($nFileHandle, LOCK_EX);
$iCurLine = 0;
while (($sCurLine = fgets($nFileHandle, 4096)) !== FALSE) {
$iCurLine++;
$bIsIPRec = strpos($sCurLine, $sIPHash);
$iLastReq = strtok($sCurLine, '|');
// this record expired anyway:
if ( (time() - $iLastReq) > $iSecDelay ) {
// is it also our IP?
if ($bIsIPRec !== FALSE) {
$sContent .= time()."|".$sIPHash.PHP_EOL;
$bReqAllow = true;
}
} else {
if ($bIsIPRec !== FALSE) $iWait = ($iSecDelay-(time()-$iLastReq));
$sContent .= $sCurLine.PHP_EOL;
}
}
}
if ($iWait == -1 && $bReqAllow == false) {
// no record yet, create one
$sContent .= time()."|".$sIPHash.PHP_EOL;
echo "Request from new user successful!";
} elseif ($bReqAllow == true) {
echo "Request from old user successful!";
} else {
echo "Request failed! Wait " . $iWait . " seconds!";
}
ftruncate($nFileHandle, 0);
rewind($nFileHandle);
fwrite($nFileHandle, $sContent);
flock($nFileHandle, LOCK_UN);
fclose($nFileHandle);
?>
Osservazioni
Nuovi utenti
Se l'hash IP non corrisponde ad alcun record, viene creato un nuovo record. Attenzione:l'accesso potrebbe non riuscire se non disponi dei diritti per farlo.
Memoria
Se prevedi molto traffico, passa a una soluzione di database come questo tutti insieme.
Codice ridondante
"Ma minxomat", potresti dire, "ora ogni client scorre l'intero file!". Sì, in effetti, ed è così che lo voglio per la mia soluzione. In questo modo, ogni cliente è responsabile della pulizia dell'intero file. Anche così, l'impatto sulle prestazioni è contenuto, perché se ogni client esegue la pulizia, la dimensione del file verrà mantenuta al minimo. Cambialo, se in questo modo non funziona per te.