8
votes

PHP, PDO et SQLSRV exécutent plusieurs fois sur une instruction insertion

J'utilise PDO et PHP pendant un certain temps avec des serveurs MySQL et Apache. J'ai récemment été chargé de convertir une application Web héritée pour une entreprise à une nouvelle configuration. L'ancienne configuration est une pile Web standard Linux (Apache / PHP / MySQL / FileZilla) et la nouvelle configuration sera un serveur Windows 2003 avec IIS / PHP (installation rapide CGI install) / SQL Server 2003 / No FTP.

J'ai presque tout ce qui fonctionne, à l'exception d'une conversion d'une instruction MySQL pour mettre à jour une table avec des informations d'accès au fichier. Utilisation de PDO avec pilote SQLSRV et exécution d'une instruction insertion dans un script PHP 'Fichier Télécharger', insère plusieurs enregistrements dans la table SQL.

Le téléchargement.php utilise plusieurs requêtes sur le serveur SQL. Une fois pour vérifier l'existence et les variables de fichier dans une table, puis met à jour une autre table avec les informations d'accès.

Voir ci-dessous pour Download.PHP Code

Débogage Affiche l'impression / écho de $ Compter comme 1. La vérification des enregistrements SQL Server, affiche toujours plus d'un inséré. Parfois, il ne s'agit que d'une ligne supplémentaire pour un total de deux, mais d'autres fois, il est aussi élevé que quatre déclarations supplémentaires étant insérées. Le nombre de dollars reste indiqué comme 1, dans tous les cas.

Ce script PHP particulier vérifie des informations sur la base de données SQL avant d'appeler cette instruction insertion. Premièrement, la vérification de l'authentification pour l'accès au fichier (réussite), vérifie l'existence du fichier (réussite), puis met à jour la table d'accès avec des informations pour le téléchargement (erreur) et sert enfin le PDF à l'utilisateur (réussite).

Lorsque je délivrant manuellement la déclaration d'insertion dans l'analyseur de requête, il réussit et fonctionne comme prévu; Il insère une ligne à chaque fois. L'erreur semble être avec la mise en œuvre SQLSRV ou PDD de l'exécution ().

J'ai recherché sur Stackoverflow, ServerFault et le Tout-Puissant Google pour obtenir des informations à ce sujet. Les seuls types de résultats renvoyés dans lesquels les utilisateurs ont besoin d'exécuter plusieurs requêtes / inserts dans une instruction / exécution. Où est mon problème est le contraire; Je souhaite cependant exécuter une seule instruction insertion, plus d'une est toujours exécutée.

question est la suivante: pourquoi cela se produit-il et comment puis-je empêcher l'insert multiple de se produire?

update par demande

Le Code qui accède à ce fichier est un lien singulier d'une autre page Web. La page répertorie les fichiers actuels que l'utilisateur est autorisé à accéder et à présenter des liens vers le script download.php pour la vérification, la mise à jour et la portion réelle du PDF.

page Afficher la page contient une liste de liens (imprimés en une boucle de boucle) agencée comme: xxx

lorsque l'utilisateur clique sur ce lien, le script ci-dessous est ce qui fonctionne en plus de l'autre code ci-dessus pour télécharger.php. Il sert avec succès le fichier PDF. Le contenu est envoyé par téléchargement.php sous forme d'en-tête PHP / Inline PDF:

voir ci-dessous pour le code

En regardant les journaux du serveur affiche Deux obtenir une demande de téléchargement.php: xxx

J'ai testé dans Firefox , Opera, et IE (6-9B) et les résultats sont les mêmes.

Mettre à jour deux

Mettre l'ensemble du fichier download.php ici: < / p> xxx


9 commentaires

S'il vous plaît poster plus de code. Si vous obtenez de multiples inserts, votre script est probablement appelé plusieurs fois, soit en raison de la logique défectueuse (par exemple, lorsque la poste n'a pas encore été soumise) ou en raison de règles de réécriture erronées.


Regardez le journal d'accès de votre serveur pendant que ce script fonctionne pour voir si vous le frappez en réalité plusieurs fois.


