Saturday, July 30, 2016

How to Create a PHP/MySQL Powered Forum from Scratch_part1

In this tutorial, we're going to build a PHP/MySQL powered forum from scratch. This tutorial is perfect for getting used to basic PHP and database usage. Let's dive right in!

Step 1: Creating Database Tables

It's always a good idea to start with creating a good data model when building an application. Let's describe our application in one sentence: We are going to make a forum which has users who create topics in various categories. Other users can post replies. As you can see, I highlighted a couple of nouns which represent our table names.

Users
  • Categories
  • Topics
  • Posts
These three objects are related to each other, so we'll process that in our table design. Take a look at the scheme below.

https://school.codequs.com/p/rJqQzyIO
Looks pretty neat, huh? Every square is a database table. All the columns are listed in it and the lines between them represent the relationships. I'll explain them further, so it's okay if it doesn't make a lot of sense to you right now.

I'll discuss each table by explaining the SQL, which I created using the scheme above. For your own scripts you can create a similar scheme and SQL too. Some editors like MySQL Workbench (the one I used) can generate .sql files too, but I would recommend learning SQL because it's more fun to do it yourself. A SQL introduction can be found at W3Schools.

Users Table
  1. CREATE TABLE users (
  2. user_id     INT(8) NOT NULL AUTO_INCREMENT,
  3. user_name   VARCHAR(30) NOT NULL,
  4. user_pass   VARCHAR(255) NOT NULL,
  5. user_email  VARCHAR(255) NOT NULL,
  6. user_date   DATETIME NOT NULL,
  7. user_level  INT(8) NOT NULL,
  8. UNIQUE INDEX user_name_unique (user_name),
  9. PRIMARY KEY (user_id)
  10. ) TYPE=INNODB;
The CREATE TABLE statement is used to indicate we want to create a new table, of course. The statement is followed by the name of the table and all the columns are listed between the brackets. The names of all the fields are self-explanatory, so we'll only discuss the data types below.

user_id
"A primary key is used to uniquely identify each row in a table."
The type of this field is INT, which means this field holds an integer. The field cannot be empty (NOT NULL) and increments which each record inserted. At the bottom of the table you can see the user_id field is declared as a primary key. A primary key is used to uniquely identify each row in a table. No two distinct rows in a table can have the same value (or combination of values) in all columns. That might be a bit unclear, so here's a little example.

There is a user called John Doe. If another users registers with the same name, there's a problem, because: which user is which? You can't tell and the database can't tell either. By using a primary key this problem is solved, because both topics are unique.

All the other tables have got primary keys too and they work the same way.

user_name

This is a text field, called a VARCHAR field in MySQL. The number between brackets is the maximum length. A user can choose a username up to 30 characters long. This field cannot be NULL. At the bottom of the table you can see this field is declared UNIQUE, which means the same username cannot be registered twice. The UNIQUE INDEX part tells the database we want to add a unique key. Then we define the name of the unique key, user_name_unique in this case. Between brackets is the field the unique key applies to, which is user_name.

user_pass

This field is equal to the user_name field, except the maximum length. Since the user password, no matter what length, is hashed with sha1(), the password will always be 40 characters long.

user_email

This field is equal to the user_pass field.

user_date

This is a field in which we'll store the date the user registered. It's type is DATETIME and the field cannot be NULL.

user_level

This field contains the level of the user, for example: '0' for a regular user and '1' for an admin. More about this later.

Categories Table 
  1. CREATE TABLE categories (
  2. cat_id          INT(8) NOT NULL AUTO_INCREMENT,
  3. cat_name        VARCHAR(255) NOT NULL,
  4. cat_description     VARCHAR(255) NOT NULL,
  5. UNIQUE INDEX cat_name_unique (cat_name),
  6. PRIMARY KEY (cat_id)
  7. ) TYPE=INNODB;
 These data types basically work the same way as the ones in the users table. This table also has a primary key and the name of the category must be an unique one.

Topics Table
  1. CREATE TABLE topics (
  2. topic_id        INT(8) NOT NULL AUTO_INCREMENT,
  3. topic_subject       VARCHAR(255) NOT NULL,
  4. topic_date      DATETIME NOT NULL,
  5. topic_cat       INT(8) NOT NULL,
  6. topic_by        INT(8) NOT NULL,
  7. PRIMARY KEY (topic_id)
  8. ) TYPE=INNODB;
This table is almost the same as the other tables, except for the topic_by field. That field refers to the user who created the topic. The topic_cat refers to the category the topic belongs to. We cannot force these relationships by just declaring the field. We have to let the database know this field must contain an existing user_id from the users table, or a valid cat_id from the categories table. We'll add some relationships after I've discussed the posts table.

