Newsgroup: it.comp.www.php
Titolo: aprire e scrivere in un file in un'operazione sola (cristina)

salve a tutti,
è parecchio che seguo questo forum e sono contento di poter dire che
ho imparato molto solo leggendo i vostri post, ma adesso è agiunto il
momento di chiedervi un po' d'aiuto e spero che possiate trovare il
tempo.
##quello che voglio fare è aprire un file
$match=0;
$fp = fopen("$dir/db.txt","w+");
$lock = flock($fp, LOCK_EX);
if ($lock) {
while (!feof ($fp)) {
$data = fgets($fp,999999);
## se una delle righe matcha $var scrivere una $entry
if (preg_match("/$var/", $data)) {
fwrite($fp, "$entry");
$match=1;
}
##altrimenti scrivere la riga originale $original
else {
fwrite($fp, "$original");
}
}
##se alla fine del file nessuna riga viene matchata allora scrivere
questa riga a fondo file
if ($match==0) {
fwrite($fp, "$entry");
}
$lock = flock($fp, LOCK_UN);
}
fclose($fp);
lo scopo di questo script è:
- aprire un file
- controllare riga per riga il suo contenuto
- sostituire UNA di queste righe in caso di match con $entry
- mantenere la riga originale se non vi è match
- aggiungere una riga a fondo file se entro la fine non vi è match 
è MOLTO importante che il tutto venga fatto in una sola operazione
mille grazie
cristina

 match
Non puoi. O almeno io non conosco nessun modo per farlo.
Un file non e` una sequnza di righe, ma di byte, quindi o sostituisci una
serie di bytes con una sequenza di altri byte, ma della stessa lunghezza,
o devi scrivere su un altro file e poi sostituirli.
Inoltre il tuo script e` sbagliato perche` sostituisce quello che viene
DOPO l'espressione da "matchare", e non l'espressione stessa. Dovresti
usare fseek per tornare indietro prima di scrivere.
Se vuoi che il tutto SEMBRI atomico, devi giustamente lockare il file (in
lettura), aprirne un altro in scritturae lockarlo, parsare il primo e 
scrivere sul secondo, quindi cambiare nome a tutti e due, mettendo al
secondo il nome del primo, e infine togliere i due lock. Non ho mai
provato, ma credo si possa rinominare un file lockato.
Bye.

 provato, ma credo si possa rinominare un file lockato.
Che bordello eheheh :-) se il file è lockato sia il lettura che scrittura
non è possibile rinominarlo... sarebbe troppo facile...
Saprei come fare in questo caso, ma è un po' tosto scrivere il codice php
dentro questo post quindi mi limitero' a dire i passaggi da eseguire... che
sono:
- leggere file riga per riga con file(), viene restituito un array (una riga
del file per ogni elemento dell'array)
- con un ciclo (per esempio for) esaminare tutti gli elementi dell'array, se
viene trovato il match sostituire elemento array con entry.
- alla fine del ciclo si avrà un array che corrisponde alle righe del
"nuovo" file.
- se è stato trovato match e sostituito con entry allora scrivi il contenuto
dell'array nel file (aprendo il file in scrittura verrà automaticamnete
eliminato dal file i dati precedenti) tutto cio' puo' essere fatto con un
ciclo foreach() per esempio, se si usa php4.
- se NON è stato trovato match e quindi NON sostituito con entry, apri il
file in append e scrivi in fondo al file la riga che ci devi scrivere.
Tutto ciò puo' essere benissimo fatto in un operazione unica e in un unico
file php.
byez
   Alex

file php.
Il problema e' che se quel file e' ad accesso concorrente, e contiene
molte righe, fra il momento in cui si apre il file in scrittura ed il
momento in cui chiudi il comportamento del sistema e' indeterminato.
Leonardo
-- 
For Light is but the left hand of Darkness; and Darkness but the right
hand of Light. Blessed then be also Darkness, and Creation unfinished.
(Tenets of the Yomeshta cult)                                  +++ATH0

 scrittura non è possibile rinominarlo... sarebbe troppo facile... Saprei
Si`, ho provato. Effettivamente e` impossibile. :/
Mi sa che l'unico modo e` un lock esplicito, magari implementato con un
file, e che lo script php e il processo che crea il file siano d'accordo
a controllare se c'e` e, in caso, a crearlo/distruggerlo rispettivamente
prima e dopo aver usato il file.
Bye.

 Si`, ho provato. Effettivamente e` impossibile. :/
