diff --git a/add_photo.php b/add_photo.php new file mode 100644 index 0000000..62322aa --- /dev/null +++ b/add_photo.php @@ -0,0 +1,30 @@ + + + + + + + Admin Page + + + + + +
+

Admin Page

+
+
+
+ New Photo +
+
+ Logout +
+
+
+
+ + \ No newline at end of file diff --git a/config.php b/config.php index b29a8f8..d2a8dc1 100644 --- a/config.php +++ b/config.php @@ -1,5 +1,6 @@ 'localhost', @@ -9,6 +10,8 @@ const PARAMS = [ "CHARSET" => 'utf8mb4' ]; +const MEDIA_ROOT = __DIR__ . "/media/"; + $dsn = "mysql:host=" . PARAMS['HOST'] . ";dbname=" . PARAMS['DB'] . ";charset=" . PARAMS['CHARSET']; $pdoOptions = [ diff --git a/data.txt b/data.txt new file mode 100644 index 0000000..53dc6a2 --- /dev/null +++ b/data.txt @@ -0,0 +1,53 @@ +array(3) { + [0]=> + array(7) { + ["username"]=> + string(8) "useraxel" + ["name"]=> + string(4) "Axel" + ["email"]=> + string(18) "useraxel@photo.com" + ["level"]=> + string(8) "reporter" + ["age"]=> + int(25) + ["password"]=> + string(18) "useraxel1766616750" + ["hashed_password"]=> + string(60) "$2y$12$hYQWEVJC0OjEc4ugnZNh2OZIb80qeQxjcBqTHX1wbULcxYXpr.Rbq" + } + [1]=> + array(7) { + ["username"]=> + string(9) "userchris" + ["name"]=> + string(5) "Chris" + ["email"]=> + string(19) "userchris@photo.com" + ["level"]=> + string(5) "guest" + ["age"]=> + int(32) + ["password"]=> + string(19) "userchris1766616751" + ["hashed_password"]=> + string(60) "$2y$12$3UlXEjtlF58v2tV0JelOdez0VwC0IreO0oRdHTZz7mj.s2Llwx7gK" + } + [2]=> + array(7) { + ["username"]=> + string(7) "usertom" + ["name"]=> + string(3) "Tom" + ["email"]=> + string(17) "usertom@photo.com" + ["level"]=> + string(5) "admin" + ["age"]=> + int(31) + ["password"]=> + string(17) "usertom1766616751" + ["hashed_password"]=> + string(60) "$2y$12$C0wzZ5hdTDLReiIt2hX72ewNCUQGX2LYFihvCoAA/cAqjnNuQAeo6" + } +} diff --git a/functions.php b/functions.php index 6faf6a6..e0fd2da 100644 --- a/functions.php +++ b/functions.php @@ -21,22 +21,33 @@ function connectDatabase(string $dsn, array $pdoOptions): PDO return $pdo; } +function getCategories() { + global $pdo; + + $stmt = $pdo->prepare("SELECT * FROM categories ORDER BY name ASC"); + $stmt->execute(); + + $categories = $stmt->fetchAll(PDO::FETCH_ASSOC); + + return $categories; +} function parseCategories(string $cat_string) { $cat_string = trim($cat_string); $cats = explode(" ", $cat_string); - $filtered_cats = array_filter($cats, function($cat) { - if(mb_strlen($cat) <= 4) + $filtered_cats = array_filter($cats, function ($cat) { + if (mb_strlen($cat) <= 4) return false; - return(ctype_alnum($cat)); + return (ctype_alnum($cat)); }); return $filtered_cats; } -function insertCategories(array $cats) { +function insertCategories(array $cats) +{ global $pdo; try { @@ -51,21 +62,213 @@ function insertCategories(array $cats) { } $pdo->commit(); - } - catch (Exception $e) { + } catch (Exception $e) { $pdo->rollBack(); throw $e; } } +function insertError(string $username, string $password) { + global $pdo; -class User { - function createUser() { + $stmt = $pdo->prepare("INSERT INTO errors (username, password) VALUES (:username, :password)"); + $stmt->execute([ + ':username' => $username, + ':password' => $password + ]); +} +function insertLog(int $userid) { + global $pdo; + $stmt = $pdo->prepare("INSERT INTO logs (user_id) VALUES (:user_id)"); + $stmt->execute([ + ':user_id' => $userid + ]); +} +function insertPhoto(int $user_id, int $category_id, string $file, $description) { + global $pdo; + + $stmt = $pdo->prepare("INSERT INTO photos (user_id, category_id, file, description) VALUES (:user_id, :category_id, :file, :description)"); + $stmt->execute([ + ':user_id' => $user_id, + ':category_id' => $category_id, + ':file' => $file, + ':description' => $description + ]); +} + +class ValidationError extends Exception { } +class User +{ + private ?int $id; + public string $username; + public string $hashed_password; + public int $age; + public string $email; + public string $level; + + const LEVELS = ['admin', 'reporter', 'guest']; + + public function __construct(int $id, string $username, string $hashed_password, int $age, string $email, string $level) { + $this->id = $id; + $this->username = $username; + $this->hashed_password = $hashed_password; + $this->age = $age; + $this->email = $email; + $this->level = $level; } - function createUserStmt() { + public function getId() { + return $this->id; } - function createUsers() { + + static function authorize(string $username, string $password) { + global $pdo; + + $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username"); + $stmt->execute([ + ':username' => $username + ]); + $user_arr = $stmt->fetch(PDO::FETCH_ASSOC); + if (!$user_arr) { + throw new ValidationError("User not found"); + } + if (password_verify($password, $user_arr['password'])) { + return new User( + $user_arr['id'], + $user_arr['username'], + $user_arr['password'], + $user_arr['age'], + $user_arr['email'], + $user_arr['level'] + ); + } + throw new ValidationError("Password is not correct"); + } + + static function createUser(string $username, string $password, int $age, string $name, string $email, string $level) { + global $pdo; + + $stmt = $pdo->prepare("INSERT INTO users (username, password, age, email, level) VALUES (:username, :password, :age, :email, :level)"); + + $hashed_password = password_hash($password, PASSWORD_BCRYPT); + $stmt->execute([ + ':username' => $username, + ':password' => $hashed_password, + ':age' => $age, + ':email' => $email, + ':level' => $level, + ]); + + $id = $pdo->lastInsertId(); + + return new User($id, $username, $hashed_password, $age, $email, $level); + } +} + +function createRandomUsers() { + $names = ['ChrIS2','JohHn2','3toM','rAY','AxEl', '1bOraT']; + + $random_level = array_values(User::LEVELS); + shuffle($random_level); + + $mapped_names = array_map(function($name) { + $result = preg_replace('/[^a-zA-Z]/', '', $name); + $result = strtolower($result); + return ucfirst($result); + }, $names); + + $used_name_ids = []; + $users_array = array_map(function($level) use ($mapped_names, &$used_name_ids) { + $random_name_id = array_rand($mapped_names); + $random_name = $mapped_names[$random_name_id]; + $suffix_username = ""; + if(in_array($random_name_id, $used_name_ids)) { + $suffix_username = strval(rand(10, 200)); + } + $used_name_ids[] = $random_name_id; + + $username = 'user' . strtolower($random_name) . $suffix_username; + $email = $username . '@photo.com'; + $password = $username . time(); + $hashed_password = password_hash($password, PASSWORD_BCRYPT); + $age = rand(18, 47); + + $user = array( + 'username' => $username, + 'name' => $random_name, + 'email' => $email, + 'level' => $level, + 'age' => $age, + 'password' => $password, + 'hashed_password' => $hashed_password + ); + + return $user; + }, $random_level); + + return $users_array; +} + +function login(User $user) { + $_SESSION['id_user'] = $user->getId(); + $_SESSION['username'] = $user->username; + $_SESSION['level'] = $user->level; +} +function logout() { + unset($_SESSION['id_user']); + unset($_SESSION['username']); + unset($_SESSION['level']); +} +function middlewareAuthorized(?string $role = null) { + if(!isset($_SESSION['id_user'])) + header("Location: index.php"); + + if(!empty($role)) { + if($_SESSION['level'] != $role) { + http_response_code(403); + echo "403 - Permission Denied"; + exit; + } } +} + +/** + * Upload file to server + * @param array $file + * @param string $subfolder_name like 'products/' + * @return string|false + */ +function upload_file($file, $subfolder_name) { + if (isset($file) && $file['error'] === UPLOAD_ERR_OK) { + $uploadDir = MEDIA_ROOT; + + // Create new unique filename + $fileName = pathinfo($file['name'], PATHINFO_FILENAME); + $fileExtension = pathinfo($file['name'], PATHINFO_EXTENSION); + + $newFileName = time() . "-" . rand(100, 500) . '-' . $_SESSION['id_user'] . '.' . $fileExtension; + + // media/{subfolder_name}/{new_file.png} + $uploadFile = $uploadDir . $subfolder_name . $newFileName; + $filepath_db = $subfolder_name . $newFileName; + + // Get file type + $fileType = mime_content_type($file['tmp_name']); + + // if subfolder is not exists + if (!is_dir($uploadDir . $subfolder_name)) { + mkdir($uploadDir . $subfolder_name, 0775, true); + } + + // Upload file to server + if (strpos($fileType, 'image') === 0) { + if (move_uploaded_file($file['tmp_name'], $uploadFile)) { + return $filepath_db; + } else { + return false; + } + } + } + return false; } \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..24cc094 --- /dev/null +++ b/index.php @@ -0,0 +1,35 @@ + + + + + + + Login + + + + +
+
+ + + +
+ + +
+
+ + +
+ +
+
+ + + + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..317240f --- /dev/null +++ b/login.php @@ -0,0 +1,34 @@ +getId()); + if($user->level == 'admin') + header("Location: admins.php"); + else + header("Location: photos.php"); +} +catch (ValidationError $ex) { + insertError($username, $password); + error_redirect($ex->getMessage()); +} +catch (Exception $ex) { + error_redirect("500 - Server error"); +} + +echo "AAA"; \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..392ab4d --- /dev/null +++ b/logout.php @@ -0,0 +1,4 @@ + + + + + + + Add Photo + + + + +
+

Add Photo

+ +
+ + + + + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + \ No newline at end of file diff --git a/photos.php b/photos.php new file mode 100644 index 0000000..6357900 --- /dev/null +++ b/photos.php @@ -0,0 +1,23 @@ + + + + + + + + Photos + + + + +
+

Welcome to our site

+
+ Logout +
+
+ + \ No newline at end of file diff --git a/random_users.php b/random_users.php new file mode 100644 index 0000000..3820032 --- /dev/null +++ b/random_users.php @@ -0,0 +1,10 @@ + U fajlu category.php pozvati funkciju getCategories. Ovu funkciju napisati u functions.php fajlu. Funkcija getCategories STRIKTNO +prima promenljivu $cat = " na2t5u25re spo12r54t funn82y cake2! 8sea au#!tumn!"; i vraća niz koji sadrži reči koje se sastoje SAMO iz brojeva i slova i čija je dužina podatka veća od 4. + 2. `createUsers` osim toga, sta kreira korisnika rade parsiranje iz string-ova i autogenerisanje random podataka šta predstavlja **God Function** i uništava **Single Responsibility Principle**. -Bolje uraditi klas `User` koji će imati `createUserStmp`, `createUser` i `createUsers` koji uzimaju prototip objekata od klasa User. \ No newline at end of file +Bolje uraditi klas `User` koji će imati `createUser` koji uzimaju prototip objekata od klasa User. A za kreiranje random korisnika biće funkcija izvan `createRandomUsers` +> Kreirati funkciju createUsers i smestiti je u fajl functions.php. Pozvati ovu funkciju u fajlu users.php. Niz $names = +['ChrIS2','JohHn2','3toM','rAY','AxEl', '1bOraT'] i niz $level = ['admin','reporter','guest'] smestiti u fajl config.php. Funkcija +createUsers treba striktno da prima odgovarajuće parametre i da striktno vrati niz sa 3 korisnika. Niz users treba da poseduje 3 +podniza sa indeksima: username, password, hashed_password, age, name, email, level. Primenom funkcije array_map sve +vrednosti u nizu names promeniti tako da se uklone svi brojevi i da samo prvi karakter bude veliko slovo + +3. Isto iz drugog koraka, bolje uraditi klasu `User` i vratiti umesto asociativnog niza prototip klasa `User` sa svima metodami za odbradu i poljami. + +3. Bolje logiku za `User` ostaviti samo u klasu, kreirati `LEVELS` konstantu u klase nego u config.php koji odgovara za sav aplikaciju. + +4. Nemamo ponavljanjih imena (*'ChrIS2','JohHn2','3toM','rAY','AxEl', '1bOraT'*) i zato taj uslov nikada nece biti ispunjen. +> Ukoliko je već korišćeno neko ime u nizu, dodati slučajni broj između 10 i 200 na kraj username-a (na primer useraxel123). \ No newline at end of file diff --git a/users.php b/users.php new file mode 100644 index 0000000..9a4abda --- /dev/null +++ b/users.php @@ -0,0 +1,22 @@ +beginTransaction(); + + foreach ($random_users as $rand_user) { + User::createUser( + $rand_user['username'], + $rand_user['password'], + $rand_user['age'], + $rand_user['name'], + $rand_user['email'], + $rand_user['level'] + ); + } + + $pdo->commit(); +} +catch(Exception $ex) { + $pdo->rollBack(); + print($ex->getMessage()); +} \ No newline at end of file diff --git a/web_prog_task_15.sql b/web_prog_task_15.sql deleted file mode 100644 index 8b7db48..0000000 --- a/web_prog_task_15.sql +++ /dev/null @@ -1,193 +0,0 @@ --- phpMyAdmin SQL Dump --- version 5.2.3 --- https://www.phpmyadmin.net/ --- --- Хост: localhost --- Время создания: Дек 24 2025 г., 13:06 --- Версия сервера: 12.0.2-MariaDB --- Версия PHP: 8.4.14 - -SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -START TRANSACTION; -SET time_zone = "+00:00"; - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; - --- --- База данных: `web_prog_task_15` --- - --- -------------------------------------------------------- - --- --- Структура таблицы `categories` --- - -CREATE TABLE `categories` ( - `id` int(11) NOT NULL, - `name` varchar(50) NOT NULL, - `code` int(11) DEFAULT 0, - `date_time_added` datetime DEFAULT current_timestamp() -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - --- --- Дамп данных таблицы `categories` --- - -INSERT INTO `categories` (`id`, `name`, `code`, `date_time_added`) VALUES -(1, 'nature', 7106, '2025-12-23 12:53:25'), -(2, 'sport', 3419, '2025-12-23 12:53:25'), -(3, 'funny', 4055, '2025-12-23 12:53:25'); - --- -------------------------------------------------------- - --- --- Структура таблицы `errors` --- - -CREATE TABLE `errors` ( - `id` int(11) NOT NULL, - `username` varchar(50) NOT NULL, - `password` varchar(255) NOT NULL, - `date_time` datetime DEFAULT current_timestamp() -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - --- -------------------------------------------------------- - --- --- Структура таблицы `logs` --- - -CREATE TABLE `logs` ( - `id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `date_time_added` datetime DEFAULT current_timestamp() -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - --- -------------------------------------------------------- - --- --- Структура таблицы `photos` --- - -CREATE TABLE `photos` ( - `id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `category_id` int(11) NOT NULL, - `file` varchar(255) NOT NULL, - `description` text DEFAULT NULL, - `date_time_added` datetime DEFAULT current_timestamp() -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - --- -------------------------------------------------------- - --- --- Структура таблицы `users` --- - -CREATE TABLE `users` ( - `id` int(11) NOT NULL, - `username` varchar(50) NOT NULL, - `password` varchar(255) NOT NULL, - `age` int(11) NOT NULL, - `email` varchar(100) NOT NULL, - `level` enum('admin','reporter','guest') NOT NULL, - `date_time_added` datetime DEFAULT current_timestamp() -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; - --- --- Индексы сохранённых таблиц --- - --- --- Индексы таблицы `categories` --- -ALTER TABLE `categories` - ADD PRIMARY KEY (`id`); - --- --- Индексы таблицы `errors` --- -ALTER TABLE `errors` - ADD PRIMARY KEY (`id`); - --- --- Индексы таблицы `logs` --- -ALTER TABLE `logs` - ADD PRIMARY KEY (`id`), - ADD KEY `user_id` (`user_id`); - --- --- Индексы таблицы `photos` --- -ALTER TABLE `photos` - ADD PRIMARY KEY (`id`), - ADD KEY `user_id` (`user_id`), - ADD KEY `category_id` (`category_id`); - --- --- Индексы таблицы `users` --- -ALTER TABLE `users` - ADD PRIMARY KEY (`id`); - --- --- AUTO_INCREMENT для сохранённых таблиц --- - --- --- AUTO_INCREMENT для таблицы `categories` --- -ALTER TABLE `categories` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; - --- --- AUTO_INCREMENT для таблицы `errors` --- -ALTER TABLE `errors` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT для таблицы `logs` --- -ALTER TABLE `logs` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT для таблицы `photos` --- -ALTER TABLE `photos` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT для таблицы `users` --- -ALTER TABLE `users` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - --- --- Ограничения внешнего ключа сохраненных таблиц --- - --- --- Ограничения внешнего ключа таблицы `logs` --- -ALTER TABLE `logs` - ADD CONSTRAINT `logs_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`); - --- --- Ограничения внешнего ключа таблицы `photos` --- -ALTER TABLE `photos` - ADD CONSTRAINT `photos_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), - ADD CONSTRAINT `photos_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`); -COMMIT; - -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;