[PHP] Problème insertion bdd

Bonjour,

Je ne suis pas développeur mais je dois effectuer un très simple formulaire qui insère des données dans ma BDD (donc relativement très très simple :))

Petit problème que je n’avais pas eu lors d’autres tests sur des trucs perso : si mon visiteur insère un ’ dans un champ, aucune insertion se fait dans la bdd. En lisant des tutos j’ai cru comprendre que la fonction “htmlspecialchars” pouvait résoudre ce problème.

Or ca ne marche pas et meme si je ne mets pas de ’ l’insertion ne se fait pas.

Une erreur de syntaxe ?

Voici ma page de traitement en php :

     <?php

$var1 = htmlspecialchars($_POST['raison']);
$var2 = htmlspecialchars($_POST['adresse']);
$var3 = htmlspecialchars($_POST['contact']);
$var3 = htmlspecialchars($_POST['ville']);
$var4 = htmlspecialchars($_POST['tel']);
$var5 = htmlspecialchars($_POST['etage']);
$var6 = htmlspecialchars($_POST['elec']);
$var7 = htmlspecialchars($_POST['ether']);
$var8 = htmlspecialchars($_POST['ip']);
$var9 = htmlspecialchars($_POST['sel1']);
$var10 = htmlspecialchars($_POST['scan']);
$var11 = htmlspecialchars($_POST['scanmail']);
$var12 = htmlspecialchars($_POST['os']);
$var13 = htmlspecialchars($_POST['nombre']);
$var14 = htmlspecialchars($_POST['mailfai']);
$var15 = htmlspecialchars($_POST['smtp']);


$conn = mysqli_connect("localhost","root","root","app");
if (mysqli_connect_errno()) {
    printf("Échec de la connexion : %s\n", mysqli_connect_error());
    exit();
}
$req = $conn->query("INSERT INTO donnees (raison, adresse, ville, contact, tel, etage, elec, ether, ip, sel1, scan, scanmail, os, nombre, mailfai, smtp) VALUES( $var1, $var2, $var3, $var4, $var5, $var6, $var7, $var8, $var9, $var10, $var11, $var12, $var13, $var14, $var15)");

?>

<?php
   header('Location: succes.php');      
?>

Salut,

Je vois que tu débutes de chez début (rassure-toi, on a tous fait ça)…

  1. htmlspecialchars
    http://fr.php.net/manual/fr/function.htmlspecialchars.php
    Le fatal paragraphe, c’est ça :

Certains caractères ont des significations spéciales en HTML, et doivent être remplacés par des entités HTML pour conserver leurs significations.

Or tes saisies de formulaires ne sont pas des textes en HTML, dont certains caractères pourraient avoir une signification spéciale (en HTML). S’il y a une apostrophe quelque part, c’est une apostrophe, rien de plus.
Donc c’est une erreur d’utiliser cette fonction (pour faire ce que tu désires).

  1. tes variables
    Comme il y en a une quinzaine, il est évident qu’il convient d’utiliser des tableaux et de les parcourir au moyen d’une boucle. La manière de faire dépend évidemment de ton cas de figure.
    Dans $POST tu disposes à la fois de noms (raison, adresse…) et des valeurs correspondantes. S’il n’y a que des données à insérer dans une seule table de la base et que les noms dans $POST sont bien aussi les noms de champs de la base, tu peux parcourir $POST (qui est un tableau) pour fabriquer à la fois la liste des noms (= liste des champs de la requête insert) et la liste des valeurs, correctement formatées.
    Un truc de ce genre :

    $champs = ‘(’;
    $valeurs = ‘(’;
    foreach ($_POST as $nom => $valeur) {
    $champs .= $nom . ', ';
    $valeurs .= ‘"’ . $valeur . '", ';
    }
    echo $champs . “\n”;
    echo $valeurs. “\n”;
    $champs = substr($champs, 0, strlen($champs) - 2) . ‘)’;
    $valeurs = substr($valeurs, 0, strlen($valeurs) - 2) . ‘)’;
    echo $champs . “\n”;
    echo $valeurs . “\n”;

    $sql = 'INSERT INTO donnees ’ . $champs . ’ VALUES ’ . $valeurs;
    echo $sql . “\n”;

    Note : je t’ai mis des “echo” pour que tu puisses voir le résultat (rien de mieux pour comprendre). Tu peux bien sûr les supprimer.
    Note : comme je l’ai déjà dit, il faut éventuellement adapter tout ça à ta situation particulière. C’est juste pour donner un aperçu…

