Skip to content
Snippets Groups Projects
Commit 53ecbe23 authored by Giildo's avatar Giildo
Browse files

:tada: Exam

parents
Branches
No related merge requests found
Showing
with 546 additions and 0 deletions
.idea
.vscode
.sass-cache
\ No newline at end of file
# Examen de Prog web 2
## L2 S4 automne 2022
Consignes :
- Forkez ce repository sur votre compte gitlab en utilisant le bouton Fork en haut à droite de la page.
![Image de fork](./assets/img/fork.png)
- Clonez le repository sur votre machine locale.
- Vous avez 1h30 (jusqu'à 9h30) pour réaliser l'examen. C'est l'heure des commits qui sera pris en compte.
- Vous avez le droit à toutes les ressources que vous voulez (internet, notes, votre projet, etc.)
- Utilisation de VSCodium obligatoire et le travail doit être réalisé sur un ordinateur de la fac.
### Exercice 1 - AJAX (10 points)
Dans le fichier `/assets/js/loadGame.js` :
- ajouter une fonction pour charger, avec ajax, les trois premiers jeux de la base de
données : `/assets/db/database.sqlite` (API = `/assets/actions/gameServer.php`). Ensuite les insérer dans le DOM,
dans `main > section` du fichier `index.php`. (3 points)
- ajouter une fonction pour charger, en ajax, la quantité totale de jeux dans la base (
API = `/assets/actions/gameTableSize.php`). (2 points)
- ajouter un événement sur le bouton "Load more" pour lancer la fonction créée au premier point qui permettra de charger
les jeux trois par trois. Quand tous le jeux sont chargés faire disparaitre le bouton (2 point)
Dans le fichier `/assets/actions/gameServer.php` :
- utiliser le fichier `Database.php` pour charger les trois premiers jeux dans la base de données et les retourner en
JSON. (2 points)
Dans le fichier `/assets/actions/gameTableSize.php` :
- utiliser le fichier `Database.php` pour charger le nombre de jeu total dans la base et le retourner en JSON. (1
points)
### Exercice 2 - CSS (3 points)
Dans le fichier `/assets/css/index.css` :
- ajouter le style à la section pour permettre d'avoir un affichage avec trois cards par ligne sur desktop, deux sur
tablette et une sur mobile.
N.B. : si vous souhaitez utiliser du SASS des fichiers sont à votre disposition dans le dossier `/assets/sass`, si
vous préférez travailler directement en CSS, vous pouvez utiliser le fichier `/assets/css/index.css`. Si vous utilisez
le fichier SCSS, vous devez compiler le fichier en CSS pour que les changements soient pris en compte et que je les
corrige.
### Exercice 3 - PHP (3 points)
Dans le fichier `/assets/actions/register.php` :
- ajouter une fonction qui permet d'insérer le nouvel utilisateur dans la base de données.
- ajouter une redirection sur la page de connexion si l'inscription est réussie ou sur la page d'inscription si elle
échoue.
### Exercice 4 - HTML (2 points)
Dans le fichier `register.php` :
- ajouter un formulaire pour permettre à l'utilisateur de s'inscrire sur le site. Attention un style existe déjà,
utilisez une structure pour permettre de l'adapter au mieux.
### Exercice 5 - Question (2 points)
Ci-dessous merci de répondre à ces deux questions (merci de répondre avec quelques mots simples et de ne pas
copier/coller, je ne souhaite pas de définition toute faite, mais une réponse personnelle) :
- Quel est le protocole utilisé pour communiquer avec le serveur ?
- JS est un langage asynchrone ou synchrone ? Expliquez.
<?php
require_once __DIR__ . '/assets/locale/Translate.php';
$translate = new Translate('fr');
$specificJS = '
<script src="/assets/js/random.js" defer type="module"></script>
<script src="/assets/js/bubbles.js" defer type="module"></script>
';
$specificCSS = '
<link rel="stylesheet" href="/assets/css/formPages.css"/>
';
require_once __DIR__ . '/assets/template/head.php';
if (!$userConnected) {
header('Location: /login.php?target=' . base64_encode($_SERVER['REQUEST_URI']));
}
require_once __DIR__ . '/assets/template/nav.php';
?>
<main>
<div>
<h1><?php echo $translate->getTrad('admin.title'); ?></h1>
<form action="/assets/actions/admin.php" method="post" enctype="multipart/form-data">
<label>
<?php echo $translate->getTrad('admin.picture'); ?>
<input type="file" name="picture" required/>
</label>
<label>
<?php echo $translate->getTrad('admin.name'); ?>
<input type="text" name="name" required/>
</label>
<label>
<?php echo $translate->getTrad('admin.description'); ?>
<textarea name="description" required></textarea>
</label>
<label>
<?php echo $translate->getTrad('admin.price'); ?>
<input type="number" step="0.01" name="price" required/>
</label>
<label>
<?php echo $translate->getTrad('admin.releaseDate'); ?>
<input type="date" name="releaseDate" required/>
</label>
<button type="submit">
<?php echo $translate->getTrad('admin.add'); ?>
</button>
</form>
</div>
</main>
<?php
require_once __DIR__ . '/assets/template/footer.php';
?>
<?php
require_once __DIR__ . '/../db/Database.php';
$db = new Database();
$result = $db->insertGame(
$_POST['name'],
$_FILES['picture'],
$_POST['description'],
$_POST['price'],
$_POST['releaseDate'],
);
if ($result) {
header('Location: /index.php');
} else {
header('Location: /admin.php?error=1');
}
<?php
// utiliser le fichier Database.php pour charger les trois premiers jeux dans la base de données et les retourner en JSON. (2 points)
require_once __DIR__ . '/../db/Database.php';
<?php
// utiliser le fichier Database.php pour charger le nombre de jeu total dans la base et le retourner en JSON. (1 points)
require_once __DIR__ . '/../db/Database.php';
<?php
require_once __DIR__ . '/../db/Database.php';
$db = new Database();
$result = $db->login(
$_POST['username'],
$_POST['password'],
);
if ($result) {
session_start();
$_SESSION['username'] = $_POST['username'];
if (isset($_GET['target'])) {
header('Location: ' . base64_decode($_GET['target']));
} else {
header('Location: /index.php');
}
} else {
header('Location: /login.php?error=1');
}
<?php
/**
* ajouter une fonction qui permet d'insérer le nouvel utilisateur dans la base de données.
* ajouter une redirection sur la page de connexion si l'inscription est réussie ou sur la page d'inscription si elle échoue.
*/
require_once __DIR__ . '/../db/Database.php';
body, html {
overflow: hidden; }
main {
width: 100%;
height: calc(100vh - var(--nav-height));
display: flex;
justify-content: center;
align-items: center; }
main > div {
background-color: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(10px);
padding: 1rem 2rem;
border-radius: 1.25rem;
margin: 0 auto; }
main > div h2 {
text-align: center;
margin: 0 0 1rem;
font-size: 2rem; }
main > div form {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem; }
main > div form label {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
width: 100%; }
main > div form label input, main > div form label textarea {
width: 100%;
padding: 0.5rem;
box-sizing: border-box;
border: none;
border-bottom: 1px solid var(--color-primary);
font-size: 1rem;
font-weight: 500;
background-color: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(10px);
transition: all 0.2s ease-in-out; }
main > div form label input:focus, main > div form label textarea:focus {
background-color: rgba(255, 255, 255, 0.8); }
/*# sourceMappingURL=formPages.css.map */
{
"version": 3,
"mappings": "AAAA,UAAW;EACT,QAAQ,EAAE,MAAM;;AAGlB,IAAK;EACH,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,+BAA+B;EACvC,OAAO,EAAE,IAAI;EACb,eAAe,EAAE,MAAM;EACvB,WAAW,EAAE,MAAM;EAEnB,UAAM;IACJ,gBAAgB,EAAE,wBAAwB;IAC1C,eAAe,EAAE,UAAU;IAC3B,OAAO,EAAE,SAAS;IAClB,aAAa,EAAE,OAAO;IACtB,MAAM,EAAE,MAAM;IAEd,aAAG;MACD,UAAU,EAAE,MAAM;MAClB,MAAM,EAAE,QAAQ;MAChB,SAAS,EAAE,IAAI;IAGjB,eAAK;MACH,OAAO,EAAE,IAAI;MACb,cAAc,EAAE,MAAM;MACtB,WAAW,EAAE,MAAM;MACnB,GAAG,EAAE,IAAI;MAGT,qBAAM;QACJ,OAAO,EAAE,IAAI;QACb,cAAc,EAAE,MAAM;QACtB,WAAW,EAAE,UAAU;QACvB,GAAG,EAAE,MAAM;QACX,KAAK,EAAE,IAAI;QAEX,2DAAgB;UACd,KAAK,EAAE,IAAI;UACX,OAAO,EAAE,MAAM;UACf,UAAU,EAAE,UAAU;UACtB,MAAM,EAAE,IAAI;UACZ,aAAa,EAAE,8BAA8B;UAC7C,SAAS,EAAE,IAAI;UACf,WAAW,EAAE,GAAG;UAChB,gBAAgB,EAAE,wBAAwB;UAC1C,eAAe,EAAE,UAAU;UAC3B,UAAU,EAAE,oBAAoB;UAEhC,uEAAQ;YACN,gBAAgB,EAAE,wBAAwB",
"sources": ["../sass/formPages.scss"],
"names": [],
"file": "formPages.css"
}
\ No newline at end of file
body > header {
width: 100%;
height: 500px;
position: relative;
background-image: url("/assets/img/header.jpg");
background-position: center;
background-size: cover;
display: flex;
align-items: center;
justify-content: center; }
body > header h1 {
background-color: rgba(255, 255, 255, 0.5);
padding: 20px 40px;
border-radius: 5px;
font-size: 3rem;
backdrop-filter: blur(10px); }
main {
margin: 0 4rem; }
main section a {
color: black; }
main section a article {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
border: 1px solid var(--color-primary);
background-color: var(--color-primary-transparent);
box-sizing: border-box;
border-radius: 1rem; }
main section a article header {
position: relative;
height: 200px;
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: center;
width: 100%; }
main section a article header img {
left: 0;
right: 0;
top: 0;
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 1rem 1rem 0 0;
position: absolute;
z-index: -1; }
main section a article header h3 {
padding: 1rem 0;
text-align: center;
width: 100%;
font-size: 2rem;
background-color: rgba(255, 255, 255, 0.5); }
main section a article p {
padding: 0.75rem;
font-size: 0.75rem; }
/*# sourceMappingURL=index.css.map */
{
"version": 3,
"mappings": "AACE,aAAS;EACP,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,KAAK;EACb,QAAQ,EAAE,QAAQ;EAClB,gBAAgB,EAAE,6BAA6B;EAC/C,mBAAmB,EAAE,MAAM;EAC3B,eAAe,EAAE,KAAK;EACtB,OAAO,EAAE,IAAI;EACb,WAAW,EAAE,MAAM;EACnB,eAAe,EAAE,MAAM;EAEvB,gBAAG;IACD,gBAAgB,EAAE,wBAAwB;IAC1C,OAAO,EAAE,SAAS;IAClB,aAAa,EAAE,GAAG;IAClB,SAAS,EAAE,IAAI;IACf,eAAe,EAAE,UAAU;;AAMjC,IAAK;EACH,MAAM,EAAE,MAAM;EAGZ,cAAE;IACA,KAAK,EAAE,KAAK;IAEZ,sBAAQ;MACN,MAAM,EAAE,IAAI;MACZ,OAAO,EAAE,IAAI;MACb,cAAc,EAAE,MAAM;MACtB,WAAW,EAAE,MAAM;MACnB,MAAM,EAAE,8BAA8B;MACtC,gBAAgB,EAAE,gCAAgC;MAClD,UAAU,EAAE,UAAU;MACtB,aAAa,EAAE,IAAI;MAEnB,6BAAO;QACL,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI;QACb,cAAc,EAAE,MAAM;QACtB,WAAW,EAAE,OAAO;QACpB,eAAe,EAAE,MAAM;QACvB,KAAK,EAAE,IAAI;QAEX,iCAAI;UACF,IAAI,EAAE,CAAC;UACP,KAAK,EAAE,CAAC;UACR,GAAG,EAAE,CAAC;UACN,KAAK,EAAE,IAAI;UACX,MAAM,EAAE,KAAK;UACb,UAAU,EAAE,KAAK;UACjB,aAAa,EAAE,aAAa;UAC5B,QAAQ,EAAE,QAAQ;UAClB,OAAO,EAAE,EAAE;QAGb,gCAAG;UACD,OAAO,EAAE,MAAM;UACf,UAAU,EAAE,MAAM;UAClB,KAAK,EAAE,IAAI;UACX,SAAS,EAAE,IAAI;UACf,gBAAgB,EAAE,wBAAwB;MAI9C,wBAAE;QACA,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,OAAO",
"sources": ["../sass/index.scss"],
"names": [],
"file": "index.css"
}
\ No newline at end of file
:root {
--color-primary: #2F90A3;
--color-primary-transparent: rgba(47, 144, 163, 0.2);
--color-secondary: #F0DF46;
--color-secondary-bgc: #fffbd6;
--color-secondary-transparent: rgba(240, 223, 70, 0);
--nav-height: 64px; }
html {
font-size: 20px; }
html, body {
overflow-x: hidden; }
@keyframes bubbleMove {
0% {
transform: translateY(0); }
100% {
transform: translateY(100%); } }
body {
font-size: 0.8rem;
margin: 0;
min-height: 100vh;
box-sizing: border-box;
background-color: var(--color-secondary-bgc);
font-family: 'Roboto', sans-serif; }
body h1, body h2, body h3, body h4, body h5, body h6 {
font-family: 'Raleway', 'Roboto', sans-serif; }
body a {
color: var(--color-primary);
text-decoration: none; }
body button {
background-color: var(--color-primary);
color: #fff;
border: none;
border-radius: 0.5rem;
padding: 0.25rem 0.5rem;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease-in-out; }
body button:hover {
background-color: #2a7d8f; }
body .bubble {
background: radial-gradient(ellipse at center, var(--color-secondary-transparent) 20%, var(--color-secondary) 100%);
border-radius: 50%;
position: absolute;
animation-name: bubbleMove;
animation-duration: 5s;
animation-direction: alternate;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
z-index: -1; }
body nav {
position: sticky;
top: 0;
width: 100%;
height: var(--nav-height);
background-color: var(--color-secondary); }
body nav ul {
display: flex;
justify-content: space-around;
align-items: center;
height: 100%;
list-style: none;
margin: 0; }
body nav ul li {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem; }
/*# sourceMappingURL=style.css.map */
{
"version": 3,
"mappings": "AAAA,KAAM;EACJ,eAAe,CAAC,QAAQ;EACxB,2BAA2B,CAAC,wBAAwB;EAEpD,iBAAiB,CAAC,QAAQ;EAC1B,qBAAqB,CAAC,QAAQ;EAC9B,6BAA6B,CAAC,sBAAsB;EAEpD,YAAY,CAAC,KAAK;;AAGpB,IAAK;EACH,SAAS,EAAE,IAAI;;AAGjB,UAAW;EACT,UAAU,EAAE,MAAM;;AAGpB,qBAOC;EANC,EAAG;IACD,SAAS,EAAE,aAAa;EAE1B,IAAK;IACH,SAAS,EAAE,gBAAgB;AAI/B,IAAK;EACH,SAAS,EAAE,MAAM;EACjB,MAAM,EAAE,CAAC;EACT,UAAU,EAAE,KAAK;EACjB,UAAU,EAAE,UAAU;EACtB,gBAAgB,EAAE,0BAA0B;EAC5C,WAAW,EAAE,oBAAoB;EAEjC,oDAAuB;IACrB,WAAW,EAAE,+BAA+B;EAG9C,MAAE;IACA,KAAK,EAAE,oBAAoB;IAC3B,eAAe,EAAE,IAAI;EAGvB,WAAO;IACL,gBAAgB,EAAE,oBAAoB;IACtC,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,IAAI;IACZ,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,cAAc;IACvB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,GAAG;IAChB,MAAM,EAAE,OAAO;IACf,UAAU,EAAE,oBAAoB;IAEhC,iBAAQ;MACN,gBAAgB,EAAE,OAAO;EAI7B,YAAQ;IACN,UAAU,EAAE,uGAAuG;IACnH,aAAa,EAAE,GAAG;IAClB,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,UAAU;IAC1B,kBAAkB,EAAE,EAAE;IACtB,mBAAmB,EAAE,SAAS;IAC9B,yBAAyB,EAAE,QAAQ;IACnC,yBAAyB,EAAE,WAAW;IACtC,OAAO,EAAE,EAAE;EAGb,QAAI;IACF,QAAQ,EAAE,MAAM;IAChB,GAAG,EAAE,CAAC;IACN,KAAK,EAAE,IAAI;IACX,MAAM,EAAE,iBAAiB;IACzB,gBAAgB,EAAE,sBAAsB;IAExC,WAAG;MACD,OAAO,EAAE,IAAI;MACb,eAAe,EAAE,YAAY;MAC7B,WAAW,EAAE,MAAM;MACnB,MAAM,EAAE,IAAI;MACZ,UAAU,EAAE,IAAI;MAChB,MAAM,EAAE,CAAC;MAET,cAAG;QACD,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,MAAM;QACnB,eAAe,EAAE,MAAM;QACvB,SAAS,EAAE,IAAI",
"sources": ["../sass/style.scss"],
"names": [],
"file": "style.css"
}
\ No newline at end of file
<?php
class Database
{
private PDO $pdo;
public function __construct()
{
$this->pdo = new PDO('sqlite:' . __DIR__ . '/database.sqlite');
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->initGameTable();
}
private function initGameTable(): void
{
$this->pdo->exec('CREATE TABLE IF NOT EXISTS game (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255) NOT NULL,
image VARCHAR(255) NOT NULL,
description TEXT,
price FLOAT NOT NULL,
release_date DATE NOT NULL
)');
$this->pdo->exec('CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
password VARCHAR(255) NOT NULL,
username VARCHAR(255) NOT NULL UNIQUE
)');
}
public function getGames()
{
// Charger ici les jeux de la base de données trois par trois
}
/**
* @param $id
* @return mixed
*/
public function getGame($id)
{
$statement = $this->pdo->prepare('SELECT * FROM game WHERE id = :id');
$statement->bindValue(':id', $id, PDO::PARAM_INT);
$statement->execute();
return $statement->fetch();
}
public function getGameTableSize()
{
// Retourner le nombre de jeux dans la base de données
}
/**
* @param $username
* @param $password
* @return bool
*/
public function register($username, $password)
{
// Faire une fonction pour enregistrer un utilisateur dans la base de données.
}
public function login($username, $password)
{
$statement = $this->pdo->prepare('SELECT * FROM user WHERE username = :username');
$statement->bindValue(':username', htmlspecialchars($username), PDO::PARAM_STR);
$statement->execute();
$user = $statement->fetch();
if ($user) {
return password_verify($password, $user['password']);
}
return false;
}
public function insertGame($name, $picture, $description, $price, $releaseDate)
{
if (
$this->checkField($name, true, 2, 255) &&
$this->checkField($description, false) &&
$this->checkField($price, true, 1, 255, '/^[0-9,.]+$/') &&
$this->checkField($releaseDate, true, 1, 255, '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/')
) {
try {
$pictureName = $this->savePicture($picture);
if (!$pictureName) {
return false;
}
$statement = $this->pdo->prepare('INSERT INTO game (name, image, description, price, release_date) VALUES (:name, :image, :description, :price, :release_date)');
$statement->bindValue(':name', htmlspecialchars($name), PDO::PARAM_STR);
$statement->bindValue(':image', $pictureName, PDO::PARAM_STR);
$statement->bindValue(':description', htmlspecialchars($description), PDO::PARAM_STR);
$statement->bindValue(':price', $price, PDO::PARAM_INT);
$statement->bindValue(':release_date', $releaseDate, PDO::PARAM_STR);
return $statement->execute();
} catch (Exception $e) {
return false;
}
}
return false;
}
/**
* @param $field
* @param $isRequired
* @param $minLength
* @param $maxLength
* @param $regex
*
* @return bool
*/
private function checkField($field, $isRequired, $minLength = null, $maxLength = null, $regex = null)
{
if ($isRequired && empty($field)) {
return false;
}
if ($minLength && strlen($field) < $minLength) {
return false;
}
if ($maxLength && strlen($field) > $maxLength) {
return false;
}
if ($regex && !preg_match($regex, $field)) {
return false;
}
return true;
}
public function savePicture($picture)
{
$extension = pathinfo($picture['name'], PATHINFO_EXTENSION);
$filename = uniqid() . '.' . $extension;
$result = move_uploaded_file($picture['tmp_name'], __DIR__ . '/../../public/uploads/' . $filename);
if (!$result) {
return false;
}
return $filename;
}
}
File added
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7.97,16L5,19C4.67,19.3 4.23,19.5 3.75,19.5A1.75,1.75 0 0,1 2,17.75V17.5L3,10.12C3.21,7.81 5.14,6 7.5,6H16.5C18.86,6 20.79,7.81 21,10.12L22,17.5V17.75A1.75,1.75 0 0,1 20.25,19.5C19.77,19.5 19.33,19.3 19,19L16.03,16H7.97M7,8V10H5V11H7V13H8V11H10V10H8V8H7M16.5,8A0.75,0.75 0 0,0 15.75,8.75A0.75,0.75 0 0,0 16.5,9.5A0.75,0.75 0 0,0 17.25,8.75A0.75,0.75 0 0,0 16.5,8M14.75,9.75A0.75,0.75 0 0,0 14,10.5A0.75,0.75 0 0,0 14.75,11.25A0.75,0.75 0 0,0 15.5,10.5A0.75,0.75 0 0,0 14.75,9.75M18.25,9.75A0.75,0.75 0 0,0 17.5,10.5A0.75,0.75 0 0,0 18.25,11.25A0.75,0.75 0 0,0 19,10.5A0.75,0.75 0 0,0 18.25,9.75M16.5,11.5A0.75,0.75 0 0,0 15.75,12.25A0.75,0.75 0 0,0 16.5,13A0.75,0.75 0 0,0 17.25,12.25A0.75,0.75 0 0,0 16.5,11.5Z" /></svg>
\ No newline at end of file
assets/img/fork.png

1.25 KiB

assets/img/header.jpg

339 KiB

assets/img/img.png

937 KiB

0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment