OOP CRUD MVC Web App With PDO Using Core PHP

Language

This is a simple PHP web application developed using OOP Pattern, PDO, and Core PHP. This project will help you learn how to develop a web application with MVC (Model-View-Controller). For those who are not familiar in MVC, the MVC (Model-View-Controller) is an application/software design pattern comprised of three interconnected parts which are the model, view, and controller.

Talking about the web application, this has a registration page which the user can create their new account, and also it has a secure login feature. The web application is a kind of the application of a post which user can create, edit, read, and delete posts. The delete and edit post-action buttons are only visible to users who created the post. The application is composed of 3 Controllers which are the Pages, Posts, and Users. The Pages Controller handles the public pages, Posts Controllers handles the posts side, and Users Controllers handles the users' login and registrations.

Controllers:

Pages.php

  1. <?php
  2. class Pages extends Controller {
  3. public function __construct(){
  4.  
  5. }
  6.  
  7. public function index(){
  8. if(isLoggedIn()){
  9. redirect('posts');
  10. }
  11. $data = [
  12. 'title' => 'SharePosts',
  13. 'description' => 'Simple social network built on the Emmizy MVC framework',
  14. 'info' => 'You can contact me with the following details below if you like my program and willing to offer me a contract and work on your project',
  15. 'name' => 'Omonzebaguan Emmanuel',
  16. 'location' => 'Nigeria, Edo State',
  17. 'contact' => '+2348147534847',
  18. 'mail' => '[email protected]'
  19. ];
  20.  
  21. $this->view('pages/index', $data);
  22. }
  23.  
  24. public function about(){
  25. $data = [
  26. 'title' => 'About Us',
  27. 'description' => 'App to share posts with other users'
  28. ];
  29.  
  30. $this->view('pages/about', $data);
  31. }
  32.  
  33. public function contact(){
  34. $data = [
  35. 'title' => 'Contact Us',
  36. 'description' => 'You can contact us through this medium',
  37. 'info' => 'You can contact me with the following details below if you like my program and willing to offer me a contract and work on your project',
  38. 'name' => 'Omonzebaguan Emmanuel',
  39. 'location' => 'Nigeria, Edo State',
  40. 'contact' => '+2348147534847',
  41. 'mail' => '[email protected]'
  42. ];
  43.  
  44. $this->view('pages/contact', $data);
  45. }
  46. }

