This commit is contained in:
2025-05-01 14:37:08 -06:00
parent b6008d462e
commit 5cd4571a92
91 changed files with 1009 additions and 36 deletions
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Day 21</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>
</head>
<body>
<h2>Hello cruel world!</h2>
</body>
</html>
+4
View File
@@ -0,0 +1,4 @@
document.addEventListener('DOMContentLoaded', function() {
let h2 = document.querySelector('h2');
h2.innerText = 'The DOM is Magical';
});
+4
View File
@@ -0,0 +1,4 @@
body {
background-color: indigo;
color: white;
}
+14
View File
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Day 22</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>
</head>
<body>
<div class="square"></div>
</body>
</html>
View File
+20
View File
@@ -0,0 +1,20 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
width: 100%;
border: 1px solid red;
}
.square {
position: absolute;
width: 200px;
height: 200px;
background-color: pink;
bottom: 0;
left: 0;
}
View File
+6
View File
@@ -0,0 +1,6 @@
div {
height: 100px;
width: 100px;
background-color: black;
border: 1px solid white;
}
View File
View File
+17
View File
@@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<title>Dummy Title</title>
<link href="css/styles.css" type="text/css" rel="stylesheet">
<script src="js/index.js" defer></script>
</head>
<body>
<?php
for ($i = 0; $i < 100; $i++)
echo '<div></div>';
?>
</body>
</html>
View File
+14
View File
@@ -0,0 +1,14 @@
document.querySelectorAll('div').forEach((d) => {
d.style.backgroundColor = 'black';
d.addEventListener('click', populate);
})
function populate() {
if (this.style.backgroundColor === 'black') {
this.style.backgroundColor = 'red';
this.style.borderRadius = '50%';
} else {
this.style.backgroundColor = 'black';
this.style.borderRadius = '0%';
}
}
View File
+11
View File
@@ -0,0 +1,11 @@
div {
position: absolute;
top: 0px;
height: 100px;
width: 100px;
background-color: black;
}
button {
float: right;
}
View File
View File
+15
View File
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<title>Dummy Title</title>
<link href="css/styles.css" type="text/css" rel="stylesheet">
<script src="js/index.js" defer></script>
</head>
<body>
<button>Button</button>
<div></div>
</body>
</html>
View File
+9
View File
@@ -0,0 +1,9 @@
const div = document.querySelector('div');
const button = document.querySelector('button')
let times = 1;
button.addEventListener('click', (e) => {
let px = 300 * times;
times++;
div.style.top = px + 'px';
});
+13
View File
@@ -0,0 +1,13 @@
<?php
require_once 'functions/init.php';
if (!isset($_SESSION['id']))
header('Location: catalog.php');
// UI Components
foreach (glob('components/cart/*.php') as $file)
require_once $file;
require_once 'components/head.php';
require_once 'components/foot.php';
+17
View File
@@ -0,0 +1,17 @@
<?php
include_once 'functions/init.php';
include_once 'functions/catalog.php';
// UI Components
foreach (glob('components/products/*.php') as $file)
require_once $file;
include_once 'components/head.php';
echo '<h1>Catalog</h1>';
echo '<div id="catalog" class="std_width center">';
echo catalog_grid(fetch_catalog());
echo '</div>';
include_once 'components/foot.php';
+20
View File
@@ -0,0 +1,20 @@
<?php
function cart_item($item)
{
$item = '
<div class="row">
<div class="square img_container">
</div>
<div class="row space_between">
<p>' . $item['description'] . '</p>
<select>
<input type="number">
</select>
</div>
</div>
';
return $item;
}
+18
View File
@@ -0,0 +1,18 @@
</body>
<footer>
<?php
$scripts = '';
switch ($_SERVER['SCRIPT_NAME']) {
case '/index.php':
$scripts .= '<script src="js/login.js"></script>';
break;
}
echo $scripts;
?>
</footer>
</html>
+21
View File
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="css/base.css">
<link rel="stylesheet" href="css/colors.css">
<?php
switch ($_SERVER['SCRIPT_NAME']) {
case '/create-account.php':
echo '<script src="js/create-account.js" defer></script>';
break;
case '/product.php':
if (!isset($_SESSION['id']))
echo '<script src="js/login-modal.js" defer></script>';
break;
}
?>
</head>
<body>
<?php include_once 'nav.php'; ?>
+25
View File
@@ -0,0 +1,25 @@
<?php
$nav = '
<nav>
<ul>
<div class="row space_between">
<div>
<li><a href="catalog.php">Products</a></li>
</div>
<div class="absolute_h_center">
<a href="index.php"><h4>ACME Store</h4></a>
</div>
<div>
' . (isset($_SESSION['id']) ? '<li><a href="cart.php">Cart</a></li>' : '') . '
' . (isset($_SESSION['id']) ? '<li><a href="logout.php">Logout</a></li>' : '') . '
' . (!isset($_SESSION['id']) ? '<li><a href="index.php">Login</a></li>' : '') . '
' . (!isset($_SESSION['id']) ? '<li><a href="create-account.php">Signup</a></li>' : '') . '
</div>
</div>
</ul>
</nav>
';
echo $nav;
+19
View File
@@ -0,0 +1,19 @@
<?php
function product_card($product)
{
$card = '
<a class="card column center full_width padding" href="product.php?id=' . $product['id'] . '">
<div class="img_container">
<img src="img/' . $product['image'] . '">
</div>
<div class="row">
<h4>' . $product['name'] . '</h4>
<h5>' . $product['price'] . '</h5>
</div>
</a>
';
return $card;
}
+16
View File
@@ -0,0 +1,16 @@
<?php
function catalog_grid($products)
{
$grid = '
<div class="grid center">
';
foreach ($products as $p)
$grid .= product_card($p);
$grid .= '
</div>
';
return $grid;
}
+36
View File
@@ -0,0 +1,36 @@
<?php
function product_page($product)
{
$page = '
<div class="product_page_card column center full_width padding">
<div class="img_container">
<img src="img/' . $product['image'] . '">
</div>
<div class="column">
<div class="row space_between">
<h3>' . $product['name'] . '</h3>
<h3>' . $product['price'] . '</h3>
</div>
<p>' . $product['description'] . '</p>
<form class="row" id="add_to_cart">
<input type="hidden" name="is_logged_in" value="' . (isset($_SESSION['id']) ? 'true' : 'false') . '">
<div class="column margin">
<label for="quantity">Quantity:</label>
<input type="number" value="1" id="quantity" name="quantity" min="1">
</div>
<input type="submit" value="Add to Cart" class="margin">
</form>
</div>
</div>
<div class="modal">
<div class="modal_content">
' . login_form() . '
</div>
</div>
';
return $page;
}
View File
+27
View File
@@ -0,0 +1,27 @@
<?php
function login_form()
{
$form = '
<div class="card center">
<form method="post" id="login_form">
<div class="column center">
<div class="column">
<label for="username">Username:</label>
<input id="username" name="username" autofocus required>
</div>
<div class="column">
<label for="password">Password:</label>
<input id="password" type="password" name="password" required>
</div>
<a href="create-account.php">Signup Instead</a>
<input type="submit" class="button submit" id="login_submit">
</div>
</form>
</div>
';
return $form;
}
+40
View File
@@ -0,0 +1,40 @@
<?php
function signup_form()
{
$form = '
<div class="card center">
<form method="post" class="column center">
<div class="column">
<label for="username">Username:</label>
<input id="username" name="username" autofocus required>
</div>
<div class="column">
<label for="password">Password:</label>
<input id="password" type="password" name="password" required>
</div>
<div class="column">
<label for="v_password">Verify Password:</label>
<input id="v_password" type="password" name="v_password" required>
</div>
<a href="index.php">Login Instead</a>
<div class="row full_width">
<input type="submit" class="button submit">
<input type="reset" class="button">
</div>
<div class="column center error">
<p id="err_username"></p>
<p id="err_match"></p>
<p id="err_length"></p>
<p id="err_num"></p>
</div>
</form>
</div>
';
return $form;
}
+17
View File
@@ -0,0 +1,17 @@
{
"name": "violet/catalog",
"autoload": {
"psr-4": {
"Violet\\Catalog\\": "src/"
}
},
"authors": [
{
"name": "Josh Ashton",
"email": "me@joshashton.dev"
}
],
"require": {
"vlucas/phpdotenv": "^5.6"
}
}
+18
View File
@@ -0,0 +1,18 @@
<?php
require_once 'functions/init.php';
require_once 'functions/user.php';
if (isset($_POST['username']) && isset($_POST['password']) && isset($_POST['v_password'])) {
if (!signup($_POST['username'], $_POST['password'], $_POST['v_password']))
echo '<p>Username is taken, or password do not match.</p>';
else {
header('Location: catalog.php');
}
}
require_once 'components/head.php';
require_once 'components/user/signup.php';
echo signup_form();
require_once 'components/foot.php';
+216
View File
@@ -0,0 +1,216 @@
/********** GENERAL **********/
* {
margin: 0;
padding: 0;
}
h1 {
font-size: 6vw;
}
h2 {
font-size: 4vw;
}
h3 {
font-size: 3vw;
}
h4 {
font-size: 2vw;
}
h5,
h6,
p,
a,
label {
font-size: 1vw;
}
/********** NAV BAR **********/
nav {
margin-bottom: 25px;
}
nav ul {}
nav ul li {
display: inline-block;
list-style: none;
}
nav ul li a {
display: block;
padding: 15px 15px 15px 15px;
text-decoration: none;
}
/********** LAYOUT CLASSES **********/
.absolute_h_center {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.center {
text-align: center;
margin: 0 auto;
}
.center_children {
align-items: center;
justify-content: center;
}
.row {
display: flex;
flex-direction: row;
}
.column {
display: flex;
flex-direction: column;
}
.space_between {
justify-content: space-between;
}
.grid {
display: grid;
grid-template-columns: 20% 20% 20% 20%;
column-gap: 75px;
row-gap: 25px;
}
/********** CARDS **********/
.card {
display: block;
width: 250px;
height: 250px;
border: 1px solid black;
}
.product_page_card {
display: block;
border: 1px solid black;
}
.card .img_container img {
min-width: 60%;
max-width: 60%;
height: auto;
}
.product_page_card .img_container img {
min-width: 30%;
max-width: 30%;
height: auto;
border: 1px solid red;
}
/********** MARGINS & PADDING **********/
.padding {
padding: 25px;
}
.padding-top {
padding-top: 25px;
}
.padding-right {
padding-right: 25px;
}
.padding-bottom {
padding-bottom: 25px;
}
.padding-left {
padding-left: 25px;
}
.margin {
margin: 25px;
}
.margin-top {
margin-top: 25px;
}
.margin-right {
margin-right: 25px;
}
.margin-bottom {
margin-bottom: 25px;
}
.margin-left {
margin-left: 25px;
}
/********** SIZING **********/
.std_width {
width: 70%;
}
.full_width {
width: 100%;
}
/********** MODALS **********/
.modal {
display: none;
position: fixed;
z-index: 1;
padding-top: 100px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
backdrop-filter: blur(10px);
}
.modal.fade-in {
display: block;
animation: fade-in 0.7s ease-in forwards;
}
.modal.fade-out {
display: none;
animation: fade-out 0.7s ease-out forwards;
}
.modal_content {
display: fit-content;
margin: auto;
width: 40%;
height: max-content;
}
@keyframes fade-in {
0% {
opacity: 0;
display: none;
}
100% {
opacity: 1;
display: block;
}
}
@keyframes fade-out {
0% {
opacity: 1;
display: block;
}
100% {
opacity: 0;
display: none;
}
}
+28
View File
@@ -0,0 +1,28 @@
:root {
--bg: #EBF2FA;
--gold: #FFD700;
--brwn: #F4A460;
--blue: #1E90FF;
--red: #DC143C;
}
nav {
background-color: var(--bg);
border-bottom: 2px solid var(--gold);
}
nav *,
nav *:visited {
color: var(--blue);
text-decoration: none;
font-weight: 800;
transition-duration: 500ms;
}
nav ul li a:hover {
background-color: var(--gold);
}
body {
background-color: var(--bg);
}
+38
View File
@@ -0,0 +1,38 @@
<?php
function pretty_dump($arg)
{
ob_start();
echo '<pre>';
print_r($arg);
echo '</pre>';
return ob_get_clean();
}
function random_string()
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$rand_string = '';
for ($i = 0; $i < 512; $i++)
$rand_string = $characters[rand(0, strlen($characters) - 1)];
return $rand_string;
}
function verify_hash($arg, $hash_salt)
{
list($salt_hex, $hash) = explode('.', $hash_salt, 2);
$salt = hex2bin($salt_hex);
$calculated_hash = hash('sha512', $salt . $arg . $_ENV['SALT']);
return hash_equals($hash, $calculated_hash);
}
function hash_salt($arg = null)
{
if (!$arg)
$arg = random_string();
$salt1 = random_bytes(256);
$salt2 = $_ENV['SALT'];
return bin2hex($salt1) . '.' . hash('sha512', $salt1 . $arg . $salt2);
}
+14
View File
@@ -0,0 +1,14 @@
<?php
function fetch_catalog()
{
$conn = get_connection();
$result = $conn->query('SELECT * FROM product');
return $result;
}
function fetch_product($id)
{
$result = exec_stmt('SELECT * FROM product WHERE id = ?', 'i', $id);
return $result->fetch_assoc();
}
+39
View File
@@ -0,0 +1,39 @@
<?php
// Use environment variables for the database password and IP address.
$db = $_ENV['DATABASE'];
$db_user = $_ENV['DATABASE_USER'];
$db_pass = $_ENV['DATABASE_PASSWORD'];
$ip_addr = $_ENV['IP_ADDRESS'];
// Make some constants
if ($_SERVER['HTTP_HOST'] == 'localhost:2440') {
define('HOST', 'localhost');
define('USER', $db_user);
define('PASS', $db_pass);
define('DB', $db);
} else {
define('HOST', $ip_addr);
define('USER', $db_user);
define('PASS', $db_pass);
define('DB', $db);
}
function exec_stmt($stmt, $param_types, ...$args)
{
$conn = get_connection();
$stmt = $conn->prepare($stmt);
$stmt->bind_param($param_types, ...$args);
$stmt->execute();
$result = $stmt->get_result();
if ($result)
return $result;
else
return mysqli_insert_id($conn);
}
function get_connection()
{
$conn = new mysqli(HOST, USER, PASS, DB);
return $conn;
}
+13
View File
@@ -0,0 +1,13 @@
<?php
session_start();
header("Content-Security-Policy: default-src 'self'; font-src 'self' https://www.nerdfonts.com/assets/fonts/Symbols-2048-em%20Nerd%20Font%20Complete.woff2; style-src 'self' 'unsafe-inline' https://nerdfonts.com/assets/css/webfont.css https://www.nerdfonts.com/assets/css/webfont.css; script-src 'self' 'unsafe-inline'; img-src 'self';");
// Initialize Composer.
require_once 'vendor/autoload.php';
require_once 'functions/base.php';
// Load environment variables.
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->safeLoad();
require_once 'functions/db.php';
+62
View File
@@ -0,0 +1,62 @@
<?php
if (isset($_POST['form_id'])) {
require_once '../vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->safeLoad();
require_once 'base.php';
require_once 'db.php';
switch ($_POST['form_id']) {
case 'create-account':
if (isset($_POST['username'])) {
$result['exists'] = (username_exists(urldecode($_POST['username'])) ? 'True' : 'False');
echo json_encode($result);
}
break;
}
}
function username_exists($username)
{
$result = exec_stmt('SELECT username FROM user WHERE username = ?', 's', $username)->fetch_assoc();
if (isset($result['username']))
return true;
else
return false;
}
function login($username, $password)
{
$user = exec_stmt('SELECT id FROM user WHERE username = ? AND password = ?', 'ss', $username, $password)->fetch_assoc();
if (!isset($user['id']))
return false;
$_SESSION['id'] = $user['id'];
return true;
}
function signup($username, $password, $verify_password)
{
echo 'test';
if (username_exists($username))
return false;
echo 'username=' . $username;
if ($password != $verify_password)
return false;
$user_id = exec_stmt('INSERT INTO user (username, password) VALUES (?, ?)', 'ss', $username, $password);
echo 'user_id=' . $user_id;
if (!isset($user_id))
return false;
$_SESSION['id'] = $user_id;
return true;
}
-10
View File
@@ -1,10 +0,0 @@
<?php
$head = <<<EOL
<head>
<title>E-Commerce</title>
<link rel="stylesheet" href="css/styles.css">
</head>
EOL;
echo $head;
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

