データベース
これは、PHPとMySQLを使用してブログを作成する方法に関するシリーズの第2部です。ここで最初の部分を入手できます
前回のチュートリアルで中断したところから続行します。このセクションでは、データベースの設計とユーザー認証(登録とログイン)に取り組みます。 complete-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で、これらのテーブルを作成するデータベース(この場合はcomplete-blog-php)をクリック/選択してから、ページ上部のナビゲーションバーにある[SQL]タブをクリックします。下のスペースにSQLスクリプトが表示されている場合は、それを削除して上のスクリプトを所定のスペースに貼り付け、[移動]をクリックしてテーブルを作成します。
代わりにこれらのテーブルを手動で作成することを選択した場合は、postテーブルのslugフィールドをUNIQUEにすることを忘れないでください。また、postsテーブルのuser_idフィールドを、usersテーブルのidを参照する外部キーとして設定することを忘れないでください。 ONDELETEおよびONUPDATEオプションの値としてNOACTIONを設定して、ユーザーが削除または更新されたときに、その投稿が投稿テーブルに残り、削除されないようにします。
次に、usersテーブルに数人のユーザーを挿入し、postsテーブルに数人の投稿を挿入します。これを行うには、次の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')
データベースに接続し、これらの投稿をクエリしてWebページに表示しましょう。
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に送信されて表示されます。したがって、データベースからすべての投稿を取得するには、関数でそれを実行し、結果を連想配列として返し、ループしてページに表示します。
したがって、includesフォルダに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(); ?>
2行のコードを追加しました。 1つ目は、public_functions.php(関数を保持する)ファイルをindex.phpファイルに含めます。コードの2行目は、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;
}
これで、ページをリロードできます。
すべてがうまくいけば、「最近の記事」のタイトルの下にサムネイルとしてスタイル設定された単一の投稿が表示されます。データベースに2つのレコードを挿入しましたが、表示されているのは1つだけであることを思い出してください。これは、レコードの1つで公開フィールドがfalse(つまり、0)に設定されており、公開された記事のみが表示されるため、公開された記事が1つだけ表示されるためです。
ただし、現時点での投稿はどのトピックにも分類されていません。トピックテーブルを作成し、投稿とトピックテーブルの間に多対多の関係を形成しましょう。これを行うために、トピックを格納するトピックと、投稿とトピックの関係を処理するpost_topicテーブルの2つの新しいテーブルを作成します。
トピック:
+----+-----------+------------------------+------------+
| 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テーブルです。これは、投稿とトピックの関係を処理するテーブルです。特定のトピックの下に投稿が作成されると、その投稿のID(post_id)と、その投稿が作成されたトピックのID(topic_id)がpost_topicテーブルに挿入されます。
投稿が削除されると、post_topicテーブルのエントリも自動的に削除されるように、この関係を確立しましょう。投稿が正しく存在しない場合に、投稿の関係に関する情報を保持したくないですか?
post_topicテーブルをクリック/選択してから、PHPMyAdminナビゲーションバーの構造タブをクリックします。次に、構造タブのすぐ下にあるリレーションビューをクリックします(PHPMyAdminのバージョンによっては別の場所に表示される場合があります)。次に、以下のフォームに記入します。
ヒント:[+制約の追加]リンクは、新しい制約を追加するために使用されます。
ONDELETEとONUPDATEは、それぞれCASCADEとNO ACTIONに設定されているため、投稿またはトピックが削除されると、post_topicテーブルの関係情報も自動的に削除されます。 (画像では、ONUPDATEをNOACTIONではなくCASCADEに設定するのを間違えました。申し訳ありません。)
[保存]をクリックすると、それだけです。これで、テーブルが関連付けられました。ただし、投稿とトピックの関係を確立するには、トピックテーブルにトピックを入力し、最終的には実際の関係情報であるpost_topicテーブルに入力する必要があります。
次に、2つのテーブルにいくつかのエントリを挿入しましょう。
トピック:
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テーブルで定義された関係は、トピックテーブルのID 1のトピックが、投稿テーブルのID1の投稿に属していることを示しています。 ID2のトピックとID2の投稿についても同じことが言えます。
index.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);
$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ループ内には、2つのリンクがあり、クリックすると、filtered_posts.phpとsingle_post.phpの2つのページに移動します。
Filtered_posts.phpは、ユーザーが特定のトピックをクリックしたときに、そのトピックの下にあるすべての投稿を一覧表示するページです。
single_post.phpは、ユーザーが投稿のサムネイルをクリックしたときに、コメントとともに投稿全体を詳細に表示するページです。
これらの2つのファイルには、public_functions.phpファイルのいくつかの関数が必要です。 filtered_posts.phpにはgetPublishedPostsByTopic()とgetTopicNameById()という2つの関数が必要ですが、single_posts.phpにはgetPost()とgetAllTopics()が必要です。
filtered_posts.phpファイルから始めましょう。 public_functions.phpを開き、次の2つの関数を関数のリストに追加します。
/* * * * * * * * * * * * * * * *
* 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'];
}
まず、アプリケーションのルートフォルダー(つまり、complete-blog-php / filtered_posts.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;
}
今はよさそうですか?
最後にもう1つ、パブリックエリアはほぼ完成します。ユーザー登録とログインを実装します。
ユーザー登録とログイン
ユーザーの登録とログインに関するチュートリアルはすでに作成しているので、この部分についてはほとんど説明しません。
ルートフォルダにregister.phpとlogin.phpという名前の2つのファイルを作成します。それらのそれぞれを開き、このコードをそれらに配置します:
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 / contains / registerration_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ファイルは、フォーム検証エラーを表示するコードを含むファイルです。 complete-blog-php / includes内にerrors.phpを作成し、このコードを貼り付けます:
<?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.