8768 sujets

Développement web côté serveur, CMS

Pages :
Comme je vieillis et que j'aimerais passer le flambeau à d'autres personnes, il est important que la saisie des informations du site de mon association puisse se faire online, et non pas sur mon PC comme je le fais depuis 20 ans.

La conséquence de ce fait, c'est que j'ai besoin d'une BD-R, ce que j'étais jusqu'à présent parvenu à éviter.

Je n'ai eu aucun problème à créer la DB et ses tables avec phpMySQL.
A ma grande surprise, je suis également parvenu facilement à lire en PHP PDO les quelques infos entrées manuellement par phpMySQL.

Par contre je ne parviens pas à faire un INSERT depuis le programme PHP.
Je suppose que je dois faire de travers quelque chose qu'un utilisateur confirmé n'aurait aucune difficulté à réaliser.
Voici le code en question:

try {
    $connection = new PDO("mysql:host=$host;dbname=$dbname", $dbuser, $dbpw);
}
catch(Exception $e) {
    die("Erreur: " . $e -> getMessage . " " . $e -> getCode());
}
echo "<pre>connecté</pre>;

$sql = "INSERT INTO Members (mbID, pupitre, lastName, firstName) VALUE (?,?,?,?)";
$stmt = $connection -> prepare($sql);
if($smt === FALSE) die("Erreur sql");
else echo "<pre>sql OK</pre>");

$mbID = 'xxx';
$pupitre = 'guest';
$lastName = 'Dupont';
$firstName = 'Fernand';
try {
	$stmt -> execute($mbID, $pupitre, $lastName, $firstName);
}
catch(Exception $e) {
	die("Erreur: " . $e -> getMessage . " " . $e -> getCode());
}
echo "<pre>INSERT OK</pre>");

Les différents "echo" me disent que tout s'est bien passé.
La suite du programme de test lit le contenu de la table et affiche le contenu de chaque ligne.
Ce code montre que cette ligne n'a pas été insérée, ce que confirme l'examen de la table par phpMySQL.

Une idée sur les raisons de ce comportement??

Merci de votre aide.
Modérateur
Bonjour,

Je te conseille d'utiliser la méthode bindValue() plutôt que des ?. C'est plus robuste selon moi. Quand une variable est insérée dans ta requête, tu as alors plus d'assurance qu'il n'y ait pas d'effets indésirables de syntaxe.

Exemple (tu noteras l'emploi d'un integer pour $mbID. Si $mbID est une chaîne, il faudra corriger le code en conséquence, et en particulier remplacer PDO::PARAM_INT par PDO::PARAM_STR):
$mbID = 123;
$pupitre = 'guest';
$lastName = 'Dupont';
$firstName = 'Fernand';
$sql = "INSERT INTO Members (mbID, pupitre, lastName, firstName)";
$sql.=" VALUES(:mbID,:pupitre,:lastName,:firstName)";
$stmt=$connection->prepare($sql);
$stmt->bindValue(":mbID",$mbID,PDO::PARAM_INT);
$stmt->bindValue(":pupitre",$pupitre,PDO::PARAM_STR);
$stmt->bindValue(":lastName",$lastName,PDO::PARAM_STR);
$stmt->bindValue(":firstName",$firstName,PDO::PARAM_STR);
if ($stmt->execute()) echo "OK";
else echo "NOK";

Amicalement,
Modifié par parsimonhi (09 Jan 2019 - 13:00)
Je reconnais bien là le côté verbeux de cette syntaxe "à la COBOL", mais tant qu'on n'a pas continuellement à le faire à la main, on doit pouvoir faire.
Mon essai ci-dessus comportait un VALUE qui peut expliquer que ça foire, encore faudrait il que "prepare" lève une erreur.
De la même façon, je suis passé aux ? en pensant que la syntaxe :nom était la cause de l'erreur: en général plus c'est compliqué, plus on a de chance de se tromper, surtout dans une techno qu'on ne maitrise pas.

Voici ce que j'ai fait

$sql = "INSERT INTO Members (mbID, pupitre, lastName, firstName)";
$sql .= " VALUES(:mbID,:pupitre,:lastName,:firstName)";
$stmt = $connection -> prepare($sql);
$mbID = 'fdupont';
$pupitre = 'guest';
$lastName = 'Dupont';
$firstName = 'Fernand';
$stmt -> bindValue(':mbID', $mbID, PDO::PARAM_STR);
$stmt -> bindValue(':pupitre', $pupitre, PDO::PARAM_STR);
$stmt -> bindValue(':lastName', $lastName, PDO::PARAM_STR);
$stmt -> bindValue(':firstName', $firstName, PDO::PARAM_STR);
if($stmt -> execute()) dump("INSERT OK");
else stop("INSERT failed");

Réponse : INSERT failed
savoir le pourquoi est une autre affaire, mais au moins ça l'air d'avoir fait quelque chose...
Modérateur
Bonjour,

