Qui peut m'expliquer un peu ce code qui... fonctionne bien

Consultez la formation SEO spéciale Wordpress
par WebRankInfo / Ranking Metrics

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 16, 2017 14:01

Bonjour,

J'ai un petit bout de code là, qui remplit bien son office.
Mais je ne pige pas bien les différentes étapes. Si quelqu'un veut bien les détailler en bon français, je l'en remercie par avance :

Code: Tout sélectionner
$sql = "INSERT INTO pmot_clef (libelle,libelle_url) VALUES ('$libelle','$libelle_url')";
$stmt = $dbh->prepare ($sql); /* On prépare la requête */
$stmt->execute();

//on récupère l'id du tuple qui vient d'être créé pour incrémenter le compteur
$nouveau_tuple=$dbh->LastInsertId();

//on incrémente le compteur du nouveau tuple créé
 $sql = "UPDATE mot_clef SET compteur=compteur+1 WHERE id=".$nouveau_tuple."";
 $stmt = $dbh->prepare ($sql); /* On prépare la requête */
 $stmt->execute();
 


Donc ça fonctionne. Mais précisément : pourquoi la valeur de $nouveau_tuple est-elle attribuée via $dbh et non $stmt ?
Ou autrement dit, pourquoi utilise-t'on la fonction LastInsertId() avec $dbh plutôt qu'avec $stmt ?

Merci d'avance


MikeR
WRInaute passionné
WRInaute passionné
 
Messages: 1692
Enregistré le: 9 Jan 2010

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 16, 2017 22:51

LastInsertedID te donne directement l'Id de la dernière ligne insérée ou updatée (id étant une clé primaire autoincrement). C'est plus rapide que de préparer une requète pour retrouver la valeur max d'Id et de l'exécuter.

Louis63
WRInaute discret
WRInaute discret
 
Messages: 112
Enregistré le: 22 Fév 2016

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 16, 2017 23:04

tu ne veux pas lire la doc, pourtant, c'est très utile :
http://php.net/manual/fr/pdostatement.execute.php

exemple 1 : pas de paramètre à execute, car ils ont déjà été passés
exemple 2 : les paramètres sont transmis directement à la fonction execute

dans ton code, il n'y a pas de paramètre donc execute sans rien fonctionne, sans besoin de bindparam


spout
WRInaute accro
WRInaute accro
 
Messages: 8336
Enregistré le: 14 Mai 2003

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Ven Mar 17, 2017 6:18

Oui il a pas envie de lire la doc qui explique ça très bien et il s'obstine à mettre des failles d'injection SQL.

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Ven Mar 17, 2017 18:06

Salut à vous et merci pour vos réponses.
MikeR a écrit:LastInsertedID te donne directement l'Id de la dernière ligne insérée ou updatée (id étant une clé primaire autoincrement). C'est plus rapide que de préparer une requète pour retrouver la valeur max d'Id et de l'exécuter.

Non, ce n'est pas ma question.
Dans cette ligne précise :
Code: Tout sélectionner
$nouveau_tuple=$dbh->LastInsertId();

Pourquoi n'a-t'on pas plutôt :
Code: Tout sélectionner
$nouveau_tuple=$stmt->LastInsertId();

Ah bah si, c'est ma question : tu veux dire que la fonction LastInsertedID() est une sorte de requête pré-programmée qui n'a plus besoin que d'appeler les paramètres de la BD, pour être exécutée. Mais comment donc cette fonction peut-elle savoir quelle est la table concernée ?

Louis63 a écrit:tu ne veux pas lire la doc, pourtant, c'est très utile :
http://php.net/manual/fr/pdostatement.execute.php

exemple 1 : pas de paramètre à execute, car ils ont déjà été passés
exemple 2 : les paramètres sont transmis directement à la fonction execute

dans ton code, il n'y a pas de paramètre donc execute sans rien fonctionne, sans besoin de bindparam