Ho riprovato controllando i permessi (erano cannati quelli della
directory).
Un file lockato si puo` rinominare tranquillamente, basta che apache
abbia permesso di scrittura sulla directory che lo contiene.
Ho usato questo script:
<?php
        $fp = fopen("prova.x", "r+");
        flock($fp, LOCK_EX);
        rename("prova.x", "prova.y");
        flock($fp, LOCK_UN);
        fclose($fp);
?>
(Naturalmente ho creato un file "prova.x" prima di eseguirlo)
Bye.

 operazione atomica.
bravo, questa è l'unico modo esatto!
infatti per assicurare l'atomicità devi PER FORZA aprire il file in lettura,
scrittura!!
tutti gli altri tentativi falliscono miseramente in ambienti concorrenti,
non è poi neanche immaginabile fermare il multitasking :))
Considerate che in caso di 2 lock contemporanei il primo processo che lo fa
passa ed il secondo aspetta, poi appena il primo chiude il file perde il
lock e subentra IMMEDIATAMENTE il secondo, anche se la nuova operazione di
open (in scrittura) del primo processo è successiva alla prima close.
é una questione di scheduling di processi in attesa e che implica
l'immediato prerilascio del processore quando si è liberata una risorsa a
causa della cui inaccessibilità un processo si era sospeso.
Io affronto sempre il problema in questo modo:
- apri il file in lettura-scrittura
- fai la lock (magari con timeout se vuoi essere fine...)
- leggi il file
- elabori il contenuto del file
- fai un seek all'inizio del file
- azzeri il file
- riscrivi il nuovo contenuto
- fai la close.
questo è l'unico modo atomico (in effetti non lo è perchè la definizione di
atomicità implica che l'operazione viene conclusa con una sola operazione
non interrompibile, mentre nel nostro caso se c'è un problema hardware,
mancanza di corrente, mancanza di risorse sul server... si hanno problemi)
per eseguire l'operazione.
Ti raccomando di azzerare il file solo dopo aver fatto tutte le elaborazioni
e quindi "un attimo" prima di scriverci il nuovo contenuto. Questo per
evitare che se il processo termina accidentalmente non perdi il contenuto
del file (al massimo non viene aggiornato).
Spero di essere stato utile,
Ciao,
Tommaso
www.softwareplanet.net

 e tu ti trovi con un "buco" di dati.
Non so se dico giusto pero'... file() non richiede l'apertura con fopen()
quindi si potrebbe fare cosě:
- apri con fopen() in write
- lock del file in scrittura (nessuno puo' scriverci, solo leggere)
- leggi il file con file() (anche se fopen č in w non importa perchč a
file() non interessa fopen())
- fai le varie operazioni
- scrivi sul file precedentemente aperto e lockato
- sblocchi il file
- chiudi il file
Durante questa operazione chiunque puo' leggere il file ma non scriverci
sopra quindi non c'č pericolo che in quella frazione di secondo qualcuno
cambi il contenuto del file...
Ti ripeto, non so se dico il giusto perchč non ho mai provato č solo un
ragionamento intuitivo.

 file() non interessa fopen())
non penso sia possibile ciò... se il file è bloccato non deve essere
accedibile con alcuna istruzione di I/O, quindi anche file()

 leggi il file con file() (anche se fopen č in w non importa perchč a
Occhio che se apri un file in "w" ti viene azzerato, quindi quando lo
riapri con file() non ci trovi piu` niente. :)
Cmq, non credo funzioni, perche` quando hai un lock in scrittura niente
altro puo` accedere a quel file, nemmeno altre istruzioni del tuo script.
Bye.