1) Vérifie via phpMyAdmin que l'utilisateur que tu utilises dans php a bien les droits nécessaires (il faut qu'il puisse faire des INSERT).
2) Teste directement dans phpMyAdmin si ta requête SQL fonctionne (y a un onglet SQL qui te permet de faire ça).

Note : bien vu pour le VALUES au lieu de VALUE, j'étais passé à côté sans le voir.

Amicalement,
Modérateur
Bonjour,

Tu peux aussi ajouter le code suivant à la fin de ton php pour avoir des précisions sur l'erreur.
echo "\nPDOStatement::errorInfo():\n";
$arr = $stmt->errorInfo();
print_r($arr);

Amicalement,
ça répond
PDOStatement::errorInfo(): Array ( [0] => HY093 [1] => [2] => ) 

Vraisemblablement c'est le nom d'un ou plusieurs champs qui ne correspond pas à ce qu'il attend, ou bien le nombre de paramètres?
Je suis un peu perdu...
Voici la définition de la table:

CREATE TABLE `Members` (
  `mbID` varchar(32) COLLATE latin1_general_ci NOT NULL,
  `pupitre` varchar(16) COLLATE latin1_general_ci NOT NULL,
  `lastName` varchar(128) COLLATE latin1_general_ci NOT NULL,
  `firstName` varchar(128) COLLATE latin1_general_ci NOT NULL,
  `phone` varchar(1024) COLLATE latin1_general_ci NOT NULL,
  `mail` varchar(1024) COLLATE latin1_general_ci NOT NULL,
  `groups` varchar(1024) COLLATE latin1_general_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
Si j'écris simplement

$sql = "INSERT INTO `Members`(`mbID`, `pupitre`, `lastName`, `firstName`, `phone`, `mail`, `groups`) VALUES ('fdupont','guest','Dupont','Fernand','','','')";
$stmt = $connection -> prepare($sql);
if($stmt -> execute()) ....

ça marche!
Comme j'en avais l'intuition, c'est donc bien dans cette façon "propre" de travailler que s'est glissée une erreur que je ne vois pas.
Je devrais arriver à trouver ça, ou à faire un code qui évite ce genre d'erreur, qui est sans doute une faute de frappe quelque part dans un de ces f... noms de variables!
Modifié par PapyJP (09 Jan 2019 - 15:58)
Salut,

cela vient probablement de là


`phone` varchar(1024) COLLATE latin1_general_ci NOT NULL,
  `mail` varchar(1024) COLLATE latin1_general_ci NOT NULL,
  `groups` varchar(1024) COLLATE latin1_general_ci NOT NULL


tu indique NOT NULL pour ces 3 valeurs et pourtant dans ta requête tu ne mets rien du coup MySQL te retourne une erreur.


INSERT INTO `Members`(`mbID`, `pupitre`, `lastName`, `firstName`, `phone`, `mail`, `groups`) VALUES ('fdupont','guest','Dupont','Fernand','','','')


Ici tu le gérais correctement, avec PDO il te faudra le en faire tout autant.
Ce n'est pas que ça: j'y avais pensé, j'ai ajouté les variables correspondantes contenant des chaînes vide, ça ne change rien:

$sql = "INSERT INTO Members (mbID, pupitre, lastName, firstName, phone, mail, groups)";
	$sql .= " VALUES(:mbID,:pupitre,:lastName,:firstName)";
	$stmt = $connection -> prepare($sql);
	$mbID = 'fdupont';
	$pupitre = 'guest';
	$lastName = 'Dupont';
	$firstName = 'Fernand';
	$phone = '';
	$mail = '';
	$groups = '';
	$stmt -> bindValue(':mbID', $mbID, PDO::PARAM_STR) ;
	$stmt -> bindValue(':pupitre', $pupitre, PDO::PARAM_STR);
	$stmt -> bindValue(':lastName', $lastName, PDO::PARAM_STR);
	$stmt -> bindValue(':firstName', $firstName, PDO::PARAM_STR);
	$stmt -> bindValue(':phone', $phone, PDO::PARAM_STR);
	$stmt -> bindValue(':mail', $mail, PDO::PARAM_STR);
	$stmt -> bindValue(':groups', $groups, PDO::PARAM_STR); 
       if($stmt -> execute()) ...

renvoie aussi l'erreur HY093
Mai bon! le plus dur est passé, c'est un problème de faute de frappe quelque part, pas un problème de logique dans le code, c'est l'essentiel.
Modérateur
Bonjour

Il faut aussi modifier :
[quote=PapyJP]
$sql .= " VALUES(:mbID,:pupitre,:lastName,:firstName)";
[/code]

Je vois aussi que tu travailles en latin-1 : pas pratique pour les hiéroglyphes ! Je te conseille de tout mettre en UTF8 (interclassement dans la base mySQL : utf8-unicode-ci). Il faudra aussi rajouter dans le php juste après la connexion à la base :

$pdo->exec("SET NAMES 'utf8'");


Amicalement,
Le point suivant qui me préoccupe, c'est assure le support des caractères UTF-8.
Je constate que c'est à peu près aussi mal fichu que je le craignais.
Apparemment:
phpmyadmin gère les données dans un code ASCII étendu
Cela donne "ténor" (entré manuellement dans phpmyadmin) et "Françoise" (entré par une requête PHP).
Si je fais une requête SELECT * en PHP, cela affiche respectivement "t?nor" et "Françoise".
Bon, quand on le sait on doit pouvoir gérer ça, mais y a-t-il un moyen d'éviter ce m... ?

Anecdote authentique:
Quand on a installé Oracle Applications au Japon, on a constaté que les champs définis par les développeurs US étaient trop petits pour entrer le nom des gens, car un caractère japonais nécessite 4 octets en UTF-8.

Modifié par PapyJP (09 Jan 2019 - 16:50)
Modérateur
Bonjour,

PapyJP a écrit :
Le point suivant qui me préoccupe, c'est assure le support des caractères UTF-8.


Mets tout en UTF8 sinon tu vas souffrir, donc page qui consulte et met à jour la base en UTF8, base en UTF8, interclassement en UTF8 (utf8-unicode-ci qui permet de faire la différence entre sur et sûr).

Si tu commences à entrer des trucs à la main d'une part, et via tes scripts, et que tout n'est pas en UTF8, ce sera une prise de tête.

Amicalement,
Voici le bout de code qui assure que les noms sont bien cohérents:

$fieldNames = ['mbID', 'pupitre', 'lastName', 'firstName', 'phone', 'mail', 'groups'];
$placeholders = [];
foreach($fieldNames as $name) $placeholders[] = ":$name";
$fields = implode(", ", $fieldNames);
$values = implode(', ', $placeholders);
$sql = "INSERT INTO Members ($fields) VALUES ($values)";
$stmt = $connection -> prepare($sql);
	
$dataList = ['fleroy', 'web', 'Leroy', 'Françoise'];
$i = 0;
foreach($fieldNames as $name) $stmt -> bindValue(":$name", strval($dataList[$i++]), PDO::PARAM_STR);
if($stmt -> execute())  ...

Bon, ça ne marche que parce que tous les champs sont numériques, mais ça n'est pas très difficile à régler.
Hello, je t'invite à lire ce tutoriel qui devrait répondre à toutes tes interrogations (principalement sur comment gérer les erreurs liées à l'objet PDO et avoir des informations détaillées sur l'erreur).

Petite astuce non précisée dans le tutoriel, si tes fichiers (de script) sont encodés en ANSI (comme le fait de base windows 7 et antérieur) force les en UTF-8.

Nb : ton erreur est ici
$sql .= " VALUES(:mbID,:pupitre,:lastName,:firstName)";
tu déclares 4 variables associatives et tu en assignes 7 plus bas.
Merci de ta réponse
J’ai corrigé le code, il n’y a plus d’erreur actuellement (jusqu’aux prochaines modifs bien entendu) Smiley cligne
Je n’encode rien en ANSI depuis une bonne dizaine d’années, c’est phpMySQL qui code les infos en ANSI ce qui est sans doute dû à une erreur dans la façon dont j’ai créé la db, je peux la recréer à partir de zéro si nécessaire car il n’y a pratiquement rien d’utile dedans à part la définition des tables, mais ce n’est pas un gros travail. Mais je ne sais pas comment créer une db en UTF8 avec phpMySQL....
Exemple pour une table en utf8 :
-- création d'une base de donnée
CREATE DATABASE IF NOT EXISTS test DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Modérateur
Bonjour,

Pour l'uTF8, au risque de me répéter, il faut :
1) choisir un interclassement commençant par utf8 quand tu crées un champ
2) quand tu te connectes à la base dans ton code php, juste après la ligne $connection = new PDO("...");, il faut ajouter :
$pdo->exec("SET NAMES 'utf8'");


Normalement, ça devrait suffire. Mais bon, je ne garantie pas qu'il n'y ait rien d'autre à faire en fonction de ton contexte.

Et bien évidemment, ce qu'il y a déjà dans la base, il faut le refaire de zéro, ou bien se lancer dans des exports-imports qui risquent d'être plus longs à faire marcher que de repartir de zéro.

Amicalement,
Merci beaucoup
J'avais déjà modifié toutes les tables pour mettre utf8_general_ci, mais la base est créée par l'hébergeur avec latin1_general_ci et je n'a pas trouvé le moyen de modifier cette valeeur. Inutile de supprimer la base et de la renommer, j'aurais eu le même résultat.
J'ai donc ajouté la commande $pdo->exec("SET NAMES 'utf8'"); et il ne semble plus y avoir de problème, mais je vais tester ça plus à fond.
Je dois m'absenter pour quelques jours, je continuerai à mon retour.
Modifié par PapyJP (10 Jan 2019 - 09:28)
Pages :