Que se passe-t-il si vous venez de faire un simple fichier de test qui n'a que le code associé à l'insert?


@Michael j'ai vérifié les journaux du serveur après le redémarrage des IIS. Le script est en fait appelant deux fois download.php. Si les variables € _ get ne sont pas définies ou non des valeurs attendues, le script sort. Ensuite, la logique passe dans la récupération des informations de fichier et le téléchargement. Pourquoi cela causerait-il que le script de téléchargement ou ma fonction soit exécuté plus d'une fois?


@Penguincoder Veuillez afficher le code qui se produit avant le code d'insertion, la pièce qui examine $ _ obtenir et sort.


@Farray: avec un fichier de test et des variables codées en papier, l'instruction insertion ne s'exécute qu'une fois comme prévu. Basé sur cela, la cause probable de mon erreur serait-elle les multiples déclarations PDO PREPARY / EXÉCUTE dans mon téléchargement.php? Comment pourrais-je exécuter deux déclarations distinctes à l'aide de PDO sans traverser les préparations réelles?


@Michael: a ajouté le fichier complet. Pour ajouter, la sortie (0); fonctionne comme prévu. Lorsque l'insert est exécuté (deux fois / download.php étant appelé deux fois sur un clic / appel), le serveur SQL montre des horodatages de quelques millisecondes à part. Lorsque le script sort (aucun $ _ obtenir des valeurs ou incorrect) aucun insert n'est exécuté. (Comportement attendu pour cette sortie)


Je ne sais pas si cette source de vos problèmes, mais aussi loin que je me souviens, SQLSRV (au moins à la V2.0) n'autorise pas / comme les paramètres nommés dans les requêtes, c'est-à-dire que vous devriez simplement utiliser ? < / code> au lieu de : fichier .


