[RESOLU] Je sèche sur les insertions TEXTE avec des ' (apostrophes)

Eléphanteau du PHP | 25 Messages

17 nov. 2022, 16:47

Bonjour tt le monde,

Voici mon problème :
- Formulaire de saisie
- Dans ce formulaire j'ai un champ texte qui peut contenir des apostrophes Ex : I'love it
- A la validation ça fonctionne pas

Je comprends bien que les apostrophes se retrouvent dans ma requête SQL et donc ça ne marche pas.
J'ai à peu près compris qu'il fallait utiliser "PDO :: quote" pour que cela fonctionne...
Mais soit je ne sais pas l'utiliser soit j'ai rien compris :(

Voici la fonction que j'ai écrit (sans le QUOTE) pour avoir votre avis...
Les apostrophes peuvent se retrouver uniquement sur le $titre.
function enregistrementDB() {

    $titre = $_POST['titre'];
    $volume = $_POST['volume'];
    $vehicle = $_POST['vehicle'];
    $Akey = $_POST['Akey'];
    $tempo = $_POST['tempo'];
    $chorus = $_POST['chorus'];
    $disc = $_POST['disc'];
    $track = $_POST['track'];
    $conn = connectionDB();

    if (!exist($titre, $volume, $vehicle, $Akey)) {

        //on insère les données si les champs sont remplis
        if (!empty($titre) && !empty($volume) && !empty($vehicle) && !empty($Akey) && !empty($tempo) && !empty($track)) {

            $sth = $conn->prepare(
                "INSERT INTO aebersold(titre,volume,vehicle,Akey,tempo,chorus,disc,track)
                    VALUES (:titre, :volume, :vehicle, :Akey, :tempo, :chorus, :disc, :track)"
            );
            $sth->bindParam(':titre', $titre);
            $sth->bindParam(':volume', $volume);
            $sth->bindParam(':vehicle', $vehicle);
            $sth->bindParam(':Akey', $Akey);
            $sth->bindParam(':tempo', $tempo);
            $sth->bindParam(':chorus', $chorus);
            $sth->bindParam(':disc', $disc);
            $sth->bindParam(':track', $track);
            $sth->execute();
            echo ('Les données sont enregistrées, merci.') . '</br>';

        }

    }

}
Merci d'avance pour votre aide :)

Eléphanteau du PHP | 25 Messages

17 nov. 2022, 17:13

Je viens d'y arriver en faisant cela :

Je créer une fonction de validation de la donnée :
function valid_donnees($validonnee) {
    
    $validonnee = addslashes($validonnee);

    return $validonnee;
}
Que j'appelle dans ma fonction d'enregistrement
function enregistrementDB() {

    $titre = valid_donnees($_POST['titre']);
    $volume = $_POST['volume'];
    $vehicle = $_POST['vehicle'];
    $Akey = $_POST['Akey'];
    $tempo = $_POST['tempo'];
    $chorus = $_POST['chorus'];
    $disc = $_POST['disc'];
    $track = $_POST['track'];
    $conn = connectionDB();

    if (!exist($titre, $volume, $vehicle, $Akey)) {

        //on insère les données si les champs sont remplis
        if (!empty($titre) && !empty($volume) && !empty($vehicle) && !empty($Akey) && !empty($tempo) && !empty($track)) {

            $sth = $conn->prepare(
                "INSERT INTO aebersold(titre,volume,vehicle,Akey,tempo,chorus,disc,track)
                    VALUES (:titre, :volume, :vehicle, :Akey, :tempo, :chorus, :disc, :track)"
            );
            $sth->bindParam(':titre', $titre);
            $sth->bindParam(':volume', $volume);
            $sth->bindParam(':vehicle', $vehicle);
            $sth->bindParam(':Akey', $Akey);
            $sth->bindParam(':tempo', $tempo);
            $sth->bindParam(':chorus', $chorus);
            $sth->bindParam(':disc', $disc);
            $sth->bindParam(':track', $track);
            $sth->execute();
            echo ('Les données sont enregistrées, merci.') . '</br>';

        }

    }

}
Est-ce une bonne solution ?
Que va t'il se passer lors de l'insertion dans ma BD et surtout à la récupération de la donnée ?

Eléphanteau du PHP | 25 Messages

17 nov. 2022, 17:21

Bon je fais un peu les questions et les réponses mais je crois avoir trouvé la solution :
Dans ma requête de recherche je mets un STRIPSLASHES
    <tbody>
        <tr>
            <td><?php foreach ($donnees as $donnee) {echo stripslashes($donnee['titre']) . "</br>";}?></td>
            <td><?php foreach ($donnees as $donnee) {echo $donnee['volume'] . "</br>";}?></td>
Et là ça fonctionne :)

