Cómo crear un blog en PHP y una base de datos MySQL – DB Design

La base de datos

Esta es la segunda parte de una serie sobre cómo crear un blog con PHP y MySQL. Puedes conseguir la primera parte aquí.

Continuaremos donde lo dejamos en el último tutorial. En esta sección trabajaremos en el diseño de nuestra base de datos y la autenticación de usuarios (registro e inicio de sesión). Crea una base de datos llamada blog-completo-php. En esta base de datos, cree 2 tablas: publicaciones y usuarios con los siguientes campos.

publicaciones:

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

usuarios:

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

Puede crear estas tablas usando estos comandos.

usuarios:

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;

publicaciones:

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

Puede ejecutar estos scripts mediante el símbolo del sistema de SQL o PHPMyAdmin. En PHPMyAdmin, haga clic / seleccione la base de datos en la que desea crear estas tablas (en este caso blog-completo-php), luego haga clic en la pestaña SQL en la barra de navegación en algún lugar en la parte superior de la página. Si ve algún script SQL en el espacio a continuación, elimínelo y pegue el script de arriba en el espacio provisto y haga clic en ‘Ir’ para crear las tablas.

Si elige crear estas tablas manualmente, recuerde hacer el babosa campo en la tabla de publicaciones ÚNICO, y recuerde configurar el user_id campo de la tabla de publicaciones como la clave externa que hace referencia a la identificación en usuarios chaquete. Establezca NO ACTION como el valor para las opciones ON DELETE y ON UPDATE para que cuando se elimine o actualice un usuario, sus publicaciones permanezcan en la tabla de publicaciones y no se eliminen.

Ahora inserte algunos usuarios en el usuarios tabla y algunas publicaciones en el publicaciones chaquete. Puede hacerlo ejecutando estas consultas SQL para insertar:

usuarios:

INSERT INTO `users` (`id`, `username`, `email`, `role`, `password`, `created_at`, `updated_at`) VALUES
(1, 'Awa', 'info@codewithawa.com', 'Admin', 'mypassword', '2018-01-08 12:52:58', '2018-01-08 12:52:58')

mensajes:

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

Vamos a conectarnos a la base de datos, consultar estas publicaciones y mostrarlas en la página web.

En el config.php, agreguemos código para conectar nuestra aplicación a la base de datos. Después de agregar el código, nuestro config.php El archivo se verá así:

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

Esto devuelve un objeto de conectividad de base de datos. $ conn que podemos usar en toda nuestra aplicación para consultar la base de datos.

Por lo tanto, cree un archivo con nombre public_functions.php en la carpeta incluye. Este archivo contendrá todas nuestras funciones PHP para el área pública. Todas las páginas que utilizan cualquiera de las funciones de este archivo deben tener este archivo incluido en la sección superior de la página.

Creemos nuestra primera función en nuestro recién creado public_functions.php. Nombraremos la función getPublishedPosts () y recuperará todas las publicaciones del publicaciones tabla en la base de datos y devolverlos como una matriz asociativa:

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

En la sección superior de la index.php filete, justo debajo de la línea que incluye config.php, agregue este código para consultar la base de datos:

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

Agregamos dos líneas de código. El primero incluye el public_functions.php (que contiene las funciones) archivo a nuestro index.php filete. La segunda línea de código llama al getPublishedPosts () función que consulta la base de datos y devuelve publicaciones recuperadas de la base de datos en una variable llamada $ publicaciones. Ahora recorramos y mostremos estas publicaciones en el index.php página.

Abre nuestro famoso index.php archivo de nuevo. En la sección de contenido en algún lugar en el medio, encontrará un


etiqueta y un comentario que indica dónde vendrá más contenido. En el espacio, justo debajo del


etiqueta, agregue este código:

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

Está bien, por favor, no recargues la página todavía. Agreguemos estilo a esta lista de publicaciones. Abierto public_styling.css y agregue este código:

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

Ahora puedes volver a cargar la página.