Posts Table
  1. CREATE TABLE posts (
  2. post_id         INT(8) NOT NULL AUTO_INCREMENT,
  3. post_content        TEXT NOT NULL,
  4. post_date       DATETIME NOT NULL,
  5. post_topic      INT(8) NOT NULL,
  6. post_by     INT(8) NOT NULL,
  7. PRIMARY KEY (post_id)
  8. ) TYPE=INNODB;
This is the same as the rest of the tables; there's also a field which refers to a user_id here: the post_by field. The post_topic field refers to the topic the post belongs to.
"A foreign key is a referential constraint between two tables. The foreign key identifies a column or a set of columns in one (referencing) table that refers to a column or set of columns in another (referenced) table."
Now that we've executed these queries, we have a pretty decent data model, but the relations are still missing. Let's start with the definition of a relationship. We're going to use something called a foreign key. A foreign key is a referential constraint between two tables. The foreign key identifies a column or a set of columns in one (referencing) table that refers to a column or set of columns in another (referenced) table. Some conditions:
  • The column in the referencing table the foreign key refers to must be a primary key
  • The values that are referred to must exist in the referenced table
By adding foreign keys the information is linked together which is very important for database normalization. Now you know what a foreign key is and why we're using them. It's time to add them to the tables we've already made by using the ALTER statement, which can be used to change an already existing table.

We'll link the topics to the categories first:
  1. ALTER TABLE topics ADD FOREIGN KEY(topic_cat) REFERENCES categories(cat_id)
  2.  ON DELETE CASCADE ON UPDATE CASCADE;
The last part of the query already says what happens. When a category gets deleted from the database, all the topics will be deleted too. If the cat_id of a category changes, every topic will be updated too. That's what the ON UPDATE CASCADE part is for. Of course, you can reverse this to protect your data, so that you can't delete a category as long as it still has topics linked to it. If you would want to do that, you could replace the 'ON DELETE CASCADE' part with 'ON DELETE RESTRICT'. There is also SET NULL and NO ACTION, which speak for themselves.

Every topic is linked to a category now. Let's link the topics to the user who creates one.
  1. ALTER TABLE topics ADD FOREIGN KEY(topic_by) REFERENCES users(user_id)
  2.  ON DELETE RESTRICT ON UPDATE CASCADE;
This foreign key is the same as the previous one, but there is one difference: the user can't be deleted as long as there are still topics with the user id of the user. We don't use CASCADE here because there might be valuable information in our topics. We wouldn't want that information to get deleted if someone decides to delete their account. To still give users the opportunity to delete their account, you could build some feature that anonymizes all their topics and then delete their account. Unfortunately, that is beyond the scope of this tutorial.

Link the posts to the topics:
  1. ALTER TABLE posts ADD FOREIGN KEY(post_topic) REFERENCES topics(topic_id) ON DELETE CASCADE ON UPDATE CASCADE;
And finally, link each post to the user who made it:
  1. ALTER TABLE posts ADD FOREIGN KEY(post_by) REFERENCES users(user_id) ON DELETE RESTRICT ON UPDATE CASCADE;
That's the database part! It was quite a lot of work, but the result, a great data model, is definitely worth it.

Step 2: Introduction to the Header/Footer System

Each page of our forum needs a few basic things, like a doctype and some markup. That's why we'll include a header.php file at the top of each page, and a footer.php at the bottom. The header.php contains a doctype, a link to the stylesheet and some important information about the forum, such as the title tag and metatags.

header.php
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

  3. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="nl" lang="nl">

  4. <head>

  5.     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

  6.     <meta name="description" content="A short description." />

  7.     <meta name="keywords" content="put, keywords, here" />

  8.     <title>PHP-MySQL forum</title>

  9.     <link rel="stylesheet" href="style.css" type="text/css">

  10. </head>

  11. <body>

  12. <h1>My forum</h1>

  13.     <div id="wrapper">

  14.     <div id="menu">

  15.         <a class="item" href="/forum/index.php">Home</a> -

  16.         <a class="item" href="/forum/create_topic.php">Create a topic</a> -

  17.         <a class="item" href="/forum/create_cat.php">Create a category</a>

  18.          

  19.         <div id="userbar">

  20.         <div id="userbar">Hello Example. Not you? Log out.</div>

  21.     </div>

  22.         <div id="content">
The wrapper div will be used to make it easier to style the entire page. The menu div obviously contains a menu with links to pages we still have to create, but it helps to see where we're going a little bit. The userbar div is going to be used for a small top bar which contains some information like the username and a link to the logout page. The content page holds the actual content of the page, obviously.

