web-dev-qa-db-fra.com

PHP fichier_cot_contents verrouillage du fichier

Le Senario :

Vous avez un fichier avec une chaîne (valeur moyenne de la peine) sur chaque ligne. Pour les arguments Sake, disons que ce fichier est de 1 Mo de taille (des milliers de lignes).

Vous avez un script qui lit le fichier, modifie certaines des chaînes dans le document (non seulement ajouté mais également en supprimant et modifiant certaines lignes), puis écrase toutes les données avec les nouvelles données.

Les questions :

  1. Est-ce que "le serveur" php, système d'exploitation ou httpd, etc., a déjà des systèmes en place pour arrêter les problèmes tels que celui-ci (lecture/écriture à mi-chemin de l'écriture)?

  2. Si tel est le cas, veuillez expliquer comment cela fonctionne et donne des exemples ou des liens vers la documentation pertinente.

  3. Sinon, y a-t-il des choses que je peux activer ou configurer, telles que le verrouillage d'un fichier jusqu'à ce qu'une écriture soit terminée et que toutes les autres lectures et/ou écrivent échouent jusqu'à ce que le script précédent ait fini d'écrire?

Mes hypothèses et autres informations :

  1. Le serveur en question est en cours d'exécution PHP et Apache ou LightPD.

  2. Si le script est appelé par un utilisateur et est à mi-chemin de l'écriture dans le fichier et un autre utilisateur lit le fichier à ce moment exact. L'utilisateur qui lit qu'il n'obtiendra pas le document complet, car il n'a pas encore été écrit. (Si cette hypothèse est fausse, veuillez me corriger)

  3. Je ne suis concerné que par PHP écrivant et lecture à un fichier texte, et en particulier, les fonctions "fopen"/"fopen" et principalement "file_put_contents". J'ai examiné le "File_put_Contents "Documentation mais n'a pas trouvé le niveau de détail ou une bonne explication de ce que le drapeau" Lock_ex "est ou fait.

  4. Le scénario est un exemple de scénario pire des cas où je supposerais que ces problèmes sont plus susceptibles de se produire, en raison de la grande taille du fichier et de la manière dont les données sont éditées. Je tiens à en apprendre davantage sur ces problèmes et de ne pas vouloir ou de ne pas vouloir ni besoin de réponses ou de commentaires tels que "Utilisez MySQL" ou "Pourquoi faites-vous cela" parce que je ne le fais pas, je veux juste en savoir plus sur le dossier de lecture/écriture avec PHP et ne semble pas regarder dans les bons endroits/documentation et oui, je comprends PHP n'est pas la langue parfaite pour travailler avec des fichiers dans cette manière.

9
hozza

Je sais que ceci a vieilli, mais au cas où quelqu'un circule dans cela. IMHO Le moyen d'y aller, c'est comme ça:

1) Ouvrez le fichier d'origine (E.G. original.txt) à l'aide de fichiers_get_contents ('original.txt').

2) Faites vos modifications/modifications.

3) Utilisez FILE_PUT_Contents ('original.txt.tmp') et écrivez-le sur un fichier temporel original.txt.tmp.

4) Déplacez ensuite le fichier TMP dans le fichier d'origine, remplaçant le fichier d'origine. Pour cela, vous utilisez Rename ('original.txt.tmp', 'original.txt').

Avantages: Bien que le fichier soit traité et écrit dans le fichier n'est pas verrouillé et que d'autres peuvent toujours lire l'ancien contenu. Au moins sur les boîtes Linux/Unix Renommer est une opération atomique. Toute interruption de l'écriture de fichier ne touche pas le fichier d'origine. Une fois que le fichier n'a été entièrement écrit sur disque est-il déplacé. Plus intéressant, lisez-y dans les commentaires à http://php.net/manual/fr/funfunction.rrename.php

Modifier vers l'adresse MOBMENTS (aussi pour commenter):

https://stackoverflow.com/questions/7054844/is-rename-atomic a des références supplémentaires à ce que vous devrez peut-être faire si vous utilisez des systèmes de fichiers.

Sur la serrure partagée pour la lecture, je ne suis pas sûr de savoir pourquoi cela serait nécessaire comme dans cette implémentation, il n'y a aucune écriture au fichier directement. Le troupeau de PHP (qui est utilisé pour obtenir le verrou) est un peu mais peu fiable et peut être ignoré par d'autres processus. C'est pourquoi je suggère d'utiliser le renommer.

Le fichier de renommée devrait idéalement être nommé de manière unique au processus qui fait le renommage de manière à vous assurer que les processus ne font pas la même chose. Mais cela n'empêche bien pas l'édition du même dossier de plus d'une personne en même temps. Mais au moins, le fichier sera laissé intact (dernier édition WINS).

