[Tut] PHP Login Form with MySQL database and form validation - Printable Version +- Sick Gaming (https://www.sickgaming.net) +-- Forum: Programming (https://www.sickgaming.net/forum-76.html) +--- Forum: PHP Development (https://www.sickgaming.net/forum-82.html) +--- Thread: [Tut] PHP Login Form with MySQL database and form validation (/thread-99131.html) |
[Tut] PHP Login Form with MySQL database and form validation - xSicKxBot - 04-04-2022 PHP Login Form with MySQL database and form validation <div style="margin: 5px 5% 10px 5%;"><img src="https://www.sickgaming.net/blog/wp-content/uploads/2022/03/php-login-form-with-mysql-database-and-form-validation.jpg" width="550" height="573" title="" alt="" /></div><div><div class="modified-on" readability="7.0697674418605"> by <a href="https://phppot.com/about/">Vincy</a>. Last modified on March 1st, 2022.</div> <p>Login form – an entry point of a website to authenticate users. PHP login system requires users to register with the application first to log in later.</p> <p>The registered users are managed in a database at the back end. On each l<a href="https://phppot.com/wordpress/how-to-limit-login-attempts-in-wordpress/">ogin attempt via the PHP login form</a>, it verifies the database to find a match.</p> <p>It is a very simple and essential job. At the same time, it should be designed with security to guard the site. It should filter anonymous hits 100% not to let unregistered users get in.</p> <p>The PHP login form action stores the logged-in user in a session. It uses <a href="https://www.php.net/manual/en/language.variables.superglobals.php" target="_blank" rel="noopener">PHP $_SESSION one of its superglobals</a>. It’s better to validate the existence of this session at the beginning of each page to be protected.</p> <p>This PHP code can also be used to add an admin login for your control panel. Also, it can be used as a common authentication entry for both admin and user side of an application.</p> <h2>PHP login form code</h2> <p>This example is to design a PHP login form working with backend processing. The login page in PHP shows the UI elements like social login, forgot password and etc.</p> <p>It posts data to process a username/password-based login authentication. This example uses the database to authenticate the user login.</p> <p>This PHP login system is capable of linking the following code to the additional login form controls.</p> <ol> <li>Link PHP <a href="https://phppot.com/php/php-forgot-password-recover-code/">forgot/reset password</a> feature.</li> <li>Link <a href="https://phppot.com/php/php-wizard-like-registration/">User registration PHP example</a> to the sign-up option.</li> <li>Also, Link <a href="https://phppot.com/php/facebook-open-authentication-in-php/">Oauth login with Facebook</a>, <a href="https://phppot.com/php/login-with-twitter-using-oauth1-0a-protocol-via-api-in-php/">Twitter</a> and <a href="https://phppot.com/php/simple-php-linkedin-oauth-login-integration/">Linkedin</a>.</li> </ol> <p><img loading="lazy" class="alignnone size-large wp-image-16170" src="https://phppot.com/wp-content/uploads/2022/02/php-login-form-550x573.jpg" alt="php login form" width="550" height="573" srcset="https://phppot.com/wp-content/uploads/2022/02/php-login-form-550x573.jpg 550w, https://phppot.com/wp-content/uploads/2022/02/php-login-form-288x300.jpg 288w, https://phppot.com/wp-content/uploads/2022/02/php-login-form.jpg 690w" sizes="(max-width: 550px) 100vw, 550px"></p> <h2>HTML form template</h2> <p>The landing page renders this template into the UI to let the user log in. It will happen when there is no logged-in session.</p> <p>This form accepts the user’s login details username or email and a secure password. The <a href="https://phppot.com/jquery/prevent-form-double-submit-using-jquery/">submit event</a> triggers the PHP login form validation and posts the login data to the PHP.</p> <p>This PHP login form is responsive to the different viewport sizes. It uses <a href="https://phppot.com/php/php-responsive-image-gallery-using-css-media-queries/">simple CSS media queries for adding site responsiveness</a>.</p> <p>The form tag calls a JavaScript function <em>validate()</em> on the submit event. The below code includes the PHP login form validation script at the end.</p> <p class="code-heading">view/login-form.php</p> <pre class="prettyprint"><code class="language-php"> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>User Login</title> <link href="./view/css/form.css" rel="stylesheet" type="text/css" /> <style> body { font-family: Arial; color: #333; font-size: 0.95em; background-image: url("./view/images/bg.jpeg"); } </style> </head> <body> <div> <form action="login-action.php" method="post" id="frmLogin" onSubmit="return validate();"> <div class="login-form-container"> <div class="form-head">Login</div> <?php if (isset($_SESSION["errorMessage"])) { ?> <div class="error-message"><?php echo $_SESSION["errorMessage"]; ?></div> <?php unset($_SESSION["errorMessage"]); } ?> <div class="field-column"> <div> <label for="username">Username</label><span id="user_info" class="error-info"></span> </div> <div> <input name="user_name" id="user_name" type="text" class="demo-input-box" placeholder="Enter Username or Email"> </div> </div> <div class="field-column"> <div> <label for="password">Password</label><span id="password_info" class="error-info"></span> </div> <div> <input name="password" id="password" type="password" class="demo-input-box" placeholder="Enter Password"> </div> </div> <div class=field-column> <div> <input type="submit" name="login" value="Login" class="btnLogin"></span> </div> </div> <div class="form-nav-row"> <a href="#" class="form-link">Forgot password?</a> </div> <div class="login-row form-nav-row"> <p>New user?</p> <a href="#" class="btn form-link">Signup Now</a> </div> <div class="login-row form-nav-row"> <p>May also signup with</p> <a href="#"><img src="view/images/icon-facebook.png" class="signup-icon" /></a><a href="#"><img src="view/images/icon-twitter.png" class="signup-icon" /></a><a href="#"><img src="view/images/icon-linkedin.png" class="signup-icon" /></a> </div> </div> </form> </div> <script> function validate() { var $valid = true; document.getElementById("user_info").innerHTML = ""; document.getElementById("password_info").innerHTML = ""; var userName = document.getElementById("user_name").value; var password = document.getElementById("password").value; if(userName == "") { document.getElementById("user_info").innerHTML = "required"; $valid = false; } if(password == "") { document.getElementById("password_info").innerHTML = "required"; $valid = false; } return $valid; } </script> </body> </html> </code></pre> <h2>PHP login form action</h2> <p>A PHP endpoint script that is an action target of the login form handles the login data.</p> <p>This login page in PHP sanitizes the data before processing them. It uses <a href="https://phppot.com/php/php-input-filtering/">PHP <i>filter_var</i> function to sanitize</a> the user entered authentication details.</p> <p>It conducts the authentication process after receiving the user credentials.</p> <p>This program puts the authenticated user details in a session. Then, it <a href="https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#login" target="_blank" rel="noopener">acknowledges the user</a> accordingly.</p> <p class="code-heading">login-action.php</p> <pre class="prettyprint"><code class="language-php"> <?php namespace Phppot; use \Phppot\Member; if (! empty($_POST["login"])) { session_start(); $username = filter_var($_POST["user_name"], FILTER_SANITIZE_STRING); $password = filter_var($_POST["password"], FILTER_SANITIZE_STRING); require_once (__DIR__ . "/class/Member.php"); $member = new Member(); $isLoggedIn = $member->processLogin($username, $password); if (! $isLoggedIn) { $_SESSION["errorMessage"] = "Invalid Credentials"; } header("Location: ./index.php"); exit(); } </code></pre> <h2>PHP login authentication model class</h2> <p>It contains the processLogin() function to check the PHP login form data with the database. It uses PHP <em>password_verify()</em> function to validate the user-entered password. This PHP function compares the password with the hashed password on the database.</p> <p>The getMemberById() function reads the member result by member id. After successful login, it is called from the case to display the dashboard. It returns the array of data to be displayed on the dashboard.</p> <p class="code-heading">class/Member.php</p> <pre class="prettyprint"><code class="language-php"> <?php namespace Phppot; use \Phppot\DataSource; class Member { private $dbConn; private $ds; function __construct() { require_once "DataSource.php"; $this->ds = new DataSource(); } function getMemberById($memberId) { $query = "select * FROM registered_users WHERE id = ?"; $paramType = "i"; $paramArray = array($memberId); $memberResult = $this->ds->select($query, $paramType, $paramArray); return $memberResult; } public function processLogin($username, $password) { $query = "select * FROM registered_users WHERE user_name = ? OR email = ?"; $paramType = "ss"; $paramArray = array($username, $username); $memberResult = $this->ds->select($query, $paramType, $paramArray); if(!empty($memberResult)) { $hashedPassword = $memberResult[0]["password"]; if (password_verify($password, $hashedPassword)) { $_SESSION["userId"] = $memberResult[0]["id"]; return true; } } return false; } } </code></pre> <h2>Show dashboard and logout link after PHP login</h2> <p>After successful login, the site says there exists a session of the logged-in user. It can be shown in different ways.</p> <p>In most sites, the site header displays the logged-in user’s profile link. It can be a clickable avatar that slides down a profile menu.</p> <p>This PHP login system redirects the user to a dashboard page after login. This dashboard page shows a welcome message, about-user with an avatar.</p> <p>The landing page checks the PHP session if any user has already login. If so, it will redirect to this dashboard page.</p> <p class="code-heading">view/dashboard.php</p> <pre class="prettyprint"><code class="language-php"> <?php namespace Phppot; use \Phppot\Member; if (! empty($_SESSION["userId"])) { require_once __DIR__ . './../class/Member.php'; $member = new Member(); $memberResult = $member->getMemberById($_SESSION["userId"]); if(!empty($memberResult[0]["display_name"])) { $displayName = ucwords($memberResult[0]["display_name"]); } else { $displayName = $memberResult[0]["user_name"]; } } ?> <html> <head> <title>User Login</title> <style> body { font-family: Arial; color: #333; font-size: 0.95em; } .dashboard { background: #d2edd5; margin: 15px auto; line-height: 1.8em; color: #333; border-radius: 4px; padding: 30px; max-width: 400px; border: #c8e0cb 1px solid; text-align: center; } a.logout-button { color: #09f; } .profile-photo { width: 100px; border-radius: 50%; } </style> </head> <body> <div> <div class="dashboard"> <div class="member-dashboard"> <p>Welcome <b><?php echo $displayName; ?>!</b></p> <p><?php echo $memberResult[0]["about"]; ?></p> <p><img src="./view/images/photo.jpeg" class="profile-photo" /></p> <p>You have successfully logged in!</p> <p>Click to <a href="./logout.php" class="logout-button">Logout</a></p> </div> </div> </div> </body> </html> </code></pre> <p><img loading="lazy" class="alignnone size-large wp-image-16193" src="https://phppot.com/wp-content/uploads/2022/02/php-logged-in-user-dashboard-550x457.jpg" alt="PHP Logged in User Dashboard" width="550" height="457" srcset="https://phppot.com/wp-content/uploads/2022/02/php-logged-in-user-dashboard-550x457.jpg 550w, https://phppot.com/wp-content/uploads/2022/02/php-logged-in-user-dashboard-300x250.jpg 300w, https://phppot.com/wp-content/uploads/2022/02/php-logged-in-user-dashboard.jpg 600w" sizes="(max-width: 550px) 100vw, 550px"></p> <h3>Logging out from the site</h3> <p>This is a general routine to log out from the site. The following script clears the PHP session. Then it redirects back to login page in PHP.</p> <p>Sometimes, the logout case may clear cookies. Example: In the case of using a cookie-based <a href="https://phppot.com/php/secure-remember-me-for-login-using-php-session-and-cookies/">Remember Me feature in login</a>.</p> <p class="code-heading">view/dashboard.php</p> <pre class="prettyprint"><code class="language-php"> <?php session_start(); $_SESSION["user_id"] = ""; session_destroy(); header("Location: index.php"); </code></pre> <h2>Files structure</h2> <p>See the below image that shows the file structure of this simple PHP login form example. It contains a featured login form UI with the application <em>view</em> files.</p> <p>The <i>login action</i> calls the PHP model on the submit event. It performs backend authentication with the database.</p> <p><img loading="lazy" class="alignnone size-full wp-image-16188" src="https://phppot.com/wp-content/uploads/2022/02/php-login-form-files.jpg" alt="php login form files" width="250" height="242"></p> <h2>Database script</h2> <p>Look at this SQL script which contains the CREATE statement and sample row data.</p> <p>By importing this SQL, it creates database requisites in your development environment.</p> <p>The sample data helps to try a login that returns success response on the authentication.</p> <p><strong>Test data:</strong> <code>username: kate_91</code> <code>password: admin123</code></p> <p class="code-heading">sql/database.sql</p> <pre class="prettyprint"><code class="language-php"> -- -- Database: `blog_eg` -- -- -------------------------------------------------------- -- -- Table structure for table `registered_users` -- CREATE TABLE `registered_users` ( `id` int(8) NOT NULL, `user_name` varchar(255) NOT NULL, `display_name` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, `photo` text DEFAULT NULL, `about` text DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- -- Dumping data for table `registered_users` -- INSERT INTO `registered_users` (`id`, `user_name`, `display_name`, `password`, `email`, `photo`, `about`) VALUES (1, 'kate_91', 'Kate Winslet', '$2y$10$LVISX0lCiIsQU1vUX/dAGunHTRhXmpcpiuU7G7.1lbnvhPSg7exmW', '[email protected]', 'images/photo.jpeg', 'Web developer'); -- -- Indexes for dumped tables -- -- -- Indexes for table `registered_users` -- ALTER TABLE `registered_users` ADD PRIMARY KEY (`id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `registered_users` -- ALTER TABLE `registered_users` MODIFY `id` int(8) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; </code></pre> <h2>Secure DataSource using MySQL with prepared statements</h2> <p>This DataSource is a common file to be used in any stand-alone PHP application. It uses MySQLi with prepared statement to execute database queries. It works with PHP 8 and 7+</p> <p class="code-heading">class/DataSource.php</p> <pre class><code class="language-php"> <?php namespace Phppot; /** * Generic datasource class for handling DB operations. * Uses MySqli and PreparedStatements. * * @version 2.3 */ class DataSource { // PHP 7.1.0 visibility modifiers are allowed for class constants. // when using above 7.1.0, declare the below constants as private const HOST = 'localhost'; const USERNAME = 'root'; const PASSWORD = ''; const DATABASENAME = 'blog_eg'; private $conn; /** * PHP implicitly takes care of cleanup for default connection types. * So no need to worry about closing the connection. * * Singletons not required in PHP as there is no * concept of shared memory. * Every object lives only for a request. * * Keeping things simple and that works! */ function __construct() { $this->conn = $this->getConnection(); } /** * If connection object is needed use this method and get access to it. * Otherwise, use the below methods for insert / update / etc. * * @return \mysqli */ public function getConnection() { $conn = new \mysqli(self::HOST, self::USERNAME, self::PASSWORD, self::DATABASENAME); if (mysqli_connect_errno()) { trigger_error("Problem with connecting to database."); } $conn->set_charset("utf8"); return $conn; } /** * To get database results * @param string $query * @param string $paramType * @param array $paramArray * @return array */ public function select($query, $paramType="", $paramArray=array()) { $stmt = $this->conn->prepare($query); if(!empty($paramType) && !empty($paramArray)) { $this->bindQueryParams($stmt, $paramType, $paramArray); } $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { $resultset[] = $row; } } if (! empty($resultset)) { return $resultset; } } /** * To insert * @param string $query * @param string $paramType * @param array $paramArray * @return int */ public function insert($query, $paramType, $paramArray) { print $query; $stmt = $this->conn->prepare($query); $this->bindQueryParams($stmt, $paramType, $paramArray); $stmt->execute(); $insertId = $stmt->insert_id; return $insertId; } /** * To execute query * @param string $query * @param string $paramType * @param array $paramArray */ public function execute($query, $paramType="", $paramArray=array()) { $stmt = $this->conn->prepare($query); if(!empty($paramType) && !empty($paramArray)) { $this->bindQueryParams($stmt, $paramType="", $paramArray=array()); } $stmt->execute(); } /** * 1. Prepares parameter binding * 2. Bind prameters to the sql statement * @param string $stmt * @param string $paramType * @param array $paramArray */ public function bindQueryParams($stmt, $paramType, $paramArray=array()) { $paramValueReference[] = & $paramType; for ($i = 0; $i < count($paramArray); $i ++) { $paramValueReference[] = & $paramArray[$i]; } call_user_func_array(array( $stmt, 'bind_param' ), $paramValueReference); } /** * To get database results * @param string $query * @param string $paramType * @param array $paramArray * @return array */ public function numRows($query, $paramType="", $paramArray=array()) { $stmt = $this->conn->prepare($query); if(!empty($paramType) && !empty($paramArray)) { $this->bindQueryParams($stmt, $paramType, $paramArray); } $stmt->execute(); $stmt->store_result(); $recordCount = $stmt->num_rows; return $recordCount; } } </code></pre> <h2>Conclusion</h2> <p>We have seen a <a href="https://phppot.com/php/bootstrap-login-form-template/">simple example on the PHP login form</a>. Hope this will be useful to have a featured, responsive login form.</p> <p>The article interlinks the constellations of a login form. It will be helpful to integrate more features with the existing login template.</p> <p>Let me know your feedback on the comments section if you need any improvements on this PHP login system.</p> <p><a class="download" href="https://phppot.com/downloads/php-login-form.zip">Download</a></p> <p> <!-- #comments --> </p> <div class="related-articles"> <h2>Popular Articles</h2> </p></div> <p> <a href="https://phppot.com/php/php-login-form/#top" class="top">↑ Back to Top</a> </p> </div> https://www.sickgaming.net/blog/2022/03/01/php-login-form-with-mysql-database-and-form-validation/ |