Je compte ouvrir un topic sur cette fameuse doc' de manière à pouvoir la lire. Il y a des choses que je ne comprends pas dans la présentation, raison pour laquelle je ne m'en sers pas.
Exemple :
Code: Tout sélectionner
public bool PDOStatement::execute ([ array $input_parameters ] )

Je n'arrive pas à traduire cela en code opérationnel. Qu'est-ce que ce "public bool" ? (souvent on a public string). C'est une présentation formelle de la fonction. Mais je ne sais pas lire ça.

spout a écrit:Oui il a pas envie de lire la doc qui explique ça très bien et il s'obstine à mettre des failles d'injection SQL.

Fais pas dans le suspens spout, c'est pas les oiseaux. Elle est où ici, la fenêtre par laquelle entre les corbeaux ?


spout
WRInaute accro
WRInaute accro
 
Messages: 8336
Enregistré le: 14 Mai 2003

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Ven Mar 17, 2017 18:57

là:
Code: Tout sélectionner
$sql "UPDATE mot_clef SET compteur=compteur+1 WHERE id=".$nouveau_tuple.""

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Ven Mar 17, 2017 19:16

Hum... Et l'erreur viendrait de la variable $nouveau_tuple, passée en paramètre de recherche ?
Si oui, je n'arrive pas à voir le problème, puisque la valeur de la variable ne provient pas d'une donnée transmise par _GET[] ou $_POST[]. Donc comment pourrait-elle contenir une valeur dangereuse ?
Mais en attendant d'en savoir plus et si le problème vient bien de là, j'imagine que la solution serait alors d'utiliser les requêtes préparées, avec bind_param() ? Si oui, je ne vois pas l'intérêt pour la raison ci-dessus. Ca m'a tout l'air d'alourdir le code d'une ligne de plus (mais mes compétences sont un peu boiteuses, j'en conviens).


MikeR
WRInaute passionné
WRInaute passionné
 
Messages: 1692
Enregistré le: 9 Jan 2010

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Ven Mar 17, 2017 22:59

Alorsladaccord a écrit:]Mais comment donc cette fonction peut-elle savoir quelle est la table concernée ?

On se fout de la table.Il te donne la valeur du dernier id autoincrémenté dans ton contexte. Le dernier. C'est à toi de savoir ce à quoi il se rapporte.


niap
WRInaute discret
WRInaute discret
 
Messages: 137
Enregistré le: 17 Oct 2009

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Sam Mar 18, 2017 10:50

Alorsladaccord a écrit:
Code: Tout sélectionner
public bool PDOStatement::execute ([ array $input_parameters ] )

Je n'arrive pas à traduire cela en code opérationnel. Qu'est-ce que ce "public bool" ? (souvent on a public string). C'est une présentation formelle de la fonction. Mais je ne sais pas lire ça.

public bool ça veut dire que c'est une fonction publique (accessible à n'importe quel instance de l'objet) et qu'elle renvoit une valeur de type boolean (true ou false).

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Mar Mar 21, 2017 14:07

niap a écrit:
Alorsladaccord a écrit:
Code: Tout sélectionner
public bool PDOStatement::execute ([ array $input_parameters ] )

Je n'arrive pas à traduire cela en code opérationnel. Qu'est-ce que ce "public bool" ? (souvent on a public string). C'est une présentation formelle de la fonction. Mais je ne sais pas lire ça.

public bool ça veut dire que c'est une fonction publique (accessible à n'importe quel instance de l'objet) et qu'elle renvoit une valeur de type boolean (true ou false).


Salut niap,

Et ce que tu nous dis-là, ce sont des classiques de l'informatique transcendantale, valable pour n'importe quel langage ? Je suis donc supposé apprendre quoi, pour comprendre le manuel PHP ? Les rigueurs théoriques de base de l'informatique, quel que soit le langage ? Genre BTS première année, un truc comme ça ?


MikeR
WRInaute passionné
WRInaute passionné
 
Messages: 1692
Enregistré le: 9 Jan 2010

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Mar Mar 21, 2017 14:43

