Problème avec File_put_contents

Petit nouveau ! | 6 Messages

10 janv. 2012, 00:46

Bonjour bonjour,

Bonjour

J'ai un petit soucis avec la fonction file_put_contents.

Je m'explique :
Voici un code :

Code : Tout sélectionner

$data = array('a'=>rand(),'b'=>rand(),'c'=>rand()); file_put_contents($filename,json_encode($data), LOCK_EX);
Ce qui se passe, c'est que parfois (relativement rarement néanmoins), ce qui est écrit dans le fichier n'est pas correct (typiquement j'ai deux accolades fermantes, comme si le contenu précédent n'était pas effacé)
J'ai pensé à un problème d'écritures simultanées, mais le problème est que ce fichier ne peut être écrit que par cette fonction et que cette fonction ne peut être appelée deux fois en même temps. (néanmoins je peux avoir une lecture (via une fonction appelée par un autre client) et une écriture via cette fonction en simultané)

Auriez vous une idée du problème (ou de comment le résoudre ?)

Merci d'avance !

Eléphant du PHP | 209 Messages

10 janv. 2012, 11:17

Salut,

Si l'objet que tu encodes en json est un objet vide, tu peux avoir des accolades.
Tu peux tester ce que tu encodes en json dans ton fichier et vérifier qu'il ne s'agit pas d'un objet vide éventuellement ;)

Mammouth du PHP | 2278 Messages

10 janv. 2012, 12:39

Question naïve:
quel est le but du paramètre LOCK_EX ?
Vanitas vanitatum et omnia vanitas
Mes derniers livres :
Sauvez les Mots chez BoD,
Tous les chemins mènent à ROM chez BoD

Petit nouveau ! | 6 Messages

10 janv. 2012, 12:53

Non l'objet encode n'est vraiment pas vide, mon script est exactement de la forme de ce que j'ai écrit
et le résultat que j obtiens est par exemple :
{"a":5,"b":7,"c":12}}

et j'ai rajoute le lock ex ensuite (le bug apparaît également sans), afin d essayer de verrouiller fichier pendant son écriture mais ça ne change rien

Petit nouveau ! | 6 Messages

10 janv. 2012, 23:06

Bonjour

Je n'ai toujours pas résolu le problème

Après quelques tests, j'ai néanmoins remarqué le soucis suivant :
Voilà deux scripts php que je fais tourner en même temps :

Code : Tout sélectionner

<?php // Fichier "ecriture.php" set_time_limit(0); ignore_user_abort(true); $filename = 'test.json'; $puiss = array(); for($i=0;$i<10;$i++){ $puiss[$i]=pow(10,$i+1); } for ($i = 0; $i < 100000; $i++) { $data = array('a' => (mt_rand()%$puiss[rand()%10]), 'b' => (mt_rand()%$puiss[rand()%10]), 'c' => (mt_rand()%$puiss[rand()%10])); file_put_contents($filename, json_encode($data), LOCK_EX); } echo 'fini'; ?>

Code : Tout sélectionner

<?php // Fichier lecture.php set_time_limit(0); ignore_user_abort(true); $filename = 'test.json'; for ($i = 0; $i < 1000000; $i++) { $data = file_get_contents($filename); if (json_decode($data, true) == false) { echo 'Erreur !! - "'.$data.'"'; break; } } echo 'fini'; ?>
Donc je fais tourner les deux en même temps et le script lecture et le script lecture s'arrête quasi immédiatement, me montrant la chaine de caractère vide ...
Alors que selon moi, le LOCK_EX aurait du empêcher cela !

EDIT : je viens de récupérer l'erreur dont je parlasi ci-avant en faisant ce test : j'ai obtenu

Code : Tout sélectionner

{"a":71395911,"b":8808,"c":17}6}

ViPHP
AB
ViPHP | 5818 Messages

11 janv. 2012, 00:25

Pourquoi utilises-tu json_encode pour sérialiser ton tableau ? serialize() ne te convient pas ?

Petit nouveau ! | 6 Messages

11 janv. 2012, 00:50

heu si, mais j'avais pris ce format car je connaissais pas la fonction serialize

mais cela n'explique pas pourquoi on a le problème :)

ViPHP
AB
ViPHP | 5818 Messages

11 janv. 2012, 01:14

Faut utiliser des fonctions adaptées à ce que tu fais...
As-tu le même problème si tu fais :
$data = array('a'=>rand(),'b'=>rand(),'c'=>rand());

file_put_contents($filename,serialize ($data));

$tab = file_get_contents(unserialize ($filename));

echo '<pre>';
print_r($tab);
echo '</pre>';

Petit nouveau ! | 6 Messages

11 janv. 2012, 01:30

oui j'ai le même problème (plus de données qui ne veulent rien dire, mais des données vides dans le fichier lors de l'ouverture)

Mais, certes je n'écrivais peut être pas un bon format de fichier (peut être stocker le format json n'est pas correct si l'on est un puriste), mais je ne comprends tout de même pas pourquoi le fichier était mal écrit, la chaîne semblant être correctement calculée

Petit nouveau ! | 6 Messages

11 janv. 2012, 02:07

J'ai trouvé comment résoudre le bug (mais je ne l'ai pas parfaitement compris néanmoins).

file_get_contents ne respecte pas les verrous et par conséquent, peut ouvrir le fichier alors qu'il est en écriture.
si on remplace le file_get_contents par des fopen, flock fread alors le problème n'apparait plus ...

Reste à comprendre pourquoi la lecture pouvait affecter la lecture

ViPHP
AB
ViPHP | 5818 Messages

11 janv. 2012, 03:39

...peut être stocker le format json n'est pas correct si l'on est un puriste)...
C'est surtout qu'à priori on s'en sert surtout pour faire des échanges php/javascript. A part dans ce cas je n'utilise jamais ces fonctions mais toujours serialize, unserialize. C'est pour cette raison que ton code m'étonnais un peu, je trouvais que tu prenais peut-être des "risques inutiles".
Mais bon le pb était ailleurs et merci pour le retour :)