[PHP] [Ajax] afficher les informations d'articles e-shop en JSON depuis MySQL

Avatar du membre
voxdemonix
Messages : 1336
Enregistré le : lun. févr. 02, 2015 7:28 pm

[PHP] [Ajax] afficher les informations d'articles e-shop en JSON depuis MySQL

Message par voxdemonix » mar. févr. 21, 2017 2:25 pm

musique d'entrain :
Niveau requis pour utilisation : moyen.
Nécessite au moins PHP5.4+ avec PDO (php-mysql)
Ce tutoriel s'intègre dans une suite de tutoriel permettant d'appréhender l'ajax voir Farm Link.
Licence du tuto : [WTFPL]

Introduction
  • Nous allons ici étudier un script PHP, rédigé par votre humble serviteur en programmation fonctionnelle, permettant de faire de l'ajax. L'objectif d'origine de ces fonctions est de recevoir les requêtes GET provenant d'une interface cliente (page web angularjs) d'une boutique en ligne, de récupérer des articles dans une table de Base de Données puis afficher les informations au format JSON.
    Le but de ce topic est de vous aider a mettre en place le plus rapidement possible une fonction ajax côté serveur (pour les tuto côté client il faudra voir du côté du Farm Link en bas de page).

    Donc ce script analyse les variables $_GET afin de récupérer les informations lui permettant de forger des requêtes SQL. Ensuite il récupère les informations de la base de données MySQL/MariaDB et les affiche dans un JSON.
    Pour fonctionner il faut bien entendu disposer d'une base de données contenant une table (nom gérable via $tableName) et contenant au moins les cellules : id, categorie.
    Afin d'éviter les doublons entre deux requêtes clientes lorsque des articles ont des informations recherchées quasi identique: lors d'une requête GET le client doit mentionner les articles qu'il a visionné dernièrement en ajoutant dans ses requêtes GET les variables banItemX = identifiant article à bannir comme dans l'exemple suivant : ajax.php?banItem1=6&banItem2=7&banItem3=8
    La sécurité anti injection SQL est gérée suivant les cas par les requêtes préparées de PDO ou par une moulinette qui vérifie la correspondance entre la table de données et les infos postées par l'utilisateur puis qui injecte les infos depuis la base de données en lieu et place des données envoyées par l'user. Sauf pour les $_GET["banItemX"] qui eux sont directement convertis en integer afin de casser toutes injections.
Les paramètres GET accepté par le script :
  • Paramètres obligatoires :
    • &articleMax=[integer] gère la LIMITE SQL (nombre d'entrées max à renvoyer)
      &orderByAttributs=[string] l'attribut pour ORDER BY (par exemple l'id, le prix, etc)
      &orderByAttributsLastValue=[float] la valeur la plus haute (ou basse selon la recherche) de l'attribut ORDER BY afin de commencer la recherche à partir de là
      &categorie=[string] le nom de la catégorie d'article (peut facilement être remplacer par une seconde condition de recherche)
      &orderByType=[1|-1] décide du sens de la recherche (1 pour plus petit au plus grand (> et ASC), -1 pour plus grand au plus petit (< et DESC))
    Paramètres optionnels :
    • &forceChangeOrderSymbole=[1|2] 1 pour > (plus grand que) ou 2 pour < (plus petit que) permet de changer le sens de la recherche sans affecter le reste (ASC ou DESC). Par défaut 1 (>) est sélectionné.
      &banItem1=[integer] reçoit les identifiants à bannir (peut avoir un nombre "infini" (voir limite GET) ex: banItem2, banItem3, etc). Par défaut aucun élément n'est bannis.
    Exemples :
    • www.hostname.be/ajaxArticles.php?articleMax=10&orderByAttributsLastValue=42&orderByAttributs=prix&orderByType=1&categorie=film
      • On demande à voir les 10 prochains articles après celui qui à l'id 42, classé par la cellule prix du plus petit au plus grand, de la catégorie film
