База данни
Това е втората част от поредицата за Как да създадете блог с PHP и MySQL. Можете да получите първата част тук
Ще продължим там, където спряхме в последния урок. В този раздел ще работим върху дизайна на нашата база данни и удостоверяването на потребителя (регистрация и влизане). Създайте база данни с име full-blog-php. В тази база данни създайте 2 таблици: публикации и потребители със следните полета.
публикации:
+----+-----------+--------------+------------+
| 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 | |
+----------------+--------------+------------+
потребители:
+----+-----------+------------------------+------------+
| 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 | |
+----------------+--------------+---------+------------+
Можете да създадете тези таблици с помощта на тези команди.
потребители:
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;
публикации:
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
Можете да стартирате тези скриптове с помощта на SQL командния ред или PHPMyAdmin. В PHPMyAdmin щракнете/изберете базата данни, в която искате да бъдат създадени тези таблици (в този случай full-blog-php), след това щракнете върху раздела SQL в лентата за навигация някъде в горната част на страницата. Ако видите някакъв SQL скрипт в пространството по-долу, премахнете го и поставете скрипта по-горе в предоставеното пространство и щракнете върху „Отиди“, за да създадете таблиците.
Ако вместо това сте избрали да създадете тези таблици ръчно, не забравяйте да направите полето на sg в таблицата за публикации УНИКАЛНО и не забравяйте да зададете полето user_id на таблицата с публикации като външен ключ, който препраща към id в таблицата с потребители. Задайте БЕЗ ДЕЙСТВИЕ като стойност за опциите ON DELETE и ON UPDATE, така че когато потребител бъде изтрит или актуализиран, публикациите му остават в таблицата с публикации и не се изтриват.
Сега вмъкнете няколко потребители в таблицата с потребители и няколко публикации в таблицата с публикации. Можете да направите това, като изпълните тези SQL заявки за вмъкване:
потребители:
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')
публикации:
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')
Нека се свържем с базата данни, да потърсим тези публикации и да ги покажем на уеб страницата.
В config.php нека добавим код за свързване на нашето приложение към базата данни. След като добавим кода, нашият файл config.php ще изглежда така:
<?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/');
?>
Това връща обект за свързване на база данни $conn, който можем да използваме в цялото си приложение за заявка към базата данни.
Това приложение е структурирано по начин, по който PHP кодът е възможно най-отделен от HTML. Операции като заявка към базата данни и изпълнение на някаква логика върху данни се извършват във функции на PHP и резултатите се изпращат до HTML, за да бъдат показани. Ето защо, за да получим всички публикации от базата данни, ще направим това във функция и ще върнем резултатите като асоциативен масив, който да се преглежда и показва на страницата.
Затова създайте файл с име public_functions.php в папката с включвания. Този файл ще съдържа всички наши PHP функции за обществената зона. Всички страници, използващи някоя от функциите в този файл, трябва да включват този файл в горната част на страницата.
Нека създадем първата си функция в новосъздадената ни public_functions.php. Ще наречем функцията getPublishedPosts() и тя ще извлече всички публикации от таблицата с публикации в базата данни и ще ги върне като асоциативен масив:
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 ...
?>
В горната част на файла index.php, точно под реда, който включва config. php , добавете този код, за да направите заявка към базата данни:
<!-- 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(); ?>
Добавихме два реда код. Първият включва файла public_functions.php (който съдържа функциите) към нашия файл index.php. Вторият ред от код извиква функцията getPublishedPosts(), която отправя заявки към базата данни и връща публикации, извлечени от базата данни в променлива, наречена $posts. Сега нека прегледаме и покажем тези публикации на страницата index.php.
Отворете отново нашия известен файл index.php. В секцията със съдържание някъде по средата ще намерите маркер
и коментар, указващ къде предстои още съдържание. В пространството, точно под маркера
, добавете този код:
<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 ?>
Добре, моля, не презареждайте страницата още. Нека добавим стил към този списък с публикации. Отворете public_styling.css и добавете този код към него:
/* 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;
}
Сега можете да презаредите страницата.
Ако всичко е минало добре, ще видите една публикация, оформена като миниатюра под заглавието „Последни статии“. Не забравяйте, че бяхме вмъкнали два записа в базата данни, но се показва само един. Това е така, защото публикуваното поле на един от записите е зададено на false (тоест 0) и тъй като се показват само публикувани статии, виждаме само една, публикувана.
Но нашите публикации към момента не са класифицирани в нито една тема. Нека създадем таблица с теми и да формираме връзка „Много към много“ между публикациите и таблицата с теми. За да направим това, ще създадем две нови таблици:теми за съхраняване на теми и таблица post_topic за обработка на връзката между публикации и теми.
теми:
+----+-----------+------------------------+------------+
| 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) | |
+----------------+--------------+---------+------------+
Това, което наистина ни интересува, е таблицата post_topic. Това е таблицата, която обработва връзката между публикациите и темите. Когато публикация е създадена под определена тема, идентификаторът на тази публикация (post_id), както и идентификаторът на темата (topic_id), под която е създадена тази публикация, се вмъкват в таблицата post_topic.
Нека установим тази връзка, така че когато публикация бъде изтрита, нейният запис в таблицата post_topic също ще бъде автоматично изтрит; не искате да съхранявате информация за връзката на публикация, когато публикацията не съществува, нали?
Щракнете/изберете таблицата post_topic, след което щракнете върху раздела структура на навигационната лента на PHPMyAdmin. След това щракнете върху Relation View точно под раздела структура (може да бъде намерен някъде другаде в зависимост от вашата версия на PHPMyAdmin). След това попълнете формуляра по-долу, както следва:
Съвет:Връзката +Добавяне на ограничение се използва за добавяне на ново ограничение.
ON DELETE и ON UPDATE са зададени съответно на CASCADE и NO ACTION, така че когато публикация или тема бъдат изтрити, информацията за връзката й в таблицата post_topic също се изтрива автоматично. (На изображението направих грешка, като настроих ON UPDATE на CASCADE вместо NO ACTION, съжалявам за това).
Щракнете върху запазване и това е всичко. Сега таблиците са свързани. Но за да установим връзка между публикации и теми, трябва да попълним таблицата с теми с теми и евентуално таблицата post_topic, която е действителната информация за връзката.
Сега нека вмъкнем няколко записа в двете таблици:
теми:
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)
Връзката, дефинирана в таблицата post_topic казва, че темата с идентификатор 1 в таблицата с теми принадлежи на публикацията с идентификатор 1 в таблицата с публикации. Същото важи и за темата с идентификатор 2 и публикацията с идентификатор 2.
На всяка публикация на страницата index.php ще покажем темата, под която е създадена публикацията.
За да направим това, трябва да модифицираме нашия getPublishedPosts(), който създадохме в public_functions.php, за да запитаме темата на всяка публикация от базата данни и да върнем публикацията заедно с нейната тема.
Променете файла 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);
$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;
}
?>
Сега отидете на файла index.php. В рамките на цикъла foreach, директно под етикета на изображението , добавете оператора if за показване на темата. Вашият foreach цикъл трябва да изглежда така след модифициране:
<?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 ?>
Сега презаредете страницата и ще видите темата, показана в публикацията.
Вътре в този foreach цикъл забелязвате, че има две връзки, които при щракване ще ви отведат до две страници:filtered_posts.php и single_post.php.
filtered_posts.php е страница, която изброява всички публикации в конкретна тема, когато потребителят щракне върху тази тема.
single_post.php е страница, която показва пълната публикация в детайли заедно с коментари, когато потребителят щракне върху миниизображението на публикацията.
Тези два файла се нуждаят от няколко функции от нашия файл public_functions.php. filtered_posts.php се нуждае от две функции, наречени getPublishedPostsByTopic() и getTopicNameById() докато single_posts.php се нуждае от getPost() и getAllTopics().
Нека започнем с файла filtered_posts.php. Отворете public_functions.php и добавете тези две функции към списъка с функции:
/* * * * * * * * * * * * * * * *
* 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'];
}
Нека първо създадем файла filtered_posts.php в основната папка на нашето приложение (тоест full-blog-php/filtered_posts.php). Просто ще продължа и ще поставя целия код на тази страница във файла:
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 -->
Сега опреснете страницата, щракнете върху темата и ако ви отведе до страница, показваща публикации под тази тема, значи правите правилното нещо.
Нека направим същото с single_post.php. Отворете public_functions.php и добавете тези 2 функции към него:
/* * * * * * * * * * * * * * *
* 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;
}
Сега създайте файла complete-blog-php/single_post.php и поставете този код в него:
<?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'); ?>
Нека сега приложим стилизиране към това. Отворете public_styling.css и добавете този код за стил към него:
/* * * * * * * * *
* 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;
}
Изглежда добре сега, нали?
Последно нещо, което трябва да направите и почти ще приключим с обществената зона:Ще приложим регистрация и влизане на потребители.
Регистрация и влизане на потребител
Тъй като вече направих урок за регистрация и влизане на потребители, ще бъда почти по-точен с тази част и няма да обяснявам много.
Създайте два файла в основната си папка с име register.php и login.php. Отворете всеки от тях и поставете този код в тях:
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 -->
В горните секции на двата файла включихме файл с име registration_login.php за обработка на логиката на регистрация и влизане. Това е файлът, към който ще бъде изпратена информацията от формуляра за вход и регистрация и ще се извърши комуникация с базата данни. Нека го създадем в нашата папка с включването и да изплюем този код вътре:
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;
}
?>
Отидете на http://localhost/complete-blog-php/register.php и ще видите грешка, която казва, че файлът errors.php не е намерен.
errors.php файлът е файлът с код за показване на грешки при валидиране на формуляра. Създайте errors.php вътре в complete-blog-php/includes и поставете този код в него:
<?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 ?>
Още веднъж отворете public_styling.css, нека добавим това последно парче стилизиращ код за този файл errors.php и няколко други елемента:
/* 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;
}
И сега съобщението за грешка е изчезнало. Щракнете върху бутона за регистрация, без да попълвате формуляра и ще видите красиви съобщения за грешки.
Нека създадем нов потребител, като попълним формуляра на страницата register.php и щракнем върху бутона за регистрация. Можете да предоставите каквато и да е валидна информация за потребителското име, имейла и паролата; просто се уверете, че ги помните, защото ще ги използваме за влизане много скоро на страницата за вход.
Когато потребител влезе, определено ще трябва да може да излезе. В главната папка на приложението създайте файл с име logout.php.
complete-blog-php/logout.php:
<?php
session_start();
session_unset($_SESSION['user']);
session_destroy();
header('location: index.php');
?>
Също така, когато потребител влезе, искаме да покажем неговото име и връзка или бутон, върху който да щракне, за да излезе. За обществената зона ще направим това във файла banner.php, който включихме. Отворете файла banner.php и променете кода, за да изглежда така:
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.