The attentive reader might have already noticed we're missing some things. There is no </body> or </html> tag. They're in the footer.php page, as you can see below.
  1. </div><!-- content -->
  2. </div><!-- wrapper -->
  3. <div id="footer">Created for Nettuts+</div>
  4. </body>
  5. </html>
When we include a header and a footer on each page the rest of the page get embedded between the header and the footer. This method has got some advantages. First and foremost, everything will be styled correctly. A short example:
  1. <?php
  2. $error = false;
  3. if($error = false)
  4. {
  5.     //the beautifully styled content, everything looks good
  6.     echo '<div id="content">some text</div>';
  7. }
  8. else
  9. {
  10.     //bad looking, unstyled error :-( 
  11. ?>
As you can see, a page without errors will result in a nice page with the content. But if there's an error, everything looks really ugly; so that's why it's better to make sure not only real content is styled correctly, but also the errors we might get.

Another advantage is the possibility of making quick changes. You can see for yourself by editing the text in footer.php when you've finished this tutorial; you'll notice that the footer changes on every page immediately. Finally, we add a stylesheet which provides us with some basic markup - nothing too fancy.
  1. body {
  2.     background-color: #4E4E4E;
  3.     text-align: center;         /* make sure IE centers the page too */
  4. }
  5. #wrapper {
  6.     width: 900px;
  7.     margin: 0 auto;             /* center the page */
  8. }
  9. #content {
  10.     background-color: #fff;
  11.     border: 1px solid #000;
  12.     float: left;
  13.     font-family: Arial;
  14.     padding: 20px 30px;
  15.     text-align: left;
  16.     width: 100%;                /* fill up the entire div */
  17. }
  18. #menu {
  19.     float: left;
  20.     border: 1px solid #000;
  21.     border-bottom: none;        /* avoid a double border */
  22.     clear: both;                /* clear:both makes sure the content div doesn't float next to this one but stays under it */
  23.     width:100%;
  24.     height:20px;
  25.     padding: 0 30px;
  26.     background-color: #FFF;
  27.     text-align: left;
  28.     font-size: 85%;
  29. }
  30. #menu a:hover {
  31.     background-color: #009FC1;
  32. }
  33. #userbar {
  34.     background-color: #fff;
  35.     float: right;
  36.     width: 250px;
  37. }
  38. #footer {
  39.     clear: both;
  40. }
  41. /* begin table styles */
  42. table {
  43.     border-collapse: collapse;
  44.     width: 100%;
  45. }
  46. table a {
  47.     color: #000;
  48. }
  49. table a:hover {
  50.     color:#373737;
  51.     text-decoration: none;
  52. }
  53. th {
  54.     background-color: #B40E1F;
  55.     color: #F0F0F0;
  56. }
  57. td {
  58.     padding: 5px;
  59. }
  60. /* Begin font styles */
  61. h1, #footer {
  62.     font-family: Arial;
  63.     color: #F1F3F1;
  64. }
  65. h3 {margin: 0; padding: 0;}
  66. /* Menu styles */
  67. .item {
  68.     background-color: #00728B;
  69.     border: 1px solid #032472;
  70.     color: #FFF;
  71.     font-family: Arial;
  72.     padding: 3px;
  73.     text-decoration: none;
  74. }
  75. .leftpart {
  76.     width: 70%;
  77. }
  78. .rightpart {
  79.     width: 30%;
  80. }
  81. .small {
  82.     font-size: 75%;
  83.     color: #373737;
  84. }
  85. #footer {
  86.     font-size: 65%;
  87.     padding: 3px 0 0 0;
  88. }
  89. .topic-post {
  90.     height: 100px;
  91.     overflow: auto;
  92. }
  93. .post-content {
  94.     padding: 30px;
  95. }
  96. textarea {
  97.     width: 500px;
  98.     height: 200px;
  99. }
Step 3: Getting Ready for Action

Before we can read anything from our database, we need a connection. That's what connect.php is for. We'll include it in every file we are going to create.
  1. <?php
  2. //connect.php
  3. $server = 'localhost';
  4. $username   = 'usernamehere';
  5. $password   = 'passwordhere';
  6. $database   = 'databasenamehere';
  7. if(!mysql_connect($server, $username,  $password))
  8. {
  9.     exit('Error: could not establish database connection');
  10. }
  11. if(!mysql_select_db($database)
  12. {
  13.     exit('Error: could not select the database');
  14. }
  15. ?>
Simply replace the default values of the variables at the top of the page with your own date, save the file and you're good to go!
Source: tutsplus (countinue )

For more information , please support and follow us.
 Suggest for you:

The Complete PHP with MySQL Developer Course (New)

PHP MySQL Database Connections

Learn Database Design with MySQL

Modern Programming with PHP

Learn Redis from Scratch

No comments:

Post a Comment