Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Cách tạo blog trong cơ sở dữ liệu PHP và MySQL - Thiết kế DB

Cơ sở dữ liệu

Đây là phần thứ hai trong loạt bài về Cách tạo blog với PHP và MySQL. Bạn có thể xem phần đầu tiên tại đây

Chúng tôi sẽ tiếp tục nơi chúng tôi đã dừng lại trong hướng dẫn cuối cùng. Trong phần này, chúng tôi sẽ làm việc trên thiết kế cơ sở dữ liệu của chúng tôi và xác thực người dùng (đăng ký và đăng nhập). Tạo một cơ sở dữ liệu có tên là complete-blog-php. Trong cơ sở dữ liệu này, hãy tạo 2 bảng:bài đăng và người dùng với các trường sau.

bài đăng:

+----+-----------+--------------+------------+
|     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    |            |
+----------------+--------------+------------+

người dùng:

+----+-----------+------------------------+------------+
|     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              |            |
+----------------+--------------+---------+------------+

Bạn có thể tạo các bảng này bằng các lệnh này.

người dùng:

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;

bài đăng:

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

Bạn có thể chạy các tập lệnh này bằng cách sử dụng dấu nhắc lệnh SQL hoặc PHPMyAdmin. Trên PHPMyAdmin, nhấp / chọn cơ sở dữ liệu bạn muốn các bảng này được tạo trong (trong trường hợp này là complete-blog-php), sau đó nhấp vào tab SQL trên thanh điều hướng ở đâu đó ở đầu trang. Nếu bạn thấy bất kỳ tập lệnh SQL nào trong khoảng trống bên dưới, hãy xóa nó và dán tập lệnh ở trên vào khoảng trống được cung cấp và nhấp vào 'Bắt ​​đầu' để tạo bảng.

Thay vào đó, nếu bạn chọn tạo các bảng này theo cách thủ công, hãy nhớ đặt trường slug trên bảng bài đăng là DUY NHẤT và nhớ đặt trường user_id của bảng bài đăng làm khóa ngoại tham chiếu id trên bảng người dùng. Đặt KHÔNG CÓ HÀNH ĐỘNG làm giá trị cho các tùy chọn BẬT XÓA và BẬT CẬP NHẬT để khi người dùng bị xóa hoặc cập nhật, bài đăng của họ vẫn còn trên bảng bài đăng và không bị xóa.

Bây giờ, hãy chèn một vài người dùng vào bảng người dùng và một vài bài đăng vào bảng bài đăng. Bạn có thể làm điều đó bằng cách chạy các truy vấn SQL sau để chèn:

người dùng:

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')

bài đăng:

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')

Hãy kết nối với cơ sở dữ liệu, truy vấn các bài đăng này và hiển thị trên trang web.

Trong config.php, hãy thêm mã để kết nối ứng dụng của chúng ta với cơ sở dữ liệu. Sau khi thêm mã, tệp config.php của chúng tôi sẽ giống như sau:

<?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/');
?>

Điều này trả về một đối tượng kết nối cơ sở dữ liệu $ conn mà chúng ta có thể sử dụng trong toàn bộ ứng dụng của mình để truy vấn cơ sở dữ liệu.

Ứng dụng này đã được cấu trúc theo cách mà mã PHP càng tách biệt với HTML càng tốt. Các hoạt động như truy vấn cơ sở dữ liệu và thực hiện một số logic trên dữ liệu được thực hiện trong các hàm PHP và kết quả được gửi đến HTML sẽ được hiển thị. Do đó, để lấy tất cả các bài đăng từ cơ sở dữ liệu, chúng tôi sẽ thực hiện điều đó trong một hàm và trả về kết quả dưới dạng một mảng liên kết được lặp lại và hiển thị trên trang.