ynx
Mammouth du PHP | 586 Messages

17 nov. 2022, 18:14

Bonjour,

Etrange que ton code initial ne fonctionne pas avec les apostrophes.
La méthode avec addslashes/stripslashes fonctionne mais n'est pas recommandée. La bonne pratique pour échapper les caractères sql réservés est d'utiliser une requête préparée (ou PDO::quote() si on ne fait pas de requête préparée).

Tu utilises correctement une requête préparée avec des paramètres via bindParam() donc à priori ton code initial devrait pouvoir enregistrer les données avec apostrophes sans soucis.
Es-tu sûr que le problème initial venait bien de l'apostrophe, quel est le message d'erreur à l'enregistrement (pense à activer le rapport d'erreur PDO et l'affichage des erreurs PHP si pas déjà fait) ?

En théorie, le minimum pour éviter les erreurs ou les failles de sécurité :
- lors de l'enregistrement en bdd : utiliser une requête préparée avec des paramètres
- lors de l'affichage des données récupérées en bdd : utiliser htmlspecialchars() si les données sont affichés dans une page html

Eléphanteau du PHP | 25 Messages

18 nov. 2022, 09:34

Merci pour ta réponse :)

Oui je trouve ça bizarre aussi car au début ça fonctionnait sans problème.

A l'enregistrement je ne vois pas d'erreur, j'ai juste ma page qui n'affiche rien.
Comment j'affiche le rapport d'erreur ?

J'ai bien mis en place les rapports à la connexion mais est-ce suffisant ?
function connectionDB() {
    $servername = 'localhost';
    $dbname = '********';
    $username = '********';
    $password = '*********';
    try {
        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) {
        echo "Erreur : " . $e->getMessage();
    }
    return $conn; // renvoie la variable $conn pour faire le lien avec les autres fonctions
}

ynx
Mammouth du PHP | 586 Messages

18 nov. 2022, 14:10

Oui le rapport d'erreur PDO semble être bien activé lors de ta connexion avec PDO::ATTR_ERRMODE.
Si c'est pas déjà le cas, vérifie également que l'affichage des erreurs est bien activé (display_errors = On) et que le rapport d'erreur PHP est bien défini au niveau maximum (error_reporting = E_ALL) dans le fichier php.ini (plus d'info : tutoriels/page-blanche-script-php-comme ... 73178.html)

Pour vérifier que tu vois bien les messages d'erreurs SQL, tu peux volontairement ajouter une erreur de syntaxe dans ta requête (INFERT INTO... au lieu de INSERT INTO par exemple) et exécuter ton code.

Si les rapports d'erreurs sont bien activés mais que tu ne vois pas d'erreur à l'enregistrement avec ta requête correcte, le problème peut donc venir d'autre part. Essaye d'ajouter des echo pour suivre le fil d'éxecution de ton code et t'assurer qu'il passe bien dans chaque bloc if.
Que fait la fonction exist() dans ton code ? La condition if (!exist($titre, $volume, $vehicle, $Akey)) est bien validée lorsque le titre possède une apostrophe ?

Eléphanteau du PHP | 25 Messages

18 nov. 2022, 16:26

OMG... c'est le drame ^^

J'ai effectué les vérifications et effectivement il me manquait le display_errors = On
J'ai corrigé et maintenant je me tape un nombre hallucinant d'erreur même sans avoir créer volontairement une erreur ^^

Une série de :
Notice: Undefined index: titre in /Users/STEPHANE/Documents/WEB/htdocs/Ref_Aebersold/functions.php on line 32

Les notices disparaissent quand je fais un enregistrement. SI je comprends bien c'est parce que la donnée n'est pas encore initiée ?
Le niveau d'alerte est trop haut ?

ynx
Mammouth du PHP | 586 Messages

18 nov. 2022, 17:10

Bonne nouvelle si les erreurs d'affichent, tu devrais pouvoir plus facilement déboguer ton code ainsi.

Les messages de type "Notice" sont des erreurs non bloquantes pour PHP. Tu pourrais désactiver l'affichage de ces messages dans la configuration de PHP (error_reporting = E_ALL & ~E_NOTICE) mais ce n'est pas recommandé de masquer les erreurs, il est mieux de les corriger.