Alorsladaccord a écrit:Et ce que tu nous dis-là, ce sont des classiques de l'informatique transcendantale, valable pour n'importe quel langage ? Je suis donc supposé apprendre quoi, pour comprendre le manuel PHP ? Les rigueurs théoriques de base de l'informatique, quel que soit le langage ? Genre BTS première année, un truc comme ça ?

Oui, c'est le b-a-ba de la programmation objet qui est mise oeuvre dans pas mal de langages (php, java, c++). Il y a de nombreux sites d'initiation là dessus (et certains utilisant php comme example).

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Mar Mar 21, 2017 15:25

Ok,

J'm'en vais télécharger quelques docs sur ça, histoire de moins vous prendre la tête...

Merci

noren
WRInaute accro
WRInaute accro
 
Messages: 2872
Enregistré le: 8 Avr 2011

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 23, 2017 11:59

spout a écrit:là:
Code: Tout sélectionner
$sql = "UPDATE mot_clef SET compteur=compteur+1 WHERE id=".$nouveau_tuple.""


En quoi s'agit-il d'une réelle faille dans la mesure ou l'on sait d'ou vient $nouveau_tuple. Ta remarque m'intéresse même si de mon côté j'ai tendance a utiliser cette forme pour les requêtes préparées :

"
$result = bdd->prepare(UPDATE mot_clef SET compteur=compteur+1 WHERE id= ?)
$result->execute($params);
";

ou alors id=:id, combiné avec bindvalue


spout
WRInaute accro
WRInaute accro
 
Messages: 8336
Enregistré le: 14 Mai 2003

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 23, 2017 12:15

Code: Tout sélectionner
$nouveau_tuple = $_GET['nouveau_tuple'];

?nouveau_tuple=2;DELETE FROM membres--

noren
WRInaute accro
WRInaute accro
 
Messages: 2872
Enregistré le: 8 Avr 2011

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 23, 2017 12:33

Un truc m'échappe surement, mais dans son code $nouveau_tuple n'est pas récupéré a partir d'un get :

Code: Tout sélectionner
$nouveau_tuple=$dbh->LastInsertId();


spout
WRInaute accro
WRInaute accro
 
Messages: 8336
Enregistré le: 14 Mai 2003

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 23, 2017 12:38

Ok oui, dans ce cas no stress.

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Mar 23, 2017 13:06

spout a écrit:
Code: Tout sélectionner
$nouveau_tuple = $_GET['nouveau_tuple']; 

?nouveau_tuple=2;DELETE FROM membres--

Oui, mais dans ce cas-là, j'applique une fonction PHP sanitize int sur le tuple récupéré par _GET ou _POST.

Par contre, j'ai trouvé une erreur bizarre, qui ne se produit qu'en localhost.
Voilà : si je fais cela sur mon serveur (OVH mais peu importe je présume) :
Code: Tout sélectionner
$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT));

Alors, tout fonctionne bien.

Par contre, si je travaille en local (version PHP plus ancienne sans nul doute)
Alors ça me déclenche une erreur me disant que la variable n'est pas initialisée.
Il faut alors que je fasse comme ça
Code: Tout sélectionner
if(isset($_GET['nouveau_tuple'])) {$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT)); }


La question que je me pose est :
- Faut-il obligatoirement faire de même sur le code en production (sur le serveur OVH) ?
- Et pourquoi n'y-a-t'il pas la même erreur sur celui-ci ?

Anonymus
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 10
Enregistré le: 10 Juin 2015

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Mer Avr 05, 2017 18:56

Bonjour,