Étape 3) & 4) deviendrait alors ceci:

$tempfile = uniqid(microtime(true)); // make sure we have a unique name
file_put_contents($tempFile); // write temp file
rename($tempfile, 'original.txt'); // ideally on the same filesystem
4
Dom

1) Non 3) Non

Il existe plusieurs problèmes avec l'approche initiale suggérée:

Premièrement, certains systèmes de type UNIX telles que Linux peuvent ne pas avoir de support de verrouillage mis en œuvre. Le système d'exploitation ne verrouille pas les fichiers par défaut. J'ai vu les systèmes SysCalls étant NOP (sans fonctionnement), mais ce sont quelques années de retour, vous devez donc vérifier si une serrure définie par votre instance de l'application est respectée par une autre instance. (C'est-à-dire 2 visiteurs simultanés). Si le verrouillage n'est toujours pas immenté [très probable que ce soit], le système d'exploitation vous permet d'écraser ce fichier.

Lecture de fichiers volumineux, ligne-côté n'est pas réalisable pour des raisons de performance. Je suggère d'utiliser File_Get_Contents () pour charger le fichier entier dans la mémoire, puis exploser () pour obtenir les lignes. Alternativement, utilisez Freead () pour lire le fichier en blocs. L'objectif est de minimiser le nombre d'appels de lecture.

En ce qui concerne le verrouillage du fichier:

Lock_ex signifie une serrure exclusive (généralement pour écrire). Un seul processus peut contenir une serrure exclusive pour un fichier donné à un moment donné. LOCK_SH est une serrure partagée (généralement pour la lecture), plusieurs processus peuvent contenir un verrou partagé pour un fichier donné à un moment donné. Lock_un déverrouille le fichier. Le déverrouillage est effectué automatiquement au cas où vous utiliseriez File_Get_Contents () http://fr.wikipedia.org/wiki/file_locking#in_unix-like_systems

Solution élégante

PHP prend en charge les filtres de flux de données destinés aux données de traitement des fichiers ou des autres intrants. Vous voudrez peut-être créer un tel filtre à l'aide de l'API standard. http://php.net/manual/fr/function.stream-filter-register.phphttp://php.net/manual/fr/filters.php

solution alternative (en 3 étapes):

  1. Créer une file d'attente. Au lieu de traiter un nom de fichier, utilisez la base de données ou un autre mécanisme pour stocker des noms de fichiers uniques quelque part en attente/et traitée dans/traité. De cette façon, rien n'est écrasé. La base de données sera également utile pour stocker des informations supplémentaires, telles que les métadonnées, les horodatages fiables, les résultats de traitement et autres.

  2. Pour des fichiers jusqu'à quelques MB, lisez le fichier entier dans la mémoire, puis le traiter (fichier_get_contents () + exploser () + foreach ())

  3. Pour les fichiers plus volumineux, lisez le fichier en blocs (c'est-à-dire 1024 octets) et processus + écrivez en temps réel chaque bloc en lecture (prudent sur la dernière ligne qui ne se termine pas avec\n. Il doit être traité dans le lot suivant)

4
user42242

In PHP Documentation pour File_put_contents () Vous pouvez trouver dans exemple # 2 L'utilisation Pour Lock_ex , mettez simplement:

file_put_contents('somefile.txt', 'some text', LOCK_EX);

Le LOCK_EX est une constante avec un entier valeur que peut être utilisée sur certaines fonctions dans un Bitwise .

Il existe également une fonction spécifique afin de contrôler le verrouillage des fichiers: FLOCK () de manière.

1
Augusto Pascutti

Une question que vous n'avez pas mentionnée que vous n'aviez pas besoin de faire attention aux conditions de course où deux instances de votre script fonctionnent à la fois, par exemple cet ordre d'occurrence:

  1. Instance de script 1: lit le fichier
  2. Instance de script 2: lit le fichier
  3. Instance de script 1: écrit les modifications apportées au fichier
  4. Instance de script 2: écrase les modifications de la première instance de script au fichier avec ses propres changements (car à ce stade, sa lecture est devenue obsolète).

Donc, lors de la mise à jour d'un fichier volumineux, vous devez verrouiller_ex ce fichier avant de la lire et ne pas libérer le verrou tant que les écritures ont été effectuées. Dans cet exemple, je pense que la deuxième instance de script se bloque un peu pendant qu'il attend son tour d'accéder au fichier, mais c'est mieux que les données perdues.

0
Thoracius Appotite