commit 801dcc31e1aa6e08bc3ed4ab09fd10303595b0bc
parent 2a3318f095e97e7ceaeccbe359c6252a8b33d51a
Author: Gerco van Woudenbergh <[email protected]>
Date: Tue, 6 Jun 2023 13:42:33 +0200
Merge pull request #1 from friedelschoen/login
login functionality from iwa
Diffstat:
8 files changed, 669 insertions(+), 0 deletions(-)
diff --git a/Lollipop/DatabaseObject.php b/Lollipop/DatabaseObject.php
@@ -0,0 +1,169 @@
+<?php
+
+namespace Lollipop {
+ require_once "SQLDatabase.php";
+
+ abstract class DatabaseObject
+ {
+ protected string $table;
+ protected string $primary;
+
+ protected SQLDatabase $db;
+ protected array $data = [];
+ protected array $changed_keys = [];
+
+ function __construct(SQLDatabase $db)
+ {
+ $this->db = $db;
+ $this->primary = $this->get_primary();
+ $this->table = $this->get_table();
+ }
+
+ abstract static function get_primary(): string;
+ abstract static function get_table(): string;
+
+ public function setData($data)
+ {
+ $this->data = $data;
+ }
+ public function where(string $key, string $value)
+ {
+ $sql = "SELECT * FROM {$this->table} WHERE $key = ?";
+ $value = array($value);
+ $stmt = $this->db->conn->prepare($sql);
+ $stmt->execute($value);
+ $result = $stmt->get_result();
+ if ($result->num_rows == 0) {
+ return false;
+ }
+ $this->data = $result->fetch_assoc();
+ return true;
+ }
+
+ public function where_array(array $values) : bool
+ {
+ $sql = "SELECT * FROM {$this->table} WHERE ";
+ $params = [];
+ $i = 0;
+ foreach($values as $key => $param){
+ if($i > 0)
+ $sql .= " and ";
+ $sql .= "{$key} = ?";
+ $params[] = $param;
+ }
+
+ $stmt = $this->db->conn->prepare($sql);
+ $stmt->execute($params);
+ $result = $stmt->get_result();
+
+ if ($result->num_rows == 0) {
+ return false;
+ }
+
+ $this->data = $result->fetch_assoc();
+ return true;
+ }
+ public function load(string $id): bool
+ {
+ /*this fuction accepts an $id value for the primary key
+ * loads the row into data[]
+ * returns bool if row is found
+ */
+ $sql = "SELECT * FROM {$this->table} WHERE {$this->primary} = ?";
+
+ $stmt = $this->db->conn->prepare($sql);
+ $stmt->execute([$id]);
+ $result = $stmt->get_result();
+
+ if ($result->num_rows == 0) {
+ return false;
+ }
+
+ $this->data = $result->fetch_assoc();
+ return true;
+ }
+
+ public function save() : bool
+ {
+ if (!$this->changed_keys)
+ return false;
+
+ $sql = "UPDATE {$this->table} SET ";
+
+ $values = [];
+ foreach ($this->changed_keys as $index => $key) {
+ if ($index > 0)
+ $sql .= ', ';
+ $sql .= "$key = ?";
+ $values[] = $this->data[$key];
+ }
+
+ $sql .= " WHERE {$this->primary} = ?";
+ $values[] = $this->data[$this->primary];
+
+ $stmt = $this->db->conn->prepare($sql);
+
+ $this->changed_keys = [];
+
+ if($stmt->execute($values))
+ return true;
+ else
+ return false;
+ }
+
+ public function add() : bool
+ /* this function add the set variables to the database */
+ {
+ if (!$this->changed_keys)
+ return false;
+
+ $sql = "INSERT INTO {$this->table} (";
+ $sql_val = ") VALUES (";
+ $values = [];
+
+ foreach ($this->changed_keys as $index => $key) {
+ if ($index > 0){
+ $sql .= ', ';
+ $sql_val .= ', ';
+ }
+ $sql .= $key;
+ $sql_val .= "?";
+ $values[] = $this->data[$key];
+ }
+
+ $sql .= $sql_val . ")";
+ $stmt = $this->db->conn->prepare($sql);
+
+ $this->changed_keys = [];
+
+ if($stmt->execute($values))
+ return true;
+ else
+ return false;
+ }
+ public function delete()
+ {
+ $sql = "DELETE FROM {$this->table} WHERE {$this->primary} = ?";
+ $stmt = $this->db->conn->prepare($sql);
+ $stmt->execute([$this->data[$this->primary]]);
+ $this->data = [];
+ $this->changed_keys = [];
+ }
+
+ public function __get(string $name)
+ {
+ return $this->data[$name];
+ }
+
+ public function __set(string $name, $value)
+ {
+ $this->data[$name] = $value;
+ $this->changed_keys[] = $name;
+ }
+
+ public function getData()
+ {
+ return $this->data;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/Lollipop/Router.php b/Lollipop/Router.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Lollipop {
+ class Router
+ {
+ protected array $routes = [];
+ protected string $path;
+
+ protected function match(string $match, array &$route_vars): bool
+ {
+ $route_split = explode('/', $this->path);
+ $match_split = explode('/', $match);
+
+ if (sizeof($route_split) != sizeof($match_split)) {
+ return false;
+ }
+
+ foreach ($match_split as $index => $m) {
+ if (str_starts_with($m, ':')) {
+ $route_vars[substr($m, 1)] = $route_split[$index];
+ } else if ($m != $route_split[$index]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ function addRoute(string|array $method, string $match, string|callable $func)
+ {
+ if (is_string($method))
+ $method = [$method];
+
+
+ $this->routes[] = array(
+ "method" => $method,
+ "match" => $match,
+ "func" => $func,
+ );
+ }
+
+ function includeRoute(string $path, array $_PARAM)
+ {
+ include $path;
+ }
+
+ function route(string $base = null)
+ {
+ $this->path = $_SERVER["REQUEST_URI"];
+
+ if (strpos($this->path, '?'))
+ $this->path = explode('?', $this->path)[0];
+
+ if ($base && strpos($this->path, $base))
+ $this->path = explode($base, $this->path)[1];
+
+ $method = $_SERVER["REQUEST_METHOD"];
+
+ foreach ($this->routes as $route) {
+ if ($route["method"] != null && !in_array($method, $route["method"]))
+ continue;
+
+ $vars = [];
+ if ($this->match($route["match"], $vars)) {
+ if (is_callable($route["func"])) {
+ return $route["func"]($vars);
+ } else {
+ return $this->includeRoute($route["func"], $vars);
+ }
+ }
+ }
+
+ echo "404 '$this->path' not found!";
+ return null;
+ }
+ }
+}
+\ No newline at end of file
diff --git a/Lollipop/SQLDatabase.php b/Lollipop/SQLDatabase.php
@@ -0,0 +1,129 @@
+<?php
+
+namespace Lollipop {
+ use mysqli;
+
+ class SQLDatabase
+ {
+ public mysqli $conn;
+
+ function __construct(string $host, string $username, string $password, string $database = null, int $port = null)
+ {
+ $this->conn = new mysqli($host, $username, $password, $database, $port);
+ }
+
+ function get(string $table_class)
+ {
+ /* this function accepts a $table_name creates a Database object with the class $table_name
+ * retuns a Database object
+ */
+ $cls = new $table_class($this);
+ return $cls;
+ }
+
+ function all_where(string $table_name, array $vars)
+ {
+ /* this function accepts a table name and an array[$column_name => $value]
+ * statement is select * from $table_name where $column_name = $value AND etc...
+ * returns an array of classes
+ */
+ if (!sizeof($vars)) {
+ return [];
+ }
+ $cls = new $table_name($this);
+
+ $sql = "SELECT * FROM {$cls->get_table()} WHERE ";
+ $params = [];
+
+ $i = 0;
+ foreach ($vars as $key => $value) {
+ if ($i > 0) {
+ $sql .= ' AND ';
+ }
+ $sql .= " $key LIKE ?";
+ $params[] = $value;
+ $i++;
+ }
+
+ $stmt = $this->conn->prepare($sql);
+ $stmt->execute($params);
+ $result = $stmt->get_result();
+
+ if (!$result || $result->num_rows == 0) {
+ return [];
+ }
+
+ $objects = [];
+ while ($row = $result->fetch_assoc()) {
+ $o = new $table_name($this);
+ $o->setData($row);
+ $objects[] = $o;
+ }
+ return $objects;
+ }
+
+ function all(string $table_name)
+ {
+ /* loads whole table $table_name
+ * returns array of objects
+ */
+ $cls = new $table_name($this);
+
+ $sql = "SELECT * FROM {$cls->get_table()}";
+
+ $result = $this->conn->query($sql);
+
+ if (!$result || $result->num_rows == 0) {
+ return [];
+ }
+
+ $objects = [];
+ while ($row = $result->fetch_assoc()) {
+ $o = new $table_name($this);
+ $o->setData($row);
+ $objects[] = $o;
+ }
+ return $objects;
+ }
+ public function getDateRange(string $table_name, array $query, $order)
+ {
+ if($query == null)
+ return [];
+
+ $cls = new $table_name($this);
+
+ $sql = "SELECT * FROM {$cls->get_table()} WHERE ";
+ $index = 0;
+ $values = [];
+ foreach($query as $key => $q) {
+ foreach ($q as $k => $value) {
+ if ($index > 0) {
+ $sql .= " AND ";
+ }
+ $sql .= "{$key} {$k} ?";
+ $values[] = $value;
+ $index++;
+ }
+ }
+
+ $sql .= " ORDER BY date_time " . $order;
+ $sql .= " LIMIT 1000";
+ $stmt = $this->conn->prepare($sql);
+ $stmt->execute($values);
+ $result = $stmt->get_result();
+
+ if ($result->num_rows == 0) {
+ return [];
+ }
+
+ $objects = [];
+ while ($row = $result->fetch_assoc()) {
+ $o = new $table_name($this);
+ $o->setData($row);
+ $objects[] = $o;
+ }
+ return $objects;
+ }
+ }
+}
+?>
+\ No newline at end of file
diff --git a/Lollipop/Template.php b/Lollipop/Template.php
@@ -0,0 +1,147 @@
+<?php
+namespace Lollipop {
+use ErrorException;
+ Class Template{
+ function template(string $uri, array $data) : string{
+ /* this function takes a uri and a string array data */
+ /* opens a stream to the uri specified file and stores the content in $file*/
+
+ return $this->insert_data(file_get_contents($uri), $data);
+ }
+
+ private function insert_data(string $file, array $data):string{
+ $html = "";
+ $filesize = strlen($file);
+
+ for($i = 0; $i < $filesize-1; $i++){
+ if ($file[$i] == '{' && $file[$i + 1] == '{') {
+ for ($j = $i; $j < $filesize-1; $j++) {
+ if ($file[$j] == '}' && $file[$j + 1] == '}') {
+ $html .= $this->parse_template(trim(substr($file, $i + 2, $j - $i - 2)), $data);
+ $i = $j + 1;
+ break;
+ }
+ }
+ } else {
+ $html .= $file[$i];
+ }
+ }
+ return $html;
+ }
+
+ private function parse_template(string $expr, array $data) {
+ $tokens = [];
+ $in_string = false;
+ $buffer = '';
+
+ foreach (str_split($expr) as $c) {
+ if ($c == '"' && !$in_string) { // string start
+ $in_string = true;
+ } else if ($c == '"') { // string end
+ $in_string = false;
+ } else if ($c == ' ' && !$in_string) {
+ if ($buffer) {
+ $tokens[] = $buffer;
+ $buffer = '';
+ }
+ } else {
+ $buffer .= $c;
+ }
+ }
+ if ($buffer)
+ $tokens[] = $buffer;
+
+ return $this->eval_tokens($tokens, $data);
+ }
+
+ private function eval_tokens(array $tokens, array $data) {
+ $funcs = [
+ "add" => function(array &$tokens) {
+ $right = array_pop($tokens);
+ $left = array_pop($tokens);
+
+ if ($left == null || $right == null)
+ throw new ErrorException("Stack is empty");
+
+ return $left + $right;
+ },
+ "sub" => function(array &$tokens) {
+ $right = array_pop($tokens);
+ $left = array_pop($tokens);
+
+ if ($left == null || $right == null)
+ throw new ErrorException("Stack is empty");
+
+ return intval($left) - intval($right);
+ },
+ "mul" => function(array &$tokens) {
+ $right = array_pop($tokens);
+ $left = array_pop($tokens);
+
+ if ($left == null || $right == null)
+ throw new ErrorException("Stack is empty");
+
+ return intval($left) * intval($right);
+ },
+ "div" => function(array &$tokens) {
+ $right = array_pop($tokens);
+ $left = array_pop($tokens);
+
+ if ($left == null || $right == null)
+ throw new ErrorException("Stack is empty");
+
+ return intval($left) / intval($right);
+ },
+ "cat" => function(array &$tokens) {
+ $right = array_pop($tokens);
+ $left = array_pop($tokens);
+
+ if ($left == null || $right == null)
+ throw new ErrorException("Stack is empty");
+
+ return $left . $right;
+ },
+
+ "to_int" => function(array &$tokens) {
+ $val = array_pop($val);
+
+ if ($val == null)
+ throw new ErrorException("Stack is empty");
+
+ return inval($val);
+ },
+
+ "include" => function (array &$tokens) {
+ $name = array_pop($tokens);
+
+ if (!$name)
+ throw new ErrorException("Stack is empty");
+
+ include($name);
+ },
+ "eval" => function (array &$tokens) {
+ $expr = array_pop($tokens);
+
+ if (!$expr)
+ throw new ErrorException("Stack is empty");
+
+ return eval("return ($expr);");
+ }
+ ];
+
+ $stack = [];
+ foreach ($tokens as $token) {
+ if ($token[0] != '!') {
+ $stack[] = array_key_exists($token, $data) ? $data[$token] : $token;
+ } else {
+ $stack[] = $funcs[substr($token, 1)]($stack);
+ }
+ }
+
+ if (sizeof($stack) != 1)
+ throw new ErrorException("Stack-size is not 1");
+
+ return $stack[0];
+ }
+ }
+}
+\ No newline at end of file
diff --git a/Model/Login_handler.php b/Model/Login_handler.php
@@ -0,0 +1,46 @@
+<?php
+class Login_handler
+{
+ function login(string $email, string $pwd) : bool
+ //this function return true when user is autheticated uses set_globals to set $_SESSION variables
+ {
+ //create a SQLDatabase class
+ $db = new Lollipop\SQLDatabase("86.92.67.21", "friedel", "hailiwa", "lollipop");
+ //create a Database object class, with the table User
+ $u = $db->get(Model\User::class);
+
+ //check if the email exists in db
+ if(!$u->where('email', $email)){
+ //email does not exist
+ return false;
+ }else{
+ if(password_verify($pwd, $u->pwd)){
+ //authenticated -> set $_SESSION variables
+ $this->set_globals($u, $db);
+ return true;
+ } else {
+ //password did not match
+ return false;
+ }
+ }
+ }
+
+ private function set_globals(Lollipop\DatabaseObject $u, Lollipop\SQLDatabase $db)
+ //this function sets Session variables which incluse
+ //email, first_name, last_name and array user_permissions
+ {
+ //start session and set
+ session_start();
+ $_SESSION['email'] = $u->email;
+ $_SESSION['first_name'] = $u->fname;
+ $_SESSION['last_name'] = $u->lname;
+
+ //get permissions form db and set sessions_permissions
+ $p = $db->all_where(Model\Permission_user::class, array('email' => $u->email));
+ foreach($p as $permission){
+ $user_permissions[] = $permission->id;
+ }
+ $_SESSION['user_permissions'] = $user_permissions;
+ }
+}
+?>
+\ No newline at end of file
diff --git a/logic/login.php b/logic/login.php
@@ -0,0 +1,18 @@
+<?php
+include "utils\autoloader.php";
+
+//create login class
+$login_handler = new Login_handler;
+$msg = "";
+if ($_SERVER["REQUEST_METHOD"] == "POST") {
+ if(isset($_POST['email']) || !isset($_POST['password'])){
+ // fetch data from the form pass to login_handler function
+ if(($login_handler->login($_POST['email'], $_POST['password']))){
+ //authenticated
+ header('Location: /dashboard');
+ }else{
+ $msg = "<p style=\"color:red\">Incorrect username of password.</p>";
+ }
+ }
+}
+?>
+\ No newline at end of file
diff --git a/utils/autoloader.php b/utils/autoloader.php
@@ -0,0 +1,19 @@
+<?php
+
+spl_autoload_register(function ($class_name) {
+ if (DIRECTORY_SEPARATOR != "\\")
+ $class_name = str_replace("\\", DIRECTORY_SEPARATOR, $class_name);
+
+ $sr = DIRECTORY_SEPARATOR;
+ $filename = $class_name . '.php';
+ if (!file_exists($filename)) {
+ $filename = 'Model' . $sr . $class_name . '.php';
+ if (!file_exists($filename)) {
+ return false;
+ } else {
+ include 'Model' . $sr . $class_name . '.php';
+ }
+ } else {
+ include $class_name . '.php';
+ }
+});
+\ No newline at end of file
diff --git a/views/login.php b/views/login.php
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<?php
+ session_start();
+ if (isset($_SESSION['email'])) {
+ header('Location: /dashboard');
+ }
+ include "logic/login.php";
+?>
+<html>
+<head>
+ <title>Login Page</title>
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
+ integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
+</head>
+<body>
+ <div class="container mx-auto text-center">
+ <div class="row">
+ <div class="col-md-12 title">
+ <h1>Welcome to Lollipop</h1>
+ <h4>Please log in</h4>
+ </div>
+ </div>
+ </div>
+ <div class="container mt-5">
+ <div class="row justify-content-center">
+ <div class="col-md-6">
+ <div class="card">
+ <div class="card-header">Login</div>
+ <div class="card-body">
+ <form method="POST" action="/">
+ <div class="form-group">
+ <label for="email">Email:</label>
+ <input type="email" class="form-control" id="email" name="email"
+ placeholder="Enter email">
+ </div>
+ <div class="form-group">
+ <label for="password">Password:</label>
+ <input type="password" class="form-control" id="password" name="password"
+ placeholder="Enter password">
+ </div>
+ <button type="submit" name='login_btn' class="btn btn-primary">Login</button>
+ </form>
+ </div>
+ <div class="row justify-content-center">
+ <?php
+ //display login $msg
+ echo $msg;
+ ?>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</body>
+
+</html>
+\ No newline at end of file