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 + +
+ + + + + +
``` -> This was used for creating a `mail server` on `Windows localhost`, since there is not one like in Linux. This plugin was used for the sending and receiving of emails on localhost, this is not needed on a live domain - -## Details - -> Details of important Features of the Application - -### Registration / Signup System - -* A `status icon` in the top left corner shows online or logged out status -* registration is done through the `signup` page. -* `username` cannot be changed after signing up, since i thought it would be an exploitable weakness -* `email` required for registration. -* Password needs to be re-entered for additional confirmation -* Passwords `encrypted` before being stored in database so even owners donot have access to them -* User can set a `profile image` at signup. In case they dont, their profile image is set to a default image. - -> currently the upload image button does not give a visible response on clicking and uploading an image, but it does work. It is purely a design matter and not a back-end issue - -* There are also additional information fields that are `optional`, i.e; a user can signup without setting them. -* Optional fields are `gender`, `full name`, `profile headline` and `bio` -* Implemented several `authentication methods` to verify user info before registering him. -* Authentication checks for: - * `empty fields` - * `invalid username or email` - * `password mismatch` - * `wrong profile image error` - * `SQL errors` - * `internal server errors` - -### Login System - -* `username` and `password` required for logging in. -* Authentication checks to return valid error messages. -* Authentication checks for: - * `wrong username` - * `wrong password` - -### Profile System - -* Each is assigned a `user profile` on registration. -* Profile can be accessed through the `menu options` which become visible after logging in or the `link` beneath the profile image on the right. -* Profile page displays all of the User's information, except (naturally) for the password. -* Displayed information: - * `profile image` - * `username` - * `full name` - * `gender` - * `headline` - * `bio` -* Profile page cannot be accessed without logging in. -* Signup page cannot be page `after logging in`. - -### Profile Editing System - -* User can edit his profile information with the help of the `profile editing system` -* Profile Editing page can be accessed from `menu option` or `link` below profile image on the right -* `username` cannot be changed -* Profile Editing already has the existing information so user does not have to type everything all over again if he merely wishes to slightly edit current information. -* Current password required for changing password. -* Changing password also requires confirmation / re-entering of new password. -* user profile image can also be changed. -* Authentication checks for: - * `empty fields` - * `invalid information` - * `wrong current password` - * `new password mismatch` - * `image upload errors` ### Contact System -* contact system is accessible with or without logging in -* uses `PHPMailer` to create an email server with which it sends emails. -* options for subscribing to newsletter (or basically any additional option for contacting) -* does not require PHPMailer on live domain (only required on windows localhost) +The application has a simple contact system that uses the setup mail server to send an email to itself, containing the sender information as well as the message. The contact form is accessible on being logged in or not. When not logged it, it requires the sender name and email. And when logged in, it uses the current user's username and email to send the contact mail. +The system uses an email template to send the emails, which can be updated, improved or replaced. -### Security +## Future Improvements -* `Password hashing` before storing in database. -* Filtering of information obtained from `$_GET` and `$_POST` methods to prevent `header injection`. -* Implementation of `MySQLi Prepared Statements` for **advanced** database security. +There are somethings i have in mind for adding to this project later on. However, that is a commitment i may or may not be able to stay true to. If any of you people end up improving on this in any way, it would be an honor to have you contribute to this project. - **Example:** -```php -$sql = "select uidUsers from users where uidUsers=?;"; - $stmt = mysqli_stmt_init($conn); - if (!mysqli_stmt_prepare($stmt, $sql)) - { - header("Location: ../signup.php?error=sqlerror"); - exit(); - } - else - { - mysqli_stmt_bind_param($stmt, "s", $userName); - mysqli_stmt_execute($stmt); - mysqli_stmt_store_result($stmt); - } -``` +That being said, these are some possible improvements i have in my mind right now: -### KLiK - Social Media Website +- OAuth login. (login via 3rd party applications like gmail or github etc). +- Requirement for mail confirmation with new address for email update. +- Keep a `data` column in database with JSON encoded text and move extra fields like first name, last name, bio and headline etc into it. That will make the table more manageable and create more flexibility to add as many data fields as needed in JSON format. +- Raw functionality of a simple admin dashboard, with a simple list of all users with functionality to: + - search for a user. + - filter users. + - delete users. + - activate/ deactivate users. + - create users. + - update non-critical (and maybe critical too) information for users. +- option to delete account, with confirmation via email being necessary for that. +- cover images for users. +- User levels assigned upon registration (admin, normal-user etc) and permissions system for that. -Check out the complete project for this login system. [KLiK](https://github.com/msaad1999/KLiK-SocialMediaWebsite) is a complete Social Media website, along with a Complete Login/Registration system, Profile system, Chat room, Forum system and Blog/Polls/Event Management System. +## Contribution Guidelines -> Check out [KLiK here](https://github.com/msaad1999/KLiK-SocialMediaWebsite) +If you want to contribute to this project, please refer to the [Contributing Guidelines](CONTRIBUTING). -

- -

+## License + +This project has been assigned the [MIT License](LICENSE), so go ahead and feel free to use any and/or all parts of this system and to build on it. Although I would still insist that if you do end up improving this, do accidentally contribute, it would be an honour. + +## Personal Note -> Do star my projects! :) +Hey there, this was a small little side project, which was a great learning experience for me and influenced me to focus more on bigger, more complex frameworks. I have now moved on to Laravel development, and if you think you're adding too much to this system, it may be high time for you to move onto a better framework like Laravel as well. -> If you liked my work, please show support by `starring` the repository! It means a lot to me, and is all im asking for. +> As mentioned before, in case that you do actually appreciate this project or the effort put into it, you're probably too far away for me to demand a good cup of coffee, so for now, how about a star? And if you're feeling great, how about a contribution? \ No newline at end of file diff --git a/assets/includes/functions.php b/assets/includes/functions.php deleted file mode 100644 index 9f04970..0000000 --- a/assets/includes/functions.php +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/assets/setup/env.php.example b/assets/setup/env.php.example deleted file mode 100644 index bb9bad5..0000000 --- a/assets/setup/env.php.example +++ /dev/null @@ -1,18 +0,0 @@ -Name: $name
" + // . "Email: $email

" + // . "Message:

$msg"; + + /* + * ------------------------------------------------------------------------------- + * Using email template + * ------------------------------------------------------------------------------- + */ + $subject = "$name sent you a message via your contact form"; - $message = "Name: $name
" - . "Email: $email

" - . "Message:

$msg"; + $mail_variables = array(); + + $mail_variables['APP_NAME'] = APP_NAME; + $mail_variables['username'] = $name; + $mail_variables['email'] = $email; + $mail_variables['message'] = $msg; - if (isset($_POST['subscribe'])) { + $message = file_get_contents("./template_contactemail.php"); - $message .= "


" - . "IMPORTANT: Please add $email " - . "to your mailing list.
"; + foreach($mail_variables as $key => $value) { + + $message = str_replace('{{ '.$key.' }}', $value, $message); } $mail = new PHPMailer(true); diff --git a/contact/includes/template_contactemail.php b/contact/includes/template_contactemail.php new file mode 100644 index 0000000..e848a63 --- /dev/null +++ b/contact/includes/template_contactemail.php @@ -0,0 +1,223 @@ + + + + + + + New Contact Form Entry + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ + +
+ + {{ APP_NAME }}: New Contact Form Entry + +
+
 
+ + + + +
 
+
 
+ + + + +
+ + +
+ Name: {{ username }}
+ Email: {{ email }}
+ Message: +
+
+
 
+ + + + +
+
+ {{ message }} +
+
+
 
+ +
 
 
+ + + \ No newline at end of file diff --git a/index.php b/index.php index 8758ce4..f8ffdb5 100644 --- a/index.php +++ b/index.php @@ -1,14 +1,12 @@ - Verify Your Email + Password Updated