Si todo salió bien, verá una sola publicación con el estilo de una miniatura debajo del título “Artículos recientes”. Recuerde que habíamos insertado dos registros en la base de datos, pero solo se muestra uno. Esto es así porque uno de los registros tenía su publicado campo establecido en falso (es decir, 0), y como solo se muestran los artículos publicados, solo vemos uno, el publicado.

Pero nuestras publicaciones a partir de ahora no están clasificadas bajo ningún tema. Vamos a crear un temas tabla y formar una relación de varios a varios entre los publicaciones y el temas chaquete. Para hacer esto, crearemos dos tablas nuevas: temas para almacenar temas, y post_topic tabla para manejar la relación entre publicaciones y temas.

temas:

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

Lo que realmente nos interesa es la post_topic chaquete. Esta es la tabla que maneja la relación entre publicaciones y temas. Cuando se crea una publicación sobre un tema en particular, la identificación de esa publicación (ID del mensaje), así como el id del tema (topic_id) bajo el cual se crea ese puesto, se insertan en el post_topic chaquete.

Establezcamos esta relación para que cuando se elimine una publicación, su entrada en el post_topic la tabla también se eliminará automáticamente; no desea mantener información sobre la relación de una publicación cuando la publicación no existe, ¿verdad?

Haga clic / seleccione el post_topic tabla, luego haga clic en el estructura pestaña de la barra de navegación PHPMyAdmin. A continuación, haga clic en Vista de relación justo debajo de la pestaña de estructura (se puede encontrar en otro lugar dependiendo de su versión de PHPMyAdmin). Luego complete el formulario a continuación de la siguiente manera:

Consejo: el + Agregar restricción El enlace se usa para agregar una nueva restricción.

ON DELETE y ON UPDATE están configurados en CASCADE y NO ACTION respectivamente, de modo que cuando se elimina una publicación o un tema, su información de relación en el post_topic La tabla también se elimina automáticamente. (En la imagen, cometí un error al configurar ON UPDATE en CASCADE en lugar de NO ACTION, lo siento).

Haga clic en guardar y listo. Las tablas ahora están relacionadas. Pero para establecer una relación entre publicaciones y temas, necesitamos completar el temas tabla con temas y eventualmente el post_topic tabla que es la información real de la relación.

Ahora insertemos algunas entradas en las dos tablas:

temas:

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

post_topic:

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

La relación definida en el post_topic tabla dice que el tema con id 1 sobre el temas la tabla pertenece a la publicación con id 1 sobre el publicaciones chaquete. Lo mismo ocurre con el tema con id. 2 y publicar con id 2.

En cada publicación que aparece en el index.php página, vamos a mostrar el tema bajo el cual se crea la publicación.

Para hacer esto, tenemos que modificar nuestro getPublishedPosts () creamos dentro public_functions.php para consultar el tema de cada publicación desde la base de datos y devolver la publicación junto con su tema.

Modifique el archivo public_functions.php para que tenga este aspecto:

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

Ahora ve a index.php filete. Dentro del bucle foreach, directamente debajo de la etiqueta de la imagen , agregue la instrucción if para mostrar el tema. Su bucle foreach debería verse así después de modificar:

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

Ahora vuelva a cargar la página y verá el tema que se muestra en la publicación.

Dentro de este bucle foreach, observa que hay dos enlaces que, al hacer clic, lo llevarán a dos páginas: publicaciones_filtradas.php y single_post.php.

publicaciones_filtradas.php es una página que enumera todas las publicaciones de un tema en particular cuando el usuario hace clic en ese tema.

single_post.php es una página que muestra la publicación completa en detalle junto con comentarios cuando el usuario hace clic en la miniatura de la publicación.

Estos dos archivos necesitan algunas funciones de nuestro public_functions.php filete. Filter_posts.php necesita dos funciones llamadas getPublishedPostsByTopic () y getTopicNameById () mientras que single_posts.php necesita getPost () y getAllTopics ().

Empecemos con publicaciones_filtradas.php filete. Abierto public_functions.php y agregue estas dos funciones a la lista de funciones:

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

Primero creemos el archivo filter_posts.php en la carpeta raíz de nuestra aplicación (es decir, blog-completo-php/filtered_posts.php). Seguiré adelante y pegaré todo el código de esta página dentro del archivo:

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