Posts.php

  1. <?php
  2. class Posts extends Controller{
  3.  
  4. public function __construct()
  5. {
  6. if(!isLoggedIn()){
  7. redirect('users/login');
  8. }
  9. //new model instance
  10. $this->postModel = $this->model('Post');
  11. $this->userModel = $this->model('User');
  12. }
  13.  
  14. public function index(){
  15.  
  16. $posts = $this->postModel->getPosts();
  17. $data = [
  18. 'posts' => $posts
  19. ];
  20.  
  21. $this->view('posts/index', $data);
  22. }
  23.  
  24. //add new post
  25. public function add(){
  26. $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
  27. if($_SERVER['REQUEST_METHOD'] == 'POST'){
  28. $data = [
  29. 'title' => trim($_POST['title']),
  30. 'body' => trim($_POST['body']),
  31. 'user_id' => $_SESSION['user_id'],
  32. 'title_err' => '',
  33. 'body_err' => '',
  34. ];
  35.  
  36. if(empty($data['title'])){
  37. $data['title_err'] = 'Please enter post title';
  38. }
  39. if(empty($data['body'])){
  40. $data['body_err'] = 'Please enter the post content';
  41. }
  42.  
  43. //validate error free
  44. if(empty($data['title_err']) && empty($data['body_err'])){
  45. if($this->postModel->addPost($data)){
  46. flash('post_message', 'Your post have been added');
  47. redirect('posts');
  48. }else{
  49. die('something went wrong');
  50. }
  51.  
  52. //laod view with error
  53. }else{
  54. $this->view('posts/add', $data);
  55. }
  56. }else{
  57. $data = [
  58. 'title' => (isset($_POST['title']) ? trim($_POST['title']) : ''),
  59. 'body' => (isset($_POST['body'])? trim($_POST['body']) : '')
  60. ];
  61.  
  62. $this->view('posts/add', $data);
  63. }
  64. }
  65.  
  66. //show single post
  67. public function show($id){
  68. $post = $this->postModel->getPostById($id);
  69. $user = $this->userModel->getUserById($post->user_id);
  70.  
  71. $data = [
  72. 'post' => $post,
  73. 'user' => $user
  74. ];
  75.  
  76. $this->view('posts/show', $data);
  77. }
  78.  
  79. //edit post
  80. public function edit($id){
  81. if($_SERVER['REQUEST_METHOD'] == 'POST'){
  82. $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
  83. $data = [
  84. 'id' => $id,
  85. 'title' => trim($_POST['title']),
  86. 'body' => trim($_POST['body']),
  87. 'user_id' => $_SESSION['user_id'],
  88. 'title_err' => '',
  89. 'body_err' => '',
  90. ];
  91. //validate the title
  92. if(empty($data['title'])){
  93. $data['title_err'] = 'Please enter post title';
  94. }
  95. //validate the body
  96. if(empty($data['body'])){
  97. $data['body_err'] = 'Please enter the post content';
  98. }
  99.  
  100. //validate error free
  101. if(empty($data['title_err']) && empty($data['body_err'])){
  102. if($this->postModel->updatePost($data)){
  103. flash('post_message', 'Your post have been updated');
  104. redirect('posts');
  105. }else{
  106. die('something went wrong');
  107. }
  108.  
  109. //laod view with error
  110. }else{
  111. $this->view('posts/edit', $data);
  112. }
  113. }else{
  114. //check for the owner and call method from post model
  115. $post = $this->postModel->getPostById($id);
  116. if($post->user_id != $_SESSION['user_id']){
  117. redirect('posts');
  118. }
  119. $data = [
  120. 'id' => $id,
  121. 'title' => $post->title,
  122. 'body' => $post->body
  123. ];
  124.  
  125. $this->view('posts/edit', $data);
  126. }
  127. }
  128.  
  129. //delete post
  130. public function delete($id){
  131. if($_SERVER['REQUEST_METHOD'] == 'POST'){
  132. //check for owner
  133. $post = $this->postModel->getPostById($id);
  134. if($post->user_id != $_SESSION['user_id']){
  135. redirect('posts');
  136. }
  137.  
  138. //call delete method from post model
  139. if($this->postModel->deletePost($id)){
  140. flash('post_message', 'Post Removed');
  141. redirect('posts');
  142. }else{
  143. die('something went wrong');
  144. }
  145. }else{
  146. redirect('posts');
  147. }
  148. }
  149. }
  150.  

