├── README.md
├── app
├── .htaccess
├── backend
│ ├── auth
│ │ ├── config.php
│ │ ├── cookie.php
│ │ ├── delete-account.php
│ │ ├── login.php
│ │ ├── logout.php
│ │ ├── profile.php
│ │ ├── register.php
│ │ ├── update-account.php
│ │ └── user.php
│ ├── classes
│ │ ├── Token.php
│ │ ├── User.php
│ │ └── Validation.php
│ └── core
│ │ ├── Config.php
│ │ ├── Cookie.php
│ │ ├── Database.php
│ │ ├── Hash.php
│ │ ├── Helpers.php
│ │ ├── Init.php
│ │ ├── Input.php
│ │ ├── Password.php
│ │ ├── Redirect.php
│ │ └── Session.php
├── frontend
│ ├── assets
│ │ ├── css
│ │ │ ├── login-form.css
│ │ │ └── profile.css
│ │ └── js
│ │ │ ├── login-form.js
│ │ │ └── profile.js
│ ├── includes
│ │ ├── errors
│ │ │ └── 404.php
│ │ ├── footer.php
│ │ ├── header.php
│ │ ├── messages.php
│ │ └── navbar.php
│ └── pages
│ │ ├── home.php
│ │ ├── login.php
│ │ ├── profile.php
│ │ ├── register.php
│ │ └── update-account.php
└── setup
│ └── php_boilerplate.sql
├── delete-account.php
├── index.php
├── login.php
├── logout.php
├── profile.php
├── register.php
├── start.php
├── test.php
└── update-account.php
/README.md:
--------------------------------------------------------------------------------
1 | # Simple PHP Boilerplate
2 | - This project only exists for helping my colleagues in school.
3 |
4 | ## Table of Contents
5 |
6 | - [Concepts](#concepts-)
7 | - [Files Controller](#files-controller)
8 | - [Seperation of Ideas](#seperation-of-ideas)
9 | - [Level of Useability](#level-of-useability)
10 | - [Organize the Files](#organize-the-files)
11 | - [Advantages](#advantages-)
12 | - [Knowledge Requirements](#knowledge-requirements-)
13 | - [Features](#features-)
14 | - [Getting Started](#getting-started)
15 | - [Overview](#overview)
16 | - [Nice Configurations](#nice-configurations)
17 | - [Easy Validation](#easy-validation)
18 | - [CSRF Protection](#csrf-protection)
19 | - [Secure Password](#secure-password)
20 | - [Sql Injection Protection](#sql-injection-protection)
21 | - [Core Classes](#core-classes-)
22 | - [Cookie Class](#cookie-class)
23 | - [Database Class](#database-class)
24 | - [Hash Class](#hash-class)
25 | - [Helper Functions](#helper-functions)
26 | - [Input Class](#input-class)
27 | - [Password Class](#password-class)
28 | - [Redirect Class](#redirect-class)
29 | - [Session Class](#session-class)
30 | - [Helpful Classes](#helpful-classes-)
31 | - [Token Class](#token-class)
32 | - [User Class](#user-class)
33 | - [Validation Class](#validation-class)
34 |
35 | ### Concepts :
36 | When you use this app the first things you'll notice are the files and folder in the directory. The app folder composed of frontend and backend folders, which separates the front design and backend logic. The files that you saw in the outside of the app folder, I think as the controllers, think this as you play a jigsaw puzzle, you need to connect the different pieces to solve it or form it. So.. as you see the content of the files, there is no logic or designs include on it, except the require once function that use to insert or connect the files. Those require name defined in the 'start.php', to make it easier to memorize, act as an alias or be constant for the file locations.
37 |
38 | To understand the structure and idea of this app, think in this way;
39 |
40 | ##### Files Controller
41 | The files that outside in the app folders are puzzles that you need to solve. Then the files inside in the app folder are the pieces of a puzzle that you need to require or connect.
42 |
43 | ##### Separation of Ideas
44 | The app folder contains two folders that are frontend and backend folder. Think of it as the separation of logic and design in your application.
45 |
46 | ##### Level of Usability
47 | The backend folder contains auth, classes, core folders. The lower the level, the low chance that you will use in your logic. Auth is level 2, Classes is level 1, and Core is level 0. So in Auth folder, where you will put your logic that connects from your frontend pages. Then the classes folders are your objects or tools that logic behind in Auth files. Then the Core folder is the abstract ideas behind your classes folder. And that's it.
48 |
49 | ##### Organize the Files
50 | The Frontend folder contains assets, includes, and pages folders which were chopped to reuse your design and codes. Like assets folder where the css, js, images lived, includes folder where the headers, navbar, messages, footer are separated and the pages folder where you all your application pages lived.
51 |
52 |
53 |
54 | ### Advantages :
55 |
56 | - Organize File Structure
57 | - High Security
58 | - Code Reuseable
59 |
60 | ### Knowledge Requirements :
61 |
62 | - [PHP Programming Basics](https://www.youtube.com/watch?v=XKWqdp17BFo&list=PLfdtiltiRHWHjTPiFDRdTOPtSyYfz3iLW)
63 | - [Good Understanding in OOP](https://www.youtube.com/watch?v=ipp4WPDwwvk&list=PLfdtiltiRHWF0RicJb20da8nECQ1jFvla) (optional)
64 | - Open Minded
65 |
66 | ### Features :
67 |
68 | - Nice Configurations
69 | - Easy Validation
70 | - CSRF Protection
71 | - Secure Password
72 | - Sql Injection Protection
73 | - A lot of helpful classes.
74 |
75 | ### Getting Started
76 |
77 | #### [Download ZIP](https://github.com/jandaryl/simple-php-boilerplate/archive/master.zip) or Git Clone
78 | ```php
79 | git clone https://github.com/jandaryl/simple-php-boilerplate.git
80 | ```
81 |
82 | ### Setup environment
83 |
84 | Follow the steps below:
85 |
86 | 1. [Download and install Xampp](https://www.apachefriends.org/download.html), which is used to manage the system.
87 | 2. Move the files to the htdocs folder of Xampp.
88 | 3. Import the database and set the configuration.
89 |
90 | ### Overview
91 |
92 | #### Nice Configurations
93 |
94 | ``` php
95 | array(
100 | 'name' => 'AppName',
101 | ),
102 | 'mysql' => array(
103 | 'host' => '127.0.0.1',
104 | 'username' => 'root',
105 | 'password' => '',
106 | 'db_name' => 'php_boilerplate'
107 | ),
108 | ...
109 |
110 | check($_POST, array(
131 | 'username' => array(
132 | 'required' => true,
133 | 'min' => 2,
134 | 'unique' => 'users'
135 | ),
136 | 'current_password' => array(
137 | 'required' => true,
138 | 'min' => 6,
139 | 'verify' => 'password'
140 | ),
141 | 'new_password' => array(
142 | 'optional' => true,
143 | 'min' => 6,
144 | 'bind' => 'confirm_new_password'
145 | )
146 | 'confirm_new_password' => array(
147 | 'optional' => true,
148 | 'min' => 6,
149 | 'match' => 'new_password',
150 | 'bind' => 'new_password',
151 | ),
152 | ));
153 |
154 | if ($validate->passed() {
155 | // Awesome Logic...
156 | } else {
157 | echo $validate->$error(); // First error message.
158 |
159 | foreach ($validate->errors() as $error) // All error messages.
160 | {
161 | echo $error;
162 | }
163 | }
164 | ...
165 | ```
166 |
167 | ### CSRF Protection
168 |
169 | ```php
170 | ">
176 |
177 | ...
178 |
179 | array(
197 | 'algo_name' => PASSWORD_DEFAULT,
198 | 'cost' => 10,
199 | 'salt' => 50,
200 | ),
201 | ...
202 |
203 | create(array(
208 | ...
209 | 'password' => Password::hash(Input::get('password')),
210 | ...
211 | ));
212 | ...
213 |
214 | _user->data()->password)) {
219 | // Do awesome stuff...
220 | }
221 | ...
222 | ```
223 |
224 | ### Sql Injection Protection
225 | ```php
226 | _pdo = new PDO('mysql:host='.Config::get('mysql/host')...);
230 | ...
231 | $this->_query->bindvalue($x, $param);
232 | ...
233 | $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
234 | ...
235 |
236 | ```
237 |
238 | ### Core Classes :
239 |
240 | #### Cookie Class
241 | ```php
242 | get($table, $where = array())
267 | $database->get('users', array('id', '=', '13');
268 |
269 | // Insert the data to database.
270 | // $database->insert($table, $fields = array())
271 | $database->insert('users', array(
272 | 'username' => 'johnny123',
273 | 'password' => Password::hash('secret'),
274 | 'name' => 'JohnDoe',
275 | 'joined' => date('Y-m-d H:i:s')
276 | ));
277 |
278 | // Update the data from database.
279 | // $database->update($table, $id, $fields = array())
280 | $database->update('users', '13', array(
281 | 'username' => 'newusernname',
282 | 'password' => Password::hash('newsecret'),
283 | 'name' => 'newname',
284 | ));
285 |
286 | // Delete the data from database.
287 | // $database->delete($table, $where = array())
288 | $database->delete('users', array('id', '=', '13');
289 |
290 | // Get the first data from database.
291 | $database->first();
292 |
293 | // Count the data from database.
294 | $database->count();
295 |
296 | // Return a results of object data from database.
297 | $database->results();
298 |
299 | // Get error from query.
300 | $database->error();
301 |
302 | ```
303 | #### Hash Class
304 | ```php
305 | create(array(
426 | 'username' => Input::get('username'),
427 | 'password' => Password::hash(Input::get('password')),
428 | 'name' => Input::get('name'),
429 | 'joined' => date('Y-m-d H:i:s'),
430 | ));
431 |
432 | // Update the user data.
433 | $user->update(array(
434 | 'username' => Input::get('username'),
435 | 'password' => Password::hash(Input::get('password')),
436 | 'name' => Input::get('name'),
437 | 'joined' => date('Y-m-d H:i:s'),
438 | ), '13');
439 |
440 | // Find the user if exists.
441 | $user->find('13'); // return true or false
442 | $user->find('johnny123'); // return true or false
443 |
444 | // Login the user.
445 | // The 3rd argument is to check if the user want to remember.
446 | $user->login('johnny123', 'secret', true);
447 |
448 | // Check the user if exists.
449 | $user->exists();
450 |
451 | // Logout the user.
452 | // Delete the session and cookie that attached.
453 | $user->logout();
454 |
455 |
456 | // Get the user data in object way.
457 | $user->data();
458 | $user->data()->username; // 'johnny123'
459 | $user->data()->name; // 'JohnDoe'
460 |
461 | // Check if the user logged in.
462 | $user->isLoggedIn(); // Return true or false.
463 |
464 | // Delete the data from database.
465 | $user->deleteMe();
466 |
467 | ```
468 | #### Validation Class
469 | ```php
470 | true, 'can be null or no value'
478 | // required => true, 'cannot be null or no value'
479 | // bind => 'input_name', 'make connect to other input'
480 | // min => 'any_number', 'minimum length of that input'
481 | // max => 'any_number', 'maximum length of that input'
482 | // match => 'input_name', 'check if match input from another'
483 | // email => true, 'check the input if valid email'
484 | // alnum => true, 'check if the input alpha numeric'
485 | // unique => 'table_name', 'check if the input unique from table'
486 | // verify => 'password', 'only in password, check the current'
487 |
488 | $validation = $validate->check($_POST, array(
489 | 'username' => array(
490 | 'required' => true,
491 | 'unique' => 'users',
492 | 'min' => 2,
493 | 'max' => 20,
494 | 'matches' => 'password',
495 | alnum => true
496 | ),
497 | ));
498 |
499 | // Check if there is an errors.
500 | if ($validate->passed() {
501 | // Query to the database...
502 | } else {
503 | // For first error message.
504 | // echo $validate->$error();
505 |
506 | // For all error messages.
507 | foreach ($validate->errors() as $error)
508 | {
509 | echo $error;
510 | }
511 | }
512 |
513 | ```
514 |
515 | Thanks for reading! I hope this is useful...
516 |
517 | ### License
518 |
519 | Simple PHP Boilerplate is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
520 |
521 |
522 |
--------------------------------------------------------------------------------
/app/.htaccess:
--------------------------------------------------------------------------------
1 | Options --Indexes
2 |
3 |
--------------------------------------------------------------------------------
/app/backend/auth/config.php:
--------------------------------------------------------------------------------
1 | array(
6 | 'name' => 'AppName',
7 | ),
8 |
9 | 'mysql' => array(
10 | 'host' => '127.0.0.1',
11 | 'username' => 'root',
12 | 'password' => '',
13 | 'db_name' => 'php_boilerplate'
14 | ),
15 |
16 | 'password' => array(
17 | 'algo_name' => PASSWORD_DEFAULT,
18 | 'cost' => 10,
19 | 'salt' => 50,
20 | ),
21 |
22 | 'hash' => array(
23 | 'algo_name' => 'sha512',
24 | 'salt' => 30,
25 | ),
26 |
27 | 'remember' => array(
28 | 'cookie_name' => 'token',
29 | 'cookie_expiry' => 604800
30 | ),
31 |
32 | 'session' => array(
33 | 'session_name' => 'user',
34 | 'token_name' => 'csrf_token'
35 | ),
36 | );
37 |
--------------------------------------------------------------------------------
/app/backend/auth/cookie.php:
--------------------------------------------------------------------------------
1 | get('users_session', array('hash', '=', $hash));
8 |
9 | if($hashCheck->count())
10 | {
11 | $user = new User($hashCheck->first()->user_id);
12 | $user->login();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/backend/auth/delete-account.php:
--------------------------------------------------------------------------------
1 | deleteMe();
5 |
6 | Redirect::to('index.php');
7 |
--------------------------------------------------------------------------------
/app/backend/auth/login.php:
--------------------------------------------------------------------------------
1 | check($_POST, array(
11 | 'username' => array(
12 | 'required' => true,
13 | ),
14 |
15 | 'password' => array(
16 | 'required' => true
17 | ),
18 | ));
19 |
20 | if ($validation->passed())
21 | {
22 | $remember = (Input::get('remember') === 'on') ? true : false;
23 | $login = $user->login(Input::get('username'), Input::get('password'), $remember);
24 |
25 | if ($login)
26 | {
27 | Redirect::to('index.php');
28 | }
29 | else
30 | {
31 | echo '
Incorrect Credentials! Please try again...
';
32 | }
33 | }
34 | else
35 | {
36 | foreach ($validation->errors() as $error)
37 | {
38 | echo '' . cleaner($error) . '
';
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/backend/auth/logout.php:
--------------------------------------------------------------------------------
1 | logout();
5 |
6 | Redirect::to('index.php');
7 |
--------------------------------------------------------------------------------
/app/backend/auth/profile.php:
--------------------------------------------------------------------------------
1 | isLoggedIn())
5 | {
6 | Redirect::to('index.php');
7 | }
8 |
9 | $data = $user->data();
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/backend/auth/register.php:
--------------------------------------------------------------------------------
1 | check($_POST, array(
11 | 'name' => array(
12 | 'required' => true,
13 | 'min' => 2,
14 | 'max' => 50
15 | ),
16 |
17 | 'username' => array(
18 | 'required' => true,
19 | 'min' => 2,
20 | 'max' => 20,
21 | 'unique' => 'users'
22 | ),
23 |
24 | 'password' => array(
25 | 'required' => true,
26 | 'min' => 6
27 | ),
28 |
29 | 'password_again' => array(
30 | 'required' => true,
31 | 'matches' => 'password'
32 | )
33 | ));
34 |
35 | if ($validate->passed())
36 | {
37 | try
38 | {
39 | $user->create(array(
40 | 'username' => Input::get('username'),
41 | 'password' => Password::hash(Input::get('password')),
42 | 'name' => Input::get('name'),
43 | 'joined' => date('Y-m-d H:i:s'),
44 | 'groups' => 1
45 | ));
46 |
47 | Session::flash('register-success', 'Thanks for registering! You can login now.');
48 | Redirect::to('index.php');
49 | }
50 | catch(Exception $e)
51 | {
52 | die($e->getMessage());
53 | }
54 | }
55 | else
56 | {
57 | foreach ($validate->errors() as $error)
58 | {
59 | echo '' . cleaner($error) . '
';
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/backend/auth/update-account.php:
--------------------------------------------------------------------------------
1 | check($_POST, array(
11 | 'name' => array(
12 | 'required' => true,
13 | 'min' => 2,
14 | 'max' => 50
15 | ),
16 | 'username' => array(
17 | 'required' => true,
18 | 'min' => 2,
19 | 'max' => 20
20 | ),
21 | 'current_password' => array(
22 | 'required' => true,
23 | 'min' => 6,
24 | 'verify' => 'password'
25 | ),
26 | 'new_password' => array(
27 | 'optional' => true,
28 | 'min' => 6,
29 | 'bind' => 'confirm_new_password'
30 | ),
31 |
32 | 'confirm_new_password' => array(
33 | 'optional' => true,
34 | 'min' => 6,
35 | 'match' => 'new_password',
36 | 'bind' => 'new_password',
37 | ),
38 | ));
39 |
40 | if ($validation->passed())
41 | {
42 | try
43 | {
44 | $user->update(array(
45 | 'name' => Input::get('name'),
46 | 'username' => Input::get('username'),
47 | ));
48 |
49 | if ($validation->optional())
50 | {
51 | $user->update(array(
52 | 'password' => Password::hash(Input::get('new_password'))
53 | ));
54 | }
55 | Session::flash('update-success', 'Profile successfully updated!');
56 | Redirect::to('index.php');
57 | }
58 | catch(Exception $e)
59 | {
60 | die($e->getMessage());
61 | }
62 | }
63 |
64 | else
65 | {
66 | echo '' . cleaner($validation->error()) . '
';
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/backend/auth/user.php:
--------------------------------------------------------------------------------
1 | _db = Database::getInstance();
14 |
15 | $this->_sessionName = Config::get('session/session_name');
16 |
17 | $this->_cookieName = Config::get('remember/cookie_name');
18 |
19 | if (! $user)
20 | {
21 | if (Session::exists($this->_sessionName))
22 | {
23 | $user = Session::get($this->_sessionName);
24 |
25 | if ($this->find($user))
26 | {
27 | $this->_isLoggedIn = true;
28 | }
29 | }
30 |
31 | }
32 | else
33 | {
34 | $this->find($user);
35 | }
36 | }
37 |
38 | public function update($fields = array(), $id = null)
39 | {
40 | if (!$id && $this->isLoggedIn())
41 | {
42 | $id = $this->data()->uid;
43 | }
44 |
45 | if (!$this->_db->update('users', $id, $fields))
46 | {
47 | throw new Exception('Unable to update the user.');
48 | }
49 | }
50 |
51 | public function create($fields = array())
52 | {
53 | if (!$this->_db->insert('users', $fields))
54 | {
55 | throw new Exception("Unable to create the user.");
56 | }
57 | }
58 |
59 | public function find($user = null)
60 | {
61 | if ($user)
62 | {
63 | $field = (is_numeric($user)) ? 'uid' : 'username';
64 |
65 | $data = $this->_db->get('users', array($field, '=', $user));
66 |
67 | if ($data->count())
68 | {
69 | $this->_data = $data->first();
70 | return true;
71 | }
72 | }
73 | }
74 |
75 | public function login($username = null, $password = null, $remember = false)
76 | {
77 | if (! $username && ! $password && $this->exists())
78 | {
79 | Session::put($this->_sessionName, $this->data()->uid);
80 | }
81 | else
82 | {
83 | $user = $this->find($username);
84 |
85 | if ($user)
86 | {
87 | if (Password::check($password, $this->data()->password))
88 | {
89 | Session::put($this->_sessionName, $this->data()->uid);
90 |
91 | if ($remember)
92 | {
93 | $hash = Hash::unique();
94 | $hashCheck = $this->_db->get('users_session', array('user_id', '=', $this->data()->uid));
95 |
96 | if (!$hashCheck->count())
97 | {
98 | $this->_db->insert('users_session', array(
99 | 'user_id' => $this->data()->uid,
100 | 'hash' => $hash
101 | ));
102 | }
103 | else
104 | {
105 | $hash = $hashCheck->first()->hash;
106 | }
107 |
108 | Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry'));
109 | }
110 |
111 | return true;
112 | }
113 | }
114 | }
115 |
116 | return false;
117 | }
118 |
119 | public function hasPermission($key)
120 | {
121 | $group = $this->_db->get('groups', array('gid', '=', $this->data()->groups));
122 |
123 | if ($group->count())
124 | {
125 | $permissions = json_decode($group->first()->permissions, true);
126 |
127 | if ($permissions[$key] == true)
128 | {
129 | return true;
130 | }
131 | }
132 |
133 | return false;
134 | }
135 |
136 | public function exists()
137 | {
138 | return (!empty($this->_data)) ? true : false;
139 | }
140 |
141 | public function logout()
142 | {
143 | $this->_db->delete('users_session', array('user_id', '=', $this->data()->uid));
144 |
145 | Session::delete($this->_sessionName);
146 | Cookie::delete($this->_cookieName);
147 | }
148 |
149 | public function data()
150 | {
151 | return $this->_data;
152 | }
153 |
154 | public function isLoggedIn()
155 | {
156 | return $this->_isLoggedIn;
157 | }
158 |
159 | public function deleteMe()
160 | {
161 | if ($this->isLoggedIn())
162 | {
163 | $id = $this->data()->uid;
164 | }
165 |
166 | if (!$this->_db->delete('users', array('uid', '=', $id)))
167 | {
168 | throw new Exception('Unable to update the user.');
169 | }
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/app/backend/classes/Validation.php:
--------------------------------------------------------------------------------
1 | _db = Database::getInstance();
13 | $this->_user = new User;
14 | }
15 |
16 | public function check($source, $items = array())
17 | {
18 | foreach ($items as $item => $rules)
19 | {
20 | foreach ($rules as $rule => $rule_value)
21 | {
22 |
23 | $value = trim($source[$item]);
24 | $item = escape($item);
25 |
26 | if ($rule === 'optional' && ! empty($value))
27 | {
28 | $this->_optional = true;
29 | }
30 |
31 | if ($rule === 'required' && empty($value))
32 | {
33 | $this->addError("{$item} is required.");
34 | }
35 |
36 | if ($rule === 'bind' && empty($value) && ! empty($source[$rule_value]))
37 | {
38 | $this->addError("{$item} is required.");
39 | }
40 |
41 | else if (!empty($value))
42 | {
43 | switch ($rule)
44 | {
45 | case 'min':
46 |
47 | if (strlen($value) < $rule_value)
48 | {
49 | $this->addError("{$item} must be minimum of {$rule_value} character.");
50 | }
51 | break;
52 |
53 | case 'max':
54 |
55 | if (strlen($value) > $rule_value)
56 | {
57 | $this->addError("{$item} must be maximum of {$rule_value} character.");
58 | }
59 | break;
60 |
61 | case 'match':
62 |
63 | if ($value != $source[$rule_value])
64 | {
65 | $this->addError("{$rule_value} must match {$item}.");
66 | }
67 | break;
68 |
69 | case 'email':
70 |
71 | if (filter_var($value,FILTER_VALIDATE_EMAIL) !== $rule_value)
72 | {
73 | $this->addError("{$item} must valid email format.");
74 | }
75 | break;
76 |
77 | case 'alnum':
78 |
79 | if (ctype_alnum($value) !== $rule_value)
80 | {
81 | $this->addError("{$item} must alphanumeric.");
82 | }
83 | break;
84 |
85 | case 'unique':
86 | $check = $this->_db->get($rule_value, array($item, '=', $value));
87 |
88 | if ($check->count())
89 | {
90 | $this->addError("{$item} already exists.");
91 | }
92 | break;
93 |
94 | case 'verify':
95 | $check = $this->_db->get($rule_value, array($item, '=', $value));
96 |
97 | if (! Password::check($value, $this->_user->data()->password))
98 | {
99 | $this->addError("Wrong Current Password!.");
100 | }
101 | break;
102 | }
103 | }
104 | }
105 | }
106 |
107 | if (empty($this->_errors))
108 | {
109 | $this->_passed = true;
110 | }
111 |
112 | return $this;
113 | }
114 |
115 | private function addError($error)
116 | {
117 | $this->_errors[] = $error;
118 | }
119 |
120 | public function errors()
121 | {
122 | return $this->_errors;
123 | }
124 |
125 | public function error()
126 | {
127 | return $this->_errors[0];
128 | }
129 |
130 | public function passed()
131 | {
132 | return $this->_passed;
133 | }
134 |
135 | public function optional()
136 | {
137 | return $this->_optional;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/app/backend/core/Config.php:
--------------------------------------------------------------------------------
1 | _pdo = new PDO('mysql:host='.Config::get('mysql/host').';'.
17 | 'dbname='.Config::get('mysql/db_name'),
18 | Config::get('mysql/username'),
19 | Config::get('mysql/password')
20 | );
21 | }
22 | catch(PDOException $e)
23 | {
24 | die($e->getMessage());
25 | }
26 | }
27 |
28 | public static function getInstance()
29 | {
30 | if (!isset(self::$_instance))
31 | {
32 | self::$_instance = new Database();
33 | }
34 |
35 | return self::$_instance;
36 | }
37 |
38 | public function query($sql, $params = array())
39 | {
40 | $this->_error = false;
41 |
42 | if ($this->_query = $this->_pdo->prepare($sql))
43 | {
44 | $x = 1;
45 |
46 | if (count($params))
47 | {
48 | foreach ($params as $param)
49 | {
50 | $this->_query->bindvalue($x, $param);
51 | $x++;
52 | }
53 | }
54 |
55 | if ($this->_query->execute())
56 | {
57 | $this->_results = $this->_query->fetchAll(PDO::FETCH_OBJ);
58 | $this->_count = $this->_query->rowCount();
59 | }
60 | else
61 | {
62 | $this->_error = true;
63 | }
64 | }
65 |
66 | return $this;
67 | }
68 |
69 | public function action($action, $table, $where = array())
70 | {
71 | if (count($where) === 3)
72 | {
73 | $operators = array('=', '>', '<', '>=', '<=');
74 |
75 | $field = $where[0];
76 | $operator = $where[1];
77 | $value = $where[2];
78 |
79 | if (in_array($operator, $operators))
80 | {
81 | $sql = "{$action} FROM {$table} WHERE {$field} {$operator} ?";
82 |
83 | if (!$this->query($sql, array($value))->error())
84 | {
85 | return $this;
86 | }
87 | }
88 | }
89 |
90 | return false;
91 | }
92 |
93 | public function get($table, $where)
94 | {
95 | return $this->action('SELECT *', $table, $where);
96 | }
97 |
98 | public function delete($table, $where)
99 | {
100 | return $this->action('DELETE', $table, $where);
101 | }
102 |
103 | public function insert($table, $fields = array())
104 | {
105 | if (count($fields))
106 | {
107 | $keys = array_keys($fields);
108 | $values = '';
109 | $x = 1;
110 |
111 | foreach ($fields as $field)
112 | {
113 | $values .= '?';
114 |
115 | if ($x < count($fields))
116 | {
117 | $values .= ', ';
118 | }
119 |
120 | $x++;
121 | }
122 |
123 | $sql = "INSERT INTO {$table} (`".implode('`, `', $keys)."`) VALUES ({$values})";
124 |
125 | if (!$this->query($sql, $fields)->error())
126 | {
127 | return true;
128 | }
129 | }
130 |
131 | return false;
132 | }
133 |
134 | public function update($table, $id, $fields)
135 | {
136 | $set = '';
137 | $x = 1;
138 |
139 | foreach ($fields as $name => $value)
140 | {
141 | $set .= "{$name} = ?";
142 |
143 | if ($x < count($fields))
144 | {
145 | $set .= ', ';
146 | }
147 |
148 | $x++;
149 | }
150 |
151 | $sql = "UPDATE {$table} SET {$set} WHERE uid = {$id}";
152 |
153 | if (!$this->query($sql, $fields)->error())
154 | {
155 | return true;
156 | }
157 |
158 | return false;
159 | }
160 |
161 | public function results()
162 | {
163 | return $this->_results;
164 | }
165 |
166 | public function first()
167 | {
168 | return $this->results()[0];
169 | }
170 |
171 | public function error()
172 | {
173 | return $this->_error;
174 | }
175 |
176 | public function count()
177 | {
178 | return $this->_count;
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/app/backend/core/Hash.php:
--------------------------------------------------------------------------------
1 | Config::get('password/cost'),
10 | 'salt' => Hash::salt()
11 | ));
12 | }
13 |
14 | public static function rehash($hash)
15 | {
16 | return password_rehash($hash, Config::get('password/algo_name'), Config::get('password/cost'));
17 | }
18 |
19 | public static function check($password, $hash)
20 | {
21 | return password_verify($password, $hash);
22 | }
23 |
24 | public static function getInfo($hash)
25 | {
26 | return password_get_info($hash);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/backend/core/Redirect.php:
--------------------------------------------------------------------------------
1 | .panel-heading {
11 | color: #00415d;
12 | background-color: #fff;
13 | border-color: #fff;
14 | text-align:center;
15 | }
16 | .panel-login>.panel-heading a{
17 | text-decoration: none;
18 | color: #666;
19 | font-weight: bold;
20 | font-size: 15px;
21 | -webkit-transition: all 0.1s linear;
22 | -moz-transition: all 0.1s linear;
23 | transition: all 0.1s linear;
24 | }
25 | .panel-login>.panel-heading a.active{
26 | color: #029f5b;
27 | font-size: 18px;
28 | }
29 | .panel-login>.panel-heading hr{
30 | margin-top: 10px;
31 | margin-bottom: 0px;
32 | clear: both;
33 | border: 0;
34 | height: 1px;
35 | background-image: -webkit-linear-gradient(left,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0.15),rgba(0, 0, 0, 0));
36 | background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
37 | background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
38 | background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
39 | }
40 | .panel-login input[type="text"],.panel-login input[type="email"],.panel-login input[type="password"] {
41 | height: 45px;
42 | border: 1px solid #ddd;
43 | font-size: 16px;
44 | -webkit-transition: all 0.1s linear;
45 | -moz-transition: all 0.1s linear;
46 | transition: all 0.1s linear;
47 | }
48 | .panel-login input:hover,
49 | .panel-login input:focus {
50 | outline:none;
51 | -webkit-box-shadow: none;
52 | -moz-box-shadow: none;
53 | box-shadow: none;
54 | border-color: #ccc;
55 | }
56 | .btn-login {
57 | background-color: #59B2E0;
58 | outline: none;
59 | color: #fff;
60 | font-size: 14px;
61 | height: auto;
62 | font-weight: normal;
63 | padding: 14px 0;
64 | text-transform: uppercase;
65 | border-color: #59B2E6;
66 | }
67 | .btn-login:hover,
68 | .btn-login:focus {
69 | color: #fff;
70 | background-color: #53A3CD;
71 | border-color: #53A3CD;
72 | }
73 | .forgot-password {
74 | text-decoration: underline;
75 | color: #888;
76 | }
77 | .forgot-password:hover,
78 | .forgot-password:focus {
79 | text-decoration: underline;
80 | color: #666;
81 | }
82 |
83 | .btn-register {
84 | background-color: #1CB94E;
85 | outline: none;
86 | color: #fff;
87 | font-size: 14px;
88 | height: auto;
89 | font-weight: normal;
90 | padding: 14px 0;
91 | text-transform: uppercase;
92 | border-color: #1CB94A;
93 | }
94 | .btn-register:hover,
95 | .btn-register:focus {
96 | color: #fff;
97 | background-color: #1CA347;
98 | border-color: #1CA347;
99 | }
100 |
--------------------------------------------------------------------------------
/app/frontend/assets/css/profile.css:
--------------------------------------------------------------------------------
1 | .user-row {
2 | margin-bottom: 14px;
3 | }
4 |
5 | .user-row:last-child {
6 | margin-bottom: 0;
7 | }
8 |
9 | .dropdown-user {
10 | margin: 13px 0;
11 | padding: 5px;
12 | height: 100%;
13 | }
14 |
15 | .dropdown-user:hover {
16 | cursor: pointer;
17 | }
18 |
19 | .table-user-information > tbody > tr {
20 | border-top: 1px solid rgb(221, 221, 221);
21 | }
22 |
23 | .table-user-information > tbody > tr:first-child {
24 | border-top: 0;
25 | }
26 |
27 |
28 | .table-user-information > tbody > tr > td {
29 | border-top: 0;
30 | }
31 | .toppad
32 | {margin-top:20px;
33 | }
34 |
--------------------------------------------------------------------------------
/app/frontend/assets/js/login-form.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | $('#login-form-link').click(function(e) {
4 | $("#login-form").delay(100).fadeIn(100);
5 | $("#register-form").fadeOut(100);
6 | $('#register-form-link').removeClass('active');
7 | $(this).addClass('active');
8 | e.preventDefault();
9 | });
10 | $('#register-form-link').click(function(e) {
11 | $("#register-form").delay(100).fadeIn(100);
12 | $("#login-form").fadeOut(100);
13 | $('#login-form-link').removeClass('active');
14 | $(this).addClass('active');
15 | e.preventDefault();
16 | });
17 |
18 | });
19 |
--------------------------------------------------------------------------------
/app/frontend/assets/js/profile.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 | var panels = $('.user-infos');
3 | var panelsButton = $('.dropdown-user');
4 | panels.hide();
5 |
6 | //Click dropdown
7 | panelsButton.click(function() {
8 | //get data-for attribute
9 | var dataFor = $(this).attr('data-for');
10 | var idFor = $(dataFor);
11 |
12 | //current button
13 | var currentButton = $(this);
14 | idFor.slideToggle(400, function() {
15 | //Completed slidetoggle
16 | if(idFor.is(':visible'))
17 | {
18 | currentButton.html('');
19 | }
20 | else
21 | {
22 | currentButton.html('');
23 | }
24 | })
25 | });
26 |
27 |
28 | $('[data-toggle="tooltip"]').tooltip();
29 |
30 | $('button').click(function(e) {
31 | e.preventDefault();
32 | alert("This is a demo.\n :-)");
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/app/frontend/includes/errors/404.php:
--------------------------------------------------------------------------------
1 | Oops, That Page Cannot be Found!
2 |
--------------------------------------------------------------------------------
/app/frontend/includes/footer.php:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |