JeuWeb - Crée ton jeu par navigateur
[PHP] Pour quelles raisons un INSERT peut être executé 2 fois ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : [PHP] Pour quelles raisons un INSERT peut être executé 2 fois ? (/showthread.php?tid=5660)

Pages : 1 2 3 4


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - Ter Rowan - 16-09-2011

(16-09-2011, 01:17 PM)popayan a écrit : J'ai pas tout suivi et je vais peut être dire une énormité mais pourquoi ne pas mettre un token unique sur ton lien au chargement de ta page.
Ensuite, pendant le traitement tu vérifies que le token n'a jamais été utilisé, si c'est le cas tu traites, sinon tu fais rien

ca marchera peut être sur l'aspect double clic, mais pas sur l'aspect triche
je peux très bien envoyer n requêtes avec des token différents

il faut arriver à bloquer côté serveur sans information issue du client


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - niahoo - 16-09-2011

l'idée n'est pas si mauvaise, tu peux controler le token : la page qui génère le formulaire et le token enregistre ce token.
La page qui reçoit le formulaire vérifie que le token a bien été généré par l'appli auparavant.
Une fois la requête enregistrée, on supprime le token de la table de verif afin qu'il ne puisse pas être rutilisé.

ça permet d'éviter de galérer avec des transaction et peut être étendu à tous les formulaires de l'appli


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - Ter Rowan - 17-09-2011

pas faux, je n'étais pas allé au bout du raisonnement


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - php_addict - 17-09-2011

merci pour le conseil.

Je pense que le soucis vient de APC cache opcode, ou d'une mauvaise config de apache2+apc, car en le désactivant je n'arrive plus à reproduire le bug...à voir si c'est réellement le cas...


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - Sephi-Chan - 17-09-2011

Tu utilisais APC pour quoi dans ton processus ?? Seulement le cache d'opcode ou également le storage ?


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - php_addict - 17-09-2011

(17-09-2011, 10:21 AM)Sephi-Chan a écrit : Tu utilisais APC pour quoi dans ton processus ?? Seulement le cache d'opcode ou également le storage ?

cache d'opcode (mais je ne pense pas que cela vienne de là) mais également le "storage" de quelques résultats de requêtes SELECT (liste des bâtiments du jeu, liste des troupes, etc...)

par exemple, quand on clique sur "construire un bâtiment", j'ai mis mes requêtes SQL dans une transaction, et à l’intérieur de cette transaction je récupérais des données via APC qui auraient du être récupérées par un SELECT, et c'est là où je me demande si il n'y a pas concurrences d’accès aux données de APC

est crédible/possible?


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - Sephi-Chan - 17-09-2011

Mais pourquoi le fait de récupérer différentes données (celles issues du store d'APC plutôt que de la base) pousseraient-elles à avoir plusieurs insertions ?

Dans ton bug, est-ce que le code PHP qui exécute la requête est appelé deux fois ?
Ou bien est-ce que la code PHP n'est appelé qu'une fois, mais avec MySQL qui bégaye et exécute 2 fois l'opération ?

Peux-tu montrer un peu le code ?


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - php_addict - 17-09-2011

difficile de dire si le script est lancé 2 fois ou bien la requete bafouille (a priori ca ne vient finalement pas de APC...)

(17-09-2011, 10:47 AM)Sephi-Chan a écrit : Peux-tu montrer un peu le code ?

voici un extrait du code, le meilleur moyen de reproduire mon bug est de double cliquer comme un goret sur le lien qui lance ce petit bout de code:


init_submit_microtime(); // on initialise $_SESSION['submit_microtime']

if((time()-$_SESSION['submit_microtime'])>CONF_submit_delais) // on verifie qu'une demande n'a pas été soumise durant les 2 dernieres secondes
{
$_SESSION['submit_microtime']=microtime(true); // on enregistre le microtime de soumission du formulaire

construction_batiment($param1 , $param2, $etc , $etc); // on construit
}

// FUNCTION init_submit_microtime
//
//
// DESRIPTION: initialise la variable de session $_SESSION['submit_microtime'] (microtime du dernier soumission de formulaire ou lien cliqué)
//
function init_submit_microtime()
{
if(!isset($_SESSION['submit_microtime']) or empty($_SESSION['submit_microtime']))
{
$_SESSION['submit_microtime']=0;
}
}

le bug ne se produit pas à chaque double-click, et d'ailleurs vu que je verifie le double-click le bug ne peut pas se produire sauf que cela se produit quand même:
ci dessous l'enregistrement d'un double click qui s'est quand même produit:

click 1 du double-click:
time() = 1316252205
time()-$_SESSION['submit_microtime'] = 12.868062973


click 2 du double-click:

time() = 1316252205
time()-$_SESSION['submit_microtime'] = 12.868062973


donc le click 1 est strictement identique au click 2, le double click est quand même passé malgré la vérification du microtime, le resultat qui se produit est que le batiment est lancé en attente de construction pour le même niveau:

batiment en construction niv 9 et batiment en construction niv 9
AU LIEU DE:
batiment en construction niv 9 et batiment en construction niv 10

autre hypothese:: est ce le choix de la config d'apache2 qui peut etre en cause (mode worker ou forker) ?


RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - Sephi-Chan - 17-09-2011

Dans ce cas, c'est probablement le code de ta fonction de construction qui n'est pas bulletproof. Ou les fonctions de microtime qui ne sont pas fiables.

Dans tous les cas, je penche plus pour un problème dans ton code que pour un bug.

Peut-être devrais-tu automatiser ce test. Avec Apache Bench, par exemple.


ab -n 100 -c 1 http://app.dev/script.php



RE: Pour quelles raisons un INSERT peut être executé 2 fois ? - Ter Rowan - 17-09-2011

simple question, probablement pas la source mais qui sait...

Pourquoi compares tu time() à session tout en valorisant session par microtime(true)

pourquoi pas microtime(true) dans le if et dans le = ?

ça me semble plus cohérent, et peut être y a t il des deltas parfois