diff --git a/w12/.gitignore b/w12/.gitignore new file mode 100644 index 0000000..a496ede --- /dev/null +++ b/w12/.gitignore @@ -0,0 +1,2 @@ +*.jpg +/vendor \ No newline at end of file diff --git a/w12/.htaccess b/w12/.htaccess new file mode 100644 index 0000000..aa7a5f6 --- /dev/null +++ b/w12/.htaccess @@ -0,0 +1,5 @@ +RewriteEngine on +RewriteCond %{SCRIPT_FILENAME} !-f +RewriteCond %{SCRIPT_FILENAME} !-d +RewriteCond %{SCRIPT_FILENAME} !-l +RewriteRule ^(.*)$ index.php/$1 \ No newline at end of file diff --git a/w12/composer.json b/w12/composer.json new file mode 100644 index 0000000..29fb0ae --- /dev/null +++ b/w12/composer.json @@ -0,0 +1,21 @@ +{ + "name": "nuark/w12", + "description": "Work 12 app", + "type": "project", + "license": "MIT", + "autoload": { + "psr-4": { + "Nuark\\W12\\": "src/" + } + }, + "authors": [ + { + "name": "Andrew", + "email": "me@nuark.xyz" + } + ], + "require": { + "pecee/simple-router": "4.3.7.2", + "twig/twig": "^3.3" + } +} diff --git a/w12/composer.lock b/w12/composer.lock new file mode 100644 index 0000000..8285b02 --- /dev/null +++ b/w12/composer.lock @@ -0,0 +1,323 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "28d991162beec76e49d4e126da6f453e", + "packages": [ + { + "name": "pecee/simple-router", + "version": "4.3.7.2", + "source": { + "type": "git", + "url": "https://github.com/skipperbent/simple-php-router.git", + "reference": "032a2ae7e0e2d876599758f85b61bc965a63ea7c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/skipperbent/simple-php-router/zipball/032a2ae7e0e2d876599758f85b61bc965a63ea7c", + "reference": "032a2ae7e0e2d876599758f85b61bc965a63ea7c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.1" + }, + "require-dev": { + "mockery/mockery": "^1", + "phpstan/phpstan": "^0", + "phpstan/phpstan-deprecation-rules": "^0", + "phpstan/phpstan-phpunit": "^0", + "phpstan/phpstan-strict-rules": "^0", + "phpunit/phpunit": "^7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Pecee\\": "src/Pecee/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simon Sessingø", + "email": "simon.sessingoe@gmail.com" + } + ], + "description": "Simple, fast PHP router that is easy to get integrated and in almost any project. Heavily inspired by the Laravel router.", + "keywords": [ + "framework", + "input-handler", + "laravel", + "pecee", + "php", + "request-handler", + "route", + "router", + "routing", + "routing-engine", + "simple-php-router", + "url-handling" + ], + "support": { + "issues": "https://github.com/skipperbent/simple-php-router/issues", + "source": "https://github.com/skipperbent/simple-php-router/issues" + }, + "time": "2021-07-17T23:45:36+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-10-20T20:35:02+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-11-30T18:21:41+00:00" + }, + { + "name": "twig/twig", + "version": "v3.3.10", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "8442df056c51b706793adf80a9fd363406dd3674" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/8442df056c51b706793adf80a9fd363406dd3674", + "reference": "8442df056c51b706793adf80a9fd363406dd3674", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.3.10" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2022-04-06T06:47:41+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/w12/index.php b/w12/index.php new file mode 100644 index 0000000..48b2cb0 --- /dev/null +++ b/w12/index.php @@ -0,0 +1,436 @@ + false, +]); + +// start session +session_start(); + +// create favicon route +SimpleRouter::get('/favicon.ico', function() { + return; +}); + +// create main page route +SimpleRouter::get('/', function() use($twig) { + if (getSessionVariable('user') !== null) { + $user = getSessionVariable('user'); + echo $twig->render('index.twig', [ + 'user' => $user, + 'menu' => json_decode(Database::getUserMenu($user)["data"]), + 'gallery' => Database::getPublishedImages() + ]); + } else { + echo $twig->render('propose-auth.twig'); + } +}); + +// create register route +SimpleRouter::get('/register', function() use($twig) { + if (getSessionVariable('user') !== null) { + return response()->redirect('/'); + } + // get error from get parameters + $error = input()->get('error', ''); + echo $twig->render('register.twig', [ + 'error' => htmlspecialchars($error), + ]); +}); + +// create register POST route +SimpleRouter::post('/register', function() { + $login = trim(input()->post('login', '')); + $password = trim(input()->post('password', '')); + + // if login or password is empty, redirect to register page with error + if (empty($login) || empty($password)) { + return response()->redirect('/register?error=Empty login or password given!'); + } + + // try create user if ok - redirect to login page with message + try { + Database::createUser($login, $password); + $user = Database::getUser($login); + Database::createEmptyMenuForUser($user); + response()->redirect('/login?message=User created'); + } catch (PDOException $e) { + response()->redirect('/register?error=User already exists!'); + } +}); + +// create login route +SimpleRouter::get('/login', function() use($twig) { + if (getSessionVariable('user') !== null) { + return response()->redirect('/'); + } + // get message from get parameters + $message = input()->get('message', ''); + // get error from get parameters + $error = input()->get('error', ''); + echo $twig->render('login.twig', [ + 'message' => htmlspecialchars($message), + 'error' => htmlspecialchars($error), + ]); +}); + +// create login POST route +SimpleRouter::post('/login', function() { + $login = trim(input()->post('login', '')); + $password = trim(input()->post('password', '')); + + // if login or password is empty, redirect to register page with error + if (empty($login) || empty($password)) { + return response()->redirect('/login?error=Empty login or password given!'); + } + if (!Database::userExists($login)) { + return response()->redirect('/login?error=User does not exist!'); + } + if (!Database::verifyUser($login, $password)) { + return response()->redirect('/login?error=Wrong password!'); + } + + $user = Database::getUser($login); + // set session variables + setSessionVariable('user', $user); + // redirect to index page + response()->redirect('/'); +}); + +// create logout route +SimpleRouter::get('/logout', function() { + // unset session variables + unsetSessionVariable('user'); + // redirect to index page + response()->redirect('/'); +}); + +// create menu editing route +SimpleRouter::get('/editMenu', function() use($twig) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $user = getSessionVariable('user'); + echo $twig->render('edit-menu.twig', [ + 'user' => $user, + 'menu' => json_decode(Database::getUserMenu($user)["data"]), + ]); +}); + +// create menu save POST route +SimpleRouter::post('/editMenu', function() { + if (getSessionVariable('user') === null) { + return response()->json([ + 'error' => "Not authorized", + 'code' => 403, + ]); + } + try { + $user = getSessionVariable('user'); + $menuData = []; + $menu = input()->post('menu', []); + for ($i = 0; $i < count($menu->value); $i++) { + array_push($menuData, [ + 'url' => $menu->value[$i]->value['url']->value, + 'name' => $menu->value[$i]->value['name']->value, + ]); + } + Database::setUserMenu($user, json_encode($menuData)); + response()->json([ + 'data' => json_encode($menuData), + 'code' => 200, + ]); + } catch (PDOException $e) { + response()->json([ + 'error' => json_encode($e->getMessage()), + 'code' => 500, + ]); + } +}); + +// create tables lookup route +SimpleRouter::get('/lookupTables', function() use($twig) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $tables = []; + $tableData = []; + + $user = getSessionVariable('user'); + $table = input()->get('table', ''); + $sort = input()->get('sort', 'DESC'); + $col = input()->get('col', ''); + if ($table !== '') { + $cols = Database::getTableColumns($table); + if ($col === '') { + $col = $cols[0]['column_name']; + } else { + $col = $col->value; + } + $tableData = [ + "header" => $cols, + "data" => Database::getAnyTableSorted($table, $col, $sort), + ]; + } else { + $tables = array_map(function($tbl) { + return $tbl["table_name"]; + }, Database::getAvailableTables()); + } + echo $twig->render('lookup-tables.twig', [ + 'user' => $user, + 'table' => $table, + 'tables' => $tables, + 'tableData' => $tableData + ]); +}); + +// create POST router for image uploading +SimpleRouter::post('/uploadImage', function() { + if (getSessionVariable('user') === null) { + return response()->json([ + 'error' => "Not authorized", + 'code' => 403, + ]); + } + $user = getSessionVariable('user'); + $file = input()->file('file'); + $fileType = $file->type; + if ($fileType === 'image/jpeg') { + $filename = $user['login'] . '_' . time() . '.jpg'; + $fullpath = 'data/full/' . $filename; + $file->move($fullpath); + + + $size = getimagesize($fullpath); + $ratio = $size[0]/$size[1]; // width/height + if( $ratio > 1) { + $width = 200; + $height = 200/$ratio; + } + else { + $width = 200*$ratio; + $height = 200; + } + $thumb = imagecreatetruecolor($width, $height); + $source = imagecreatefromjpeg($fullpath); + + imagecopyresized($thumb, $source, 0, 0, 0, 0, $width, $height, $size[0], $size[1]); + $color = imagecolorallocate($thumb, 255, 0, 0); + imagestring($thumb, 2, 2, 2, "Watermark text :)", $color); + imagejpeg($thumb, 'data/thumb/' . $filename); + + try { + Database::addImageToGallery($filename, $user); + } catch (PDOException $e) { + return response()->json([ + 'error' => json_encode($e->getMessage()), + 'code' => 500, + ]); + } + + return response()->json([ + 'code' => 200, + ]); + } else { + return response()->json([ + 'error' => "Wrong file type", + 'code' => 400, + ]); + } +}); + +// create gallery route +SimpleRouter::get('/gallery', function() use($twig) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $user = getSessionVariable('user'); + $images = Database::getUsersImages($user); + echo $twig->render('gallery.twig', [ + 'user' => $user, + 'images' => $images, + ]); +}); + +// create image route +SimpleRouter::get('/image/{id}', function($id) use($twig) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $user = getSessionVariable('user'); + $image = Database::getImage($id); + if ($image['user_id'] !== $user['id']) { + return response()->httpCode(403); + } + + echo $twig->render('image.twig', [ + 'user' => $user, + 'image' => $image, + ]); +}); + +// create image info save POST route +SimpleRouter::post('/image/{id}', function($id) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $user = getSessionVariable('user'); + $image = Database::getImage($id); + if ($image['user_id'] !== $user['id']) { + return response()->httpCode(403); + } + + $description = input()->post('description', '')->value; + $published = boolval(input()->post('published', 0)->value)?"true":"false"; + var_dump($published); + try { + Database::updateImage($id, $description, $published); + } catch (PDOException $e) { + return response()->json([ + 'error' => json_encode($e->getMessage()), + 'code' => 500, + ]); + } + + response()->redirect('/'); +}); + +// create image DELETE route +SimpleRouter::get('/image/{id}/delete', function($id) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $user = getSessionVariable('user'); + $image = Database::getImage($id); + if ($image['user_id'] !== $user['id']) { + return response()->httpCode(403); + } + unlink('data/full/' . $image['filename']); + unlink('data/thumb/' . $image['filename']); + Database::deleteImage($id); + response()->redirect('/gallery'); +}); + +// create image serving route +SimpleRouter::all('/images', function() { + $type = input()->get('type', 'thumb'); + $filename = input()->get('filename', ''); + if (file_exists("data/$type/$filename")) { + header("Content-type: image/jpeg"); + return file_get_contents("data/$type/$filename"); + } else { + response()->httpCode(404); + } +}); + +// create export route +SimpleRouter::get('/export', function() { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + header("Content-type: application/xml"); + echo Database::exportUsersXML(); +}); + +// create import route + +// create gallery route +SimpleRouter::get('/import', function() use($twig) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $user = getSessionVariable('user'); + $message = input()->get('message', ''); + $error = input()->get('error', ''); + echo $twig->render('import.twig', [ + 'user' => $user, + 'message' => htmlspecialchars($message), + 'error' => htmlspecialchars($error), + ]); +}); + +// create import POST route +SimpleRouter::post('/import', function() { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $xml = input()->post('xml')->value; + if ($xml) { + try { + list($ok, $fail) = Database::importUsersXML($xml); + response()->redirect("/import?message=OK: $ok, FAIL: $fail"); + } catch (Exception $e) { + response()->redirect("/import?error=" . $e->getMessage()); + } + } else { + response()->redirect('/import?error=Error happened '); + } +}); + +// create image search route +SimpleRouter::get('/search', function() use($twig) { + if (getSessionVariable('user') === null) { + return response()->redirect('/'); + } + $user = getSessionVariable('user'); + $search = input()->get('search', '')->value; + $author = input()->get('author', '')->value; + $authors = Database::getUsersList(); + $images = []; + if ($search and $author) { + $images = Database::searchImages("%".$search."%", $author); + } + echo $twig->render('search.twig', [ + 'user' => $user, + 'images' => $images, + 'search' => $search, + 'author' => $author, + 'authors' => $authors, + ]); +}); + +// create recover password route +SimpleRouter::get('/recover-password', function() use($twig) { + $message = input()->get('message', ''); + $error = input()->get('error', ''); + $mail = input()->get('mail', ''); + echo $twig->render('recover-password.twig', [ + 'message' => htmlspecialchars($message), + 'error' => htmlspecialchars($error), + 'mail' => $mail, + ]); +}); + +// create recover password POST route +SimpleRouter::post('/recover-password', function() use ($twig) { + $login = input()->post('login', '')->value; + if ($login) { + try { + $user = Database::getUser($login); + if ($user) { + $newPassword = Database::generateUserNewPassword($login); + $sentMail = $twig->render('recover-password-mail.twig', [ + 'login' => $login, + 'password' => $newPassword, + ]); + response()->redirect('/recover-password?message=Success! We sent you an email with your new password&mail=' . urlencode($sentMail)); + } else { + response()->redirect('/recover-password?error=User not found'); + } + } catch (PDOException $e) { + response()->redirect('/recover-password?error=' . $e->getMessage()); + } + } else { + response()->redirect('/recover-password?error=Error happened'); + } +}); + +SimpleRouter::start(); diff --git a/w12/src/database.php b/w12/src/database.php new file mode 100644 index 0000000..17bd92d --- /dev/null +++ b/w12/src/database.php @@ -0,0 +1,222 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + + public static function getDB() { + if (!isset(self::$db)) { + try { + self::$db = new PDO(self::$dsn, self::$username, self::$password, self::$options); + } catch (PDOException $e) { + throw new PDOException($e->getMessage(), (int)$e->getCode()); + } + } + return self::$db; + } + + public static function userExists($login) { + $db = self::getDB(); + $query = $db->prepare('SELECT * FROM users WHERE login = :login'); + $query->bindParam(':login', $login); + $query->execute(); + return $query->rowCount() > 0; + } + + public static function createUser($login, $password) { + $db = self::getDB(); + $query = $db->prepare('INSERT INTO users (login, password) VALUES (:login, :password)'); + $query->bindParam(':login', $login); + $query->bindParam(':password', $password); + $query->execute(); + } + + public static function verifyUser($login, $password) { + $db = self::getDB(); + $query = $db->prepare('SELECT * FROM users WHERE login = :login AND password = :password'); + $query->bindParam(':login', $login); + $query->bindParam(':password', $password); + $query->execute(); + return $query->rowCount() > 0; + } + + public static function getUser($login) { + $db = self::getDB(); + $query = $db->prepare('SELECT * FROM users WHERE login = :login'); + $query->bindParam(':login', $login); + $query->execute(); + return $query->fetch(); + } + + public static function generateUserNewPassword($login) { + $db = self::getDB(); + $query = $db->prepare('UPDATE users SET password = :password WHERE login = :login'); + $query->bindParam(':login', $login); + $query->bindParam(':password', $password); + $password = bin2hex(random_bytes(8)); + $query->execute(); + return $password; + } + + public static function getUsersList() { + $db = self::getDB(); + $query = $db->prepare('SELECT id, login FROM users'); + $query->execute(); + return $query->fetchAll(); + } + + public static function createEmptyMenuForUser($user) { + $db = self::getDB(); + $query = $db->prepare('INSERT INTO menu (user_id) VALUES (:user_id)'); + $query->bindParam(':user_id', $user["id"]); + $query->execute(); + } + + public static function getUserMenu($user) { + $db = self::getDB(); + $query = $db->prepare('SELECT data FROM menu WHERE user_id = :user_id'); + $query->bindParam(':user_id', $user["id"]); + $query->execute(); + return $query->fetch(); + } + + public static function setUserMenu($user, $data) { + $db = self::getDB(); + $query = $db->prepare('UPDATE menu SET data = :data WHERE user_id = :user_id'); + $query->bindParam(':data', $data); + $query->bindParam(':user_id', $user["id"]); + $query->execute(); + } + + public static function addImageToGallery($filename, $user) { + $db = self::getDB(); + $query = $db->prepare('INSERT INTO images (user_id, filename) VALUES (:user_id, :filename)'); + $query->bindParam(':user_id', $user["id"]); + $query->bindParam(':filename', $filename); + $query->execute(); + } + + public static function getUsersImages($user) { + $db = self::getDB(); + $query = $db->prepare('SELECT id, filename FROM images WHERE user_id = :user_id'); + $query->bindParam(':user_id', $user["id"]); + $query->execute(); + return $query->fetchAll(); + } + + public static function getPublishedImages() { + $db = self::getDB(); + $query = $db->prepare('SELECT id, filename FROM images WHERE published = TRUE'); + $query->execute(); + return $query->fetchAll(); + } + + public static function getImage($id) { + $db = self::getDB(); + $query = $db->prepare('SELECT * FROM images WHERE id = :id'); + $query->bindParam(':id', $id); + $query->execute(); + return $query->fetch(); + } + + public static function searchImages($search, $author) { + $db = self::getDB(); + if (intval($author) !== -1) { + $query = $db->prepare('SELECT * FROM images WHERE description LIKE :search AND user_id = :author'); + $query->bindParam(':search', $search); + $query->bindParam(':author', $author); + } else { + $query = $db->prepare('SELECT * FROM images WHERE description LIKE :search'); + $query->bindParam(':search', $search); + } + $query->execute(); + return $query->fetchAll(); + } + + public static function updateImage($id, $description, $published) { + $db = self::getDB(); + $query = $db->prepare('UPDATE images SET published = :published, description = :description WHERE id = :id'); + $query->bindParam(':id', $id); + $query->bindParam(':published', $published); + $query->bindParam(':description', $description); + $query->execute(); + } + + public static function deleteImage($id) { + $db = self::getDB(); + $query = $db->prepare('DELETE FROM images WHERE id = :id'); + $query->bindParam(':id', $id); + $query->execute(); + } + + public static function getAnyTableSorted($table, $sort_by, $sort_order) { + $db = self::getDB(); + $query = $db->prepare('SELECT * FROM ' . $table . ' ORDER BY ' . $sort_by . ' ' . $sort_order); + $query->execute(); + return $query->fetchAll(); + } + + public static function getTableColumns($table) { + $db = self::getDB(); + $query = $db->prepare('SELECT column_name FROM information_schema.columns WHERE table_schema = \'public\' AND table_name = :table_name'); + $query->bindParam(':table_name', $table); + $query->execute(); + return $query->fetchAll(); + } + + public static function getAvailableTables() { + $db = self::getDB(); + $query = $db->prepare('SELECT table_name FROM information_schema.tables WHERE table_schema = \'public\' ORDER BY table_name'); + $query->execute(); + return $query->fetchAll(); + } + + public static function exportUsersXML() { + $db = self::getDB(); + $query = $db->prepare('SELECT * FROM users'); + $query->execute(); + $users = $query->fetchAll(); + $xml = new DOMDocument('1.0', 'UTF-8'); + $xml->formatOutput = true; + $root = $xml->createElement('users'); + $xml->appendChild($root); + foreach ($users as $user) { + $user_node = $xml->createElement('user'); + $root->appendChild($user_node); + $user_node->setAttribute('exported_id', $user['id']); + $user_node->setAttribute('login', $user['login']); + $user_node->setAttribute('password', $user['password']); + } + return $xml->saveXML(); + } + + public static function importUsersXML($xmlData) { + $xml = new DOMDocument(); + $xml->loadXML($xmlData); + $users = $xml->getElementsByTagName('user'); + + $ok = 0; + $fail = 0; + foreach ($users as $user) { + try { + $login = $user->getAttribute('login'); + $password = $user->getAttribute('password'); + self::createUser($login, $password); + $user = self::getUser($login); + self::createEmptyMenuForUser($user); + $ok += 1; + } catch (PDOException $e) { + $fail += 1; + } + } + return [$ok, $fail]; + } +} +?> \ No newline at end of file diff --git a/w12/src/helpers.php b/w12/src/helpers.php new file mode 100644 index 0000000..1d4e187 --- /dev/null +++ b/w12/src/helpers.php @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/w12/views/edit-menu.twig b/w12/views/edit-menu.twig new file mode 100644 index 0000000..04e6087 --- /dev/null +++ b/w12/views/edit-menu.twig @@ -0,0 +1,99 @@ + + +
+ + + +Нет изображений
+ {% endfor %} + + \ No newline at end of file diff --git a/w12/views/image.twig b/w12/views/image.twig new file mode 100644 index 0000000..6d36452 --- /dev/null +++ b/w12/views/image.twig @@ -0,0 +1,26 @@ + + + + + + +Drop XML file on page or enter content down here
+ + + + \ No newline at end of file diff --git a/w12/views/index.twig b/w12/views/index.twig new file mode 100644 index 0000000..d18661f --- /dev/null +++ b/w12/views/index.twig @@ -0,0 +1,108 @@ + + + + + + +Пусто
+ {% endif %} +Пусто
+ {% endfor %} +| + [ASC] + {{item.column_name}} + [DESC] + | + {% endfor %} +
|---|
| {{col}} | + {% endfor %} +
Пусто
+ {% endfor %} + {% else %} +Пусто
+ {% endif %} +