1/
$dbh est une référence (#ressource) à la base de données, et c'est la base de données qui gère ce genre d'infos. Pourquoi ? Parce que le système en question est fait comme ça :)

2/
Si tu travailles en local, alors tu vois l'erreur, alors que si tu travailles en distant, tu ne la vois pas. Mais rien ne dit qu'elle n'est pas là !
Au début de ton code, tu peux mettre :
ini_set('display_errors',1);
error_reporting(E_ALL);

Devrait suffire à t'afficher toutes les erreurs.

Ceci dit :
Que se passe t-il si la variable n'est pas instanciée ? Ca affiche un warning, ok, et what ??
Comme tu dis, si la valeur existe, tu fais un sanitize, mais si elle n'existe pas, tu as donc une faille de sécurité ;)

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Jeu Avr 06, 2017 12:04

Salut Anonymus, merci pour ta participation.

Ta dernière phrase confirme ma crainte. Là je termine le "gros œuvre", ensuite je verrai pour les questions de sécurité.

Mais en deux mots déjà, histoire de faire avancer un peu le truc. En quoi le fait d'appliquer une fonction sanitize sur une fonction non instanciée génère-t'il une faille de sécurité ? Une variable non instanciée diffère d'une variable avec une valeur nulle, certes, mais pourquoi la fonction sanitize (ou une autre) ne fait-elle pas tout simplement fi de l'opération ?

Il ne me semble pas qu'existait quelques années auparavant, ce problème d'instanciation obligatoire des variables. Je me trompe ?

Anonymus
Nouveau WRInaute
Nouveau WRInaute
 
Messages: 10
Enregistré le: 10 Juin 2015

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Ven Avr 07, 2017 18:02

En php, rien n'est obligatoire.. ou pas grand chose.
Le problème étant que, si tu ne t'occupes pas toi même de la valeur d'une variable, alors tu délègues cette assignation au système.
Quelle valeur va t-il lui attribuer ??

La question a toujours existé, mais avant 'on' pensait que ca n'était pas grave. Les hackeurs ont prouvé que... ben si.

Donc :
Le problème est que tu donnes des bouts de code, au fur et à mesure des réponses de chacun. Ce qui fait que personne ne sait trop comment est "l'ensemble" du code.
Ceci dit, si je me réfère au dernier morceau, j'ai ceci :

Code: Tout sélectionner
if(isset($_GET['nouveau_tuple'])) {$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT)); }

Que je peux traduire par

"si la variable $_GET['nouveau_tuple'] existe, alors $nouveau_tuple .... "

ce qui me fait penser à : " et si elle n'existe pas ?"

De là, 2 solutions :
Soit : $nouveau_tuple est false, null, comme tu veux..
Soit : tu as un truc qui s'appelle 'register_globals' qui peut (potentiellement) lui attribuer la valeur : $_POST['nouveau_tuple'] ou $_COOKIES['nouveau_tuple'], ...
Et donc, on se trouve avec ce qui disait 'spout', à savoir :

Code: Tout sélectionner
nouveau_tuple=2;DELETE FROM membres


qui ira instancier la variable 'nouveau_tuple'.

Tu vas me dire 'ouaip, mais 'register_globals' est à 'off'.
Ok, et combien de temps ? Tu verifies tous les matins ? Tu changes jamais de version d'OS, de php, de... ?

Tu peux garantir, tout simplement ce morceau de code, en mettant par exemple :
Code: Tout sélectionner
if(isset($_GET['nouveau_tuple'])) {$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT)); }
else{$nouveau_tuple =0;}

ou
Code: Tout sélectionner
$nouveau_tuple =0;
if(isset($_GET['nouveau_tuple'])) {
$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT));
}


Tu devrais aussi, puisque tu utilises 'pdo', te servir des protections de celui-ci. Après tout, il a été fait pour ca aussi.
Ainsi, ton code :
Code: Tout sélectionner
 $sql = "UPDATE mot_clef SET compteur=compteur+1 WHERE id=".$nouveau_tuple."";
 $stmt = $dbh->prepare ($sql); /* On prépare la requête */
 

devrait être écrit
Code: Tout sélectionner
 $sql = "UPDATE mot_clef SET compteur=compteur+1 WHERE id=:nouveau_tuple";
 $stmt = $dbh->prepare ($sql); /* On prépare la requête */
 $stmt->bindParam(':nouveau_tuple', $nouveau_tuple, PDO::PARAM_INT);
 

Ainsi, donc, tu demandes explicitement à pdo de n'accepter que des valeurs 'integer'.