Le message "Notice: Undefined index: titre" indique que tu essayes d'accéder l'élément d'un tableau dont la clé est "titre", mais cet élément n'existe pas.
En effet, si le formulaire n'est pas envoyé, le tableau $_POST est vide donc l'élément $_POST['titre'] n'existe pas.
Il faut toujours vérifier que la donnée POST existe avant de l'utiliser, tu peux vérifier l'existence avec les fonctions isset() ou empty().

A ta place, j'aurais inversé les conditions if (!existe(...)) et if (!empty(...)) pour commencer par vérifier que les données POST ne sont pas vides avant de les utiliser. Je n'aurais pas défini de variables intermédiaires ($titre, $volume, etc.) qui ne semble pas utile ici :
function enregistrementDB() {
	$conn = connectionDB();
	
	if (!empty($_POST['titre']) && !empty($_POST['volume']) && !empty($_POST['vehicle']) && !empty($_POST['Akey']) && !empty($_POST['tempo']) && !empty($_POST['track'] && !empty($_POST['chorus']) && !empty($_POST['disc']))) {
		if (!exist($_POST['titre'], $_POST['volume'], $_POST['vehicle'], $_POST['Akey'])) {
		
		    $sth = $conn->prepare(
		        "INSERT INTO aebersold(titre,volume,vehicle,Akey,tempo,chorus,disc,track)
		            VALUES (:titre, :volume, :vehicle, :Akey, :tempo, :chorus, :disc, :track)"
		    );
		    $sth->bindParam(':titre', $_POST['titre']);
		    $sth->bindParam(':volume', $_POST['volume']);
		    $sth->bindParam(':vehicle', $_POST['vehicle']);
		    $sth->bindParam(':Akey', $_POST['Akey']);
		    $sth->bindParam(':tempo', $_POST['tempo']);
		    $sth->bindParam(':chorus', $_POST['chorus']);
		    $sth->bindParam(':disc', $_POST['disc']);
		    $sth->bindParam(':track', $_POST['track']);
		    $sth->execute();
		    echo ('Les données sont enregistrées, merci.') . '</br>';
		}
	}
}


j'ai ajouté une vérification pour les variables $_POST['track'] et $_POST['chorus'] afin de vérifier qu'elles ne sont pas vides. Il faudra adapter le code si ces données ne sont pas obligatoires (définir une valeur par défaut si vide).

Eléphanteau du PHP | 25 Messages

18 nov. 2022, 17:17

Bon effectivement tout cela n'était pas très propre...

Du coup je me penche sur mes fonctions.
Je viens de corriger ma fonction ENREGISTREMENT comme cela :
function enregistrementDB2() {
    // Je vérifie que si 'titre' est rempli
    if (isset($_POST['titre'])) {
        $titre = valid_donnees($_POST['titre']);
        $volume = $_POST['volume'];
        $vehicle = $_POST['vehicle'];
        $Akey = $_POST['Akey'];
        $tempo = $_POST['tempo'];
        $chorus = $_POST['chorus'];
        $disc = $_POST['disc'];
        $track = $_POST['track'];
        $conn = connectionDB();

        /* je vérifie si l'entrée existe déjà ou pas dans la DB
        j'ai juste besoin de faire le check sur 4 champs car les autres peuvent être identiques
         */
        if (!exist($titre, $volume, $vehicle, $Akey)) {

            //Vérification que l'ensemble des champs sont remplis avant insertion
            if (!empty($titre) && !empty($volume) && !empty($vehicle) && !empty($Akey) && !empty($tempo) && !empty($track)) {

                $sth = $conn->prepare(
                    "INSERT INTO aebersold(titre,volume,vehicle,Akey,tempo,chorus,disc,track)
                    VALUES (:titre, :volume, :vehicle, :Akey, :tempo, :chorus, :disc, :track)"
                );
                $sth->bindParam(':titre', $titre);
                $sth->bindParam(':volume', $volume);
                $sth->bindParam(':vehicle', $vehicle);
                $sth->bindParam(':Akey', $Akey);
                $sth->bindParam(':tempo', $tempo);
                $sth->bindParam(':chorus', $chorus);
                $sth->bindParam(':disc', $disc);
                $sth->bindParam(':track', $track);
                $sth->execute();
                echo ('Les données sont enregistrées, merci.') . '</br>';

            } else {
                echo "<p><strong>Vous n'avez pas renseigné l'ensemble des champs </strong></p>";
            }

        }

    }
}
Suis-je sur la bonne voie ?