Users.php

  1. <?php
  2. class Users extends Controller{
  3. public function __construct()
  4. {
  5. $this->userModel = $this->model('User');
  6. }
  7.  
  8. public function register(){
  9. if ($_SERVER['REQUEST_METHOD'] == 'POST'){
  10. // process form
  11. $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
  12. $data = [
  13. 'name' => trim($_POST['name']),
  14. 'email' => trim($_POST['email']),
  15. 'password' => trim($_POST['password']),
  16. 'confirm_password' => trim($_POST['confirm_password']),
  17. 'name_err' => '',
  18. 'email_err' => '',
  19. 'password_err' => '',
  20. 'confirm_password_err' => ''
  21. ];
  22.  
  23. //valide name
  24. if(empty($data['name'])){
  25. $data['name_err'] = 'Please enter name';
  26. }
  27.  
  28. //validate email
  29. if(empty($data['email'])){
  30. $data['email_err'] = 'Please enter email';
  31. }else{
  32. //check for email
  33. if($this->userModel->findUserByEmail($data['email'])){
  34. $data['email_err'] = 'Email already exist';
  35. }
  36. }
  37.  
  38. //validate password
  39. if(empty($data['password'])){
  40. $data['password_err'] = 'Please enter your password';
  41. }elseif(strlen($data['password']) < 6){
  42. $data['password_err'] = 'Password must be atleast six characters';
  43. }
  44.  
  45. //validate confirm password
  46. if(empty($data['confirm_password'])){
  47. $data['confirm_password_err'] = 'Please confirm password';
  48. }else{
  49. if($data['password'] != $data['confirm_password'])
  50. {
  51. $data['confirm_password_err'] = 'Password does not match';
  52. }
  53. }
  54.  
  55. //make sure error are empty
  56. if(empty($data['name_err']) && empty($data['email_err']) && empty($data['password_err']) && empty($data['password_confirm_err'])){
  57. $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
  58. if($this->userModel->register($data)){
  59. flash('register_success', 'you are registerd you can login now');
  60. redirect('users/login');
  61. }
  62. }else{
  63. $this->view('users/register', $data);
  64. }
  65. }else{
  66. //init data
  67. $data = [
  68. 'name' => '',
  69. 'email' => '',
  70. 'password' => '',
  71. 'confirm_password' => '',
  72. 'name_err' => '',
  73. 'email_err' => '',
  74. 'password_err' => '',
  75. 'confirm_password_err' => ''
  76. ];
  77. //load view
  78. $this->view('users/register', $data);
  79. }
  80. }
  81.  
  82. public function login(){
  83. if ($_SERVER['REQUEST_METHOD'] == 'POST'){
  84. // process form
  85. $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
  86. $data = [
  87. 'email' => trim($_POST['email']),
  88. 'password' => trim($_POST['password']),
  89. 'email_err' => '',
  90. 'password_err' => ''
  91. ];
  92.  
  93. //validate email
  94. if(empty($data['email'])){
  95. $data['email_err'] = 'Please enter email';
  96. }else{
  97. if($this->userModel->findUserByEmail($data['email'])){
  98. //user found
  99. }else{
  100. $data['email_err'] = 'User not found';
  101. }
  102. }
  103.  
  104. //validate password
  105. if(empty($data['password'])){
  106. $data['password_err'] = 'Please enter your password';
  107. }elseif(strlen($data['password']) < 6){
  108. $data['password_err'] = 'Password must be atleast six characters';
  109. }
  110.  
  111. //make sure error are empty
  112. if(empty($data['email_err']) && empty($data['password_err'])){
  113. $loggedInUser = $this->userModel->login($data['email'], $data['password']);
  114. if($loggedInUser){
  115. //create session
  116. $this->createUserSession($loggedInUser);
  117. }else{
  118. $data['password_err'] = 'Password incorrect';
  119. $this->view('users/login', $data);
  120. }
  121. }else{
  122. $this->view('users/login', $data);
  123. }
  124.  
  125. }else{
  126. //init data f f
  127. $data = [
  128. 'email' => '',
  129. 'password' => '',
  130. 'email_err' => '',
  131. 'password_err' => ''
  132. ];
  133. //load view
  134. $this->view('users/login', $data);
  135. }
  136. }
  137.  
  138. //setting user section variable
  139. public function createUserSession($user){
  140. $_SESSION['user_id'] = $user->id;
  141. $_SESSION['name'] = $user->name;
  142. $_SESSION['email'] = $user->email;
  143. redirect('posts/index');
  144. }
  145.  
  146. //logout and destroy user session
  147. public function logout(){
  148. unset($_SESSION['user_id']);
  149. unset($_SESSION['name']);
  150. unset($_SESSION['email']);
  151. redirect('users/login');
  152. }
  153. }

The application has of 2 model files for Posts and Users. The models consist all the scripts that manages the data in the database and retrieves data.

Models:

