Tutoriel de programmation : Créer la base d'un blog simple



Créer la base d'un blog simple

Vous aimez créer des blogs ou des sites sous WordPress mais vous ne développez pas, et vous souhaiteriez commencer quelque part pour augmenter vos compétences sur le sujet ? Plutôt que de trifouiller les fichiers PHP d'un thème WordPress, pourquoi ne pas commencer par créer votre propre blog à partir de rien ? :)
Nous allons dans cet article coder de A à Z la base d'un blog, que l'on appellera My Lazy Blog, pour vous initier au PHP, mais aussi pour vous servir de base dans le développement d'un site.
S'agissant d'une base très légère, nous allons coder les fonctionnalités princpiales d'un blog, à savoir la création d'un back-office pour pouvoir écrire un article, puis afficher les articles sur une page, et pouvoir le commenter.

BDD

La première étape dans la création de notre site consiste à lister les objets dont on aura besoin pour le site et élaborer le schéma de notre base de données. Pour cet article nous allons simplement utiliser 4 tables :
  • adminUser : la table qui contiendra les données sur l'administrateur du site (pour accéder au back-office). Elle contiendra son id, son nom, son mot de passe et son email (qui ne sera pas utilisé pour cet article)
  • post : la table pour stocker les éléments d'un article, àsavoir : son id, son titre, son contenu, la date, et l'id de l'auteur de l'article (l'admin), et l'id de la catégorie correspondante
  • comment : la table pour les commentaires, qui stockera l'id du commentaire, le nom de l'auteur, son email, le contenu du message, la date, et l'id de l'article correspondant
  • category : la table pour stocker les id et noms des catégories
Nb : par rapport aux catégories, elles ne seront pour l'instant là qu'à titre informatif, nous n'allons pas développer une partie Recherche d'article en fonction des catégories.
Une fois les objets définis, vous allez démarrer Wamp et aller sur PHPMyAdmin.
Nb: WAMP est une suite d'outils packagé offrant sous Windows un environnement de développement à base de PHP, MySQL et serveur Apache, ainsi que des outils comme PhpMyAdmin. Il existe des équivalents Mac comme MAMP, et Linux comme LAMP.
Une fois dedans, cliquez sur "Créer la base de données", et nommez-la (ici elle aura pour nom "my_lazy_blog"). Choisissez ensuite utf8_unicode_ci pour l'interclassement.
On crée ensuite la première table (celle de "adminUser"), on indique son nombre de colonnes et on définit les paramètres nécesaires de chaque colonne.
  • pour l'id : type INT / cocher A_I / INDEX Primary
  • pour les username, password, email : type VARCHAR | valeur 255
Répétez ensuite la procédure pour les autres tables.
Pour la création des tables aux clés étrangères (foreign key) : on crée les tables avec le nom de leurs clés étrangères et on sauvegarde, puis on clique en bas sur Vue relationnelle :
On clique sur +Index, puis sur Executer, et on entre le nom des foreign key, puis on sélectionne INDEX avant d'exécuter la création de la clé.
Puis on répète ces mêmes actions pour la création des autres clés et tables. La base de donnée sera ainsi prête !

Mise en place du projet et du compte Admin

Une fois la base de données établie, nous allons créer les fichiers et dossiers de notre blog :
Dans wamp, ouvrez le « www directory » et créez un dossier avec le nom de votre blog (ici ce sera « my_lazy_blog »). Puis créez les dossiers et fichiers :
  • index.php : la page principale de votre blog
  • article.php : la page d'un article du blog
  • dossier include : qui contient le fichier config.php
  • dossier admin : qui contient les fichiers du back-office, avec index.php (qui sera pour nous la page de connexion au back-office), admin.php (l'accueil du back-office), redactor.php (la page pour créer un nouvel article), et un register.php (à supprimer plus tard - pour créer un compte admin)
  • dossier content : qui contient les dossiers css, js et img (pour contenir respectivement les fichiers css, js et les images)
Nous allons passer à la modification du fichier config.php : c'est dans ce fichier que nous allons établir la connexion à la base de données.
Dans config.php :
<?php
$dbh;
try {
    $dbh = new PDO('mysql:host=localhost;dbname=my_lazy_blog', "root", null);
    foreach($dbh->query('SELECT * FROM post') as $row) {
        print_r($row);
    }
    //$dbh = null;
} catch (PDOException $e) {
    print "Erreur !: " . $e->getMessage() . "<br/>";
    die();
}
?>
C'est le code de la doc PHP de base (cf. https://secure.php.net/manual/fr/pdo.connections.php ), qui permet d'établire une connexion SQL via PDO (et d'afficher un message en cas d'erreur). Afin de tester notre liaison avec notre base, il faut remplacer "root" et le paramètre null selon les identifiants/mot de passe de notre accès MySQL si nécessaire.
Pour tester si cela a bien marché, nous allons modifier le fichier index.php :
<?php
require_once('include/config.php');
var_dump($dbh);
?>
La fonction var_dump() va nous indiquer si la variable $dbh (qui correspond à la base de données) est bien existante. On fait le lien avec le fichier config.php grâce à require_once(). Si la connexion a été bien faite, vous devez obtenir comme message lorsque vous allez sur localhost/my_lazy_blog/index.php dans votre navigateur : "object(PDO)[1]"
Maintenant nous allons créer un compte admin pour accéder à notre back-office.
Pour le faire d'une manière très simple, nous allons modifier le fichier register.php qu'on executera qu'une seule fois pour se créer notre utilisateur. On supprimera cette page après utilisation au cas où pour plus de sécurité.
Dans register.php :
<?php
    require_once('../include/config.php');
    
    $password = password_hash("YOUR_PASSWORD", PASSWORD_DEFAULT);
    $username = "YOUR_USERNAME";
    $email = "test@test.com";
    
    $sql = "INSERT INTO adminuser(username, password, email) VALUES (:username, :password, :email)";
    $stmt = $dbh->prepare($sql);
    $stmt->bindValue(':username', $username);
    $stmt->bindValue(':password', $password);
    $stmt->bindValue(':email', $email);
    $stmt->execute();
    echo $username . "admin user had been created";
?>
password_hash() va nous permettre de chiffrer en base de données le mot de passe que l'on va se créer. Avec une autre fonction en PHP, il va checker si celui-ci est valide lors de l'authentification. Cela évite d'avoir à faire soit même la fonction du hash / salt / login / ... de façon plus complexe sur le traitement du mot de passe).
Nb : pensez à remplacer "YOUR_PASSWORD", "PASSWORD_DEFAULT" et "YOUR_USERNAME" par vos propres identifiants.
Pour vérifier que le compte administrateur a bien été créé, allez sur localhost/my_lazy_blog/admin/register.php dans votre navigateur, et vérifiez que vous obteniez sur cette page le message : "[YOUR_USERNAME] admin user had been created". Vous pouvez également vérifier dans PHPMyAdmin qu'il a bien été créé.
Passons à l'authentification au back-office :
Dans admin/index.php :
<form  method="POST">
    <div>
        <h2>Login</h2>
    </div>
  <div>
    <input id="username" type="text" name="username" placeholder="Username">
  </div>
  <div>
    <input id="password" type="password" name="password" placeholder="Password">
  </div>
  <div>
    <input type="submit" value="Submit">
  </div>
</form>
Sur cette page nous avons créé un formulaire de connexion
Côté serveur de cette page : cette page va se prendre une requête POST venant d'elle-même, du coup il faut utiliser en PHP la variable $_POST, qui est un tableau contenant toute les valeur du POST. Ainsi si on fait: $username = $_POST["username"] on aura le champ username qui a été envoyé, pareil pour $password = $_POST["password"].
<?php
    $username = $_POST["username"];
    $password = $_POST["password"];
?>
Ensuite, il faut faire une requête SQL via la PDO, pour récupérer le hash et le comparer au Username qui a été transmis :
<?php
    require_once('../include/config.php');
    session_start();

    if (isset($_POST["username"]) && isset($_POST["password"])) {
        $username = $_POST["username"];
        $password = $_POST["password"];
        
        $sql = "SELECT password, id FROM adminuser WHERE username = :username";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':username', $username);
        $stmt->execute();
        $result = $stmt->fetch();
        $isValid = password_verify($password, $result[0]);
        
        if ($isValid) {
            $_SESSION['isAdmin'] = true;
            $_SESSION['authUser'] = $username; 
            $_SESSION['id'] = $result[1];
            header('Location: /my_lazy_blog/admin/admin.php');
        }
    }
?>
On écrit la requête SQL dans une string : $sql = "SELECT password FROM adminuser WHERE username = :username;"
Ensuite comme pour register.php on fait un: $stmt = $dbh->prepare($sql);, puis $stmt->bindValue(':username', $username). binValue sert à mettre la valeur d'une variable dans une requête SQL de façon sécurisée.
On fait ensuite un $stmt->execute(); puis un $result = stmt->fetch(); Ensuite, on doit utiliser la fonction spécial vérification de mot de passe de PHP5.5 : $isValid = password_verify($password, $result); On va ensuite vérifier la correspondance du username et du password dans une condition if.
Nb : $_SESSION est une variable comme $_POST, elle va nous permettre de stocker des valeurs propre à l'utilisateur connecté, et peuvent même être récupérées ailleurs sur le site.
Nb2 : dans cet article on ne prend pas en compte la gestion de message de mauvais login, c'est une feature qu'il vous faudra intégrer.
Vérifions enfin si la connexion a bien été faite :
Dans admin/admin/php :
require_once('../include/config.php');
    if ($_SESSION['isAdmin']) {
        echo "Welcome " . $_SESSION['authUser'];
    }else {
        echo "Get out you're not authorized";
    }
Voilà ce que vous devriez obtenir lorsque vous allez dans votre naviagteur sur la page admin.php !

Le back-office

Passons maintenant à la création du back-office, en commençant par la page redactor.php :
Pour la création de cette page, il vous faut installer un WYSIWYG pour le projet. Il s'agit d'un script javascript à charger, qui permettra de transformer une simple balise en un véritable éditeur de texte (avec bouton gras, italique, insertion d'image/...). Pour se faire, choisissons un wysiwyg gratuit et très simple à installer. Pour ce projet nous allons prendre ckeditor (cf. http://ckeditor.com/download ).
Installation : copier/coller le lien CDN de la page sur notre fichier admin.php (on prendra le CDN du "Standard Package" pour la rédaction de post, qui va permettre d'utiliser la librairie de l'éditeur : http://cdn.ckeditor.com/ ).
Le HTML de redactor.php :
<html>
    <head>
        <meta charset="utf-8">
        <title>Admin Article </title>
    </head>
    <body>
        <h1>Rédaction d'un article : </h1>
        <div>
            <div>
                <div>Choisissez la catégorie :</div>
                <div>
                    <select>
                        <?php
                           foreach ($categories as $category) 
                           {
                             echo "<option value='".$category."'>".$category."</option>";
                           }
                        ?>
                    </select>
                </div>
                <div>
                    Ajouter une nouvelle catégorie :
                    <button id="addCategory">Créer une nouvelle catégorie</button>
               </div>
            </div>
            <div><textarea name="editor"></textarea></div>
        </div>

        <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
        <script src="//cdn.ckeditor.com/4.5.11/standard/ckeditor.js"></script>
        <script>
            CKEDITOR.replace( 'editor' );
        </script>
    </body>
</html>
Pour l'instant il n'y a que la sélection de catégorie qui a été implémentée, le bouton pour ajouter une nouvelle catégorie, ainsi que la zone de rédaction de l'article :
Passons à la création d'une catégorie :
<?php
    require_once('../include/config.php');
    $categories = [];
    $sql = "SELECT id, name FROM categories;";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    
    $categories = $stmt->fetchAll();
?>
Modifions maintenant notre echo qui affichera le nom de la catégorie :
<select>
<?php 
foreach ($categories as $category) 
{
echo "<option value='".$category[0]."'>".$category[1]."</option>";
}
?>
</select>
Au niveau du script, il faut maintenant ajouter une catégorie à partir du bouton Créer une catégorie : Nous allons commencer par écrire le script AJAX dans la balise <script></script> :
CKEDITOR.replace( 'editor' );
            
$('#addCategory').on('click', function(){
var newName = prompt("Entrez le nom de votre catégorie :");
$.ajax({
          method: "POST",
          data: {
              "name": newName
          }
     });
});
Modifions ensuite le PHP :
<?php
    require_once('../include/config.php');
    if(!isset($_SESSION["isAdmin"]) || (isset($_SESSION["isAdmin"]) && !$_SESSION["isAdmin"])) {
      echo "Unauthorized Access";
      exit;
    }

    $categories = [];
    if (isset($_POST["name"])) {
        $sql = "INSERT INTO category(name) VALUES (:name);";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':name', $_POST["name"]);
        $stmt->execute();
    }
    
    $sql = "SELECT id, name FROM category;";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
        
    $categories = $stmt->fetchAll();
        
    if (isset($_POST["name"])){    
        echo json_encode($categories);
        return;
    }
?>
Quand la requête AJAX va appeler la page, celle-ci va rentrer dans la condition if (qui renvoie un json). Ca va permettre d'actualiser la liste des catégories lorsqu'on en ajoute une nouvelle.
On n’oublie pas de sécuriser la page avec isset($_SESSION["isAdmin"] : si quelqu'un met l'URL de cette page, sans être loggué, il se fait jeté par la page avant même qu'elle ait affiché ou fait autre chose.
Au niveau de la requête AJAX dans le script, on rajoute de nouveaux paramètres pour permettre au script d'actualiser le HTML avec de nouvelles valeurs après ajout :
$.ajax({
method: "POST",
data: {
"name": newName
 },
dataType: "json",
success: function(categories){
var categoriesHtml;
for (category of categories){
     categoriesHtml += "<option value='" + category[0] + "'>" + category[1] +  "</option>";
}
$('#listCategories').html(categoriesHtml);
}
});
En n’oubliant pas de rajouter l’id #listCategory à la balise <select>.
Ce qui nous donne :
Dans PHPMyAdmin :
Et sur la page :
Occupons-nous maintenant du poste de l’article :
On rajoute en dessous de notre text-area dans le html :
<div>
<button id="publish">Publier</button>
</div>
Et dans le script :
$('#publish').on('click', function(){
$.ajax({
    method: "POST",
    data: { 
      "post": CKEDITOR.instances.editor.getData(),
      "title": $("#postTitle").val(),
       "category" : $("#listCategories").val()
    },
    success: function(){
       window.location.href = "/my_lazy_blog/admin/admin.php";
    }
})
});
Maintenant, introduisons le nouvel article dans notre base de données :
Dans le PHP :
 if (isset($_POST["title"]) && isset($_POST["post"])) {
        $sql = "INSERT INTO post(title, content, FK_category, FK_adminUser, date)) VALUES (:title, :content, :categoryId, :authorId, :date)";
    
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':title', $_POST['title']);
        $stmt->bindValue(':content', $_POST['post']);
        $stmt->bindValue(':categoryId', $_POST['category']);
        $stmt->bindValue(':authorId', $_SESSION['id']);
        $stmt->bindValue(':date', date("Y-m-d H:i:s"));
        $stmt->execute();
      return;
    }
Sans oublier de rajouter dans le HTML un input pour entrer le titre de l'article.
Le rendu final de la page redactor.php :
Et dans la base de données :
Affichons maintenant l’ensemble des articles dans la page d’accueil de notre backoffice (admin.php) :
On modifie le php de cette page pour rajouter la requête qui récupèrera la liste des articles avec leur titre, auteur, date et catégorie liés.
Dans admin.php :
$posts = [];
    $sql = "SELECT
                p.id as id,
                p.title as title,
                aU.username as adminUser,
                c.name as category,
                p.date as date
            FROM
                post p
            LEFT JOIN adminUser aU 
            ON p.FK_adminUser = aU.id
            LEFT JOIN category c 
            ON p.FK_category = c.id;";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    $posts = $stmt->fetchAll();
Ensuite dans le html de la page on affiche nos éléments dans un tableau, en n'oubliant pas bien sûr un bouton qui mène à la page de création (nous ne nous occuperons pas de la modification et de la suppression d’un article) :
<body>
        <?php 
            echo "<h2>Welcome " . $_SESSION['authUser']."</h2> ";
        ?>
        <div>
            <table>
                <table style="width:100%">
                  <tr class="table-first-line">
                    <th>Auteur</th>
                    <th>Titre</th>
                    <th>Catégorie</th> 
                    <th>Date</th>
                  </tr>
                  <?php
                    foreach ($posts as $post) {
                        echo "<tr>
                                <td>".$post["adminUser"]."</td>
                                <td>".$post["title"]."</td> 
                                <td>".$post["category"]."</td>
                                <td>".$post["date"]."</td>
                            </tr>";
                    }
                  ?>
            </table>
        </div>
        <div>
            <a href="/my_lazy_blog/admin/redactor.php" target="_blank">Créer un nouvel article</a>
        </div>
    </body>
Dans un fichier style.css, on ajoute un peu de style à notre page.
Le back-office est enfin prêt !

Le Front

Il est temps maintenant de s'attaquer à la page principale de notre blog : index.php
On commence d'abord par faire le squelette et le design en HTML/CSS de la page. Et pour cela nous allons inclure bootstrap à notre projet (via les liens CDN) et ajouter un minimum de style à notre blog.
Avec des données en dur, voilà à quoi ressemblera notre blog :
(Et ce uniquement avec Bootstrap et de la customisation en CSS !)
On en profite par la même occasion pour appliquer ce même style à la page d’un article (dans article.php).

La page index.php

On effectue la même manipulation que précédemment pour afficher la liste de vos articles dans le backoffice, en rajoutant la colonne « content » dans la requête SQL. Vous devriez obtenir dans l’index.php.
Les requêtes dans la partie PHP :
<?php
    require_once('include/config.php');
    $posts = [];
    $sql = "SELECT
                p.id as id,
                p.title as title,
                aU.username as adminUser,
                c.name as category,
                p.date as date,
                p.content as content
            FROM
                post p
            LEFT JOIN adminUser aU 
            ON p.FK_adminUser = aU.id
            LEFT JOIN category c 
            ON p.FK_category = c.id
            ORDER BY date DESC;";
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    $posts = $stmt->fetchAll();
    
?>
Le HTML de la page :
<div class="container">
            <div class="row">
                <div class="col-md-12">
                    <?php
                        foreach ($posts as $post) {
                            echo
                            "<div class='wrap-post'>
                                <div class='header-post'>
                                    <div class='title-post'>".$post["title"]."
                                        <div class='info-post'>".$post["category"].", par ".$post["adminUser"]." le ".$post["date"]."</div>
                                    </div>
                                </div>
                                <div class='content-post'>
                                    <div class='content'>".$post["content"]."</div>                
                                    <div class='fade-content'><a href='/my_lazy_blog/article.php?p=".$post["id"]."'>Lire la suite</a></div>
                               </div>
                            </div>";
                    }
                    ?>
                </div>
            </div>
        </div>
En n’oubliant pas de bien rajouter l’id de l’article à la fin de l’url.

La page article.php

Pour la page d’un article, les requêtes, le php et le HTML restent similaires à ce qu’on a fait précédemment pour l’admin.php et l’index.php, à la différence qu’on rajoute un $_GET pour récupérer l’id de l’article dans l’url :
$id = intval($_GET['p']);
    
    $sql = "SELECT
                p.id as id,
                p.title as title,
                aU.username as adminUser,
                c.name as category,
                p.date as date,
                p.content as content
            FROM
                post p
            LEFT JOIN adminUser aU 
            ON p.FK_adminUser = aU.id
            LEFT JOIN category c 
            ON p.FK_category = c.id
            WHERE p.id = :id";
    $stmt = $dbh->prepare($sql);
    $stmt->bindValue(':id', $id);
    $stmt->execute();
    $post = $stmt->fetch();
Concernant les commentaires :
Comme précédemment pour insérer et afficher des commentaires en SQL.
Insérer :
if (isset($_POST["author"]) && isset($_POST["email"]) && isset($_POST["content"]) && isset($id)) {
        $sql = "INSERT INTO comment(author, email, content, FK_post, date)
                VALUES (:author, :email, :content, :postId, :date);";
        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':author', $_POST["author"]);
        $stmt->bindValue(':email', $_POST["email"]);
        $stmt->bindValue(':content', $_POST["content"]);
        $stmt->bindValue(':postId', $id);
        $stmt->bindValue(':date', date("Y-m-d H:i:s"));
        $stmt->execute();
    }
Afficher :
$sql = "SELECT 
                c.content as content, 
                c.date as date, 
                c.author as author
            FROM 
                comment c
            WHERE c.FK_post = :id
            ORDER BY date, id DESC;";
    $stmt = $dbh->prepare($sql);
    $stmt->bindValue(':id', $id);
    $stmt->execute();
    $comments = $stmt->fetchAll();
Puis le script de l’ajout de commentaire quand on publie :
<script>
            CKEDITOR.replace( 'editor' );
            
            $('#addComment').on('click', function(){
                $.ajax({
                    method: "POST",
                    data: {
                        "author": $("#user").val(),
                        "email": $("#mail").val(),
                        "content": CKEDITOR.instances.editor.getData()
                    },
                    success: function(){
                        var newComment = "<div class='content-post'><div class='content-article'>" + CKEDITOR.instances.editor.getData() + "</div><div class='comment-name'>Par " + $("#user").val() + "</div></div>";
                        $("#listComment").prepend(newComment);
                    }
                });
            });
        </script>
Une fois que le commentaire est envoyé, au lieu de demander au serveur de nouevau la liste, on ajoute dynamiquement le nouveau commentaire via jQuery (totalement client-side).
Le HTML de la page :
<div class="container">
            <div class="row">
                <div class="col-md-12">
                    <div class="wrap-post">
                        <?php
                            echo
                            "<div class='header-post'>
                                <div class='title-post'>".$post["title"]."
                                <div class='info-post'>".$post["category"].", par ".$post["adminUser"]." le ".$post["date"]."</div>
                            </div>
                            </div>
                            <div class='content-post'>
                                <div class='content-article'>".$post["content"]."</div>                
                            </div>";
                        ?>
                    </div>
                    <div class="comments wrap-post">
                        <div class="header-post">
                            <div class="title-post">Commentaires</h2></div>
                        </div>
                        <div id="listComment">
                        <?php
                            foreach($comments as $comment) {
                                echo
                                "<div class='content-post'>
                                    <div class='content-article'>".$comment["content"]."</div>                
                                    <div class='comment-name'>Par ".$comment["author"]."</div>
                                </div>";
                            }
                        ?>
                        </div>
                    </div>
                    <div class="comments wrap-post">
                        <div class="header-post">
                            <div class="title-post">Ecrire un commentaire</h2></div>
                        </div>
                        <div class="content-post">
                            <div class="form-group">
                                <label for="user">Nom :</label>
                                <input type="text" class="form-control" id="user" value="Anonymous" />
                                <label for="mail">Email :</label>
                                <input type="email" class="form-control" id="mail" />
                            </div>
                            <div><textarea name="editor"></textarea></div>
                            <div><button id="addComment" class="flat-button">Publier</div></div>
                        </div>
                    </div>
                </div>
            </div>
Le blog est enfin prêt !

Conclusion

Désormais grâce à cet article vous pouvez créer la base d'un blog.
Bien évidemment il ne s'agit pas d'un blog complet, vu le nombre de fonctionnalités qu'il reste à faire : la recherche par catégorie, la déconnexion du back-office, la modification d'un article, la suppression d'un commentaire...
Consédirez ce blog comme une base pour vous exercer en PHP (et HTML/CSS) que vous pourrez compléter, customiser, et même améliorer !

Commentaires

Posts les plus consultés de ce blog

Tutoriel Word comment encadrer une page

Comment utiliser Whatsapp avec un numéro américain (+1)

56 applications Android infectées à désinstaller d'urgence