Problème sur requête préparée

Affichage page par page

a marqué ce sujet comme résolu.

Bonjour,

je suis débutant en programmation et essaie de comprendre le code pour afficher page par page les données sur une page html en suivant le tuto (https://zestedesavoir.com/tutoriels/351/paginer-avec-php-et-mysql/).

Et je bloque dès le début. En fait, c’est le passage à la requête préparée qui pose problème car si je passe par une requête simple cela fonctionne (lignes 19 et 20).

J’ai donc le message d’erreur suivant : Fatal error: Call to a member function fetch() on boolean in C:\wamp64\www\tests\test_1.php on line 35 que je ne comprends pas vraiment. Dans un cas comme dans l’autre, $resultSet est le résultat d’une requête.

Quelqu’un peut-il me guider sur une piste ? d’avance merci,

ci-dessous là ou j’en suis dans mon code :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?php



try
{
// On se connecte à MySQL
$cnx = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root', '', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}

$limite = 5;

// Partie "Requête"
//$query = 'SELECT * FROM `vaches` LIMIT 5';
//$resultSet = $cnx->query($query);

$query = 'SELECT * FROM `vaches` LIMIT :limite';
/* On prépare la requête à son exécution. Les marqueurs seront identifiés */
$query = $cnx->prepare($query);
/* On lie ici une valeur à la requête, soit remplacer de manière sûre un marqueur par sa valeur, nécessaire pour que la requête fonctionne. */
$query->bindValue(
    'limite',         // Le marqueur est nommé « limite »
     $limite,         // Il doit prendre la valeur de la variable $limite
     PDO::PARAM_INT   // Cette valeur est de type entier
);
/* Maintenant qu'on a lié la valeur à la requête, on peut l'exécuter pour en récupérer le résultat */
$resultSet = $query->execute();

// Partie "Boucle"
while ($element = $resultSet->fetch()) {
    // C'est là qu'on affiche les données  :)

        // début du tableau
        echo '<table bgcolor="#FFFFFF">'."\n";
            // première ligne on affiche les titres prénom et surnom dans 2 colonnes
            echo '<tr>';
            echo '<td bgcolor="#669999"><b><u>Prénom</u></b></td>';
            echo '<td bgcolor="#669999"><b><u>Surnom</u></b></td>';
            echo '</tr>'."\n";
        // lecture et affichage des résultats sur 2 colonnes, 1 résultat par ligne.    
        while($element= $resultSet -> fetch()) {
            echo '<tr>';
            echo '<td bgcolor="#CCCCCC">'.$element['prenom'].'</td>';
            echo '<td bgcolor="#CCCCCC">'.$element['surnom'].'</td>';
            echo '</tr>'."\n";
        }
        echo '</table>'."\n";
        // fin du tableau.

    // on libère le résultat
    //unset($resultSet);
}

Salut !

Je vois deux soucis ici. Le premier est que tu as deux boucles imbriquées sur le même jeu de résultat, c’est pas terrible. Il te faut supprimer le premier while. Une des raisons à cela est que les en-tête de lignes ne sont pas des données au même titre que les prénom et surnom.

Le second est que tu as déclenché mon détecteur de copier-coller.  :p
L’erreur est effectivement présente dans le tutoriel, mais elle est là volontairement depuis le début, et les validateurs du tutoriel sont au courant (il y a eu deux mises à jour, j’ai mentionné le fait à chaque fois comme à la mise en ligne).

Note que je vais probablement quand même le préciser dans les prérequis :

  • bref, de quoi pouvoir déceler le détecteur de copier-coller mis en place sur ce tutoriel  :p
+0 -0

Le second est que tu as déclenché mon détecteur de copier-coller.  :p
L’erreur est effectivement présente dans le tutoriel, mais elle est là volontairement depuis le début, et les validateurs du tutoriel sont au courant (il y a eu deux mises à jour, j’ai mentionné le fait à chaque fois).

Ymox

Drôle d’histoire, je ne vois pas l’intérêt. Comment les lectures comprennent qu’il y a un piège ?

L’idée est de confondre ceux qui viendraient ici et qui prendraient le code sans lire. Je reconnais que pour ceux qui suivent en toute confiance, ça pose problème, donc j’ajouterai des blocs pour attirer l’attention en plus des prérequis.

Quand à comment ils comprennent qu’il y a un piège, je crois que le cas de ce sujet est assez explicite, même s’il n’est pas de ceux dont je suis le plus fier.

+0 -3

Quelqu’un utilise le code fournit en exemple, parce qu’il est en train d’apprendre, il se mange une erreur. Perso si ça m’arrive je change de tuto.

C’est LA BASE de copier / coller le code, le faire fonctionner, voire le débugger en mode pas à pas pour comprendre ce qui se passe.

C’est une des N façons de lire un tutoriel, article de blog, ou gist ou quoi que ce soit.

"Détecter le copier / coller" -> Mais bon sang, dans quel intérêt ???

Et combien t’en as pas détectés, qui sont partis du site en se disant "tiens c’est foireux". T’essaies de filtrer tes lecteurs ? A ce moment là écris-le en préambule : "Y’a des pièges partout, c’est fait exprès, si ça ne vous amuse pas, ne lisez pas mon tuto, merci bisous".

+9 -0

L’erreur est un peu compliqué pour un débutant. Il doit saisir qu’il utilise une variable boolean (true/false) en tant que class/object.

Et si on compare à l’usage de prepare, execute pourrait être utilisé de la même façon… J’ai jamais vu un débutant allez chercher dans la documentation alors qu’il suit un tutoriel.

Ce qui me gène, c’est que du coup la notion même de tutoriel n’est plus grand chose. Pourquoi ne pas simplement fournir le code sans explication, si c’est pour qu’il soit copié-collé sans plus ?

Ymox

Chacun apprend à sa façon :/

Généralement, je lis le code en premier, car il y a trop de "blabla" pour moi dans les tutos. S’il y a des choses que je ne comprends pas, je lis les parties du tuto concernées. Si ce n’est pas encore suffisant, je lis la doc / d’autres tutos.

Donc sur un tuto comme le tien, je me sentirais bien con et après avoir du lire plus que nécessaire, j’aurais juste comme l’impression que tu t’es foutu de ma gueule…

1) Ton code n’est pas bon, OK, si c’est pour qu’on lise plus le tuto (même si déjà là, ça me ferait chier).

2) Même en lisant le tuto, je ne trouve aucun endroit ou tu mentionnes ce fait! Tu viens, de me faire perdre au bas mot 10 minutes (et encore, je pense que ça tiendrait plus de la demi-heure) à moi, le petit débutant en PDO, qui se sent juste mauvais et qui n’arrive pas à faire marcher ton code… Et en plus, je vais devoir aller piocher mes informations ailleurs… (l’ailleurs est partiellement dans les commentaires, certes, mais la lecture devrait se suffire à elle même). Donc, non merci !