si (! émetteur ($ _ obtenir) ||! Isset ($ _ obtenir ['get [' ']) ||! Isset ($ _ obtenir [' get> est plus simplement écrit comme Si (! Ivesset ($ _ obtenir ['F'], $ _GET ['T'])) {. Cette condition si (! Preg_Match ('/ ^ [A-ZA-Z0-9 _ \ - \ \.] {1,60} $ /', $ Fichier) ||! Preg_match ('/ ^ AV | DS | DS | CR | DP $ / ', $ Type)) { est mieux écrit comme si (! Preg_Match (' / ^ \ w .-] {1,60} $ / ', $ File) || ! In_array ($ Type, ['AV', 'DS', 'CR', 'DP'])) {


3 Réponses :


1
votes

Vous commenciez que le script de téléchargement est appelé deux fois et doit quitter si la valeur correcte n'est pas trouvée. Cela peut ne pas être le cas parce que vous abusez RowCount's de PDOSTATIMENT () Pour tester les fichiers trouvés. Cette méthode est destinée à renvoyer le nombre de lignes affectées pour supprimer, mettre à jour ou insérer des relevements, mais ne sélectionne pas . .

Si la dernière instruction SQL exécutée par la pdostatement associée a été une instruction SELECT, certaines bases de données peuvent renvoyer le nombre de lignes retournées par cette déclaration. Cependant, ce comportement n'est pas garanti pour toutes les bases de données et ne doit pas être invoquée pour des applications portables. http://php.net/manual/fr/pdostatement.rowcount.php

Ils continuent avec:

Pour la plupart des bases de données, PDostatement :: RowCount () ne renvoie pas le nombre de lignes concernées par une instruction SELECT. Au lieu de cela, utilisez PDO :: Query () pour émettre une instruction Select Count (*) avec les mêmes prédicats que votre instruction SELECT SELET, puis utilisez PdoStatement :: FetchColumn () pour récupérer le nombre de lignes qui seront renvoyées.

Si vous appelez le script download.php deux fois - 1 heure avec des valeurs de fichier incorrectes (qui permettent de transmettre votre test de regex) et d'une heure avec des valeurs correctes, il est tout à fait possible que vous insérez deux fois, même si vous ne téléchargez que si vous ne téléchargez que une fois.


2 commentaires

J'ai changé le résultat $ à $ résultat = $ statm-> fetchall (); et $ comptez to $ comte = compte ( $ résultat); et a donné chaque paramètre lié nommé un nom unique. Avec cela, l'insert pour la table d'accès ne se produit qu'une fois. Cependant, la mise à jour de PDF_INFO ne se produit jamais et le navigateur est suspendu et ne fournit jamais le fichier PDF. Plus que probablement une erreur dans une autre logique et non liée à cette question.


Les modifications que j'ai apportées qui ont donné les résultats attendus où avec un commentaire pendant boucle pour le téléchargement PDF. De cette façon, je pouvais imprimer les erreurs si cela s'est produit. Suppression de ce commentaire autour du pendant la boucle , l'insert se produit plus d'une fois, à nouveau. Semble une erreur dans ma logique PHP / Header et non liée à cette question.



1
votes

Si vous utilisez mod_rewrite de l'Apache est en effet chargé deux fois. À titre d'exemple, utilisez le code suivant sur votre page d'index: xxx

sans utiliser de redirection les incréments de sortie de 1 sur chaque rafraîchissement. Ajoutez maintenant un fichier .htaccess avec les suivants: xxx

chaque rafraîchissement augmente la page par deux. J'ai essayé la même chose en utilisant un seul Insérer la requête et la même chose se produit: avec .htaccess , deux rangées sont insérées; Sans, une ligne est insérée.

Donc, si vous utilisez mod_rewrite et il affecte télécharger.php alors je crois que c'est le problème.


4 commentaires

Merci pour la réponse, mais ce serveur est un serveur IIS sans support de réécriture d'URL.


Ah, vous avez dit que vous utilisé utiliser Apache. Désolé de ne pas la lire correctement.


Bien que, disant cela, avez-vous essayé de copier le _ session exemple de code incrémental que j'ai ci-dessus (en tant que fichier autonome pour le garder simple)? Cela pourrait être que quelque chose d'autre à propos de votre configuration de serveur rend la page de page deux fois. S'il s'agit d'incrémentation de deux ou plus chaque fois, vous savez que le problème n'est pas votre code PHP.


Testez votre code PHP avec la variable incrémentielle, chaque fois que je frappe cette page la valeur augmente de 1. Dans 150 hits, les incréments variables de la valeur appropriée de 1. Afin après ce test, cela indiquerait-il à ce que Download.php Script étant exécuté deux fois par logique de code PHP incorrect?



1
votes

Conseil: Supprimer le ?> à partir de la fin de tous vos fichiers PHP. Occasionnellement, vous finissez par obtenir un espace invisible ou une nouvelle ligne après cela, et lorsque vous émettez un format binaire comme PDF, cela devient une partie du fichier PDF et le rend corrompu. (Par conséquent, le lecteur de navigateur / pdf est suspendu.)


3 commentaires

Je suppose que vous devinez, mais votre numéro de double get peut être lié à cet ordre des événements: 1) Vous cliquez sur le lien, qui ouvre une nouvelle fenêtre de navigateur qui commence à charger à partir de votre script. 2) Le navigateur reçoit les en-têtes et comprend que le fichier doit être lu à l'aide d'un lecteur PDF. 3) Le navigateur ferme la connexion, ouvre un lecteur PDF avec l'URL comme entrée. 4) Le lecteur PDF exécute le script et télécharge le fichier à nouveau.


Le fichier PDF ne pend pas plus longtemps, après avoir corrigé une autre erreur dans mon script. Cependant, pour tester la validité de votre réponse, j'ai supprimé le ?> à partir de tous les fichiers. Il en résulte que certains fichiers PHP ne sont pas chargés correctement (500 internes) et le double fichier frappé comme dans la question initiale.


En ce qui concerne le ?> , itis très étrange, tant que vous retirez simplement le dernier dans le fichier, cela devrait être bien. En savoir plus à ce sujet ici: PHP.net/manual/fr/ ...