Il database
Questa è la seconda parte di una serie su Come creare un blog con PHP e MySQL. Puoi ottenere la prima parte qui
Continueremo da dove eravamo rimasti nell'ultimo tutorial. In questa sezione lavoreremo sulla progettazione del nostro database e sull'autenticazione degli utenti (registrazione e login). Crea un database chiamato complete-blog-php. In questo database, crea 2 tabelle: post e utenti con i seguenti campi.
post:
+----+-----------+--------------+------------+
| 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 | |
+----------------+--------------+------------+
utenti:
+----+-----------+------------------------+------------+
| 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 | |
+----------------+--------------+---------+------------+
Puoi creare queste tabelle usando questi comandi.
utenti:
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;
post:
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
È possibile eseguire questi script utilizzando il prompt dei comandi SQL o PHPMyAdmin. Su PHPMyAdmin, fai clic/seleziona il database in cui desideri creare queste tabelle (in questo caso complete-blog-php), quindi fai clic sulla scheda SQL sulla barra di navigazione da qualche parte nella parte superiore della pagina. Se vedi uno script SQL nello spazio sottostante, rimuovilo e incolla lo script sopra nello spazio fornito e fai clic su "Vai" per creare le tabelle.
Se invece hai scelto di creare queste tabelle manualmente, ricorda di rendere UNICO il campo slug nella tabella dei post e ricorda di impostare il campo user_id della tabella dei post come chiave esterna che fa riferimento all'id nella tabella degli utenti. Imposta NESSUNA AZIONE come valore per le opzioni SU CANCELLAZIONE e SU AGGIORNAMENTO in modo che quando un utente viene eliminato o aggiornato, i suoi post rimangano nella tabella dei post e non vengano eliminati.
Ora inserisci alcuni utenti nella tabella degli utenti e alcuni post nella tabella dei post. Puoi farlo eseguendo queste query SQL da inserire:
utenti:
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')
post:
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')
Connettiamoci al database, interroghiamo questi post e visualizziamoli sulla pagina web.
In config.php, aggiungiamo il codice per connettere la nostra applicazione al database. Dopo aver aggiunto il codice, il nostro file config.php sarà simile a questo:
<?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/');
?>
Questo restituisce un oggetto di connettività del database $conn che possiamo utilizzare nella nostra intera applicazione per eseguire query sul database.
Questa applicazione è stata strutturata in modo che il codice PHP sia il più separato possibile dall'HTML. Operazioni come l'interrogazione del database e l'esecuzione di alcune logiche sui dati vengono eseguite nelle funzioni PHP e i risultati inviati all'HTML per essere visualizzati. Pertanto, per ottenere tutti i post dal database, lo faremo in una funzione e restituiremo i risultati come un array associativo da scorrere e visualizzare sulla pagina.
Pertanto, crea un file denominato public_functions.php nella cartella include. Questo file conterrà tutte le nostre funzioni PHP per l'area pubblica. Tutte le pagine che utilizzano una qualsiasi delle funzioni in questo file devono avere questo file incluso nella sezione superiore della pagina.
Creiamo la nostra prima funzione nel nostro public_functions.php appena creato. Assegneremo un nome alla funzione getPublishedPosts() e recupererà tutti i post dalla tabella dei post nel database e li restituirà come un array associativo:
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 ...
?>
Nella sezione superiore del file index.php, appena sotto la riga che include config. php , aggiungi questo codice per interrogare il database:
<!-- 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(); ?>
Abbiamo aggiunto due righe di codice. Il primo include il file public_functions.php (che contiene le funzioni) nel nostro file index.php. La seconda riga di codice chiama la funzione getPublishedPosts() che interroga il database e restituisce i post recuperati dal database in una variabile chiamata $posts. Ora esaminiamo e visualizziamo questi post nella pagina index.php.
Apri di nuovo il nostro famoso file index.php. Nella sezione dei contenuti da qualche parte nel mezzo, troverai un tag
e un commento che indica dove arriveranno altri contenuti. Nello spazio, subito sotto il tag
, aggiungi questo codice:
<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, per favore, non ricaricare ancora la pagina. Aggiungiamo lo stile a questo elenco di post. Apri public_styling.css e aggiungi questo codice:
/* 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;
}
Ora puoi ricaricare la pagina.
Se tutto è andato bene, vedrai un singolo post in stile miniatura sotto il titolo "Articoli recenti". Ricorda che abbiamo inserito due record nel database ma solo uno viene visualizzato. Questo perché uno dei record aveva il campo pubblicato impostato su false (ovvero 0) e poiché solo gli articoli pubblicati vengono visualizzati, ne vediamo solo uno, quello pubblicato.
Ma i nostri post al momento non sono classificati in nessun argomento. Creiamo una tabella degli argomenti e formiamo una relazione Molti-a-Molti tra i post e la tabella degli argomenti. Per fare ciò, creeremo due nuove tabelle:topic per memorizzare gli argomenti e post_topic table per gestire la relazione tra post e argomenti.
argomenti:
+----+-----------+------------------------+------------+
| field | type | specs |
+----+-----------+------------------------+------------+
| id | INT(11) | |
| name | VARCHAR(255) | |
| slug | VARCHAR(255) | UNIQUE |
+----------------+--------------+---------+------------+
post_argomento:
+----+-----------+------------------------+------------+
| field | type | specs |
+----+-----------+------------------------+------------+
| id | INT(11) | |
| post_id | INT(11) | UNIQUE |
| topic_id | INT(11) | |
+----------------+--------------+---------+------------+
Quello che ci interessa veramente è la tabella post_topic. Questa è la tabella che gestisce la relazione tra post e argomenti. Quando un post viene creato in un determinato argomento, l'id di quel post (post_id), così come l'id dell'argomento (topic_id) sotto il quale viene creato quel post, vengono inseriti nella tabella post_topic.
Stabiliamo questa relazione in modo che quando un post viene cancellato, anche la sua voce nella tabella post_topic venga automaticamente cancellata; non vuoi conservare le informazioni sulla relazione di un post quando il post non esiste, giusto?
Fare clic/selezionare la tabella post_topic, quindi fare clic sulla scheda struttura della barra di navigazione PHPMyAdmin. Quindi, fai clic su Visualizzazione relazione appena sotto la scheda della struttura (potrebbe essere trovata da qualche altra parte a seconda della versione di PHPMyAdmin). Quindi compila il modulo sottostante come segue:
Suggerimento:il collegamento +Aggiungi vincolo viene utilizzato per aggiungere un nuovo vincolo.
ON DELETE e ON UPDATE sono tutti impostati rispettivamente su CASCADE e NO ACTION in modo che quando un post o un argomento viene eliminato, anche le informazioni sulla relazione nella tabella post_topic vengono automaticamente eliminate. (Nell'immagine ho commesso un errore impostando ON UPDATE su CASCADE invece di NO ACTION, mi dispiace per quello).
Fai clic su Salva e il gioco è fatto. Le tabelle sono ora correlate. Ma per stabilire una relazione tra post e argomenti, dobbiamo popolare la tabella degli argomenti con gli argomenti ed eventualmente la tabella post_argomento che è l'effettiva informazione sulla relazione.
Ora inseriamo alcune voci nelle due tabelle:
argomenti:
INSERT INTO `topics` (`id`, `name`, `slug`) VALUES
(1, 'Inspiration', 'inspiration'),
(2, 'Motivation', 'motivation'),
(3, 'Diary', 'diary')
post_argomento:
INSERT INTO `post_topic` (`id`, `post_id`, `topic_id`) VALUES
(1, 1, 1),
(2, 2, 2)
La relazione definita nella tabella post_topic dice che l'argomento con id 1 nella tabella degli argomenti appartiene al post con id 1 nella tabella dei post. Lo stesso vale per l'argomento con id 2 e post con id 2.
Su ogni elenco di post nella pagina index.php, visualizzeremo l'argomento in base al quale viene creato il post.
Per fare ciò, dobbiamo modificare il nostro getPublishedPosts() che abbiamo creato all'interno di public_functions.php per interrogare l'argomento di ogni post dal database e restituire il post insieme al suo argomento.
Modifica il file public_functions.php in modo che assomigli a questo:
<?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;
}
?>
Ora vai al file index.php. All'interno del ciclo foreach, direttamente sotto il tag immagine , aggiungi l'istruzione if per visualizzare l'argomento. Il tuo ciclo foreach dovrebbe apparire così dopo aver modificato:
<?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 ?>
Ora ricarica la pagina e vedrai l'argomento visualizzato nel post.
All'interno di questo ciclo foreach, noti che ci sono due link che, se cliccati, ti porteranno a due pagine:filtered_posts.php e single_post.php.
filtered_posts.php è una pagina che elenca tutti i post di un particolare argomento quando l'utente fa clic su quell'argomento.
single_post.php è una pagina che mostra l'intero post in dettaglio insieme ai commenti quando l'utente fa clic sulla miniatura del post.
Questi due file richiedono alcune funzioni dal nostro file public_functions.php. filtered_posts.php ha bisogno di due funzioni chiamate getPublishedPostsByTopic() e getTopicNameById() mentre single_posts.php ha bisogno di getPost() e getAllTopics().
Iniziamo con il file filtered_posts.php. Apri public_functions.php e aggiungi queste due funzioni all'elenco delle funzioni:
/* * * * * * * * * * * * * * * *
* 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'];
}
Per prima cosa creiamo il file filtered_posts.php nella cartella principale della nostra applicazione (ovvero complete-blog-php/filtered_posts.php). Andrò avanti e incollerò l'intero codice di questa pagina all'interno del file:
filtered_posts.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 -->
Ora aggiorna la pagina, fai clic sull'argomento e se ti porta a una pagina che mostra i post in quell'argomento, stai facendo la cosa giusta.
Facciamo la stessa cosa con single_post.php. Apri public_functions.php e aggiungi queste 2 funzioni:
/* * * * * * * * * * * * * * *
* 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;
}
Ora crea il file complete-blog-php/single_post.php e incollaci questo codice:
<?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'); ?>
Ora applichiamo lo stile a questo. Apri public_styling.css e aggiungi questo codice di stile:
/* * * * * * * * *
* 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;
}
Sembra buono ora, vero?
Un'ultima cosa da fare e avremo praticamente finito con l'area pubblica:implementeremo la registrazione e il login degli utenti.
Registrazione utente e login
Dato che ho già fatto un tutorial sulla registrazione e l'accesso degli utenti, andrò praticamente al punto con questa parte e non spiegherò molto.
Crea due file nella tua cartella principale chiamati register.php e login.php. Apri ciascuno di essi e inserisci questo codice:
register.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 -->
Nelle sezioni superiori di entrambi i file, abbiamo incluso un file denominato registration_login.php per gestire la logica di registrazione e accesso. Questo è il file a cui verranno inviate le informazioni sul modulo di accesso e registrazione e verrà effettuata la comunicazione con il database. Creiamolo nella nostra cartella include e sputiamo questo codice al suo interno:
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;
}
?>
Vai a http://localhost/complete-blog-php/register.php e vedrai un errore che dice che il file errors.php non è stato trovato.
Il file errors.php è il file con il codice per visualizzare gli errori di convalida del modulo. Crea errors.php all'interno di complete-blog-php/includes e incollaci questo codice:
<?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 ?>
Ancora una volta apri public_styling.css aggiungiamo quest'ultimo pezzo di codice di stile per questo file errors.php e alcuni altri elementi:
/* 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;
}
E ora il messaggio di errore è scomparso. Fare clic sul pulsante di registrazione senza compilare il modulo e vengono visualizzati bellissimi messaggi di errore.
Creiamo un nuovo utente compilando il form nella pagina register.php e cliccando sul pulsante registrati. Puoi fornire qualsiasi informazione valida per nome utente, e-mail e password; assicurati solo di ricordarli perché li utilizzeremo per accedere molto presto alla pagina di accesso.
Quando un utente effettua l'accesso, dovrà sicuramente essere in grado di disconnettersi. Nella cartella principale dell'applicazione, creare un file denominato logout.php.
complete-blog-php/logout.php:
<?php
session_start();
session_unset($_SESSION['user']);
session_destroy();
header('location: index.php');
?>
Inoltre, quando un utente effettua l'accesso, desideriamo visualizzare il suo nome e un collegamento o un pulsante su cui può fare clic per disconnettersi. Per l'area pubblica, lo faremo nel file banner.php che abbiamo incluso. Apri il file banner.php e modifica il codice in modo che assomigli a questo:
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.