Le code
Pour l'installer créez un ajaxArticles.php et collez le code suivant dedans.
  • Code : Tout sélectionner

    <?php
    /*  Licence GPLv3 - Papa :  voxdemonix
        infos : https://www.0rion.netlib.re/forum4/viewtopic.php?f=79&t=541&p=1156#p1156
    */
    /*  Je vous conseil d'insérer tout le bloc try dans un fichier séparé protégé par un .htaccess (deny for all)  */
    try {
        /*  éditez les informations nécessaire pour la connexion à la base de données   */
        $bdd = new PDO('mysql:host='.$main["bdd_Hostname"].';dbname='.$main['bdd_Name'].';charset=utf8', $main['bdd_Login'], $main['bdd_Pass']);
    } catch( Exception $e){
        error_log("ajax -> Error BDD connexion from ".$_SERVER["PHP_SELF"]);
    }
    
        $tableName = "Articles";
    
    
    
        function displayInJsonMyArray($myArray){
            header('Content-type: application/json');
            print_r( json_encode($myArray, JSON_NUMERIC_CHECK)  );
        }
    
    
    
        function articleOrderByList(){
                //MYSQL
            global $bdd;
            $searchCategorieArticle = $bdd->prepare('SELECT * FROM '.$tableName.' LIMIT 1');
            $searchCategorieArticle->execute();
    
                //RECOVER THE RESULT IN A TAB
            $tabCategorie = $searchCategorieArticle->fetch(PDO::FETCH_ASSOC);
            $tab = array();
    
                //READ THE TAB AND MAKE THE OPTIONS'S TAG
            foreach ($tabCategorie as $key => $value) { 
                $tab[] = $key;
            }
            return $tab;
        }
    
    
        function articleCategorieList(){
            $liste = array(); global $bdd;
            $searchCategorieArticle = $bdd->prepare('SELECT `categorie` FROM '.$tableName);
            $searchCategorieArticle->execute();
    
                //MAINTENANT LISTE LES CATEGORIES DANS $tmpCategorie, (PERMET AUSSI DE CRÉER UN FORMULAIRE SELECT)
            while($tmpCategorie = $searchCategorieArticle->fetch(PDO::FETCH_ASSOC)){
                if (!in_array($tmpCategorie["categorie"], $liste)) {
                    $liste[] = $tmpCategorie["categorie"];
                //  var_dump($tmpCategorie); echo '<br />';
                }
            }
            return $liste;
        }
    
    
        function genBanItemForMySQLRequest(){
            $banRequest = '';
            foreach( $_GET as $key => $value){
                if (stripos( ' '.$key , 'banItem' )){
                    $banRequest .= ' AND (id != '.intval($value).')';   
                }
            }
            return $banRequest;
        }
    
    
        /*
            EXPLICATIONS :
        reçoit des variables GET du style :
    opt     &banItem1= reçoit les identifiants a bannir (peut avoir un nombre "infini" (voir limite GET) ex: banItem2, banItem3, etc)
            &articleMax= gère la LIMITE SQL (nombre d'entrée max a renvoier)
            &orderByAttributs= l'attribut pour ORDER BY (par exemple l'id, le prix, etc)
            &orderByAttributsLastValue= la valeur la plus haute (ou basse selon la recherche) de l'attribut ORDER BY afin de commencer la recherche a partir de là
            &categorie= la categorie d'article (peut facilement être remplacer par une seconde condition de recherche)
            &orderByType= decide du sens de la recherche (1 pour plus petit au plus grand (> et ASC), -1 pour plus grand au plus petit (< et DESC))
    opt     &forceChangeOrderSymbole= permet de changer le sens (< ou >) de la recherche sans affecter le reste (ASC ou DESC)
        */
    
    
    
    
        $forceChangeOrderSymbole = 0; //if = 1 => > (plus grand que); if = 2 => < (plus petit que)
        if(filter_has_var(INPUT_GET, "forceChangeOrderSymbole")){
            if(isset($_GET["forceChangeOrderSymbole"]) & !empty($_GET["forceChangeOrderSymbole"])){
                switch(intval($_GET["forceChangeOrderSymbole"])){
                    case 1 :
                    case '1':
                        $forceChangeOrderSymbole = 1;
                    break;
                    case 2 :
                    case '2':
                        $forceChangeOrderSymbole = 2;
                    break;              
                }
            }
        }
        if ( filter_has_var(INPUT_GET, "articleMax") & filter_has_var(INPUT_GET, "orderByType") & filter_has_var(INPUT_GET, "orderByAttributs") & filter_has_var(INPUT_GET, "orderByAttributsLastValue")) {
            $wichCategorie = "all";
            if (filter_has_var(INPUT_GET, "categorie")) {
                $wichCategorie = strval($_GET["categorie"]); //categorie = idForTraduct, not the traducted version (https://www.0rion.netlib.re/forum4/viewtopic.php?f=9&t=211)
            }
            displaySomeArticleInJSONUniversal($_GET["articleMax"], $wichCategorie, $_GET["orderByAttributs"], $_GET["orderByAttributsLastValue"]);
        }
    
    
        function displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue){
            // $iMinimal = l'identifiant unique minimal de l'article, afin d'envoyer les suivants
            global $bdd; //PDO object
            global $forceChangeOrderSymbole;
    
            $orderByAttributs = 'id'; $orderByAttributsLastValue = 1;
            /* security */
            if(in_array(strval($inputOrderByAttributs) , articleOrderByList())){
                $orderByAttributs = strval($inputOrderByAttributs);
                $orderByAttributsLastValue = $inputOrderByAttributsLastValue;
            }
            $orderByType = 'ASC'; $orderSymbole = '>';
            if(strval($_GET["orderByType"]) == '-1'){
                $orderByType = 'DESC';
                $orderSymbole = '<';    
            }
            if($forceChangeOrderSymbole == 2){ $orderSymbole = '<'; }
            if( strval($categorie == "all") || !in_array(strval($categorie), articleCategorieList() )   ){
                $requestSomeArticles = $bdd->prepare("SELECT * FROM ".$tableName." WHERE `".$orderByAttributs."` ".$orderSymbole."= :orderByAttributsLastValue ".genBanItemForMySQLRequest()." ORDER BY `".$orderByAttributs."` ".$orderByType.", `id` ASC LIMIT :nbLimit");
            }else{
                $requestSomeArticles = $bdd->prepare("SELECT * FROM ".$tableName." WHERE `".$orderByAttributs."` ".$orderSymbole."= :orderByAttributsLastValue AND `categorie` = :categorie ORDER BY `".$orderByAttributs."` ".$orderByType.", `id` ASC LIMIT :nbLimit");
                $requestSomeArticles->bindParam(':categorie', strval($categorie), PDO::PARAM_STR);
            }
    
            $requestSomeArticles->bindParam(':nbLimit', intval($nbLimit), PDO::PARAM_INT);
            $requestSomeArticles->bindParam(':orderByAttributsLastValue', floatval($orderByAttributsLastValue), PDO::PARAM_STR);
    
            $requestSomeArticles->execute();
            //$myArticles = $requestSomeArticles->fetchAll(PDO::FETCH_CLASS); 
            $myArticles = array();
                while($tmpArticle = $requestSomeArticles->fetch(PDO::FETCH_ASSOC)){
                    $myArticles[] = arrayUniversalTraductor($tmpArticle);
                }
            displayInJsonMyArray($myArticles);
        }
    ?>