(Et si je ne suis pas un utilisateur fréquent de ZdS, la confiance que j’aurais quand je verrai des liens en serait réduite).

Bonjour,

juste pour préciser qu’effectivement j’ai copié-collé le code (d’ailleurs je l’ai clairement mentionné en début de post) et que j’essaie de comprendre au fur à mesure en suivant le tuto avant de l’appliquer à mon site. après le debbug est formateur c’est sûr ! en tout je suis sur une piste de correction donc je vais continuer…

Pour moi, il ne faut pas blâmer Ymox: après tout, c’est son tuto, il fait ce qu’il veut
Ce qui est plus "grave" est que la validation a délibérément (puisqu’elle est au courant) laissé un tuto erroné en publication

Sinon sujet résolu ? :)

+0 -0

Bonjour,

juste pour préciser qu’effectivement j’ai copié-collé le code (d’ailleurs je l’ai clairement mentionné en début de post) et que j’essaie de comprendre au fur à mesure en suivant le tuto avant de l’appliquer à mon site. après le debbug est formateur c’est sûr ! en tout je suis sur une piste de correction donc je vais continuer…

LE CARROU

Un copié/coller ce n’est pas la mort :P

Pour résumer, tes erreurs à ce stade sont celles susmentionnées :

Il me semble que c’est $query->fetch().

A-312

en lieu et place de $resultSet->fetch()

Salut !

Je vois deux soucis ici. Le premier est que tu as deux boucles imbriquées sur le même jeu de résultat, c’est pas terrible. Il te faut supprimer le premier while. Une des raisons à cela est que les en-tête de lignes ne sont pas des données au même titre que les prénom et surnom.

Ymox

Merci pour vos réflexions qui sont bien plus altruistes que ce que j’ai fait.

En conséquence, je vais mettre à jour mon tutoriel pour y mettre le code correct.

@LE CARROU et tous ceux qui ne se sont pas manifestés, mais qui étaient dans le même cas : mes plus plates excuses pour vous avoir joué ce tour de cochon.

+1 -0

Ce qui est plus "grave" est que la validation a délibérément (puisqu’elle est au courant) laissé un tuto erroné en publication

Angelo

Alors, étant le premier à avoir validé le tuto (il y a plus de 2 ans, en juin 2015), je fais mon mea culpa car je n’avais pas remarqué qu’il y avait une faute.

Même en tant que développeur aguerri (en tout cas à l’époque, puisque je fais de moins en moins de PHP depuis quelque temps) il arrive de passer à côté de certaines erreurs basiques.

À moins de tester chaque morceau de code un par un, ce qui prendrait un temps énorme à une équipe qui a déjà parfois du mal à fournir, il est impossible de garantir que tout est bon.

Alors oui, parfois quelques erreurs passent à travers les mailles du filet. Qu’elles soient volontaires ou non est un tout autre sujet (je n’ai pas la mémoire assez bonne pour savoir si j’étais au courant ou non à l’époque).

Merci donc de ne pas (trop) blâmer la validation, nous sommes humains, les erreurs ça arrive à tout le monde… ;)

