From 3a82baec9d793edf81ac2b151b0f4d4159641375 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 1 Apr 2024 11:09:25 -0400 Subject: login and register, liking on homepage --- src/web/core/_controller.php | 64 +++++++++++++++ src/web/core/_model.php | 44 ++++++++++ src/web/core/database.php | 189 +++++++++++++++++++++++++++++++++++++++++++ src/web/core/loader.php | 101 +++++++++++++++++++++++ src/web/core/router.php | 147 +++++++++++++++++++++++++++++++++ 5 files changed, 545 insertions(+) create mode 100644 src/web/core/_controller.php create mode 100644 src/web/core/_model.php create mode 100644 src/web/core/database.php create mode 100644 src/web/core/loader.php create mode 100644 src/web/core/router.php (limited to 'src/web/core') diff --git a/src/web/core/_controller.php b/src/web/core/_controller.php new file mode 100644 index 0000000..4a788d3 --- /dev/null +++ b/src/web/core/_controller.php @@ -0,0 +1,64 @@ +load = $load; + $this->main = $this->load->model('main'); + $this->db = $this->main->db; + + $info = $this->main->info; + $lang = $info['lang']; + $this->load->lang($lang); + $app = $info['app']; + if ($app) { + $this->load->app_lang($lang, $app); + } + } + + public function index() {} + + public function redirect($link) { + header('Location: '. $link, true, 301); + die(); + } + + protected function view($__name, $data = array()) { + $__root = $GLOBALS['webroot']; + $__path = $__root . '/_views/' . $__name . '.php'; + if (is_file($__path)) { + extract($data); + require($__path); + return; + } + } + + protected function is_ajax(): bool { + $_POST = json_decode( + file_get_contents("php://input"), true + ); + return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'; + } + + protected function error($code): void { + $_GET['code'] = $code; + $this->main->info['app'] = 'error'; + $error_controller = $this->load->controller('apps/error'); + $error_controller->index(); + die(); + } + +} +?> diff --git a/src/web/core/_model.php b/src/web/core/_model.php new file mode 100644 index 0000000..936fab4 --- /dev/null +++ b/src/web/core/_model.php @@ -0,0 +1,44 @@ +load = $load; + $this->main = $this->load->model('main'); + $this->db = $this->main->db; + $this->config = new Aesthetic(); + } + + /** + * @returns the base model data + */ + public function get_data(): array { + $data = array(); + $data['self'] = $this->main->user(); + + $info = $this->main->info; + $app = $info['app']; + + if ($app) { + $files = $this->config->get_files($app); + $data = array_merge($data, $files); + } else { + $files = $this->config->get_files(); + $data = array_merge($data, $files); + } + + return $data; + } +} diff --git a/src/web/core/database.php b/src/web/core/database.php new file mode 100644 index 0000000..81352a9 --- /dev/null +++ b/src/web/core/database.php @@ -0,0 +1,189 @@ +conn = $conn; + $this->query = ''; + + $this->set = FALSE; + $this->where = FALSE; + $this->param = array(); + } + + private function in($array) { + $in = 'IN ('; + foreach ($array as $idx => $item) { + if ($idx != 0) { + $in .= ","; + } + $in .= "?"; + array_push($this->param, $item); + } + $in .= ")"; + return $in; + } + + public function select($select) { + $this->query .= "SELECT $select\n"; + return $this; + } + + public function from($from) { + $this->query .= "FROM $from\n"; + return $this; + } + + public function where($cond) { + if (!$this->where) { + $this->where = TRUE; + $this->query .= "WHERE "; + } + $this->query .= "$cond "; + return $this; + } + + public function like($item) { + $this->query .= "LIKE ?\n"; + array_push($this->param, $item); + return $this; + } + + public function eq($item) { + $this->query .= "= ?\n"; + array_push($this->param, $item); + return $this; + } + + public function ne($item) { + $this->query .= "<> ?\n"; + array_push($this->param, $item); + return $this; + } + + public function lt($item) { + $this->query .= "< ?\n"; + array_push($this->param, $item); + return $this; + } + + public function le($item) { + $this->query .= "<= ?\n"; + array_push($this->param, $item); + return $this; + } + + public function where_in($column, $array) { + if (!$this->where) { + $this->where = TRUE; + $this->query .= "WHERE "; + } + if (empty($array)) { + $this->query .= "FALSE\n"; + return $this; + } + $in = $this->in($array); + $this->query .= "$column $in\n"; + return $this; + } + + public function and() { + $this->query .= "AND "; + return $this; + } + + public function or() { + $this->query .= "OR "; + return $this; + } + + public function join($table, $on, $type = 'LEFT') { + $this->query .= "$type JOIN $table ON $on\n"; + return $this; + } + + public function limit($limit) { + $this->query .= "LIMIT ?\n"; + array_push($this->param, $limit); + return $this; + } + + public function offset($offset) { + $this->query .= "OFFSET ?\n"; + array_push($this->param, $offset); + return $this; + } + + public function order_by($column, $order = 'ASC') { + $this->query .= "ORDER BY " . $column . ' ' . $order . ' '; + return $this; + } + + public function rows() { + $stmt = $this->conn->prepare($this->query); + try { + $stmt->execute($this->param); + } catch (Exception $ex) { + echo $ex; + echo '
>> caused by <<
'; + echo str_replace("\n", "
", $this->query); + } + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + public function row() { + $stmt = $this->conn->prepare($this->query); + $stmt->execute($this->param); + return $stmt->fetch(PDO::FETCH_ASSOC); + } +} + +/** + * DatabaseHelper + * allows queries on the + * xssbook postgres database + */ +class DatabaseHelper { + + private $conn; + + function __construct() { + $this->conn = NULL; + } + + private function connect() { + if ($this->conn === NULL) { + $user = getenv("POSTGRES_USER"); + $pass = getenv("POSTGRES_PASSWORD"); + $db = getenv("POSTGRES_DB"); + $host = 'db'; + $port = '5432'; + + $conn_str = sprintf("pgsql:host=%s;port=%d;dbname=%s;user=%s;password=%s", + $host, + $port, + $db, + $user, + $pass + ); + $this->conn = new \PDO($conn_str); + $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + } + return $this->conn; + } + + public function select($select) { + $conn = $this->connect(); + $query = new DatabaseQuery($conn); + return $query->select($select); + } + +} diff --git a/src/web/core/loader.php b/src/web/core/loader.php new file mode 100644 index 0000000..2091533 --- /dev/null +++ b/src/web/core/loader.php @@ -0,0 +1,101 @@ +loaded = array(); + } + + /** + * Loads a $type of object from a $dir with a given $name + * @param string $name - the name of the object to load + * @param string $dir - the directory theese objects are stored in + * @param string $type - the type of the object + */ + private function load_type($name, $dir, $type): object|NULL { + $path = $dir . '/' . $name . '.php'; + if (array_key_exists($path, $this->loaded)) { + return $this->loaded[$path]; + } + + if (!file_exists($path)) { + return NULL; + } + + $parts = explode('/', $name); + $part = end($parts); + $class = ucfirst($part) . '_' . $type; + require($path); + + $ref = NULL; + try { + $ref = new ReflectionClass($class); + } catch (Exception $_e) {} + + if ($ref === NULL) { + return NULL; + } + + $obj = $ref->newInstance($this); + $this->loaded[$path] = $obj; + + return $obj; + } + + /** + * Loads a model + * @param string $name - the name of the model to load + */ + public function model($name): object|NULL { + $root = $GLOBALS['webroot']; + $dir = $root . '/_model'; + return $this->load_type($name, $dir, 'model'); + } + + /** + * Loads a controller + * @param string $name - the name of the controller to load + */ + public function controller($name): Controller|NULL { + $root = $GLOBALS['webroot']; + $dir = $root . '/_controller'; + return $this->load_type($name, $dir, 'controller'); + } + + /** + * Loads the given common lang + * @param string $lang_code 0 the language code + */ + public function lang($lang_code): void { + $dir = $GLOBALS['webroot'] . '/lang/' . $lang_code . '/'; + $lang = $GLOBALS['lang']; + if ($handle = opendir($dir)) { + while (false !== ($entry = readdir($handle))) { + if ($entry === '.' || $entry === '..' || $entry === 'apps') { + continue; + } + $path = $dir . $entry; + require($path); + } + } + $GLOBALS['lang'] = $lang; + } + + /** + * Loads a given app specific lang + * @param string $lang_code - the language code + * @param string $name - the name of the app + */ + public function app_lang($lang_code, $name): void { + $dir = $GLOBALS['webroot'] . '/lang/' . $lang_code . '/apps/'; + $file = $dir . $name . '.php'; + if (file_exists($file)) { + $lang = $GLOBALS['lang']; + require($dir . $name . '.php'); + $GLOBALS['lang'] = $lang; + } + } + +} diff --git a/src/web/core/router.php b/src/web/core/router.php new file mode 100644 index 0000000..72c7674 --- /dev/null +++ b/src/web/core/router.php @@ -0,0 +1,147 @@ +load = $load; + $this->main = $this->load->model('main'); + } + + /** + * @param string $path - the current request path + * Gets the current route + * @return array + */ + private function get_req_route($path): array { + // trim the path + $path = trim($path); + // remove first '/' + $path = substr($path, 1); + // get path parts + $parts = explode('/', $path); + + $len = count($parts); + + // get route info + $route = array(); + // e.g. / + if ($path === '') { + $route = array( + 'route' => '', + 'slug' => 'index', + ); + // e.g. /home /login + } else if ($len === 1) { + $route = array( + 'route' => $parts[0], + 'slug' => 'index', + ); + // e.g. /home/posts + } else { + $route = array ( + 'route' => implode('/', array_slice($parts, 0, -1)), + 'slug' => end($parts) + ); + }; + + $route['app'] = $route['route']; + $routes = $GLOBALS['routes']; + if (array_key_exists($route['route'], $routes)) { + $route['route'] = $routes[$route['route']]; + } + + return $route; + } + + /** + * Gets the curret request info + * @return array + */ + private function get_req(): array { + $method = $_SERVER['REQUEST_METHOD']; + + $uri = parse_url($_SERVER['REQUEST_URI']); + $path = $uri['path']; + + return array_merge( + array( + 'uri' => $uri, + 'method' => $method, + 'lang' => $this->get_lang(), + ), + $this->get_req_route($path), + ); + } + + /** + * Gets the current language + * @return string + */ + private function get_lang(): string { + return 'en_US'; + } + + /** + * Handles a router error code + * @param int $code - the http error code + * @param bool $recursed + */ + private function handle_error($code, $recursed): void { + if ($recursed) { + die($code . ' (recursed)'); + } + + $this->main->info['slug'] = 'index'; + $this->main->info['app'] = 'error'; + $this->main->info['route'] = 'apps/error'; + $req = $this->main->info; + $_GET['code'] = $code; + + $this->handle_req($req, TRUE); + } + + /** + * @param array $req + * @param bool $recursed + */ + private function handle_req($req, $recursed = FALSE): void { + $controller = $this->load->controller($req['route']); + + if ($controller === NULL) { + $this->handle_error(404, $recursed); + return; + } + + $ref = NULL; + try { + $ref = new ReflectionMethod($controller, $req['slug']); + } catch (Exception $_e) {} + + if ($ref === NULL || !$ref->isPublic()) { + $this->handle_error(404, $recursed); + return; + + } + + $ref->invoke($controller); + } + + /** + * Handels the incomming reuqest + */ + public function handle_request(): void { + $req = $this->get_req(); + $this->main->info = $req; + $this->handle_req($req); + } + +} -- cgit v1.2.3-freya