Modifié en dernier par voxdemonix le jeu. févr. 23, 2017 7:39 pm, modifié 18 fois.
~ Infernalis Creatorem ~
  • Rejoins le côté obscure, on a des cookies !
Donation Bitcoin : 1N8QGrhJGWdZNQNSspm3rSGjtXaXv9Ngat
Donation Dash : XmowiBRku3tsEREp7PhpheY4TgeLLDyKdM

Avatar du membre
voxdemonix
Messages : 1336
Enregistré le : lun. févr. 02, 2015 7:28 pm

Re: [PHP] [MySQL] [Ajax] Fonction afficher infos article en JSON depuis MySQL

Message par voxdemonix » mar. févr. 21, 2017 6:25 pm

Fonctionnement en détail :
Note : ne serons mentionné que les noms des fonctions, leur fonctionnement et les types de sorties (avec des exemples). Il n'y aura pas de copier-coller de code afin d'éviter de devoir éditer le tutoriel à chaque édition du code source.


Listes des fonctions :
  • articleOrderByList()
    articleCategorieList()
    genBanItemForMySQLRequest()
    displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue)
    displayInJsonMyArray($myArray)

articleOrderByList()
  • Récupère la liste des attributs possible (nom de cellule) pour la table de données.
    Exemple de sorties :
    • $liste[1] = "film"
      $liste[2] = "séries"
      $liste[3] = "musiques"
articleCategorieList()
  • Retourne une liste sous forme d'un array contenant les noms des différentes catégories sans doublon.
    Exemple de sorties :
    • $liste[1] = "id"
      $liste[2] = "prix"
      $liste[3] = "nom"
      $liste[4] = "timeCreation"
genBanItemForMySQLRequest()
  • Récupère les identifiants des articles à bannir de la prochaine requête SQL. Utilise les variables $_GET[banItemX] afin de générer un morceau de requête SQL du type ' AND (id != '.intval($_GET[banItemX]).')' à insérer avant l'ORDER BY.
    Exemple de sorties :
    • $stringMorceauRequeteSQL = ' AND (id != 1) AND (id != 2) AND (id != 3) AND (id != 5) AND (id != 9) AND (id != 8)'

displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue)
  • La fonction displaySomeArticleInJSONUniversal($nbLimit, $categorie, $inputOrderByAttributs, $inputOrderByAttributsLastValue) est précédée d'un bloc de code chargé d'appréhender certaines informations envoyées par l'utilisateur avant d’exécuter la dite fonction.
    C'est la fonction principale : chargée de forger et exécuter la requête SQL, insérer les résultats dans un tableau (array) puis l'envoyer à displayInJsonMyArray($myArray).

displayInJsonMyArray($myArray)
  • Fonction toute banale recevant un tableau (array) et affichant les informations contenues via print_r() au format JSON avec la vérification des entiers.
Modifié en dernier par voxdemonix le jeu. févr. 23, 2017 1:36 pm, modifié 4 fois.
~ Infernalis Creatorem ~
  • Rejoins le côté obscure, on a des cookies !
Donation Bitcoin : 1N8QGrhJGWdZNQNSspm3rSGjtXaXv9Ngat
Donation Dash : XmowiBRku3tsEREp7PhpheY4TgeLLDyKdM

Avatar du membre
voxdemonix
Messages : 1336
Enregistré le : lun. févr. 02, 2015 7:28 pm

Re: [PHP] [MySQL] [Ajax] afficher les informations d'articles e-shop en JSON depuis MySQL

Message par voxdemonix » jeu. févr. 23, 2017 12:55 pm

~ Infernalis Creatorem ~
  • Rejoins le côté obscure, on a des cookies !
Donation Bitcoin : 1N8QGrhJGWdZNQNSspm3rSGjtXaXv9Ngat
Donation Dash : XmowiBRku3tsEREp7PhpheY4TgeLLDyKdM

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 0 invité