Explication à propos des apostrophes qui ne passent pas : en fait, les valeurs de type texte fournies à insert doivent être entre guillemets, entre autres pour cette raison.
Mais alors se pose le problème des guillemets simples (’ ‘) et des guillemets doubles (" “). Il faut évidemment choisir des guillemets double, précisément à cause des apostrophes, interprétés comme guillemets simples, ce qui fiche le souk… D’où les choses un peu bizarres à première vue comme '”’ . $valeur . '", ’ qui encadrent bien $valeur par des guillemets doubles (et une virgule et un espace au bout)…

(je ne suis pas sûr de ne pas avoir commis d’erreur dans le code proposé… Ça arrive…)

Edit : j’ai écrit $POST dans le texte, parce que le tiret fait des italiques dans le forum (c’est pas malin !).

Merci enormement pour ta réponse et de tes explications
Effectivement n’étant pas développeur j’ai du mal ^^.
En revanche pour etre sur de comprendre :
ton $champs =’(’;e t $valeurs=’(’;
correspondent à quoi ?
Il faut que j’ecrives tels quel ?

Quand on écrit $a = $a . (ou, en raccourci, $a .=), il faut que le $a après le signe “=” existe déjà, pour que php puisse l’évaluer. Il faut donc l’initialiser avant le début de la boucle foreach.
On peut évidement faire :
$champs = '';
Mais comme on sait qu’on aura besoin dans insert de (liste des champs) entre parenthèses, autant initialiser avec la parenthèse ouvrante :
$champs = '(';
qu’on fermera ici :
$champs = substr(...) . ')';
Idem pour $valeurs…

En passant, une remarque sur ce substr : à la sortie de la boucle, $champs se terminera par une virgule et un espace qu’on insère à chaque tour comme séparateur de liste, y compris le dernier. L’espace ne sert qu’à aérer un peu (les “echo” sont plus lisibles). Mais c’est évidemment une virgule en trop qu’il s’agit donc de supprimer. L’idée c’est de ne garder qu’une chaîne de longueur n-2 (= avec 2 caractères en moins que la chaîne originale).

Edit : je viens de me rendre compte que j’ai fait une erreur dans le script : ce n’est pas += (<=> somme) mais .= (point égal) (<=> concaténation). Un relent de javascript… :smile:
J’ai édité et corrigé…

Woaw merci ton script est extraordinaire
ca c’est du dèv :stuck_out_tongue:

voici un screen où on peut voir que les valeurs sont récupérées. En revanche j’ai juste refais une table qui s’appelle infos. Par contre le “insert” dans la base ne marche pas :s EDIT : j’ai oublié de mettre le connexion à la base :stuck_out_tongue: à quel endroit je dois mettre la variable qui contient la connexion à la bdd?

Une chose est sûre, il faut que tu connectes à la base de données avant de faire la requête.
En toute logique, ton script php reçoit $POST et donc tu commences par traiter ça, c’est-à-dire fabriquer le texte de la requête ($sql dans mon script). Une fois que tu as vérifié que le script génère une requête correcte, tu connectes à la base, puis tu exécutes la requête :
$req = $conn->query($sql);

Pour les images, utilise un hébergeur comme http://pix.toile-libre.org/ puis copie le lien de la miniature dans ton post. Ça évite de prendre une loupe pour y voir quelque chose…

Un petit mot de sécurité : pense à te renseigner sur les méfaits de l’injection SQL et à t’en prémunir ;-). Ta base de données risque de se vider inopinément, sinon.

Un petit lien vers la doc officielle : http://php.net/manual/fr/security.database.sql-injection.php

Les amis vous allez vous moquez de moi mais j’arrive pas à savoir comment mettre les parametres de connexion ca indique la page ne fonctionne pas

voici le code de connexion à la base mais je ne sais ni ou l’insérer ni comment, meme avec tes conseils :’( :’( :’( :’(
$conn = mysqli_connect(“localhost”,“root”,“root”,“app”);
if (mysqli_connect_errno()) {
printf(“Échec de la connexion : %s\n”, mysqli_connect_error());
exit();

Merci pour vos conseils en sécu aussi mais bon maintenant je me rappelle pourquoi je n’ai pas choisi dev :stuck_out_tongue:

Certes ! Mais peut-être une chose après l’autre…
En fait ça dépend beaucoup de l’utilisation. Si c’est un site ouvert sur le net, c’est sûr qu’il faut être prudent. Mais ça m’étonnerait quand même un peu, dans l’état actuel de la chose.

Je me permettais de dire ça parce qu’il a l’air de vouloir faire remplir ce formulaire à d’autres personnes que lui. Le risque est donc très concret, malheureusement, même sans ouverture sur internet :confused:.

Quand il y a des erreurs, il est toujours bon de recopier le message complet. Parce que “ça ne fonctionne pas” ne renseigne pas beaucoup…

oui pardonnez moi ce qui ne fonctionne pas c’est lorsque je rentre ma requete de connexion à la bdd
voici le message qui s’affiche

La page 192.168.1.114 ne fonctionne pas

Impossible de traiter cette demande via 192.168.1.114 à l’heure actuelle.
HTTP ERROR 500

Il sera effectivement sur le net mais il ne servira que quelques fois par mois où des clients devront renseigner quelques informations (il n’y aura rien d’intéressant c’est des informations pour des copieurs)
Et je suis d’accord c’est pas du tout sécur mais après je ne sais pas comment m’y prendre meme en lisant des docs j’aurai pas la possibilité de m’y pencher à cause de toute la montagne de taff à faire.
:’( :’( :cry:

Qu’est-ce que tu entends par là ?
Et que vient faire ici l’ip d’une bécane ? Et l’erreur 500 n’a rien à voir avec mysql…

Tout de suite une précision : en ce qui me concerne, je ne suis ni une agence de développement gratuite, ni un un formateur en programmation…

non non bien sur désolé d’avoir fait croire ca ce n’etait pas du tout ma pensée merci bcp en tout cas

la quete de connexion à la bdd est
$conn = mysqli_connect(“localhost”,“root”,“root”,“app”);
if (mysqli_connect_errno()) {
printf(“Échec de la connexion : %s\n”, mysqli_connect_error());
exit();
$req = $conn->query($sql);
lorsque je l’integre dans mon fichier je voulais dire

$conn = mysqli_connect("localhost","root","root","app");
if (mysqli_connect_errno()) {
    printf("Échec de la connexion : %s\n", mysqli_connect_error());
    exit();
$req = $conn->query($sql);

Il manque un } après exit();
if condition {
}
Mais ça n’explique quand même pas (a priori) cette erreur 500 ni l’adresse ip… Localhost, c’est 127.0.0.1 ou quelque chose de cette sorte.

avec le symbole “}” il n’y a plus l’erreur 500.
Je suis encore en train de chercher pourquoi ça n’intègre pas les datas dans la base

<?php

$champs = ‘(’;
$valeurs = ‘(’;
foreach ($_POST as $nom => $valeur) {
$champs .= $nom . ', ';
$valeurs .= ‘"’ . $valeur . '", ';
}
echo $champs . “\n”;
echo $valeurs. “\n”;
$champs = substr($champs, 0, strlen($champs) - 2) . ‘)’;
$valeurs = substr($valeurs, 0, strlen($valeurs) - 2) . ‘)’;
echo $champs . “\n”;
echo $valeurs . “\n”;

$conn = mysqli_connect(“localhost”,“root”,“root”,“app”);
if (mysqli_connect_errno()) {
printf(“Échec de la connexion : %s\n”, mysqli_connect_error());
exit();}
$req = $conn->query($sql);

$sql = 'INSERT INTO infos ’ . $champs . ’ VALUES ’ . $valeurs;
echo $sql . “\n”;
?>

pourtant j’ai bien la ligne qui permet de se connecter à la base

$req = $conn->query($sql);
Là tu exécutes la requête $sql … que tu définis après :
$sql = 'INSERT INTO infos ' . $champs . ' VALUES ' . $valeurs;

Oui donc du coup le code dans mon précédent message devrait fonctionner.
J’ai vérifié avec les echos il récupère bien toutes les variables.
Ensuite je lance la connexion à la base :

$conn = mysqli_connect("localhost","root","root","app");

et j’execute la requete :

$sql = 'INSERT INTO infos ' . $champs . ' VALUES ' . $valeurs;

Logiquement ça devrait suffire ?

Mais non !
mysqli_connect crée une connexion $conn au serveur mysql.
$sql crée une chaîne de caractères qui représente le texte d’une requête. Ça n’exécute rien.
C’est $conn->query ($sql) qui exécute.
Mais évidemment il faut que $sql représente une requête. Donc tu dois créer la chaîne adéquate avant d’exécuter query.
Comme tu avais fait au début :
$req = $conn->query("INSERT INTO donnees (raison, adresse, ville, contact, tel, etage, elec, ether, ip, sel1, scan, scanmail, os, nombre, mailfai, smtp) VALUES( $var1, $var2, $var3, $var4, $var5, $var6, $var7, $var8, $var9, $var10, $var11, $var12, $var13, $var14, $var15)");
Sauf que maintenant tu détermines la liste des champs et des valeurs par calcul, plutôt que les taper une par une à la main…

SOIS BENI MERCI :slight_smile:

voici le code au final merci beaucoup
<?php
$champs = ‘(’;
$valeurs = ‘(’;
foreach ($_POST as $nom => $valeur) {
$champs .= $nom . ', ';
$valeurs .= ‘"’ . $valeur . '", ';
}
$champs = substr($champs, 0, strlen($champs) - 2) . ‘)’;
$valeurs = substr($valeurs, 0, strlen($valeurs) - 2) . ‘)’;
$conn = mysqli_connect(“localhost”,“root”,“root”,“app”);
$req = $conn->query('INSERT INTO infos ’ . $champs . ’ VALUES ’ . $valeurs);
?>