Posts.php

  1. <?php
  2.  
  3. class Post {
  4. private $db;
  5. public function __construct()
  6. {
  7. $this->db = new Database;
  8. }
  9.  
  10. public function getPosts(){
  11. $this->db->query('SELECT *,
  12. posts.id as postId,
  13. user.id as userId,
  14. posts.created_at as postCreated,
  15. user.created_at as userCreated
  16. FROM posts
  17. INNER JOIN user
  18. ON posts.user_id = user.id
  19. ORDER BY posts.created_at DESC');
  20. $result = $this->db->resultSet();
  21.  
  22. return $result;
  23. }
  24.  
  25. public function addPost($data){
  26. $this->db->query('INSERT INTO posts(user_id, title, body) VALUES (:user_id, :title, :body)');
  27. $this->db->bind(':user_id', $data['user_id']);
  28. $this->db->bind(':title', $data['title']);
  29. $this->db->bind(':body', $data['body']);
  30.  
  31. //execute
  32. if($this->db->execute()){
  33. return true;
  34. }else{
  35. return false;
  36. }
  37. }
  38.  
  39. public function getPostById($id){
  40. $this->db->query('SELECT * FROM posts WHERE id = :id');
  41. $this->db->bind(':id', $id);
  42. $row = $this->db->single();
  43.  
  44. return $row;
  45. }
  46.  
  47. public function updatePost($data){
  48. $this->db->query('UPDATE posts SET title = :title, body = :body WHERE id = :id');
  49. $this->db->bind(':id', $data['id']);
  50. $this->db->bind(':title', $data['title']);
  51. $this->db->bind(':body', $data['body']);
  52.  
  53. //execute
  54. if($this->db->execute()){
  55. return true;
  56. }else{
  57. return false;
  58. }
  59. }
  60.  
  61. //delete a post
  62. public function deletePost($id){
  63. $this->db->query('DELETE FROM posts WHERE id = :id');
  64. $this->db->bind(':id', $id);
  65.  
  66. if($this->db->execute()){
  67. return true;
  68. }else{
  69. return false;
  70. }
  71. }
  72. }

Users.php

  1. <?php
  2. class User {
  3. private $db;
  4. public function __construct()
  5. {
  6. $this->db = new Database;
  7. }
  8.  
  9. //register new user
  10. public function register($data){
  11. $this->db->query('INSERT INTO user (name, email, password) VALUES (:name, :email, :password)');
  12. $this->db->bind(':name', $data['name']);
  13. $this->db->bind(':email', $data['email']);
  14. $this->db->bind(':password', $data['password']);
  15.  
  16. if($this->db->execute()){
  17. return true;
  18. }else{
  19. return false;
  20. }
  21. }
  22. //find user by email
  23. public function findUserByEmail($email){
  24. $this->db->query('SELECT * FROM user WHERE email = :email');
  25. $this->db->bind(':email', $email);
  26.  
  27. $row = $this->db->single();
  28.  
  29. //check the row
  30. if($this->db->rowCount() > 0){
  31. return true;
  32. }else{
  33. return false;
  34. }
  35. }
  36.  
  37. public function login($email, $password){
  38. $this->db->query('SELECT * FROM user where email = :email');
  39. $this->db->bind(':email', $email);
  40.  
  41. $row = $this->db->single();
  42.  
  43. $hash_password = $row->password;
  44.  
  45. if(password_verify($password, $hash_password)){
  46. return $row;
  47. }else{
  48. return false;
  49. }
  50. }
  51.  
  52. public function getUserById($id){
  53. $this->db->query('SELECT * FROM user WHERE id = :id');
  54. $this->db->bind(':id', $id);
  55.  
  56. $row = $this->db->single();
  57.  
  58. return $row;
  59. }
  60. }

And for the views, these are the files that contain the user-interface scripts such as the login page, posts page, and registration page interfaces. The application also uses .htaccess that rewrites the rules for redirecting the URL to the exact subdirectory/link/filename and this will give users user-friendly URLs. It uses also Bootstrap Framework that helps us make pleasant user interfaces.

Demo

This web application is free to download. Feel Free to download and modify the source code to enhance and develop your programming capabilities in PHP Language.

How to Run

Requirements
  • Download and Install any local web server such as XAMPP/WAMP.
  • Download the provided source code zip file. (download button is located below)
Installation/Setup
  1. Open your XAMPP/WAMP's Control Panel and start the Apache and MySQL.
  2. Extract the downloaded source code zip file.
  3. If you are using XAMPP, copy the extracted source code folder and paste it into the XAMPP's "htdocs" directory. And If you are using WAMP, paste it into the "www" directory.
  4. Browse the PHPMyAdmin in a browser. i.e. http://localhost/phpmyadmin
  5. Create a new database naming shareposts.
  6. Import the provided SQL file. The file is known as shareposts.sql located inside the database folder.
  7. Browse the Web Application in a browser. i.e. http://localhost/shareposts.

I hope this will help you with what you are looking for and helps you to understand and learn to develop a web application using Core PHP/MVX/OOP/PDO.

Enjoy :)

Note: Due to the size or complexity of this submission, the author has submitted it as a .zip file to shorten your download time. After downloading it, you will need a program like Winzip to decompress it.

Virus note: All files are scanned once-a-day by SourceCodester.com for viruses, but new viruses come out every day, so no prevention program can catch 100% of them.

FOR YOUR OWN SAFETY, PLEASE:

1. Re-scan downloaded files using your personal virus checker before using it.
2. NEVER, EVER run compiled files (.exe's, .ocx's, .dll's etc.)--only run source code.

Add new comment

CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
4 + 6 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.