Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment créer un blog en PHP et base de données MySQL - DB design

La base de données

Ceci est la deuxième partie d'une série sur Comment créer un blog avec PHP et MySQL. Vous pouvez obtenir la première partie ici

Nous continuerons là où nous nous sommes arrêtés dans le dernier tutoriel. Dans cette section, nous allons travailler sur la conception de notre base de données et l'authentification des utilisateurs (inscription et connexion). Créez une base de données nommée complete-blog-php. Dans cette base de données, créez 2 tables : articles et utilisateurs avec les champs suivants.

messages :

+----+-----------+--------------+------------+
|     field      |     type     | specs      |
+----+-----------+--------------+------------+
|  id            | INT(11)      |            |
|  user_id       | INT(11)      |            |
|  title         | VARCHAR(255) |            |
|  slug          | VARCHAR(255) | UNIQUE     |
|  views         | INT(11)      |            |
|  image         | VARCHAR(255) |            |
|  body          | TEXT         |            |
|  published     | boolean      |            |
|  created_at    | TIMESTAMP    |            |
|  updated_at    | TIMESTAMP    |            |
+----------------+--------------+------------+

utilisateurs :

+----+-----------+------------------------+------------+
|     field      |     type               | specs      |
+----+-----------+------------------------+------------+
|  id            | INT(11)                |            |
|  username      | VARCHAR(255)           | UNIQUE     |
|  email         | VARCHAR(255)           | UNIQUE     |
|  role          | ENUM("Admin","Author") |            |
|  password      | VARCHAR(255)           |            |
|  created_at    | TIMESTAMP              |            |
|  updated_at    | TIMESTAMP              |            |
+----------------+--------------+---------+------------+

Vous pouvez créer ces tableaux à l'aide de ces commandes.

utilisateurs :