Eléphanteau du PHP | 25 Messages

18 nov. 2022, 17:18

Oups nos messages se sont croisés :)
Effectivement je peux faire mieux en inversant EXIST et EMPTY
Je te rejoins aussi sur les données :)

Merci beaucoup pour ton aide /

Je vais m'atteler aux autres erreurs et ensuite je reviendrai sur cette histoire d'apostrophe.

Eléphanteau du PHP | 25 Messages

18 nov. 2022, 18:29

Bon j'ai corrigé l'ensemble des erreurs !
Merci pour ton aide :)

Maintenant voici l'erreur sur les apostrophes :

Fatal error: Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'une apostrophe' AND volume='12' AND vehicle='bebop' AND Akey='A'' at line 1 in /Users/STEPHANE/Documents/WEB/htdocs/Ref_Aebersold/functions.php:20 Stack trace: #0 /Users/STEPHANE/Documents/WEB/htdocs/Ref_Aebersold/functions.php(20): PDO->query('SELECT titre,vo...') #1 /Users/STEPHANE/Documents/WEB/htdocs/Ref_Aebersold/functions.php(108): exist('Test d'une apos...', '12', 'bebop', 'A') #2 /Users/STEPHANE/Documents/WEB/htdocs/Ref_Aebersold/index.php(132): enregistrementDB() #3 {main} thrown in /Users/STEPHANE/Documents/WEB/htdocs/Ref_Aebersold/functions.php on line 20

Eléphanteau du PHP | 25 Messages

18 nov. 2022, 18:31

J'ai trouvé !
cela vient de ma fonction EXIST ^^
Je n'ai pas fait de requête préparé dans la fonction exist contrairement à la fonction enregistrementDB.

Du coup j'ai refait ma fonction ENREGISTREMENT_BD en incluant la condition doublon

J'ai été obligé de déclaré mes variables pour l'insertion dans la requête... (si tu as une autre idée je reste à l'écoute) :
function enregistrementDB() {
    $titre = $_POST['titre'];
    $volume = $_POST['volume'];
    $vehicle = $_POST['vehicle'];
    $Akey = $_POST['Akey'];

    $conn = connectionDB();

    //Vérification que l'ensemble des champs sont remplis avant insertion
    if (!empty($_POST['titre']) && !empty($_POST['volume']) && !empty($_POST['vehicle']) && !empty($_POST['Akey']) && !empty($_POST['tempo']) && !empty($_POST['track'])) {

        /* je vérifie si l'entrée existe déjà ou pas dans la DB
        j'ai juste besoin de faire le check sur 4 champs car les autres peuvent être identiques */
        $sql = $conn->prepare("SELECT titre,volume,vehicle,Akey FROM aebersold WHERE titre='$titre' AND volume='$volume' AND vehicle='$vehicle' AND Akey='$Akey'");
        $sql->execute();
        $doublon = $sql->fetchAll();
        if (count($doublon) === 0) { // je vérifie que $doublon vaut zero c'est à dire pas de doublon
            $sth = $conn->prepare(
                "INSERT INTO aebersold(titre,volume,vehicle,Akey,tempo,chorus,disc,track)
                    VALUES (:titre, :volume, :vehicle, :Akey, :tempo, :chorus, :disc, :track)"
            );
            // insertion des données dans la DB
            $sth->bindParam(':titre', $_POST['titre']);
            $sth->bindParam(':volume', $_POST['volume']);
            $sth->bindParam(':vehicle', $_POST['vehicle']);
            $sth->bindParam(':Akey', $_POST['Akey']);
            $sth->bindParam(':tempo', $_POST['tempo']);
            $sth->bindParam(':chorus', $_POST['chorus']);
            $sth->bindParam(':disc', $_POST['disc']);
            $sth->bindParam(':track', $_POST['track']);
            $sth->execute();
            echo ('Les données sont enregistrées, merci.') . '</br>';
        } else {
            echo 'Le titre existe déjà dans la base </br>';
        }

    } else {
        echo "<p><strong>Vous n'avez pas renseigné l'ensemble des champs </strong></p>";
    }

}
ça fonctionne aussi bien sur les doublons que les apostrophes :)
J'ai un autre soucis mais je vais ouvrir un topic car c'est vraiment autre chose.