Do đó, hãy tạo một tệp có tên public_functions.php trong thư mục bao gồm. Tệp này sẽ chứa tất cả các hàm PHP của chúng tôi cho khu vực công cộng. Tất cả các trang sử dụng bất kỳ chức năng nào trong tệp này phải có tệp này bao gồm trong phần trên cùng của trang.

Hãy tạo hàm đầu tiên của chúng ta trong public_functions.php mới được tạo của chúng ta. Chúng tôi sẽ đặt tên cho hàm getPublishedPosts () và nó sẽ truy xuất tất cả các bài đăng từ bảng bài đăng trong cơ sở dữ liệu và trả về chúng dưới dạng một mảng liên kết:

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 ...
?>

Ở phần trên cùng của tệp index.php, ngay bên dưới dòng bao gồm cấu hình. php , thêm mã này để truy vấn cơ sở dữ liệu:

<!-- 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(); ?>

Chúng tôi đã thêm hai dòng mã. Đầu tiên bao gồm tệp public_functions.php (chứa các hàm) vào tệp index.php của chúng tôi. Dòng mã thứ hai gọi hàm getPublishedPosts () để truy vấn cơ sở dữ liệu và trả về các bài đăng được truy xuất từ ​​cơ sở dữ liệu trong một biến có tên là $ posts. Bây giờ, hãy lặp lại và hiển thị các bài đăng này trên trang index.php.

Mở lại tệp index.php nổi tiếng của chúng tôi. Trong phần nội dung ở đâu đó ở giữa, bạn sẽ tìm thấy thẻ


và nhận xét cho biết nơi có nhiều nội dung hơn. Trong khoảng trống, ngay bên dưới thẻ
, hãy thêm mã này:

<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 ?>

Được rồi, xin đừng tải lại trang. Hãy thêm kiểu dáng vào danh sách bài đăng này. Mở public_styling.css và thêm mã này vào nó:

/* 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;
}

Bây giờ bạn có thể tải lại trang.

Nếu mọi việc suôn sẻ, bạn sẽ thấy một bài đăng được tạo kiểu như một hình thu nhỏ bên dưới tiêu đề "Các bài viết gần đây". Hãy nhớ rằng chúng tôi đã chèn hai bản ghi vào cơ sở dữ liệu nhưng chỉ một bản ghi đang được hiển thị. Điều này là như vậy bởi vì một trong các bản ghi có trường đã xuất bản của nó được đặt thành false (nghĩa là, 0) và vì chỉ các bài báo đã xuất bản mới được hiển thị nên chúng tôi chỉ thấy một, bài đã xuất bản.

Nhưng các bài viết của chúng tôi cho đến bây giờ không được phân loại theo bất kỳ chủ đề nào. Hãy tạo một bảng chủ đề và hình thành mối quan hệ Nhiều-Nhiều giữa các bài đăng và bảng chủ đề. Để thực hiện việc này, chúng tôi sẽ tạo hai bảng mới:chủ đề để lưu trữ chủ đề và bảng post_topic để xử lý mối quan hệ giữa bài đăng và chủ đề.

chủ đề:

+----+-----------+------------------------+------------+
|     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)                |            |
+----------------+--------------+---------+------------+

Những gì chúng tôi thực sự quan tâm là bảng post_topic. Đây là bảng xử lý mối quan hệ giữa bài viết và chủ đề. Khi một bài đăng được tạo theo một chủ đề cụ thể, id của bài đăng đó (post_id), cũng như id của chủ đề (topic_id) mà bài đăng đó được tạo, sẽ được chèn vào bảng post_topic.

Hãy thiết lập mối quan hệ này để khi một bài đăng bị xóa, mục nhập của chúng trong bảng post_topic cũng sẽ tự động bị xóa; bạn không muốn giữ thông tin về mối quan hệ của một bài đăng khi bài đăng đó không tồn tại đúng không?

Nhấp / chọn bảng post_topic, sau đó nhấp vào tab cấu trúc của thanh điều hướng PHPMyAdmin. Tiếp theo, nhấp vào Chế độ xem quan hệ ngay bên dưới tab cấu trúc (nó có thể được tìm thấy ở một nơi khác tùy thuộc vào phiên bản PHPMyAdmin của bạn). Sau đó điền vào biểu mẫu bên dưới như sau:

Mẹo:Liên kết + Thêm ràng buộc được sử dụng để thêm một ràng buộc mới.

BẬT XÓA và BẬT CẬP NHẬT tất cả đều được đặt thành CASCADE và KHÔNG CÓ HÀNH ĐỘNG tương ứng để khi bài đăng hoặc chủ đề bị xóa, thông tin mối quan hệ trong bảng post_topic cũng tự động bị xóa. (Trong hình ảnh, tôi đã nhầm lẫn khi đặt BẬT CẬP NHẬT thành CASCADE thay vì KHÔNG HÀNH ĐỘNG, xin lỗi vì điều đó).

Bấm lưu và thế là xong. Các bảng hiện có liên quan với nhau. Nhưng để thiết lập mối quan hệ giữa bài đăng và chủ đề, chúng ta cần điền các chủ đề vào bảng chủ đề và cuối cùng là bảng post_topic là thông tin mối quan hệ thực tế.

Bây giờ, hãy chèn một vài mục nhập vào hai bảng:

chủ đề:

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)

Mối quan hệ được xác định trên bảng post_topic cho biết rằng chủ đề có id 1 trên bảng chủ đề thuộc về bài đăng có id 1 trên bảng bài đăng. Điều tương tự cũng đúng đối với chủ đề có id 2 và bài đăng có id 2.

Trên mỗi danh sách bài đăng trên trang index.php, chúng tôi sẽ hiển thị chủ đề mà bài viết được tạo.

Để làm điều này, chúng tôi phải sửa đổi getPublishedPosts () mà chúng tôi đã tạo bên trong public_functions.php để truy vấn chủ đề của mỗi bài đăng từ cơ sở dữ liệu và trả về bài đăng cùng với chủ đề của nó.

Sửa đổi tệp public_functions.php để trông giống như sau:

<?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;
}
?>

Bây giờ, hãy truy cập tệp index.php. Bên trong vòng lặp foreach, ngay bên dưới thẻ hình ảnh , thêm câu lệnh if để hiển thị chủ đề. Vòng lặp foreach của bạn sẽ trông như thế này sau khi sửa đổi:

<?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 ?>

Bây giờ tải lại trang và bạn sẽ thấy chủ đề được hiển thị trong bài đăng.

Bên trong vòng lặp foreach này, bạn nhận thấy rằng có hai liên kết khi được nhấp vào, sẽ đưa bạn đến hai trang:filter_posts.php và single_post.php.

filter_posts.php là một trang liệt kê tất cả các bài đăng theo một chủ đề cụ thể khi người dùng nhấp vào chủ đề đó.

single_post.php là trang hiển thị chi tiết toàn bộ bài đăng cùng với nhận xét khi người dùng nhấp vào hình thu nhỏ của bài đăng.

Hai tệp này cần một vài chức năng từ tệp public_functions.php của chúng tôi. filter_posts.php cần hai hàm có tên getPublishedPostsByTopic () và getTopicNameById () trong khi single_posts.php cần getPost () và getAllTopics ().

Hãy bắt đầu với tệp filter_posts.php. Mở public_functions.php và thêm hai hàm này vào danh sách các hàm:

/* * * * * * * * * * * * * * * *
* 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'];
}

Đầu tiên chúng ta hãy tạo tệp filter_posts.php trong thư mục gốc của ứng dụng của chúng ta (nghĩa là, complete-blog-php / filter_posts.php). Tôi sẽ tiếp tục và dán toàn bộ mã của trang này vào bên trong tệp:

Lọc_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 -->

Bây giờ, hãy làm mới trang, nhấp vào chủ đề và nếu nó đưa bạn đến trang hiển thị các bài đăng theo chủ đề đó, thì bạn đang làm đúng.

Hãy làm điều tương tự với single_post.php. Mở public_functions.php và thêm 2 hàm này vào nó:

/* * * * * * * * * * * * * * *
* 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;
}

Bây giờ, hãy tạo tệp complete-blog-php / single_post.php và dán mã này vào đó:

<?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'); ?>

Bây giờ chúng ta hãy áp dụng phong cách cho điều này. Mở public_styling.css và thêm mã kiểu này vào nó:

/* * * * * * * * *
* 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;
}

Bây giờ có vẻ ổn phải không?

Một điều cuối cùng cần làm và chúng tôi sẽ hoàn thành khá nhiều việc với khu vực công cộng:Chúng tôi sẽ triển khai đăng ký và đăng nhập người dùng.

Đăng ký và đăng nhập người dùng

Bởi vì tôi đã thực hiện một hướng dẫn về đăng ký và đăng nhập người dùng, tôi sẽ đi khá sâu vào phần này và sẽ không giải thích nhiều.

Tạo hai tệp trong thư mục gốc của bạn có tên register.php và login.php. Mở từng trong số chúng và đặt mã này vào chúng:

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 -->

Trong phần trên cùng của cả hai tệp, chúng tôi đã bao gồm một tệp có tên register_login.php để xử lý logic đăng ký và đăng nhập. Đây là tệp mà thông tin biểu mẫu đăng nhập và đăng ký sẽ được gửi đến và giao tiếp với cơ sở dữ liệu sẽ được thực hiện. Hãy tạo nó trong thư mục bao gồm của chúng tôi và lấy mã này bên trong nó:

complete-blog-php / include / register_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; 
	}
?>

Truy cập http://localhost/complete-blog-php/register.php và bạn sẽ thấy thông báo lỗi không tìm thấy tệp error.php.

Tệp error.php là tệp có mã để hiển thị lỗi xác thực biểu mẫu. Tạo error.php bên trong complete-blog-php / include và dán mã này vào đó:

<?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 ?>

Một lần nữa, mở public_styling.css, hãy thêm đoạn mã tạo kiểu cuối cùng này cho tệp error.php này và một vài phần tử khác:

/* 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;
}

Và bây giờ thông báo lỗi đã biến mất. Nhấp vào nút đăng ký mà không cần điền vào biểu mẫu và bạn sẽ thấy các thông báo lỗi hiển thị tuyệt đẹp.

Hãy tạo một người dùng mới bằng cách điền vào biểu mẫu trên trang register.php và nhấp vào nút đăng ký. Bạn có thể cung cấp bất kỳ thông tin hợp lệ nào cho tên người dùng, email và mật khẩu; chỉ cần đảm bảo rằng bạn nhớ chúng vì chúng tôi sẽ sử dụng chúng để đăng nhập rất sớm trên trang đăng nhập.

Khi người dùng đăng nhập, họ chắc chắn cần đăng xuất được. Trong thư mục gốc của ứng dụng, tạo một tệp có tên logout.php.

complete-blog-php / logout.php:

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

Ngoài ra, khi người dùng đăng nhập, chúng tôi muốn hiển thị tên của họ và một liên kết hoặc nút để họ nhấp vào để đăng xuất. Đối với khu vực công cộng, chúng tôi sẽ thực hiện điều đó trong tệp banner.php mà chúng tôi đã đưa vào. Mở tệp banner.php và sửa đổi mã để trông giống như sau:

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.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tạo bảng số trong MySQL

  2. MySQL 'Order By' - sắp xếp chính xác chữ và số

  3. Cách quản lý MySQL - dành cho Oracle DBAs

  4. Java:Chèn nhiều hàng vào MySQL với PreparedStatement

  5. Số lượng cột không khớp với số lượng giá trị ở hàng 1