Bonjour,

je continue le tuto et bloque à l’étape suivante (oui, je suis vraiment débutant).

J’en suis donc à initialiser les variables $page et $debut. Mais j’ai 3 messages d’erreur : Notice: Undefined variable: page in C:\wamp64\www\tests\test_1.php on line 27 Fatal error: Uncaught exception ’PDOException’ with message ’SQLSTATE[42000]: Syntax error or access violation: 1064 Erreur de syntaxe près de ’-10’ à la ligne 1’ in C:\wamp64\www\tests\test_1.php on line 49 PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 Erreur de syntaxe près de ’-10’ à la ligne 1 in C:\wamp64\www\tests\test_1.php on line 49

Si je comprends bien, c’est dû au calcul de $debut. On récupère $page par la méthode $_GET. En faisant un var_dump($page), je constate que $page est NULL à la première visite sur la page. Le calcul de $debut = ($page - 1) * $limite donne donc -10 ce qui n’est pas pris dans la requête. J’ai fait quelques petits tests en affectant différentes valeurs à $page pour voir si je reproduisait l’erreur et l’erreur se produit si $page = 0 également puisque $debut sera également négatif. Par contre si $page=1 pas d’erreur. Ma première idée a été de faire $debut = Abs($page - 1) * $limite mais çà ne fonctionne pas. Mais de toute façon le problème est de ne pas récupérer la valeur 1 pour la page 1 à la première visite avec la méthode $_GET.

Je comprends pas.

mon code :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php


//*******************************************************************
//affichage page par page tutoriel Ymox sur le site Zeste de Savoir
//https://zestedesavoir.com/tutoriels/351/paginer-avec-php-et-mysql/

//*******************************************************************

try
{
// On se connecte à MySQL
$cnx = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root', '', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}


$limite = 10;
$page = $_GET['page'];
//var_dump($page);
//$page = 1;
//$debut = 0;
$debut = Abs(($page - 1)) * $limite;


// Partie "Requête"
/* On calcule donc le numéro du premier enregistrement */

$query = 'SELECT * FROM `vaches` LIMIT :limite OFFSET :debut';
/* On prépare la requête à son exécution. Les marqueurs seront identifiés */
$query = $cnx->prepare($query);
/* On lie ici une valeur à la requête, soit remplacer de manière sûre un marqueur par sa valeur, nécessaire pour que la requête fonctionne. */
$query->bindValue(
    'limite',         // Le marqueur est nommé « limite »
     $limite,         // Il doit prendre la valeur de la variable $limite
     PDO::PARAM_INT   // Cette valeur est de type entier
);
$query->bindValue(
    'debut',         // Le marqueur est nommé « début »
     $debut,         // Il doit prendre la valeur de la variable $debut
     PDO::PARAM_INT   // Cette valeur est de type entier
);

/* Maintenant qu'on a lié la valeur à la requête, on peut l'exécuter pour en récupérer le résultat */
$resultSet = $query->execute();

// début du tableau
echo '<table bgcolor="#FFFFFF">'."\n";
// première ligne on affiche les titres prénom et surnom dans 2 colonnes
echo '<tr>';
echo '<td bgcolor="#669999"><b><u>Prénom</u></b></td>';
echo '<td bgcolor="#669999"><b><u>Surnom</u></b></td>';
echo '</tr>'."\n";

// Partie "Boucle"
// lecture et affichage des résultats sur 2 colonnes, 1 résultat par ligne.    
while($element= $query -> fetch()) {
echo '<tr>';
echo '<td bgcolor="#CCCCCC">'.$element['prenom'].'</td>';
echo '<td bgcolor="#CCCCCC">'.$element['surnom'].'</td>';
echo '</tr>'."\n";
}
echo '</table>'."\n";
// fin du tableau.

// on libère le résultat
//unset($resultSet);
?>
+0 -0

Le souci de $page qui n’est pas défini est partiellement réglé plus loin dans le tutoriel (juste avant la partie "Afficher des liens vers d’autres pages que les suivante et précédente").

Je dis partiellement parce que, comme cela y est expliqué, la solution fournie est uniquement fonctionnelle et pas totalement sécuritaire — cela aurait demandé tant d’explications que cela pourrait faire un tutoriel à part. Qui plus est, on sortait du sujet de la pagination.

Petite note : les noms de variables en PHP commencent par des $, mais sur ce forum, cela délimite aussi des parties mathématiques dans les messages, d’où la mise en page un peu déroutante du tien. Pour éviter cela, tu peux encadrer les noms de tes variables avec des ``. Et si tu édites ton message ci-dessus, ce sera plus simple de te lire  ;)

+0 -0

Merci à vous j’avais pourtant lu l’ensemble du tuto… maintenant tout fonctionne et je pense avoir bien compris, je vais apporter les améliorations de sécurité et ma propre mise en forme

pour ce qui est du CSS, je suis repartis d’un jeu de données d’un autre tuto, mais effectivement personnellement j’utilise CSS

merci à vous tous

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte