diff --git a/README.md b/README.md index 1e952f3..62c63fe 100644 --- a/README.md +++ b/README.md @@ -7,244 +7,279 @@ # Table of Contents - [Table of Contents](#table-of-contents) - - [Installation](#installation) - - [Requirements](#requirements) - - [Installation Steps](#installation-steps) - - [Getting started](#getting-started) - - [Existing Accounts:](#existing-accounts) - - [Features](#features) + - [Getting Started](#getting-started) + - [Requirements](#requirements) + - [Installation](#installation) + - [Existing Account(s)](#existing-accounts) + - [Project File Structure](#project-file-structure) + - [Building on top of System](#building-on-top-of-system) - [Components](#components) - - [Languages](#languages) - - [Development Environment](#development-environment) - - [Database](#database) - - [DBMS](#dbms) - - [API](#api) - - [Frameworks and Libraries](#frameworks-and-libraries) - - [External Plugins](#external-plugins) - - [Details](#details) - - [Registration / Signup System](#registration--signup-system) - - [Login System](#login-system) - - [Profile System](#profile-system) - - [Profile Editing System](#profile-editing-system) + - [Languages](#languages) + - [Development Environment](#development-environment) + - [External Resources/Plugins](#external-resourcesplugins) + - [Features](#features) + - [Easy Integration](#easy-integration) + - [Login | Signup](#login--signup) + - [User Profile | Profile Editing](#user-profile--profile-editing) + - [Email Verification | Account Activation](#email-verification--account-activation) + - [Password Resetting](#password-resetting) + - [Auth Verification](#auth-verification) + - [Remember Me Feature](#remember-me-feature) + - [GLOBAL temp ERROR & STATUS values](#global-temp-error--status-values) - [Contact System](#contact-system) - - [Security](#security) - - [KLiK - Social Media Website](#klik---social-media-website) + - [Future Improvements](#future-improvements) + - [Contribution Guidelines](#contribution-guidelines) + - [License](#license) + - [Personal Note](#personal-note) -## Installation +## Getting Started -#### Requirements +### Requirements * PHP * Apache server * MySQL > All of these requirements can be collectively completed by simply installing a server stack like `Wamp` or `Xampp` -#### Installation Steps -1. Import the `DBcreation.sql` file in the `includes` folder into phpMyAdmin. There is no need for any change in the .sql file. This will create the database required for the application to function. +### Installation +1. Import the file `assets/setup/db.inc.php` into the current DBMS. The dump file also creates database, so no other action is needed. If databse needs to be updated, change it in the dump file. -2. Edit the `dbh.inc.php` file in the `includes` folder to create the database connection. Change the password and username to the ones being used within `phpMyAdmin`. There is no need to change anything else. +2. Edit the `assets/setup/env.php` and change the variables to correct values. Port value is usually not needed in Database connections. Only edit if you know what you are doing. Setup the email server configurations, which will be used to send confirmation, validation and notification emails. ```php -$serverName = "localhost"; -$dBUsername = "root"; -$dBPassword = "examplePassword"; -$dBName = "loginsystem"; +if (!defined('APP_NAME')) define('APP_NAME' ,'Login System'); +if (!defined('APP_ORGANIZATION')) define('APP_ORGANIZATION' ,'KLiK'); +if (!defined('APP_OWNER')) define('APP_OWNER' ,'msaad1999'); +if (!defined('APP_DESCRIPTION')) define('APP_DESCRIPTION' ,'Embeddable PHP Login System'); -$conn = mysqli_connect($serverName, $dBUsername, $dBPassword, $dBName, 3307); -if (!$conn) -{ - die("Connection failed: ". mysqli_connect_error()); -} -``` -> The port number does not need to be changed under normal circumstances, but if you are running into a problem or the server stack is installed on another port, feel free to change it, but do so carefully. +if (!defined('DB_DATABASE')) define('DB_DATABASE', 'klik_loginsystem'); +if (!defined('DB_HOST')) define('DB_HOST','127.0.0.1'); +if (!defined('DB_USERNAME')) define('DB_USERNAME','root'); +if (!defined('DB_PASSWORD')) define('DB_PASSWORD' ,''); +if (!defined('DB_PORT')) define('DB_PORT' ,''); -3. Edit the `email-server.php` file in the `includes` folder and change the variables accordingly: - * `$SMTPuser` : email address on `gmail` - * `$SMTPpwd` : email address password - * `SMTPtitle` : hypothetical company's name +if (!defined('MAIL_HOST')) define('MAIL_HOST', 'smtp.gmail.com'); +if (!defined('MAIL_USERNAME')) define('MAIL_USERNAME', 'example.email@gmail.com'); +if (!defined('MAIL_PASSWORD')) define('MAIL_PASSWORD', 'example_password'); +if (!defined('MAIL_ENCRYPTION')) define('MAIL_ENCRYPTION', 'ssl'); +if (!defined('MAIL_PORT')) define('MAIL_PORT', 465); +``` + +### Existing Account(s) +The database already contains a sample account to test things out with. Use that or head over to the signup page and start making new accounts. ```php -$SMTPuser = 'klik.official.website@gmail.com'; -$SMTPpwd = 'some-example-password'; -$SMTPtitle = "KLiK inc."; -``` -> This step is mainly for setting up an email account to enable the `contact` and `password reset system`, all of which require mailing. +// credentials for existing account -#### Getting started -The database already contains two pre-made accounts for you to explore around with. If not sufficient, head over to the `signup page` and start making new accounts. -##### Existing Accounts: -``` -username: admin -password: admin -``` -``` username: user password: user ``` -> **Note:** The GUI files are in the `root directory`, and the `backend files` are present in the `includes` folder. The main HTML structuring files are the `HTML-head.php` and `HTML-footer.php`, which also reside in the includes folder +### Project File Structure -## Features + +| Path / File | Purpose | +| -- | -- | +| `[accessible URLs/Pages]` | All folders in root director except assets. | +| `assets/css` | Folder for global or layout-specific custom CSS files. | +| `assets/images` | Images used in website UI. | +| `assets/includes` | Functions or classes. | +| `assets/js` | Custom js files. | +| `assets/README assets` | Pictures/screenshots used in project's README. | +| `assets/setup` | Project configuration and setup files. | +| `assets/uploads` | Folder for all content uploaded by application users. | +| `assets/uploads/users` | Images uploaded by users. | +| `assets/vendor` | Folder for all plugins/resources.| + +### Building on top of System -* [Registration / Signup System](#registration-signup-system) -* [Login System](#login-system) -* [Profile System](#profile-system) -* [Profile Editing System](#profile-editing-system) -* [Contact System](#contact-system) +Best way to start building any custom application after setting up this Authentication system would include adopting the same file structure conventions, in order to avoid extra and/or unneeded effort to synchronise the entire project. New pages can be quickly added by creating more folders in the root directory, with the main frontend file being `index.php`, backend functionalities in `includes` folder and custom styling in the `custom.css` file, present in the same top-level folder as that of index.php. +New function groups or classes can be created in new files in `assets/includes/` folder, and will have to be included in relevant pages. if the added functionalities are mostly universal, they can be required in th `assets/layouts/header.php` file. In the same way, more global css files can be saved in `assets/css` and included in the header.php layout file. Same convention will hold for JS files, with the scripts being in `assets/js/` and included in `assets/layouts/footer.php` file. + +Additional plugins or offline resources can be placed in `assets/vendor/` folder and linked-to in either the header or footer layout file, depending on the file type to be linked. ## Components -#### Languages -``` -PHP 5.6.40 -SQL 14.0 -HTML5 -CSS3 -``` +### Languages -#### Development Environment -``` -WampServer Stack 3.0.6 -Windows 10 -``` +- PHP-7.3.11 +- MySQLi API +- HTML5 +- CSS3 -#### Database -``` -MySQL Database 8.0.13 -``` +### Development Environment -#### DBMS -``` -phpMyAdmin 4.8.3 -``` +- Apache-2.4.41 +- Windows 10 -#### API -``` -MySQLi APIs +### External Resources/Plugins + +- PHPMailer-6.0.6 +- Bootstrap-4.3.1 +- Font awesome-5.12.0 +- JQuery-3.4.1 + +## Features + +### Easy Integration + +The application is designed to be easily embeddable and is meant to be built upon. The current UI has been built mostly on raw bootstrap, and is meant to be completely replaces rather than improved upon. The purpose of this project is to provide the needed backend functionality, and all UI elements should be replaced and rebuilt when creating a separate application. + +It is recommended that the application be installed/embedded into the project before creation of application backend and preferably the frontend as well. Otherwise, if the existing file structure conflicts with this project's, it may cause problems and will make it difficult to re-synchronise the entire project again. + +The project was created with the standard PHP development file structure, in order to maintain flexibility. Simply add more features/ pages in the same way the sample page-folders in the root folder are created. + +In each page folder, the index.php is the main target page, the includes folder holds the backend functionality and the custom.css enables custom designs on top of a global css file without interfering with other pages. + +### Login | Signup + +The system supports a default and secure login and signup system. The user can signup to make a new account, and then will be prompted to login to the new account with his credentials. The user can also set his profile image on signup. To make a new account, the user must set a unique username and email. There are also additional information fields available, but they are optional and can be skipped. + +The login system also supports a `remember me` feature, which will keep the user logged in for a certain time (currently a month) even if the browser or system is turned off. + +### User Profile | Profile Editing + +The system supports a proper user profile accessible on registration. Currently only a few extra-information fields have been put into the database, namely the user's first name, last name, gender, profile headline and bio. These are only meant to showcase the use of additional user information. The user also has a profile image that he can choose/set at signup and can also update it later. + +There is also a profile update system, in which the user can update all of his information. In current system, the user must have a unique username and emai, so the system confirms the availability of new username or email if they were changed for profile updation. + +> The system can also update the user's profile image, and deletes the old image afterwards to prevent useless images piling up in the server's file system. + +There is also a separate check for the password updation, which requires the user to input the current password and confirm the new password as well. Once password is updated, a notification email is sent to the user on his (now) current email address. + +### Email Verification | Account Activation + +On signup / registration, the system gives the user access to the new account, but with limited access. On successful signup, a confirmation mail is sent to the user's email, with a secure verification link. once the link is accessed, the account is unlocked/activated and the user can access all the additional functionalities. The link is created with encrypted selector and token fields, while the respective entry is created in the database for verification whenever the link is accessed. + +The database fields which determines if the account is verified/unlocked or not is the `verified_at` column. If the column is NULL, then the account is not verified. The verification email sent to the user sets that column value to the current Date/Time at that point, hence unlocking the account. + +On login, the script checks the `verified_at` column and sets the value of `$_SESSION['auth']` accordingly. If the user is unverified, he is redirected to the `APPLICATION_PATH/verify` page where he is prompted to activate his account with the sent email. In case that the user did not receive the email, an option is provided for him to resend that email. Once the account is activated and the page is refreshed, the user will be redirected away from the verify page to the default `APPLICATION_PATH/home` page. + +### Password Resetting + +There is also a password reset system, or well known terminology, a `forgot password?` feature. Link to that feature is present on the login page below the login form, and requires that the user input his email with which he had signed up. If the email is not present in the database, the request is ignored, and if it is, a highly secure confirmation email is sent to the user. The user can access the link provided in that email, which will force him to recreate his password, and once done, will prompt the user to log in with the new credentials. + +the confirmation / reset email uses the `auth_tokens` table in the database to create a secure selector and token for the user, then appends them to the reset link after encryption. The token has a certain expiry time (currently 1 hour), after which it becomes invalid. + +### Auth Verification + +The system handles authentication checks with the help of specific functions stored in `assets/includes/auth_functions.php`. There are multiple functions to determine current state of the user. And the checks can be applied to any page in just one like by simply calling the respective function at the top of the file. + +The available functions (as of right now) are: + +```php +function check_logged_in() { ... } +function check_logged_in_butnot_verified() { ... } +function check_logged_out() { ... } +function check_verified() { ... } +function check_remember_me() { ... } +function force_login($email) { ... } ``` -#### Frameworks and Libraries +Each page can be set to accept users in a certain state by simply calling the respective function at the top of the file. + +```php +// Home page, only meant for verified users + +define('TITLE', "Home"); +include '../assets/layouts/header.php'; +check_verified(); ``` -BootStrap v4.2.1 + +### Remember Me Feature + +The system's login system has a `remember me` feature, which keeps the user logged in even if the browser or device is shutdown. During logging in, if the user checked the `rememer me` option, the feature sets a secure cookie with encrypted selector and token values, and creates the respective values in the auth_tokens table in the database. + +```php +$selector = bin2hex(random_bytes(8)); +$token = random_bytes(32); +setcookie( + 'rememberme', + $selector.':'.bin2hex($token), + time() + 864000, + '/', + NULL, + false, + true +); ``` -#### External Plugins +To validate the cookie, the system uses the `check_remember_me()` function in the `assets/includes/auth_functions.php` file. Once the encrypted values are verified against the ones stored in the database, it calls the `force_login()` method which simply creates the relevant session variables for the user and logs him/her in. + +### GLOBAL temp ERROR & STATUS values + +The project uses a global ERROR variable for any errors, assigned as an associative array to $_SESSION['ERRORS'], with the keys being error names and values being error messages. These values are temporary, meaning that the error values disappear when the page is refreshed, returning the page to its original state. This keeps the URLs clean (by not using URL queries) and the associative array means that on occurence of any error, a new key with any name could be created and given the error message as the value, and could easily be dealt with on the frontend files as well. + +For example, an example of creating an error an assigning it to $_SESSION['ERRORS'] in a backend script is: + +```php +// checking email availability + +if ($_SESSION['email'] != $email && !availableEmail($conn, $email)) { + + $_SESSION['ERRORS']['emailerror'] = 'email already taken'; + header("Location: ../"); + exit(); +} ``` -[PHPMailer 6.0.6](https://github.com/PHPMailer/PHPMailer) + +Similarly, this is how the error can be accessed on the visible frontend file: + +```html +// profile update form with email field + +
-
-
+
|
+ ||||||||||||
+ | ||||||||||||
+ |