Ahora actualice la página, haga clic en el tema y si lo lleva a una página que muestra publicaciones sobre ese tema, entonces está haciendo lo correcto.

Hagamos lo mismo con single_post.php. Abierto public_functions.php y agregue estas 2 funciones:

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

Ahora crea el archivo blog-completo-php/single_post.php y pega este código en él:

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

Apliquemos ahora el estilo a esto. Abierto public_styling.css y agregue este código de estilo:

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

Se ve bien ahora, ¿verdad?

Una última cosa que hacer y habremos terminado con el área pública: implementaremos el registro e inicio de sesión de usuario.

Registro e inicio de sesión de usuario

Debido a que ya hice un tutorial sobre el registro e inicio de sesión de usuario, iré al grano con esta parte y no daré muchas explicaciones.

Cree dos archivos en su carpeta raíz llamados register.php y login.php. Abra cada uno de ellos y coloque este código en ellos:

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

En las secciones superiores de ambos archivos, incluimos un archivo llamado registration_login.php para manejar la lógica de registro e inicio de sesión. Este es el archivo al que se enviará la información del formulario de inicio de sesión y registro y se realizará la comunicación con la base de datos. Creámoslo en nuestro incluye carpeta y escupe este código dentro de ella:

blog-completo-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'=>'a@a.com', 'password'=> 'mypass']
		return $user; 
	}
?>

Ir http: //localhost/complete-blog-php/register.php y verá un error que dice que errors.php archivo no encontrado.

errors.php archivo es el archivo con código para mostrar errores de validación de formularios. creado errors.php dentro blog-completo-php/ incluye y pega este código en él:

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

Una vez más abierto public_styling.css agreguemos esta última pieza de código de estilo para esto errors.php archivo y algunos otros elementos:

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

Y ahora el mensaje de error desapareció. Haga clic en el botón de registro sin completar el formulario y verá hermosos mensajes de error procesados.

Creemos un nuevo usuario completando el formulario en el register.php página y haciendo clic en el botón de registro. Puede proporcionar cualquier información válida para el nombre de usuario, correo electrónico y contraseña; solo asegúrese de recordarlos porque los usaremos para iniciar sesión muy pronto en la página de inicio de sesión.

Cuando un usuario inicia sesión, definitivamente deberá poder cerrar la sesión. En la carpeta raíz de la aplicación, cree un archivo llamado logout.php.

complete-blog-php / logout.php:

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

Además, cuando un usuario inicia sesión, queremos mostrar su nombre y un enlace o botón para que haga clic para cerrar la sesión. Para el área pública, lo haremos en el banner.php archivo que incluimos. Abierto banner.php archivo y modifique el código para que se vea así:

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

Comprueba la sesión para ver si un usuario está disponible (conectado). Si está conectado, el nombre de usuario se muestra con el enlace de cierre de sesión. Cuando hay un usuario que ha iniciado sesión, el banner no se muestra ya que es una especie de pantalla de bienvenida para los usuarios invitados.

Observa que el banner tiene un formulario de inicio de sesión y este banner se incluye dentro index.php filete. Por lo tanto, debemos incluir el código que maneja el registro y el inicio de sesión dentro de nuestro index.php archivo también. Abra index.php y agregue esta línea directamente debajo de la inclusión para public_functions.php:

sección superior de blog-completo-php/index.php:

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

Y eso es todo con el registro de usuario y el inicio de sesión. En la siguiente sección, comenzamos a trabajar en el área de administración.

Muchas gracias por quedarse hasta este momento. Espero que lo haya encontrado util. Si tiene alguna inquietud, déjela en los comentarios a continuación. Tus comentarios siempre son muy útiles y si tienes algún error en tu código, haré todo lo posible para ayudarte.

Me alentaré mucho a crear más de estos tutoriales con una calidad mejorada si comparte, se suscribe a mi sitio y lo recomienda a sus amigos.

Awa Melvine

Siguiente parte: Backend (área de administración)

Deja un comentario