+18 -7
View File
@@ -1,9 +1,20 @@
<?php
echo '<!doctype html>';
echo '<html lang="en">';
include('head.php');
include_once 'functions/init.php';
require_once 'functions/user.php';
echo '<body>';
include('nav.php');
echo '</body>';
echo '</html>';
if (isset($_POST['username']) && isset($_POST['password'])) {
if (login($_POST['username'], $_POST['password']))
header('Location: catalog.php');
else
echo '<p>Username and/or password are incorrect!</p>';
}
include_once 'components/head.php';
include_once 'components/user/login.php';
if (isset($_SESSION['id'])) {
echo '<h1>Welcome to the store</h1>';
} else
echo login_form();
include_once 'components/foot.php';
+65
View File
@@ -0,0 +1,65 @@
const username_field = document.querySelector('#username');
const password_field = document.querySelector('#password');
const v_password_field = document.querySelector('#v_password');
const submit_button = document.querySelector('input[type="submit"]');
const err_username = document.querySelector('#err_username');
const err_match = document.querySelector('#err_match');
const err_length = document.querySelector('#err_length');
const err_num = document.querySelector('#err_num');
function handle_input() {
const password = password_field.value;
const v_password = v_password_field.value;
if (password != v_password && v_password != '')
err_match.innerText = 'Passwords do not match.';
else
err_match.innerText = '';
if (password.length < 8)
err_length.innerText = 'Password must be at least 8 characters long.';
else
err_length.innerText = '';
const num_regex = /\d/;
if (!num_regex.test(password))
err_num.innerText = 'Password must have at least 1 digit.';
else
err_num.innerText = '';
if (err_match.innerText == '' && err_length.innerText == '' && err_num.innerText == '' && err_username == '' && v_password != '')
submit_button.disabled = false;
else
submit_button.disabled = true;
}
function handle_username() {
const username = username_field.value;
fetch('functions/user.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'form_id=create-account&username=' + username,
})
.then(response => {
if (!response.ok) {
console.log('Failed to check if username exists!');
}
return response.json(); // Parse response body as JSON
})
.then(data => {
if (data['exists'] == 'True')
err_username.innerText = 'Username is taken.';
else
err_username.innerText = '';
});
}
username_field.addEventListener('blur', handle_username);
password_field.addEventListener('input', handle_input);
v_password_field.addEventListener('input', handle_input);
submit_button.disabled = true;
+31
View File
@@ -0,0 +1,31 @@
const add_to_cart = document.querySelector('input[type="submit"]');
const modal = document.querySelector('.modal');
const username = document.querySelector('#username');
const password = document.querySelector('#password');
const login_button = document.querySelector('#login_submit');
add_to_cart.addEventListener('click', (e) => {
e.preventDefault();
if (modal.classList[0] === "fade-in") {
modal.classList.remove("fade-in");
modal.classList.add("fade-out");
} else {
modal.classList.remove("fade-out");
modal.classList.add("fade-in");
}
modal.addEventListener('click', () => {
if (modal.classList[0] === "fade-in") {
modal.classList.remove("fade-in");
modal.classList.add("fade-out");
} else {
modal.classList.remove("fade-out");
modal.classList.add("fade-in");
}
})
});
Executable → Regular
+7
View File
@@ -0,0 +1,7 @@
<?php
include_once 'functions/init.php';
foreach (array_keys($_SESSION) as $key)
unset($_SESSION[$key]);
header('Location: .');
-19
View File
@@ -1,19 +0,0 @@
<?php
$nav = <<<EOL
<div id="nav">
<ul id="nav-ul">
<li id="nav-ul-li">
<a href="#">
Home
</a>
</li>
<li id="nav-ul-li">
<a href="#">
Cart
</a>
</li>
</ul>
</div>
EOL;
echo $nav;
+21
View File
@@ -0,0 +1,21 @@
<?php
if (!isset($_GET['id']))
header('Location: catalog.php');
require_once 'functions/init.php';
require_once 'functions/catalog.php';
// UI Components
foreach (glob('components/products/*.php') as $file)
require_once $file;
require_once 'components/user/login.php';
require_once 'components/head.php';
echo '<div id="product_page" class="std_width center">';
$product = fetch_product($_GET['id']);
echo product_page($product);
echo '</div>';
require_once 'components/foot.php';
+1
View File
@@ -0,0 +1 @@
mariadb -u root -p < setup.sql
+43
View File
@@ -0,0 +1,43 @@
CREATE DATABASE IF NOT EXISTS catalog;
USE catalog;
CREATE TABLE IF NOT EXISTS user
(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(1024) NOT NULL,
login_token VARCHAR(1024) NOT NULL UNIQUE,
salt VARCHAR(256) NOT NULL,
INDEX (login_token)
);
CREATE TABLE IF NOT EXISTS product
(
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(500) NOT NULL,
image VARCHAR(100),
price FLOAT NOT NULL
);
INSERT INTO product (name, description, image, price) VALUES
("Anvil", "A heavy steel block used for hammering and shaping metal.", "anvil.jpg", 75.00),
("Axle Grease", "A thick lubricant used to reduce friction in axles and other moving parts.", "axle_grease.jpg", 8.50),
("Atom Re-Arranger", "A device of questionable scientific validity that purports to rearrange atoms.", "atom_rearranger.jpg", 499.99),
("Bed Springs", "Coiled metal springs used in mattresses and furniture for support.", "bed_springs.jpeg", 35.75),
("Bird Seed", "A mixture of seeds formulated as food for pet birds.", "bird_seed.jpg", 12.20),
("Blasting Powder", "An explosive material used for demolition and mining. Handle with extreme caution!", "blasting_powder.JPG", 150.00),
("Cork", "The bark of the cork oak tree, often used for bottle stoppers and insulation.", "cork.jpg", 2.50),
("Disintegration Pistol", "A fictional weapon capable of breaking down matter at a molecular level.", "disintegration_pistol.png", 299.00),
("Earthquake Pills", "Pills that supposedly induce seismic activity. Effects not guaranteed.", "earthquake_pills.jpg", 55.00),
("Female Roadrunner costume", "A feathered costume designed to resemble a female roadrunner.", "roadrunner_costume_female.jpg", 62.99),
("Giant Rubber Band", "An oversized elastic band, useful for large-scale stretching or launching.", "giant_rubber_band.jpg", 19.95),
("Instant Girl", "A product that claims to instantly create a companion. Results may vary significantly.", "instant_girl.jpg", 78.30),
("Iron Carrot", "A carrot made of iron. Purpose unclear.", "iron_carrot.jpeg", 22.50),
("Jet Propelled Unicycle", "A single-wheeled vehicle powered by a jet engine. For experienced riders only.", "jet_propelled_unicycle.jpg", 599.00),
("Out-Board Motor", "A detachable motor mounted on the outside of a boat's transom.", "outboard_motor.jpg", 210.00),
("Railroad Track", "A section of steel rail used for train tracks.", "railroad_track.jpeg", 315.50),
("Rocket Sled", "A sled propelled by a rocket engine, designed for high-speed travel on rails.", "rocket_sled.jpg", 850.00),
("Super Outfit", "A costume that allegedly grants the wearer extraordinary abilities. Claims not verified.", "super_outfit.jpeg", 95.00),
("Time Space Gun", "A fictional device that manipulates the fabric of spacetime. Use with caution.", "time_space_gun.jpeg", 675.00),
("X-Ray", "An electromagnetic radiation with high energy, often used for medical imaging.", "x_ray.jpeg", 1.00);