Ca m'a tout l'air d'alourdir le code d'une ligne de plus (mais mes compétences sont un peu boiteuses, j'en conviens).


En fait, quand tu te réveilles un beau matin et que ton répertoire est 'vide', que ton code a 'disparu' ben tu te dis que la prochaine fois tu compteras pas les lignes ;)


a+ !

Alorsladaccord
WRInaute impliqué
WRInaute impliqué
 
Messages: 510
Enregistré le: 30 Juil 2014

Re: Qui peut m'expliquer un peu ce code qui... fonctionne bien

Message le Sam Avr 08, 2017 12:53

Salut cher Anonymus et merci beaucoup pour ta réponse très complète. J'embraye avec quelques questions supplémentaires, pour préciser un peu la chose, si tu veux bien.

Anonymus a écrit:
Code: Tout sélectionner
if(isset($_GET['nouveau_tuple'])) {$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT)); }

Que je peux traduire par :
"si la variable $_GET['nouveau_tuple'] existe, alors $nouveau_tuple .... "
ce qui me fait penser à : " et si elle n'existe pas ?"

Eh bien, je ne comprends pas bien ce point.
Par exemple, si je fais cela :
Code: Tout sélectionner
$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT));

Alors j'ai une erreur PHP en local. Cette erreur, je la supprime en ajoutant la condition if ci-dessus.
Partant de là, je ne comprends pas ce que je risque : si la condition if n'est pas vérifiée et bien c'est qu'il n'y a pas de variable $_GET. Donc il ne se passe rien. Et s'il ne se passe rien, un pirate ne peut rien faire avec le rien. Me dis-je.


Anonymus a écrit:
Tu vas me dire 'ouaip, mais 'register_globals' est à 'off'.
Ok, et combien de temps ? Tu verifies tous les matins ? Tu changes jamais de version d'OS, de php, de... ?

C'est vrai, je ne suis pas allé chercher jusque là. Ceci dit, ça vaut aussi pour le hacker : va-t'il vérifier chaque matin si le register_globals de mon site est à off ? Enfin en théorie, tu as surement raison.

Code: Tout sélectionner
if(isset($_GET['nouveau_tuple'])) {$nouveau_tuple = filter_var($_GET['nouveau_tuple', FILTER_SANITIZE_NUMBER_INT)); }
else{$nouveau_tuple =0;}

Oui, mais ça ne me plait pas : parce que maintenant, la variable $nouveau_tuple est créée et cela peut générer l'exécution d'autres conditions par la suite, alors qu'en fait, elle n'est avait pas été réceptionnée par l'URL.

Anonymus a écrit:
Tu devrais aussi, puisque tu utilises 'pdo', te servir des protections de celui-ci. Après tout, il a été fait pour ca aussi.
Ainsi, ton code :
Code: Tout sélectionner
 $sql = "UPDATE mot_clef SET compteur=compteur+1 WHERE id=".$nouveau_tuple."";
 $stmt = $dbh->prepare ($sql); /* On prépare la requête */
 

devrait être écrit
Code: Tout sélectionner
 $sql = "UPDATE mot_clef SET compteur=compteur+1 WHERE id=:nouveau_tuple";
 $stmt = $dbh->prepare ($sql); /* On prépare la requête */
 $stmt->bindParam(':nouveau_tuple', $nouveau_tuple, PDO::PARAM_INT);
 

Ainsi, donc, tu demandes explicitement à pdo de n'accepter que des valeurs 'integer'.

Ok, ça je vais le faire à la fin, quand je repasserai sur la sécurité du site, point par point. Deux précautions valent mieux qu'une, j'en conviens.


Encore merci pour ta réponse, Anonymus. Une reco, une !


Formation recommandée sur ce thème :

Formation SEO spéciale Wordpress : apprenez à optimiser le référencement naturel d'un site fait avec Wordpress... Formation Ranking Metrics animée par un expert SEO / Wordpress.

Tous les détails sur le site Ranking Metrics : programme, prix, dates et lieux, inscription en ligne.

Lectures recommandées sur ce thème :