CREATE TABLE `users` (
  `id` int(11) AUTO_INCREMENT PRIMARY KEY NOT NULL,
  `username` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `role` enum('Author','Admin') DEFAULT NULL,
  `password` varchar(255) NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

messages :

CREATE TABLE `posts` (
 `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
 `user_id` int(11) DEFAULT NULL,
 `title` varchar(255) NOT NULL,
 `slug` varchar(255) NOT NULL UNIQUE,
 `views` int(11) NOT NULL DEFAULT '0',
 `image` varchar(255) NOT NULL,
 `body` text NOT NULL,
 `published` tinyint(1) NOT NULL,
 `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Vous pouvez exécuter ces scripts à l'aide de l'invite de commande SQL ou de PHPMyAdmin. Sur PHPMyAdmin, cliquez/sélectionnez la base de données sous laquelle vous souhaitez créer ces tables (dans ce cas, complete-blog-php), puis cliquez sur l'onglet SQL de la barre de navigation quelque part en haut de la page. Si vous voyez un script SQL dans l'espace ci-dessous, supprimez-le et collez le script ci-dessus dans l'espace prévu et cliquez sur "Go" pour créer les tables.

Si vous avez plutôt choisi de créer ces tables manuellement, n'oubliez pas de rendre le champ slug de la table post UNIQUE et de définir le champ user_id de la table posts comme clé étrangère faisant référence à id sur la table des utilisateurs. Définissez AUCUNE ACTION comme valeur pour les options ON DELETE et ON UPDATE afin que lorsqu'un utilisateur est supprimé ou mis à jour, ses publications restent dans la table des publications et ne soient pas supprimées.

Insérez maintenant quelques utilisateurs dans la table des utilisateurs et quelques publications dans la table des publications. Vous pouvez le faire en exécutant ces requêtes SQL pour insérer :

utilisateurs :

INSERT INTO `users` (`id`, `username`, `email`, `role`, `password`, `created_at`, `updated_at`) VALUES
(1, 'Awa', '[email protected]', 'Admin', 'mypassword', '2018-01-08 12:52:58', '2018-01-08 12:52:58')

messages : 

INSERT INTO `posts` (`id`, `user_id`, `title`, `slug`, `views`, `image`, `body`, `published`, `created_at`, `updated_at`) VALUES
(1, 1, '5 Habits that can improve your life', '5-habits-that-can-improve-your-life', 0, 'banner.jpg', 'Read every day', 1, '2018-02-03 07:58:02', '2018-02-01 19:14:31'),
(2, 1, 'Second post on LifeBlog', 'second-post-on-lifeblog', 0, 'banner.jpg', 'This is the body of the second post on this site', 0, '2018-02-02 11:40:14', '2018-02-01 13:04:36')

Connectons-nous à la base de données, interrogeons ces publications et affichons-les sur la page Web.

Dans config.php, ajoutons du code pour connecter notre application à la base de données. Après avoir ajouté le code, notre fichier config.php ressemblera à ceci :

<?php 
	session_start();
	// connect to database
	$conn = mysqli_connect("localhost", "root", "", "complete-blog-php");

	if (!$conn) {
		die("Error connecting to database: " . mysqli_connect_error());
	}
    // define global constants
	define ('ROOT_PATH', realpath(dirname(__FILE__)));
	define('BASE_URL', 'http://localhost/complete-blog-php/');
?>

Cela renvoie un objet de connectivité de base de données $conn que nous pouvons utiliser dans l'ensemble de notre application pour interroger la base de données.

Cette application a été structurée de manière à ce que le code PHP soit aussi séparé que possible du HTML. Les opérations telles que l'interrogation de la base de données et l'exécution d'une logique sur les données sont effectuées dans des fonctions PHP et les résultats sont envoyés à HTML pour être affichés. Par conséquent, pour obtenir tous les messages de la base de données, nous le ferons dans une fonction et renverrons les résultats sous forme de tableau associatif à parcourir et à afficher sur la page.

Par conséquent, créez un fichier nommé public_functions.php dans le dossier includes. Ce fichier contiendra toutes nos fonctions PHP pour la zone publique. Toutes les pages utilisant l'une des fonctions de ce fichier doivent avoir ce fichier inclus dans la section supérieure de la page.

Créons notre première fonction dans notre nouveau public_functions.php. Nous nommerons la fonction getPublishedPosts() et elle récupérera tous les articles de la table des articles dans la base de données et les renverra sous forme de tableau associatif :

public_functions.php :

<?php 
/* * * * * * * * * * * * * * *
* Returns all published posts
* * * * * * * * * * * * * * */
function getPublishedPosts() {
	// use global $conn object in function
	global $conn;
	$sql = "SELECT * FROM posts WHERE published=true";
	$result = mysqli_query($conn, $sql);

	// fetch all posts as an associative array called $posts
	$posts = mysqli_fetch_all($result, MYSQLI_ASSOC);

	return $posts;
}

// more functions to come here ...
?>

Dans la section supérieure du fichier index.php, juste en dessous de la ligne qui inclut config. php , ajoutez ce code pour interroger la base de données :

<!-- config.php should be here as the first include  -->

<?php require_once( ROOT_PATH . '/includes/public_functions.php') ?>

<!-- Retrieve all posts from database  -->
<?php $posts = getPublishedPosts(); ?>

Nous avons ajouté deux lignes de code. Le premier inclut le fichier public_functions.php (qui contient les fonctions) dans notre fichier index.php. La deuxième ligne de code appelle la fonction getPublishedPosts() qui interroge la base de données et renvoie les publications extraites de la base de données dans une variable appelée $posts. Passons maintenant en revue et affichons ces articles sur la page index.php.

Ouvrez à nouveau notre célèbre fichier index.php. Dans la section de contenu quelque part au milieu, vous trouverez une balise


et un commentaire indiquant où plus de contenu est à venir. Dans l'espace, juste en dessous de la balise
, ajoutez ce code :

<hr>
<!-- more content still to come here ... -->

<!-- Add this ... -->
<?php foreach ($posts as $post): ?>
	<div class="post" style="margin-left: 0px;">
		<img src="<?php echo BASE_URL . '/static/images/' . $post['image']; ?>" class="post_image" alt="">
		<a href="single_post.php?post-slug=<?php echo $post['slug']; ?>">
			<div class="post_info">
				<h3><?php echo $post['title'] ?></h3>
				<div class="info">
					<span><?php echo date("F j, Y ", strtotime($post["created_at"])); ?></span>
					<span class="read_more">Read more...</span>
				</div>
			</div>
		</a>
	</div>
<?php endforeach ?>

Ok s'il vous plaît ne rechargez pas la page pour l'instant. Ajoutons du style à cette liste de publications. Ouvrez public_styling.css et ajoutez-y ce code :

/* CONTENT */
.content {
	margin: 5px auto;
	border-radius: 5px;
	min-height: 400px;
}
.content:after {
	content: "";
	display: block;
	clear: both;
}
.content .content-title {
	margin: 10px 0px;
	color: #374447;
	font-family: 'Averia Serif Libre', cursive;
}
.content .post {
	width: 335px;
	margin: 9px;
	min-height: 320px;
	float: left;
	border-radius: 2px;
	border: 1px solid #b3b3b3;
	position: relative;
}
.content .post .category {
	margin-top: 0px;
	padding: 3px 8px;
	color: #374447;
	background: white;
	display: inline-block;
	border-radius: 2px;
	border: 1px solid #374447;
	box-shadow: 3px 2px 2px;
	position: absolute;
	left: 5px; top: 5px;
	z-index: 3;
}
.content .post .category:hover {
	box-shadow: 3px 2px 2px;
	color: white;
	background: #374447;
	transition: .4s;
	opacity: 1;
}
.content .post .post_image {
	height: 260px;
	width: 100%;
	background-size: 100%;
}
.content .post .post_image {
	width: 100%;
	height: 260px;
}
.content .post .post_info {
	height: 100%;
	padding: 0px 5px;
	font-weight: 200;
    font-family: 'Noto Serif', serif;
}
.content .post .post_info {
	color: #222;
}
.content .post .post_info span {
	color: #A6A6A6;
	font-style: italic;
}
.content .post .post_info span.read_more {
	position: absolute;
	right: 5px; bottom: 5px;
}

Vous pouvez maintenant recharger la page.

Si tout s'est bien passé, vous verrez un seul article sous la forme d'une vignette sous le titre "Articles récents". Rappelez-vous que nous avions inséré deux enregistrements dans la base de données mais qu'un seul est affiché. En effet, l'un des enregistrements avait son champ publié défini sur faux (c'est-à-dire 0), et puisque seuls les articles publiés peuvent être affichés, nous n'en voyons qu'un, celui publié.

Mais nos messages à partir de maintenant ne sont classés sous aucun sujet. Créons une table de sujets et formons une relation plusieurs à plusieurs entre les publications et la table de sujets. Pour ce faire, nous allons créer deux nouvelles tables :les sujets pour stocker les sujets et la table post_topic pour gérer la relation entre les publications et les sujets.

sujets :

+----+-----------+------------------------+------------+
|     field      |     type               | specs      |
+----+-----------+------------------------+------------+
|  id            | INT(11)                |            |
|  name          | VARCHAR(255)           |            |
|  slug          | VARCHAR(255)           | UNIQUE     |
+----------------+--------------+---------+------------+

post_topic :

+----+-----------+------------------------+------------+
|     field      |     type               | specs      |
+----+-----------+------------------------+------------+
|  id            | INT(11)                |            |
|  post_id       | INT(11)                |  UNIQUE    |
|  topic_id      | INT(11)                |            |
+----------------+--------------+---------+------------+

Ce qui nous intéresse vraiment, c'est la table post_topic. C'est le tableau qui gère la relation entre les messages et les sujets. Lorsqu'un message est créé sous un sujet particulier, l'identifiant de ce message (post_id), ainsi que l'identifiant du sujet (topic_id) sous lequel ce message est créé, sont insérés dans la table post_topic.

Établissons cette relation afin que lorsqu'un article est supprimé, son entrée dans la table post_topic soit automatiquement supprimée également ; vous ne voulez pas conserver d'informations sur la relation d'une publication lorsque la publication n'existe pas, n'est-ce pas ?

Cliquez/sélectionnez la table post_topic, puis cliquez sur l'onglet structure de la barre de navigation PHPMyAdmin. Ensuite, cliquez sur Relation View juste sous l'onglet structure (il peut se trouver ailleurs en fonction de votre version de PHPMyAdmin). Remplissez ensuite le formulaire ci-dessous comme suit :

Astuce :Le lien + Ajouter une contrainte permet d'ajouter une nouvelle contrainte.

ON DELETE et ON UPDATE sont tous définis sur CASCADE et NO ACTION respectivement, de sorte que lorsqu'un message ou un sujet est supprimé, ses informations de relation dans la table post_topic sont également automatiquement supprimées. (Dans l'image, j'ai fait une erreur en définissant ON UPDATE sur CASCADE au lieu de NO ACTION, désolé pour cela).

Cliquez sur enregistrer et c'est tout. Les tables sont désormais liées. Mais pour établir une relation entre les messages et les sujets, nous devons remplir la table des sujets avec des sujets et éventuellement la table post_topic qui est l'information sur la relation réelle.

Insérons maintenant quelques entrées dans les deux tables :

sujets :

INSERT INTO `topics` (`id`, `name`, `slug`) VALUES
(1, 'Inspiration', 'inspiration'),
(2, 'Motivation', 'motivation'),
(3, 'Diary', 'diary')

post_topic :

INSERT INTO `post_topic` (`id`, `post_id`, `topic_id`) VALUES
(1, 1, 1),
(2, 2, 2)

La relation définie sur la table post_topic indique que le sujet avec l'identifiant 1 sur la table des sujets appartient à la publication avec l'identifiant 1 sur la table des messages. Il en va de même pour le sujet avec l'identifiant 2 et le message avec l'identifiant 2.

Sur chaque liste de publication sur la page index.php, nous allons afficher le sujet sous lequel la publication est créée.

Pour ce faire, nous devons modifier notre getPublishedPosts() que nous avons créé dans public_functions.php pour interroger le sujet de chaque article de la base de données et renvoyer l'article avec son sujet.

Modifiez le fichier public_functions.php pour qu'il ressemble à ceci :

<?php 
/* * * * * * * * * * * * * * *
* Returns all published posts
* * * * * * * * * * * * * * */
function getPublishedPosts() {
	// use global $conn object in function
	global $conn;
	$sql = "SELECT * FROM posts WHERE published=true";
	$result = mysqli_query($conn, $sql);
	// fetch all posts as an associative array called $posts
	$posts = mysqli_fetch_all($result, MYSQLI_ASSOC);

	$final_posts = array();
	foreach ($posts as $post) {
		$post['topic'] = getPostTopic($post['id']); 
		array_push($final_posts, $post);
	}
	return $final_posts;
}
/* * * * * * * * * * * * * * *
* Receives a post id and
* Returns topic of the post
* * * * * * * * * * * * * * */
function getPostTopic($post_id){
	global $conn;
	$sql = "SELECT * FROM topics WHERE id=
			(SELECT topic_id FROM post_topic WHERE post_id=$post_id) LIMIT 1";
	$result = mysqli_query($conn, $sql);
	$topic = mysqli_fetch_assoc($result);
	return $topic;
}
?>

Allez maintenant dans le fichier index.php. Dans la boucle foreach, directement sous la balise d'image , ajoutez l'instruction if pour afficher le sujet. Votre boucle foreach devrait ressembler à ceci après modification :

<?php foreach ($posts as $post): ?>
	<div class="post" style="margin-left: 0px;">
		<img src="<?php echo BASE_URL . '/static/images/' . $post['image']; ?>" class="post_image" alt="">
        <!-- Added this if statement... -->
		<?php if (isset($post['topic']['name'])): ?>
			<a 
				href="<?php echo BASE_URL . 'filtered_posts.php?topic=' . $post['topic']['id'] ?>"
				class="btn category">
				<?php echo $post['topic']['name'] ?>
			</a>
		<?php endif ?>

		<a href="single_post.php?post-slug=<?php echo $post['slug']; ?>">
			<div class="post_info">
				<h3><?php echo $post['title'] ?></h3>
				<div class="info">
					<span><?php echo date("F j, Y ", strtotime($post["created_at"])); ?></span>
					<span class="read_more">Read more...</span>
				</div>
			</div>
		</a>
	</div>
<?php endforeach ?>

Maintenant, rechargez la page et vous verrez le sujet affiché dans le message.

À l'intérieur de cette boucle foreach, vous remarquez qu'il y a deux liens qui, une fois cliqués, vous mèneront à deux pages :filtered_posts.php et single_post.php.

filtered_posts.php est une page qui répertorie tous les messages sous un sujet particulier lorsque l'utilisateur clique sur ce sujet.

single_post.php est une page qui affiche le message complet en détail avec des commentaires lorsque l'utilisateur clique sur la vignette du message.

Ces deux fichiers ont besoin de quelques fonctions de notre fichier public_functions.php. filtered_posts.php a besoin de deux fonctions appelées getPublishedPostsByTopic() et getTopicNameById() tandis que single_posts.php a besoin de getPost() et getAllTopics().

Commençons par le fichier filtered_posts.php. Ouvrez public_functions.php et ajoutez ces deux fonctions à la liste des fonctions :

/* * * * * * * * * * * * * * * *
* Returns all posts under a topic
* * * * * * * * * * * * * * * * */
function getPublishedPostsByTopic($topic_id) {
	global $conn;
	$sql = "SELECT * FROM posts ps 
			WHERE ps.id IN 
			(SELECT pt.post_id FROM post_topic pt 
				WHERE pt.topic_id=$topic_id GROUP BY pt.post_id 
				HAVING COUNT(1) = 1)";
	$result = mysqli_query($conn, $sql);
	// fetch all posts as an associative array called $posts
	$posts = mysqli_fetch_all($result, MYSQLI_ASSOC);

	$final_posts = array();
	foreach ($posts as $post) {
		$post['topic'] = getPostTopic($post['id']); 
		array_push($final_posts, $post);
	}
	return $final_posts;
}
/* * * * * * * * * * * * * * * *
* Returns topic name by topic id
* * * * * * * * * * * * * * * * */
function getTopicNameById($id)
{
	global $conn;
	$sql = "SELECT name FROM topics WHERE id=$id";
	$result = mysqli_query($conn, $sql);
	$topic = mysqli_fetch_assoc($result);
	return $topic['name'];
}

Commençons par créer le fichier filtered_posts.php dans le dossier racine de notre application (c'est-à-dire, complete-blog-php/filtered_posts.php). Je vais juste continuer et coller l'intégralité du code de cette page dans le fichier :

messages_filtrés.php :

<?php include('config.php'); ?>
<?php include('includes/public_functions.php'); ?>
<?php include('includes/head_section.php'); ?>
<?php 
	// Get posts under a particular topic
	if (isset($_GET['topic'])) {
		$topic_id = $_GET['topic'];
		$posts = getPublishedPostsByTopic($topic_id);
	}
?>
	<title>LifeBlog | Home </title>
</head>
<body>
<div class="container">
<!-- Navbar -->
	<?php include( ROOT_PATH . '/includes/navbar.php'); ?>
<!-- // Navbar -->
<!-- content -->
<div class="content">
	<h2 class="content-title">
		Articles on <u><?php echo getTopicNameById($topic_id); ?></u>
	</h2>
	<hr>
	<?php foreach ($posts as $post): ?>
		<div class="post" style="margin-left: 0px;">
			<img src="<?php echo BASE_URL . '/static/images/' . $post['image']; ?>" class="post_image" alt="">
			<a href="single_post.php?post-slug=<?php echo $post['slug']; ?>">
				<div class="post_info">
					<h3><?php echo $post['title'] ?></h3>
					<div class="info">
						<span><?php echo date("F j, Y ", strtotime($post["created_at"])); ?></span>
						<span class="read_more">Read more...</span>
					</div>
				</div>
			</a>
		</div>
	<?php endforeach ?>
</div>
<!-- // content -->
</div>
<!-- // container -->

<!-- Footer -->
	<?php include( ROOT_PATH . '/includes/footer.php'); ?>
<!-- // Footer -->

Maintenant, actualisez la page, cliquez sur le sujet et si cela vous amène à une page affichant des messages sous ce sujet, alors vous faites ce qu'il faut.

Faisons la même chose avec single_post.php. Ouvrez public_functions.php et ajoutez-y ces 2 fonctions :

/* * * * * * * * * * * * * * *
* Returns a single post
* * * * * * * * * * * * * * */
function getPost($slug){
	global $conn;
	// Get single post slug
	$post_slug = $_GET['post-slug'];
	$sql = "SELECT * FROM posts WHERE slug='$post_slug' AND published=true";
	$result = mysqli_query($conn, $sql);

	// fetch query results as associative array.
	$post = mysqli_fetch_assoc($result);
	if ($post) {
		// get the topic to which this post belongs
		$post['topic'] = getPostTopic($post['id']);
	}
	return $post;
}
/* * * * * * * * * * * *
*  Returns all topics
* * * * * * * * * * * * */
function getAllTopics()
{
	global $conn;
	$sql = "SELECT * FROM topics";
	$result = mysqli_query($conn, $sql);
	$topics = mysqli_fetch_all($result, MYSQLI_ASSOC);
	return $topics;
}

Créez maintenant le fichier complete-blog-php/single_post.php et collez-y ce code :

<?php  include('config.php'); ?>
<?php  include('includes/public_functions.php'); ?>
<?php 
	if (isset($_GET['post-slug'])) {
		$post = getPost($_GET['post-slug']);
	}
	$topics = getAllTopics();
?>
<?php include('includes/head_section.php'); ?>
<title> <?php echo $post['title'] ?> | LifeBlog</title>
</head>
<body>
<div class="container">
	<!-- Navbar -->
		<?php include( ROOT_PATH . '/includes/navbar.php'); ?>
	<!-- // Navbar -->
	
	<div class="content" >
		<!-- Page wrapper -->
		<div class="post-wrapper">
			<!-- full post div -->
			<div class="full-post-div">
			<?php if ($post['published'] == false): ?>
				<h2 class="post-title">Sorry... This post has not been published</h2>
			<?php else: ?>
				<h2 class="post-title"><?php echo $post['title']; ?></h2>
				<div class="post-body-div">
					<?php echo html_entity_decode($post['body']); ?>
				</div>
			<?php endif ?>
			</div>
			<!-- // full post div -->
			
			<!-- comments section -->
			<!--  coming soon ...  -->
		</div>
		<!-- // Page wrapper -->

		<!-- post sidebar -->
		<div class="post-sidebar">
			<div class="card">
				<div class="card-header">
					<h2>Topics</h2>
				</div>
				<div class="card-content">
					<?php foreach ($topics as $topic): ?>
						<a 
							href="<?php echo BASE_URL . 'filtered_posts.php?topic=' . $topic['id'] ?>">
							<?php echo $topic['name']; ?>
						</a> 
					<?php endforeach ?>
				</div>
			</div>
		</div>
		<!-- // post sidebar -->
	</div>
</div>
<!-- // content -->

<?php include( ROOT_PATH . '/includes/footer.php'); ?>

Appliquons maintenant le style à cela. Ouvrez public_styling.css et ajoutez-y ce code de style :

/* * * * * * * * *
* SINGLE PAGE 
* * * * * * * * */
.content .post-wrapper {
	width: 70%;
	float: left;
	min-height: 250px;
}
.full-post-div {
	min-height: 300px;
	padding: 20px;
	border: 1px solid #e4e1e1;
	border-radius: 2px;
}
.full-post-div h2.post-title {
	margin: 10px auto 20px;
	text-align: center;
}
.post-body-div {
	font-family: 'Noto Serif', serif;
	font-size: 1.2em;
}
.post-body-div p {
	margin:20px 0px;
}
.post-sidebar {
	width: 24%;
	float: left;
	margin-left: 5px;
	min-height: 400px;
}
.content .post-comments {
	margin-top: 25px;
	border-radius: 2px;
	border-top: 1px solid #e4e1e1;
	padding: 10px;
}
.post-sidebar .card {
	width: 95%;
	margin: 10px auto;
	border: 1px solid #e4e1e1;
	border-radius: 10px 10px 0px 0px;
}
.post-sidebar .card .card-header {
	padding: 10px;
	text-align: center;
	border-radius: 3px 3px 0px 0px;
	background: #3E606F;
}
.post-sidebar .card .card-header h2 {
	color: white;
}
.post-sidebar .card .card-content a {
	display: block;
	box-sizing: border-box;
	padding: 8px 10px;
	border-bottom: 1px solid #e4e1e1;
	color: #444;
}
.post-sidebar .card .card-content a:hover {
	padding-left: 20px;
	background: #F9F9F9;
	transition: 0.1s;
}

Ça a l'air bien maintenant, non ?

Une dernière chose à faire et nous en aurons pratiquement terminé avec l'espace public :nous mettrons en œuvre l'enregistrement et la connexion des utilisateurs.

Enregistrement et connexion de l'utilisateur

Comme j'ai déjà fait un tutoriel sur l'enregistrement et la connexion des utilisateurs, je vais aller droit au but avec cette partie et je n'expliquerai pas grand-chose.

Créez deux fichiers dans votre dossier racine nommés register.php et login.php. Ouvrez chacun d'eux et placez-y ce code :

registre.php :

<?php  include('config.php'); ?>
<!-- Source code for handling registration and login -->
<?php  include('includes/registration_login.php'); ?>

<?php include('includes/head_section.php'); ?>

<title>LifeBlog | Sign up </title>
</head>
<body>
<div class="container">
	<!-- Navbar -->
		<?php include( ROOT_PATH . '/includes/navbar.php'); ?>
	<!-- // Navbar -->

	<div style="width: 40%; margin: 20px auto;">
		<form method="post" action="register.php" >
			<h2>Register on LifeBlog</h2>
			<?php include(ROOT_PATH . '/includes/errors.php') ?>
			<input  type="text" name="username" value="<?php echo $username; ?>"  placeholder="Username">
			<input type="email" name="email" value="<?php echo $email ?>" placeholder="Email">
			<input type="password" name="password_1" placeholder="Password">
			<input type="password" name="password_2" placeholder="Password confirmation">
			<button type="submit" class="btn" name="reg_user">Register</button>
			<p>
				Already a member? <a href="login.php">Sign in</a>
			</p>
		</form>
	</div>
</div>
<!-- // container -->
<!-- Footer -->
	<?php include( ROOT_PATH . '/includes/footer.php'); ?>
<!-- // Footer -->

login.php :  

<?php  include('config.php'); ?>
<?php  include('includes/registration_login.php'); ?>
<?php  include('includes/head_section.php'); ?>
	<title>LifeBlog | Sign in </title>
</head>
<body>
<div class="container">
	<!-- Navbar -->
	<?php include( ROOT_PATH . '/includes/navbar.php'); ?>
	<!-- // Navbar -->

	<div style="width: 40%; margin: 20px auto;">
		<form method="post" action="login.php" >
			<h2>Login</h2>
			<?php include(ROOT_PATH . '/includes/errors.php') ?>
			<input type="text" name="username" value="<?php echo $username; ?>" value="" placeholder="Username">
			<input type="password" name="password" placeholder="Password">
			<button type="submit" class="btn" name="login_btn">Login</button>
			<p>
				Not yet a member? <a href="register.php">Sign up</a>
			</p>
		</form>
	</div>
</div>
<!-- // container -->

<!-- Footer -->
	<?php include( ROOT_PATH . '/includes/footer.php'); ?>
<!-- // Footer -->

Dans les sections supérieures des deux fichiers, nous avons inclus un fichier nommé registration_login.php pour gérer la logique d'enregistrement et de connexion. Il s'agit du fichier dans lequel les informations du formulaire de connexion et d'inscription seront soumises et la communication avec la base de données sera effectuée. Créons-le dans notre dossier d'inclusion et crachons ce code à l'intérieur :

complete-blog-php/includes/registration_login.php :

<?php 
	// variable declaration
	$username = "";
	$email    = "";
	$errors = array(); 

	// REGISTER USER
	if (isset($_POST['reg_user'])) {
		// receive all input values from the form
		$username = esc($_POST['username']);
		$email = esc($_POST['email']);
		$password_1 = esc($_POST['password_1']);
		$password_2 = esc($_POST['password_2']);

		// form validation: ensure that the form is correctly filled
		if (empty($username)) {  array_push($errors, "Uhmm...We gonna need your username"); }
		if (empty($email)) { array_push($errors, "Oops.. Email is missing"); }
		if (empty($password_1)) { array_push($errors, "uh-oh you forgot the password"); }
		if ($password_1 != $password_2) { array_push($errors, "The two passwords do not match");}

		// Ensure that no user is registered twice. 
		// the email and usernames should be unique
		$user_check_query = "SELECT * FROM users WHERE username='$username' 
								OR email='$email' LIMIT 1";

		$result = mysqli_query($conn, $user_check_query);
		$user = mysqli_fetch_assoc($result);

		if ($user) { // if user exists
			if ($user['username'] === $username) {
			  array_push($errors, "Username already exists");
			}
			if ($user['email'] === $email) {
			  array_push($errors, "Email already exists");
			}
		}
		// register user if there are no errors in the form
		if (count($errors) == 0) {
			$password = md5($password_1);//encrypt the password before saving in the database
			$query = "INSERT INTO users (username, email, password, created_at, updated_at) 
					  VALUES('$username', '$email', '$password', now(), now())";
			mysqli_query($conn, $query);

			// get id of created user
			$reg_user_id = mysqli_insert_id($conn); 

			// put logged in user into session array
			$_SESSION['user'] = getUserById($reg_user_id);

			// if user is admin, redirect to admin area
			if ( in_array($_SESSION['user']['role'], ["Admin", "Author"])) {
				$_SESSION['message'] = "You are now logged in";
				// redirect to admin area
				header('location: ' . BASE_URL . 'admin/dashboard.php');
				exit(0);
			} else {
				$_SESSION['message'] = "You are now logged in";
				// redirect to public area
				header('location: index.php');				
				exit(0);
			}
		}
	}

	// LOG USER IN
	if (isset($_POST['login_btn'])) {
		$username = esc($_POST['username']);
		$password = esc($_POST['password']);

		if (empty($username)) { array_push($errors, "Username required"); }
		if (empty($password)) { array_push($errors, "Password required"); }
		if (empty($errors)) {
			$password = md5($password); // encrypt password
			$sql = "SELECT * FROM users WHERE username='$username' and password='$password' LIMIT 1";

			$result = mysqli_query($conn, $sql);
			if (mysqli_num_rows($result) > 0) {
				// get id of created user
				$reg_user_id = mysqli_fetch_assoc($result)['id']; 

				// put logged in user into session array
				$_SESSION['user'] = getUserById($reg_user_id); 

				// if user is admin, redirect to admin area
				if ( in_array($_SESSION['user']['role'], ["Admin", "Author"])) {
					$_SESSION['message'] = "You are now logged in";
					// redirect to admin area
					header('location: ' . BASE_URL . '/admin/dashboard.php');
					exit(0);
				} else {
					$_SESSION['message'] = "You are now logged in";
					// redirect to public area
					header('location: index.php');				
					exit(0);
				}
			} else {
				array_push($errors, 'Wrong credentials');
			}
		}
	}
	// escape value from form
	function esc(String $value)
	{	
		// bring the global db connect object into function
		global $conn;

		$val = trim($value); // remove empty space sorrounding string
		$val = mysqli_real_escape_string($conn, $value);

		return $val;
	}
	// Get user info from user id
	function getUserById($id)
	{
		global $conn;
		$sql = "SELECT * FROM users WHERE id=$id LIMIT 1";

		$result = mysqli_query($conn, $sql);
		$user = mysqli_fetch_assoc($result);

		// returns user in an array format: 
		// ['id'=>1 'username' => 'Awa', 'email'=>'[email protected]', 'password'=> 'mypass']
		return $user; 
	}
?>

Accédez à http://localhost/complete-blog-php/register.php et vous verrez une erreur indiquant que le fichier errors.php est introuvable.

Le fichier errors.php est le fichier contenant le code permettant d'afficher les erreurs de validation du formulaire. Créez errors.php dans complete-blog-php/includes et collez-y ce code :

<?php if (count($errors) > 0) : ?>
  <div class="message error validation_errors" >
  	<?php foreach ($errors as $error) : ?>
  	  <p><?php echo $error ?></p>
  	<?php endforeach ?>
  </div>
<?php endif ?>

Ouvrons à nouveau public_styling.css et ajoutons ce dernier morceau de code de style pour ce fichier errors.php et quelques autres éléments :

/* NOTIFICATION MESSAGES */
.message {
	width: 100%; 
	margin: 0px auto; 
	padding: 10px 0px; 
	color: #3c763d; 
	background: #dff0d8; 
	border: 1px solid #3c763d;
	border-radius: 5px; 
	text-align: center;
}
.error {
	color: #a94442; 
	background: #f2dede; 
	border: 1px solid #a94442; 
	margin-bottom: 20px;
}
.validation_errors p {
	text-align: left;
	margin-left: 10px;
}
.logged_in_info {
	text-align: right; 
	padding: 10px;
}

Et maintenant le message d'erreur a disparu. Cliquez sur le bouton d'inscription sans remplir le formulaire et vous verrez de beaux messages d'erreur rendus.

Créons un nouvel utilisateur en remplissant le formulaire sur la page register.php et en cliquant sur le bouton d'enregistrement. Vous pouvez fournir toutes les informations valides pour le nom d'utilisateur, l'e-mail et le mot de passe ; assurez-vous simplement de vous en souvenir car nous les utiliserons pour vous connecter très bientôt sur la page de connexion.

Lorsqu'un utilisateur se connecte, il doit certainement pouvoir se déconnecter. Dans le dossier racine de l'application, créez un fichier nommé logout.php.

complete-blog-php/logout.php : 

<?php 
	session_start();
	session_unset($_SESSION['user']);
	session_destroy();
	header('location: index.php');
?>

De plus, lorsqu'un utilisateur se connecte, nous voulons afficher son nom et un lien ou un bouton sur lequel cliquer pour se déconnecter. Pour la zone publique, nous le ferons dans le fichier banner.php que nous avons inclus. Ouvrez le fichier banner.php et modifiez le code pour qu'il ressemble à ceci :

complete-blog-php/includes/banner.php :

<?php if (isset($_SESSION['user']['username'])) { ?>
	<div class="logged_in_info">
		<span>welcome <?php echo $_SESSION['user']['username'] ?></span>
		|
		<span><a href="logout.php">logout</a></span>
	</div>
<?php }else{ ?>
	<div class="banner">
		<div class="welcome_msg">
			<h1>Today's Inspiration</h1>
			<p> 
			    One day your life <br> 
			    will flash before your eyes. <br> 
			    Make sure it's worth watching. <br>
				<span>~ Gerard Way</span>
			</p>
			<a href="register.php" class="btn">Join us!</a>
		</div>

		<div class="login_div">
			<form action="<?php echo BASE_URL . 'index.php'; ?>" method="post" >
				<h2>Login</h2>
				<div style="width: 60%; margin: 0px auto;">
					<?php include(ROOT_PATH . '/includes/errors.php') ?>
				</div>
				<input type="text" name="username" value="<?php echo $username; ?>" placeholder="Username">
				<input type="password" name="password"  placeholder="Password"> 
				<button class="btn" type="submit" name="login_btn">Sign in</button>
			</form>
		</div>
	</div>
<?php } ?>

It checks the session to see if a user is available (logged in). If logged in, the username is displayed with the logout link. When there is a logged in user, the banner does not get displayed since it is some sort of a welcome screen to guest users.

You notice that the banner has a login form and this banner is included inside index.php file. Therefore we need to include the code that handles registration and login inside our index.php file also. Open index.php and add this line directly under the include for public_functions.php:

top section of complete-blog-php/index.php:

<?php require_once( ROOT_PATH . '/includes/registration_login.php') ?>

And that's it with user registration and login. In the next section, we begin work on the admin area.

Thank you so much for sticking around up to this point. I hope you found it helpful. If you have any worries, please leave it in the comments below. Your feedback is always very helpful and if you have any bugs in your code, I will try my best to help you out.

I will be very much encouraged to create more of these tutorials with improved quality if you share, subscribe to my site and recommend my site to your friends.