{"componentChunkName":"component---src-templates-blog-post-js","path":"/hands-on-project-twitter-clone-login-and-signup-bff1195190734c759a54fb09875e0cfc/","result":{"data":{"site":{"siteMetadata":{"title":"CommonLounge Archive"}},"markdownRemark":{"id":"a8312e70-ae4f-5754-a5f0-551fda98d605","excerpt":"The wait is finally over! Welcome to your final project for the PHP course. In this three part project, you’ll create a clone of Twitter from scratch using PHP…","html":"<p>The wait is finally over! Welcome to your final project for the PHP course. In this three part project, you’ll create a clone of Twitter from scratch using PHP and some basic HTML and CSS. Completing this project will require the use of all the skills that you have learnt in this course.</p>\n<h1><a href=\"#overview\"></a>Overview</h1>\n<p>Here is an overview of what you will be creating in each of the three parts:</p>\n<ol>\n<li>In the first part, you will learn how to structure your project. Then you will setup your database and create a login and signup page for your twitter clone website.</li>\n<li>In the second part, you will create the user feed and the user profile page.</li>\n<li>In the final part, you will add more features to the website such as follow / unfollow and search.</li>\n</ol>\n<p>The guidance provided in these write-ups will also help you understand how to properly structure your code to incorporate all of the above features. Let’s get started!</p>\n<h1><a href=\"#step-0-resources\"></a>Step 0: Resources</h1>\n<p>Before we begin, <a href=\"https://www.dropbox.com/sh/tm0nqcangbwtxcx/AAAiKmVrPNy9JPQCkoaTCmtaa?dl=0\">download all the project resources here</a>. This includes HTML, CSS and image files that we will be using throughout the project.</p>\n<blockquote>\n<p>We will focus mainly on PHP in this project and will use these resources to take care of the HTML and CSS.</p>\n</blockquote>\n<h1><a href=\"#step-1-directory-structure\"></a>Step 1: Directory Structure</h1>\n<p>Okay. Let’s begin by creating the directory structure for our project:</p>\n<ul>\n<li>Make sure your server running. We covered <em>Running the Server</em> in the <a href=\"https://www.commonlounge.com/discussion/baabed8cf576421392d6a49beb03a9b4\">installation tutorial</a>.</li>\n<li>Open the <code class=\"language-text\">htdocs</code> folder located in <code class=\"language-text\">{your_xampp_directory}</code>.</li>\n<li>Create a new folder inside <code class=\"language-text\">{your_xampp_directory}/htdocs</code> and call it <code class=\"language-text\">twitter</code>.</li>\n</ul>\n<p>Now create 3 new folders inside the <code class=\"language-text\">twitter</code> folder:</p>\n<ol>\n<li><code class=\"language-text\">assets</code>: for images, CSS files and javascript code. Create three folders inside the assets folder: <code class=\"language-text\">css</code>, <code class=\"language-text\">images</code>, <code class=\"language-text\">js</code>.</li>\n<li><code class=\"language-text\">core</code>: for the core files of the project. Create two folders inside the core folder: <code class=\"language-text\">classes</code> and <code class=\"language-text\">database</code>.</li>\n<li><code class=\"language-text\">includes</code>: for all files that will be included in other files.</li>\n</ol>\n<p>Your directory structure will look like this:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/Yowua83OVXTzQnS4ebkUYvGZ31536604829_kc\"></p>\n<p>Now open up the <code class=\"language-text\">project-resources</code> folder that you downloaded and copy-paste the <code class=\"language-text\">assets</code> folder into your project directory (inside <code class=\"language-text\">twitter</code> folder).</p>\n<p>Inside the <code class=\"language-text\">css</code> folder, you will see <code class=\"language-text\">style-complete.css</code> which contains all the CSS for our project. Inside the <code class=\"language-text\">images</code> folder, you will find some background and profile images.</p>\n<h1><a href=\"#step-2-database-connection\"></a>Step 2: Database Connection</h1>\n<p>Create a database in phpMyAdmin and call it <code class=\"language-text\">twitter</code>.</p>\n<p>Create the <code class=\"language-text\">connection.php</code> file inside <code class=\"language-text\">core/database/</code> folder.</p>\n<p>Then, create a file <code class=\"language-text\">index.php</code> inside the <code class=\"language-text\">twitter</code> folder and include the <code class=\"language-text\">connection.php</code> file in it.</p>\n<p><strong>Checkpoint:</strong> Open your browser and type in <code class=\"language-text\">localhost/twitter</code>. If you see a blank page, the database connection is successful. The <code class=\"language-text\">index.php</code> page will be the login and signup page.</p>\n<hr>\n<p>Solution to this section can be found in section <strong>Solution: Database Connection</strong> below.</p>\n<h1><a href=\"#step-3-classes-and-init\"></a>Step 3: Classes and init</h1>\n<p>Okay, now the next step is to answer the question: How many tables do you need? Think about it before seeing the answer below.</p>\n<p>We will have a <code class=\"language-text\">users</code> table to store the user data, a <code class=\"language-text\">tweets</code> table to store the tweets and finally a <code class=\"language-text\">follow</code> table to store the followers and following data. We can later add more tables depending on our requirements. But these are enough for now.</p>\n<hr>\n<p>For each table, you need to create a class.</p>\n<p>Remember the <code class=\"language-text\">Base</code> class which has the generic insert, update and delete functions? Yes, you will be needing that as well.</p>\n<p>Create these 4 classes in separate files inside <code class=\"language-text\">core/classes/</code> folder.</p>\n<hr>\n<p>Solution to this section can be found in section <strong>Solution: Classes and init</strong> below.</p>\n<hr>\n<p>Now we will include all these classes (and also the <code class=\"language-text\">connection.php</code> file) in file <code class=\"language-text\">core/init.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- init.php -->\n&lt;?php  \n  include 'database/connection.php';\n  include 'classes/base.php';\n  include 'classes/user.php';\n  include 'classes/tweet.php';\n  include 'classes/follow.php';\n  global $pdo;\n  session_start();\n  $getFromU = new User($pdo);\n  $getFromT = new Tweet($pdo);\n  $getFromF = new Follow($pdo);\n  define(\"BASE_URL\", \"http://localhost/twitter/\");\n?></code></pre></div>\n<p>Notice that we are setting a global <code class=\"language-text\">$pdo</code> variable to use the <code class=\"language-text\">$pdo</code> database connection object everywhere in the code. We also add the <code class=\"language-text\">session_start()</code> function and create instances of each class. We then create an instance of each of the three classes <code class=\"language-text\">User</code>, <code class=\"language-text\">Tweet</code> and <code class=\"language-text\">Follow</code>. Finally, we use the <code class=\"language-text\">define()</code> function which basically says we want to refer to <code class=\"language-text\">http://localhost/twitter/</code> as <code class=\"language-text\">BASE_URL</code>.</p>\n<p>Now, instead of including the <code class=\"language-text\">connection.php</code> file to <code class=\"language-text\">index.php</code>, we will include <code class=\"language-text\">init.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- index.php -->\n&lt;?php  \n  include 'core/init.php';\n?></code></pre></div>\n<h1><a href=\"#step-4-user-table\"></a>Step 4: User Table</h1>\n<p>Great! Now create a table <code class=\"language-text\">users</code> inside the <code class=\"language-text\">twitter</code> database with 8 columns in phpMyAdmin which should look like this:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/VMMf31STGdIPiOXG8SMiVG2BA1536613652_kc\"></p>\n<p>Most of the rows are self explanatory. <code class=\"language-text\">profileImage</code> will have the path to an image file that is stored on your machine. <code class=\"language-text\">following</code> and <code class=\"language-text\">followers</code> is the number of users the user is following, and the number of followers of a user, respectively.</p>\n<p>Create this table using phpMyAdmin.</p>\n<hr>\n<p>Solution to this section can be found in section <strong>Solution: User Table</strong> below.</p>\n<h1><a href=\"#step-5-index-login-and-sign-up-page-html\"></a>Step 5: Index (login and sign-up) page HTML</h1>\n<p>Great! You created the table <code class=\"language-text\">users</code>, have the <code class=\"language-text\">User</code> class ready and also an instance of the <code class=\"language-text\">User</code> class <code class=\"language-text\">$getFromU</code> (we created this in <code class=\"language-text\">init.php</code>).</p>\n<p>Let’s now work on the front-end and write some PHP code to create the signup and login page (i.e. <code class=\"language-text\">index.php</code>).</p>\n<blockquote>\n<p>In this section, we will provide you the HTML for index.html (for the log-in and sign-up forms). You will write the <code class=\"language-text\">.php</code> code yourself in the next section.</p>\n</blockquote>\n<hr>\n<p>Open the <code class=\"language-text\">project-resources</code> folder and find <code class=\"language-text\">index.html</code>. Copy all the HTML code from here and paste it below the PHP tags in <code class=\"language-text\">index.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- index.php -->\n&lt;?php  \n  include 'core/init.php';\n?>\n&lt;html>\n  &lt;head>\n    &lt;title>Twitter Clone&lt;/title>\n    &lt;meta charset=\"UTF-8\" />\n    &lt;link rel=\"stylesheet\" href=\"assets/css/font/css/font-awesome.css\"/>\n    &lt;link rel=\"stylesheet\" href=\"assets/css/style-complete.css\"/>\n  &lt;/head>\n&lt;body>\n&lt;div class=\"bg\">\n&lt;div class=\"wrapper\">\n&lt;!---Inner wrapper-->\n    &lt;div class=\"inner-wrapper-index\">\n      &lt;!-- main container -->\n      &lt;div class=\"main-container\">\n        &lt;!-- content left-->\n        &lt;div class=\"content-left\">\n          &lt;h1>Welcome to Twitter&lt;/h1>\n          &lt;br/>\n          &lt;p>See what's happening in the world right now.&lt;/p>\n        &lt;/div>&lt;!-- content left ends -->  \n        &lt;!-- content right ends -->\n        &lt;div class=\"content-right\">\n          &lt;!-- Log In Section -->\n          &lt;div class=\"login-wrapper\">\n            &lt;?php include 'includes/login.php' ?>\n          &lt;/div>&lt;!-- log in wrapper end -->\n          &lt;!-- SignUp Section -->\n          &lt;div class=\"signup-wrapper\">\n             &lt;?php include 'includes/signup-form.php' ?>\n          &lt;/div>\n          &lt;!-- SIGN UP wrapper end -->\n        &lt;/div>&lt;!-- content right ends -->\n      &lt;/div>&lt;!-- main container end -->\n    &lt;/div>&lt;!-- inner wrapper ends-->\n  &lt;/div>&lt;!-- ends wrapper -->\n&lt;/div>  \n&lt;/body>\n&lt;/html></code></pre></div>\n<hr>\n<p>Now we need to create the <code class=\"language-text\">login.php</code> and <code class=\"language-text\">signup-form.php</code> files that will have the login and signup forms which we will attach to the <code class=\"language-text\">index.php</code> page. Go ahead and open the <code class=\"language-text\">includes</code> folder and create two new files: <code class=\"language-text\">login.php</code> and <code class=\"language-text\">signup-form.php</code> with simple PHP open and close tags.</p>\n<p>This is how <code class=\"language-text\">includes/login.php</code> will look:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- login.php -->\n&lt;?php  ?></code></pre></div>\n<p>And <code class=\"language-text\">includes/signup-form.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- signup-form.php -->\n&lt;?php  ?></code></pre></div>\n<p><strong>Checkpoint:</strong> Save the files and open <code class=\"language-text\">http://localhost/twitter/</code>. You will see something like this:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/vzCWZn0hdHuROLtk6nMYAC5Fi1536999697_kc\"></p>\n<hr>\n<p>Now we will add the HTML for the forms. Open up the <code class=\"language-text\">project-resources</code> folder and copy paste the HTML from <code class=\"language-text\">login.html</code> and <code class=\"language-text\">signup-form.html</code> below the PHP tags inside <code class=\"language-text\">login.php</code> and <code class=\"language-text\">signup-form.php</code> respectively.</p>\n<p><strong>Checkpoint:</strong> Refresh the browser, and you should see this:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/eBNMmy9TbdecfoqeBDLkorJKs1536999704_kc\"></p>\n<p>Looking good, right? Time to make the login and signup forms work.</p>\n<h1><a href=\"#step-6-login-form\"></a>Step 6: Login Form</h1>\n<p>Let’s create a record in the users table so that we can login with an email and password. Open phpMyAdmin and in the users table, browse to the SQL tab and execute this statement:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">INSERT INTO `users`(`username`, `email`, `password`, `fullname`, `profileImage`) VALUES (\"jamesmat\",\"jamesmat@test.com\",md5(\"password\"),\"James Mat\",\"assets/images/defaultprofile1.png\")</code></pre></div>\n<p>Now check the table for the record:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/1hQxRQFnhA4LOWhPGinFuiDcA1537009434_kc\"></p>\n<blockquote>\n<p><code class=\"language-text\">md5()</code> is a hashing function which encrypts the password. You should never store the password text directly. Always store a hash of the password. That way, even if someone maliciously gets access to the database, they will not know the users’ passwords.</p>\n</blockquote>\n<hr>\n<p>OK, now this is your next task:</p>\n<p>When the user enters <code class=\"language-text\">email</code> and <code class=\"language-text\">password</code> in the login form and clicks on the <code class=\"language-text\">Login</code> button:</p>\n<ul>\n<li>Perform <em>form validation</em></li>\n<li>Check that all the inputs are non-empty. If they are, set the <code class=\"language-text\">$error</code> variable to “Please enter email and password!“.</li>\n<li>Remove special characters from the inputs using the <code class=\"language-text\">checkInput()</code> function.</li>\n<li>Check if the email has a valid format. If not, set the <code class=\"language-text\">$error</code> variable to “Invalid Email format”.</li>\n<li>Log the user in</li>\n<li>Check from the database if a user with the given email and password exists. If not, set the <code class=\"language-text\">$error</code> variable to “Invalid username or password”.</li>\n<li>If the user exists, set the session <code class=\"language-text\">user_id</code> variable to the <code class=\"language-text\">user_id</code> of the logged in user and redirect the user to <code class=\"language-text\">home.php</code>. Create <code class=\"language-text\">home.php</code>, which includes <code class=\"language-text\">core/init.php</code> and <code class=\"language-text\">echo</code>s the session <code class=\"language-text\">user_id</code> variable.</li>\n</ul>\n<p>Hint 1:</p>\n<p>Do the <em>form validation</em> etc in <code class=\"language-text\">login.php</code>, but create helper methods in <code class=\"language-text\">User</code> class.</p>\n<p>Hint 2:</p>\n<p>Create methods <code class=\"language-text\">checkInput()</code> and <code class=\"language-text\">login()</code> inside the <code class=\"language-text\">User</code> class and access them like <code class=\"language-text\">$getFromU->checkInput()</code> and <code class=\"language-text\">$getFromU->login()</code> in <code class=\"language-text\">login.php</code>.</p>\n<blockquote>\n<p>Your browser might re-submit a form when you refresh. This might cause you some confusion as you are debugging your code. For example, suppose you try to log-in, but there is some error in your code. After fixing the error, when you refresh your browser, your browser might automatically re-submit the form data as you had filled it last time. So you might see a another error even without filling the form, or you might get logged-in (if your code is working now).</p>\n</blockquote>\n<hr>\n<p><strong>Checkpoint:</strong> Enter the email and password that you added in the database and hit login.</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/pVvx1Md2g1YCvrPpQcLxAVQgc1537009439_kc\"></p>\n<p>If you are redirected to <code class=\"language-text\">home.php</code> and you see the <code class=\"language-text\">user_id</code> of the logged in user, everything is working fine. In this case the output would be:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">1</code></pre></div>\n<p>Also, try different incorrect / empty inputs and see if the corresponding error messages are displayed or not.</p>\n<hr>\n<p>Solution to this section can be found in section <strong>Solution: Login form</strong> below.</p>\n<h1><a href=\"#step-7-signup-form\"></a>Step 7: Signup form</h1>\n<p>Awesome, the login form is working as expected. Let’s get the signup form working too. This is your task:</p>\n<p>When the user enters the full-name, username, email and password in the signup form and clicks on the <code class=\"language-text\">Signup</code> button,</p>\n<ul>\n<li>Perform <em>form validation</em></li>\n<li>Check if all the inputs are not empty. If they are, set the <code class=\"language-text\">$signupError</code> variable to “Please enter email and password!“.</li>\n<li>Remove special characters from the inputs using the <code class=\"language-text\">checkInput()</code> function.</li>\n<li>Check if the email has a valid format. If not, set the <code class=\"language-text\">$signupError</code> variable to “Invalid Email format”.</li>\n<li>The full-name and username fields should be below 20 characters. If this is not true, set the <code class=\"language-text\">$signupError</code> variable to “Name must be between 6-20 characters”.</li>\n<li>If the length of the password is below 5 characters, set <code class=\"language-text\">$signupError</code> to “Password too short”.</li>\n<li>Create user account</li>\n<li>Check from the database if a user with the given email or username already exists. If a row is returned, set the <code class=\"language-text\">$signupError</code> variable to “Email already registered” or “Username already exists” respectively.</li>\n<li>If all the above checks are completed and all the inputs are correct, create a new record with the given details and set the session <code class=\"language-text\">user_id</code> variable to the <code class=\"language-text\">user_id</code> of the new user and redirect the user to <code class=\"language-text\">home.php</code>.</li>\n</ul>\n<p>Hint 1:</p>\n<p>Create new methods <code class=\"language-text\">checkEmail()</code> and <code class=\"language-text\">checkUsername()</code> inside the <code class=\"language-text\">User</code> class which will check if a user with the given email or username already exists and access them as <code class=\"language-text\">$getFromU->checkEmail()</code> and <code class=\"language-text\">$getFromU->checkUsername()</code> in <code class=\"language-text\">login.php</code>.</p>\n<p>Hint 2:</p>\n<p>Use the <code class=\"language-text\">$getFromU->create()</code> method to create the new record in the users table.</p>\n<p>Use <code class=\"language-text\">assets/images/defaultprofile1.png</code> as the default value for <code class=\"language-text\">profileImage</code> of the user. In this project, we will not implement a way for the user to edit his profile image. If you want, you can change this value in the <code class=\"language-text\">users</code> table directly from phpMyAdmin.</p>\n<hr>\n<p><strong>Checkpoint:</strong> Go ahead and refresh your browser and enter some details into the signup form. Try incorrect / empty inputs and see if the appropriate error messages are being displayed or not.</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/NSHZZ86fciwZotWxw1TLeEu4V1537034379_kc\"></p>\n<p>Once you click on <code class=\"language-text\">Signup</code>, you should be redirected to <code class=\"language-text\">home.php</code> and the new <code class=\"language-text\">user_id</code> should be displayed. In this case, the output would be:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">2</code></pre></div>\n<p>Also verify that the row created in your database table looks as you would expect it to be.</p>\n<hr>\n<p>Solution to this section can be found in section <strong>Solution: Signup form</strong> below.</p>\n<hr>\n<p>Amazing! You just finished implementing the created the login and signup flow!</p>\n<h1><a href=\"#step-8-home-page\"></a>Step 8: Home page</h1>\n<p>Now, let’s add some HTML to <code class=\"language-text\">home.php</code> and a method to fetch all the user details from the table to display them on the home page.</p>\n<hr>\n<p>Add a method in the <code class=\"language-text\">User</code> class which will fetch all the user data for a given <code class=\"language-text\">user_id</code>. Let’s call it <code class=\"language-text\">userData()</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">public function userData($user_id) {\n    $stmt = $this->pdo->prepare(\"SELECT * FROM users WHERE user_id = :user_id\");\n    $stmt->bindParam(\":user_id\", $user_id, PDO::PARAM_INT);\n    $stmt->execute();\n    return $stmt->fetch(PDO::FETCH_OBJ);\n}</code></pre></div>\n<hr>\n<p>Open the <code class=\"language-text\">project-resources</code> folder and copy-paste the HTML from <code class=\"language-text\">home_1.html</code> below the PHP tags in <code class=\"language-text\">home.php</code>.</p>\n<p>Replace the <code class=\"language-text\">echo</code> in <code class=\"language-text\">home.php</code> with the following lines to call the <code class=\"language-text\">userData()</code> method:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- home.php -->\n&lt;?php\n    include 'core/init.php';\n    $user_id = $_SESSION['user_id'];\n    $user = $getFromU->userData($user_id);\n?></code></pre></div>\n<hr>\n<p><strong>Checkpoint:</strong> Now save the file and try to login with valid email and password. You will see:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/YK4JPGVIUPrHUky4UrYgBg2Sk1537034386_kc\"></p>\n<p>This is how the home page looks like after logging-in!</p>\n<h1><a href=\"#step-9-log-out\"></a>Step 9: Log-out</h1>\n<p>So you have implemented everything required for someone to log-in, but what about log-out? Let’s do it!</p>\n<hr>\n<p>Create a <code class=\"language-text\">logout()</code> method in the <code class=\"language-text\">User</code> class. What all does it need to do?</p>\n<p>Answer:</p>\n<p>All you have to do in the <code class=\"language-text\">logout()</code> method is destroy the session and redirect the user to <code class=\"language-text\">index.php</code>!</p>\n<hr>\n<p>In <code class=\"language-text\">home.php</code>, on the top right corner, you will see a profile icon. Click on it and you will see 2 options: the first will take you to your profile page (we haven’t done this yet!) and the second one says logout.</p>\n<p>On clicking the logout button, you will be redirected to <code class=\"language-text\">logout.php</code> and this file should call the logout method. Create <code class=\"language-text\">logout.php</code> inside the <code class=\"language-text\">includes</code> folder</p>\n<hr>\n<p><strong>Checkpoint:</strong> Now save and try to logout from <code class=\"language-text\">home.php</code>. You should be redirected to the index page as expected.</p>\n<hr>\n<p>Solution to this section can be found in section <strong>Solution: Log-out</strong> below.</p>\n<h1><a href=\"#step-10-restricting-access-to-indexphp-and-homephp\"></a>Step 10: Restricting access to index.php and home.php</h1>\n<p>Final step for part 1! Phew!!</p>\n<p>In this part, you will write the code restrict access to index.php and home.php pages. A user should be able to access <code class=\"language-text\">index.php</code> only if he / she is logged-out, and a user should be able to access <code class=\"language-text\">home.php</code> only if he / she is logged-in.</p>\n<hr>\n<p>If a user tries to access <code class=\"language-text\">index.php</code> from the URL (by typing in <code class=\"language-text\">http://localhost/index.php</code> in the browser) and user has already logged in, we want to redirect the user to <code class=\"language-text\">home.php</code>.</p>\n<p>This can be done by adding the following lines in <code class=\"language-text\">index.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- index.php -->\n&lt;?php  \n  include 'core/init.php';\n  if (isset($_SESSION['user_id'])) {\n    header('Location: home.php');\n  }\n?>\n&lt;!-- html goes here --></code></pre></div>\n<hr>\n<p>And lastly, you need to restrict a user who tries to directly access the <code class=\"language-text\">home.php</code> page (by typing in <code class=\"language-text\">http://localhost/home.php</code> in the browser) without logging in! Currently, this will throw a lot of errors as the session <code class=\"language-text\">user_id</code> won’t be set and we don’t want this to happen, do we?</p>\n<p>To do this, create a method in the <code class=\"language-text\">User</code> class called <code class=\"language-text\">loggedIn()</code> which checks if the session variable <code class=\"language-text\">user_id</code> is set or not.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">public function loggedIn() {\n    if (isset($_SESSION['user_id'])) {\n      return true;\n    } \n    return false;\n}</code></pre></div>\n<p>Then, call this function in <code class=\"language-text\">home.php</code>. Like so:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- home.php -->\n&lt;?php\n    include 'core/init.php';\n    $user_id = $_SESSION['user_id'];\n    $user = $getFromU->userData($user_id);\n    if ($getFromU->loggedIn() === false) {\n        header('Location: index.php');\n    }\n?></code></pre></div>\n<hr>\n<p><strong>Checkpoint:</strong> Great! Now if you try to access <code class=\"language-text\">home.php</code> from the URL without logging in, you will be redirected to the index page. Similarly, if you are logged-in and you try to access <code class=\"language-text\">index.php</code>, you will be redirected to <code class=\"language-text\">home.php</code>.</p>\n<h1><a href=\"#summary\"></a>Summary</h1>\n<p>In this part of the project, you created the index page with login and signup forms and the home page which is the user feed. You also added some HTML and CSS and your website is starting to look better!</p>\n<p>If you lost track, got stuck, or just need to double check, the solution for each of the above steps is included below. You can also find all the code we have written so far <a href=\"https://www.dropbox.com/sh/tfyd0vktgttlsmp/AAA8Yn4V0k3L1WXC1nly36qYa?dl=0\">here</a> (that is, what your current code should look like).</p>\n<p>In the next part of the project, you will work on the user profile and the tweet feature in the user feed page. Aren’t you excited?!</p>\n<h1><a href=\"#solution-database-connection\"></a>Solution: Database Connection</h1>\n<p><code class=\"language-text\">connection.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- connection.php -->\n&lt;?php \n  $dsn  = 'mysql:host=localhost; dbname=twitter'; // database name\n  $user = 'root';\n  $pass = '';\n  try {\n    $pdo = new PDO($dsn, $user, $pass);\n  } catch(PDOException $e) {\n    echo 'Connection error! '. $e->getMessage();\n  }\n?></code></pre></div>\n<p><code class=\"language-text\">index.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- index.php -->\n&lt;?php  \n  include 'core/database/connection.php';\n?></code></pre></div>\n<h1><a href=\"#solution-classes-and-init\"></a>Solution: Classes and init</h1>\n<p><code class=\"language-text\">base.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- base.php -->\n&lt;?php \n  class Base {\n    protected $pdo;\n    function __construct($pdo) {\n      $this->pdo = $pdo;\n    }\n    public function create($table, $fields = array()) {\n      $columns = implode(',', array_keys($fields));\n      $values = ':' . implode(', :', array_keys($fields));\n      $sql = \"INSERT INTO {$table} ({$columns}) VALUES ({$values})\";\n      if ($stmt = $this->pdo->prepare($sql)) {\n        foreach ($fields as $key => $data) {\n          $stmt->bindValue(':'.$key, $data);\n        }\n        $stmt->execute();\n        return $this->pdo->lastInsertId();\n      }\n    }\n    public function update($table, $user_id, $fields = array()) {\n      $columns = '';\n      $i = 1;\n      foreach ($fields as $name => $value) {\n        $columns .= \"{$name} = :{$name}\";\n        if ($i &lt; count($fields)) {\n          $columns .= \", \";\n        }\n        $i++;\n      }\n      $sql = \"UPDATE {$table} SET {$columns} WHERE user_id = {$user_id}\";\n      if ($stmt = $this->pdo->prepare(\"$sql\")) {\n        foreach ($fields as $key => $value) {\n          $stmt->bindValue(':' . $key, $value);\n        }\n        $stmt->execute();\n      }\n    }\n    public function delete($table, $array) {\n      $sql = \"DELETE FROM {$table}\";\n      $where = \" WHERE\";\n      foreach ($array as $name => $value) {\n        $sql .= \"{$where} {$name} = :{$name}\";\n        $where = \" AND \";\n      }\n      if ($stmt = $this->pdo->prepare($sql)) {\n        foreach ($array as $name => $value) {\n          $stmt->bindValue(':'.$name, $value);\n        }\n      }\n      $stmt->execute();\n    }\n  }\n?></code></pre></div>\n<p><code class=\"language-text\">user.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- user.php -->\n&lt;?php  \n  class User extends Base {\n    function __construct($pdo) {\n      $this->pdo = $pdo;\n    }\n  }\n?></code></pre></div>\n<p><code class=\"language-text\">tweet.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- tweet.php -->\n&lt;?php  \n  class Tweet extends Base {\n    function __construct($pdo) {\n      $this->pdo = $pdo;\n    }\n  }\n?></code></pre></div>\n<p><code class=\"language-text\">follow.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- follow.php -->\n&lt;?php  \n  class Follow extends Base {\n    function __construct($pdo) {\n      $this->pdo = $pdo;\n    }\n  }\n?></code></pre></div>\n<h1><a href=\"#solution-user-table\"></a>Solution: User Table</h1>\n<p>Here is how your rows should look like when creating the table:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/mcbRbqHN9o5yneckj77xwh9BD1536613658_kc\"></p>\n<p>Make sure <code class=\"language-text\">A_I</code> for <code class=\"language-text\">user_id</code> is checked and it is the <code class=\"language-text\">PRIMARY</code> key in the table.</p>\n<h1><a href=\"#solution-login-form\"></a>Solution: Login form</h1>\n<p>This is what user.php looks like after adding <code class=\"language-text\">checkInput($var)</code> and <code class=\"language-text\">login($email, $password)</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- user.php -->\n&lt;?php  \n  class User extends Base {\n    function __construct($pdo) {\n      $this->pdo = $pdo;\n    }\n    public function checkInput($var) {\n      $var = htmlspecialchars($var);\n      $var = trim($var);\n      $var = stripslashes($var);\n      return $var;\n    }\n    public function login($email, $password) {\n      $stmt = $this->pdo->prepare(\"SELECT user_id FROM users WHERE email = :email AND password = :password\");\n      $stmt->bindParam(\":email\", $email, PDO::PARAM_STR);\n      $hash = md5($password);\n      $stmt->bindParam(\":password\", $hash, PDO::PARAM_STR);\n      $stmt->execute();\n      $user = $stmt->fetch(PDO::FETCH_OBJ);\n      $count = $stmt->rowCount();\n      if ($count > 0) {\n        $_SESSION['user_id'] = $user->user_id;\n        header('Location: home.php');\n      } else {\n        return false;\n      }\n    }\n  }\n?></code></pre></div>\n<p>The <code class=\"language-text\">login()</code> function queries the database for the email and password. If a row is returned, the session variable is set and the user is redirected to <code class=\"language-text\">home.php</code>. Otherwise, <code class=\"language-text\">login()</code> returns <code class=\"language-text\">false</code>.</p>\n<hr>\n<p><code class=\"language-text\">login.php</code> after adding form validation:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- login.php -->\n&lt;?php  \n  if (isset($_POST['login']) &amp;&amp; !empty($_POST['login'])) {\n    $email = $_POST['email'];\n    $password = $_POST['password'];\n    if(!empty($email) || !empty($password)) {\n      $email = $getFromU->checkInput($email);\n      $password = $getFromU->checkInput($password);\n      if(!filter_var($email, FILTER_VALIDATE_EMAIL)) {\n        $error = \"Invalid email format\";\n      } else {\n        if($getFromU->login($email, $password) === false) {\n          $error = \"The email or password is incorrect\";\n        }\n      }\n    } else {\n      $error = \"Please enter email and password!\";\n    }\n  }\n?>\n&lt;!-- html goes here --> </code></pre></div>\n<p>Finally, we have <code class=\"language-text\">twitter/home.php</code> file which <code class=\"language-text\">echo</code>s the <code class=\"language-text\">user_id</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- home.php -->\n&lt;?php\n    include 'core/init.php';\n    echo $_SESSION['user_id'];\n?></code></pre></div>\n<h1><a href=\"#solution-sign-up-form\"></a>Solution: Sign-up form</h1>\n<p>New methods in the <code class=\"language-text\">User</code> class:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">public function checkEmail($email) {\n    $stmt = $this->pdo->prepare(\"SELECT email FROM users WHERE email = :email\");\n    $stmt->bindParam(\":email\", $email, PDO::PARAM_STR);\n    $stmt->execute();\n    $count = $stmt->rowCount();\n    if ($count > 0) {\n        return true;\n    } else {\n        return false;\n    }\n}\npublic function checkUsername($username) {\n    $stmt = $this->pdo->prepare(\"SELECT username FROM users WHERE username = :username\");\n    $stmt->bindParam(\":username\", $username, PDO::PARAM_STR);\n    $stmt->execute();\n    $count = $stmt->rowCount();\n    if ($count > 0) {\n        return true;\n    } else {\n        return false;\n    }\n}</code></pre></div>\n<p>Form validation in <code class=\"language-text\">signup-form.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- signup-form.php -->\n&lt;?php \n  if (isset($_POST['signup'])) {\n    $fullname = $_POST['fullname'];\n    $username = $_POST['username'];\n    $password = $_POST['password'];\n    $email = $_POST['email'];\n    $signupError = \"\";\n    if(empty($fullname) || empty($username) || empty($password) || empty($email)) {\n      $signupError = 'All feilds are required';\n    } else {\n      $email = $getFromU->checkInput($email);\n      $fullname = $getFromU->checkInput($fullname);\n      $username = $getFromU->checkInput($username);\n      $password = $getFromU->checkInput($password);\n      if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {\n        $signupError = \"Invalid email\";\n      } elseif (strlen($fullname) > 20) {\n        $signupError = \"Name must be between 6-20 characters\";\n      } elseif (strlen($username) > 20) {\n        $signupError = \"Username must be between 4-20 characters\";\n      } elseif (strlen($password) &lt; 5) {\n        $signupError = \"Password too short\";\n      } else {\n        if ($getFromU->checkEmail($email) === true) {\n          $signupError = \"Email already registered\";\n        } elseif ($getFromU->checkUsername($username) === true) {\n          $signupError = \"Username already exists\";\n        }\n        else {\n          $user_id = $getFromU->create('users', array('email' => $email,'password' => md5($password), 'fullname' => $fullname, 'username' => $username, 'profileImage' =>'assets/images/defaultprofile1.png'));\n          $_SESSION['user_id'] = $user_id;\n          header('Location: home.php');\n        }\n      }\n    }\n  }\n?>\n&lt;!-- html goes here --> </code></pre></div>\n<h1><a href=\"#solution-log-out\"></a>Solution: Log-out</h1>\n<p><code class=\"language-text\">logout()</code> method in <code class=\"language-text\">User</code> class:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">public function logout() {\n    session_destroy();\n    header('Location: '. BASE_URL .'index.php');\n}</code></pre></div>\n<p><code class=\"language-text\">includes/logout.php</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">&lt;!-- logout.php -->\n&lt;?php  \n  include '../core/init.php';\n  $getFromU->logout();\n?></code></pre></div>","frontmatter":{"title":"Hands-on Project: Twitter Clone - Login and Signup","date":"September 20, 2018","description":""}}},"pageContext":{"slug":"/hands-on-project-twitter-clone-login-and-signup-bff1195190734c759a54fb09875e0cfc/","previous":{"fields":{"slug":"/quiz-php-data-objects-0e8a5c93cba7486ea86738b72b46993c/"},"frontmatter":{"title":"Quiz: PHP Data Objects"}},"next":{"fields":{"slug":"/hands-on-project-twitter-clone-tweet-user-feed-and-profile-bb5f0b83a507454e921e2a861ac1b397/"},"frontmatter":{"title":"Hands-on Project: Twitter Clone - Tweet, User Feed and Profile"}}}},"staticQueryHashes":["2841359383","2969095810"]}