@@ -0,0 +1,52 @@ | |||
# Examen PHP1 | |||
Op deze URL vinden jullie een video met korte introductie : https://youtu.be/A3R5rbwT_nw | |||
Fork deze repo (rechts boven), maak je eigen repository en ga aan de slag als een echte professional : git branchen en committen waar nodig. Uiteindelijk merge je alles naar de master-branch. | |||
Start je eigen debugserver met volgende commando: `php -S localhost:8080 -t .` Zet breakpoints, lees foutboodschappen zeer aandachtig. Probeer eerst een zicht te krijgen op de opbouw van de code! Als last resort : het probleem beschrijven (ook in de code schrijven) is al een stap in de goede richting! | |||
Push zeker je laatste commit tegen 17u ! Je krijgt tijd tot woensdag 20u, maar dit is met strafpunten: | |||
- ma 8 feb 17u : 0 strafpunten | |||
- ma 8 feb 24u : 10 strafpunten | |||
- di 9 feb 24u : 20 strafpunten | |||
- wo 10 feb 24u : 30 strafpunten | |||
Ik kijk naar de commit-tijdstippen **in de master branch !!!** | |||
Veel succes! | |||
## Debug config | |||
Maak de juiste debug-configuratie aan. Controleer eerst welke XDebug versie je hebt: `php -v`. Heeft jouw XDebug een versie kleinder dan 3.0, gebruik dan deze configuratie als debug-config. | |||
``` | |||
{ | |||
"version": "0.2.0", | |||
"configurations": [{ | |||
"name": "Listen for XDebug", | |||
"type": "php", | |||
"request": "launch", | |||
"port": 9000 | |||
}, | |||
] | |||
} | |||
``` | |||
Is jouw versie >= 3.0, gebruik dan deze (port is aangepast naar 9003): | |||
``` | |||
{ | |||
"version": "0.2.0", | |||
"configurations": [{ | |||
"name": "Listen for XDebug", | |||
"type": "php", | |||
"request": "launch", | |||
"port": 9003 | |||
}, | |||
] | |||
} | |||
``` |
@@ -0,0 +1,319 @@ | |||
/*! | |||
* Bootstrap Reboot v4.2.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2018 The Bootstrap Authors | |||
* Copyright 2011-2018 Twitter, Inc. | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) | |||
*/ | |||
*, | |||
*::before, | |||
*::after { | |||
box-sizing: border-box; | |||
} | |||
html { | |||
font-family: sans-serif; | |||
line-height: 1.15; | |||
-webkit-text-size-adjust: 100%; | |||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); | |||
} | |||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { | |||
display: block; | |||
} | |||
body { | |||
margin: 0; | |||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | |||
font-size: 1rem; | |||
font-weight: 400; | |||
line-height: 1.5; | |||
color: #212529; | |||
text-align: left; | |||
background-color: #fff; | |||
} | |||
[tabindex="-1"]:focus { | |||
outline: 0 !important; | |||
} | |||
hr { | |||
box-sizing: content-box; | |||
height: 0; | |||
overflow: visible; | |||
} | |||
h1, h2, h3, h4, h5, h6 { | |||
margin-top: 0; | |||
margin-bottom: 0.5rem; | |||
} | |||
p { | |||
margin-top: 0; | |||
margin-bottom: 1rem; | |||
} | |||
abbr[title], | |||
abbr[data-original-title] { | |||
text-decoration: underline; | |||
-webkit-text-decoration: underline dotted; | |||
text-decoration: underline dotted; | |||
cursor: help; | |||
border-bottom: 0; | |||
text-decoration-skip-ink: none; | |||
} | |||
address { | |||
margin-bottom: 1rem; | |||
font-style: normal; | |||
line-height: inherit; | |||
} | |||
ol, | |||
ul, | |||
dl { | |||
margin-top: 0; | |||
margin-bottom: 1rem; | |||
} | |||
ol ol, | |||
ul ul, | |||
ol ul, | |||
ul ol { | |||
margin-bottom: 0; | |||
} | |||
dt { | |||
font-weight: 700; | |||
} | |||
dd { | |||
margin-bottom: .5rem; | |||
margin-left: 0; | |||
} | |||
blockquote { | |||
margin: 0 0 1rem; | |||
} | |||
b, | |||
strong { | |||
font-weight: bolder; | |||
} | |||
small { | |||
font-size: 80%; | |||
} | |||
sub, | |||
sup { | |||
position: relative; | |||
font-size: 75%; | |||
line-height: 0; | |||
vertical-align: baseline; | |||
} | |||
sub { | |||
bottom: -.25em; | |||
} | |||
sup { | |||
top: -.5em; | |||
} | |||
a { | |||
color: #007bff; | |||
text-decoration: none; | |||
background-color: transparent; | |||
} | |||
a:hover { | |||
color: #0056b3; | |||
text-decoration: underline; | |||
} | |||
a:not([href]):not([tabindex]) { | |||
color: inherit; | |||
text-decoration: none; | |||
} | |||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { | |||
color: inherit; | |||
text-decoration: none; | |||
} | |||
a:not([href]):not([tabindex]):focus { | |||
outline: 0; | |||
} | |||
pre, | |||
code, | |||
kbd, | |||
samp { | |||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; | |||
font-size: 1em; | |||
} | |||
pre { | |||
margin-top: 0; | |||
margin-bottom: 1rem; | |||
overflow: auto; | |||
} | |||
figure { | |||
margin: 0 0 1rem; | |||
} | |||
img { | |||
vertical-align: middle; | |||
border-style: none; | |||
} | |||
svg { | |||
overflow: hidden; | |||
vertical-align: middle; | |||
} | |||
table { | |||
border-collapse: collapse; | |||
} | |||
caption { | |||
padding-top: 0.75rem; | |||
padding-bottom: 0.75rem; | |||
color: #6c757d; | |||
text-align: left; | |||
caption-side: bottom; | |||
} | |||
th { | |||
text-align: inherit; | |||
} | |||
label { | |||
display: inline-block; | |||
margin-bottom: 0.5rem; | |||
} | |||
button { | |||
border-radius: 0; | |||
} | |||
button:focus { | |||
outline: 1px dotted; | |||
outline: 5px auto -webkit-focus-ring-color; | |||
} | |||
input, | |||
button, | |||
select, | |||
optgroup, | |||
textarea { | |||
margin: 0; | |||
font-family: inherit; | |||
font-size: inherit; | |||
line-height: inherit; | |||
} | |||
button, | |||
input { | |||
overflow: visible; | |||
} | |||
button, | |||
select { | |||
text-transform: none; | |||
} | |||
button, | |||
[type="button"], | |||
[type="reset"], | |||
[type="submit"] { | |||
-webkit-appearance: button; | |||
} | |||
button::-moz-focus-inner, | |||
[type="button"]::-moz-focus-inner, | |||
[type="reset"]::-moz-focus-inner, | |||
[type="submit"]::-moz-focus-inner { | |||
padding: 0; | |||
border-style: none; | |||
} | |||
input[type="radio"], | |||
input[type="checkbox"] { | |||
box-sizing: border-box; | |||
padding: 0; | |||
} | |||
input[type="date"], | |||
input[type="time"], | |||
input[type="datetime-local"], | |||
input[type="month"] { | |||
-webkit-appearance: listbox; | |||
} | |||
textarea { | |||
overflow: auto; | |||
resize: vertical; | |||
} | |||
fieldset { | |||
min-width: 0; | |||
padding: 0; | |||
margin: 0; | |||
border: 0; | |||
} | |||
legend { | |||
display: block; | |||
width: 100%; | |||
max-width: 100%; | |||
padding: 0; | |||
margin-bottom: .5rem; | |||
font-size: 1.5rem; | |||
line-height: inherit; | |||
color: inherit; | |||
white-space: normal; | |||
} | |||
progress { | |||
vertical-align: baseline; | |||
} | |||
[type="number"]::-webkit-inner-spin-button, | |||
[type="number"]::-webkit-outer-spin-button { | |||
height: auto; | |||
} | |||
[type="search"] { | |||
outline-offset: -2px; | |||
-webkit-appearance: none; | |||
} | |||
[type="search"]::-webkit-search-decoration { | |||
-webkit-appearance: none; | |||
} | |||
::-webkit-file-upload-button { | |||
font: inherit; | |||
-webkit-appearance: button; | |||
} | |||
output { | |||
display: inline-block; | |||
} | |||
summary { | |||
display: list-item; | |||
cursor: pointer; | |||
} | |||
template { | |||
display: none; | |||
} | |||
[hidden] { | |||
display: none !important; | |||
} | |||
/*# sourceMappingURL=bootstrap-reboot.css.map */ |
@@ -0,0 +1,8 @@ | |||
/*! | |||
* Bootstrap Reboot v4.2.1 (https://getbootstrap.com/) | |||
* Copyright 2011-2018 The Bootstrap Authors | |||
* Copyright 2011-2018 Twitter, Inc. | |||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | |||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) | |||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} | |||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */ |
@@ -0,0 +1,150 @@ | |||
<?php | |||
session_start(); | |||
// Database class for DB operations. These work, they are NOT been tampered with. | |||
// Do not change this class. | |||
class MyDB extends SQLite3 | |||
{ | |||
function __construct() | |||
{ | |||
$this->open('./dbase/comments.db'); | |||
} | |||
function get_comments() | |||
{ | |||
$result = $this->query('SELECT * FROM comments where published = 1 order by hierarchy'); | |||
$comments = array(); | |||
$i = 0; | |||
while ($res = $result->fetchArray(SQLITE3_ASSOC)) { | |||
$comments[$i]['id'] = $res['id']; | |||
$comments[$i]['parentid'] = $res['parent_id']; | |||
$comments[$i]['author'] = $res['author']; | |||
$comments[$i]['email'] = $res['email']; | |||
$comments[$i]['comment'] = urldecode($res['comment']); | |||
$comments[$i]['offset'] = sizeof(explode('-', $res['hierarchy'])) - 1; | |||
$i += 1; | |||
} | |||
return $comments; | |||
} | |||
} | |||
// database object | |||
$db = new MyDB(); | |||
// Vraag alle comments op. | |||
$db->get_comments(); | |||
// Set some variables for easier use. | |||
$name = $_COOKIE['commentname']; | |||
$email = $_COOKIE['commentemail']; | |||
$comment = $_SESSION['comment']; | |||
$_SESSION['parent_id'] = $_GET['commentid']; | |||
// reset the name | |||
$name = null; | |||
// We might have a stale error message. Clear it | |||
if (true) { | |||
unset($_SESSION['errormsg']); | |||
} | |||
?> | |||
<html> | |||
<head> | |||
<!-- Some bootstrap, just for fun --> | |||
<link rel="stylesheet" href="./css/bootstrap.min.css"> | |||
<link rel="stylesheet" href="./style/style.css"> | |||
<script src="./js/bootstrap.min.js"></script> | |||
</head> | |||
<body> | |||
<div id="wrapwrap"> | |||
<div class="container"> | |||
<div id="header" class="row"> | |||
<!-- Vergeet je naam niet! --> | |||
<h1>Examen PHP: < Vul hier je naam in > </h1> | |||
</div> | |||
<!-- Het artikel --> | |||
<div id="main" class="row"> | |||
<div class="col-md-8 offset-md-2"> | |||
<h2>Lorem ipsum dolor sit amet.</h2> | |||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Laboriosam optio consequatur impedit, voluptatem exercitationem, nihil sit adipisci sunt maxime delectus sapiente reiciendis? Repudiandae tempora ratione quia laborum, sunt iusto suscipit.</p> | |||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Corrupti temporibus eos, perspiciatis, voluptatibus praesentium minus fugiat corporis omnis explicabo, cupiditate consequuntur! Ratione voluptates nulla rerum qui atque exercitationem saepe provident molestiae sint! Ad voluptate reprehenderit nostrum laborum quam, rem perspiciatis.</p> | |||
</div> | |||
</div> | |||
<!-- De comments-sectie, hier begint de actie! --> | |||
<div id="comments" class="row"> | |||
<?php | |||
if ($_SESSION['errormsg'] != '') { | |||
?> | |||
<!-- if error, show the error message --> | |||
<div class="alert alert-danger" role="alert"> | |||
<?php $_SESSION['errormsg']; ?> | |||
</div> | |||
<?php | |||
} | |||
?> | |||
<div class="col-md-8 offset-md-2"> | |||
<hr/> | |||
<!-- If we want to add a comment, call ourselves with the right commentid | |||
commentid 0 = a comment to the article itself--> | |||
<a href="index.php?commentid=0" class="link">Leave a comment</a> | |||
<?php if (isset($_GET['commentid']) && $_GET['commentid'] == '0') { ?> | |||
<form action="savecomment.php" method="POST"> | |||
<div class="form-group"> | |||
<label for="name">Author</label> | |||
<input id="name" name="name" type="text" class="form-control" value="<?php echo $name; ?>"></input> | |||
<label for="email">Email</label> | |||
<input id="email" name="email" type="email" class="form-control" value="<?php echo $email; ?>"></input> | |||
<label for="comment">Comment</label> | |||
<textarea id="comment" name="comment" type="textarea" class="form-control" value="<?php echo $comment; ?>"></textarea> | |||
</div> | |||
<button type="submit" class="btn btn-success mt-16">Submit</button> | |||
</form> | |||
<?php | |||
} ?> | |||
<h4>Comments</h4> | |||
<?php | |||
// Voor elke comment, toon deze | |||
foreach ($comments as $row) { | |||
?> | |||
<!-- Offset the card with each sublevel of cmments, use $row['offset'] --> | |||
<div class="card offset-md-" > | |||
<div class="card-body"> | |||
<h5 class="card-title">Comment <?php echo $row['id']; ?></h5> | |||
<blockquote class="blockquote-footer mb-0"><?php echo $row['author']; ?></blockquote> | |||
<p class="card-text"><?php echo $row['comment']; ?></p> | |||
</div> | |||
<div class="card-footer text-muted"> | |||
<!-- If we want to add a comment, call ourselves with the right commentid of the comment | |||
we are commenting --> | |||
<a href="index.php?commentid=$row['id']" class="card-link">Reply to this comment</a> | |||
<?php | |||
// als commentid == deze rij, toon het formulier | |||
if (isset($_POST['commentid']) && $_POST['parent_id'] == $row['id']) ?> | |||
<!-- het formulier, vul waarden in waar mogelijk --> | |||
<form action="savecomment.php" method="POST"> | |||
<div class="form-group"> | |||
<label for="name">Author</label> | |||
<input id="name" name="name" type="text" class="form-control" value="<?php echo $name; ?>"></input> | |||
<label for="email">Email</label> | |||
<input id="email" name="email" type="email" class="form-control" value="<?php echo $email; ?>"></input> | |||
<label for="comment">Comment</label> | |||
<textarea id="comment" name="comment" type="textarea" class="form-control" value="<?php echo $comment; ?>"></textarea> | |||
</div> | |||
<button type="submit" class="btn btn-success mt-16 ">Submit</button> | |||
</form> | |||
</div> | |||
</div> | |||
<?php | |||
} ?> | |||
</div> | |||
</div> | |||
<div id=" footer " class=" row "></div> | |||
</div> | |||
</div> | |||
</body> | |||
</html> |
@@ -0,0 +1,106 @@ | |||
<?php | |||
// reset error message | |||
unset($_SESSION['errormsg']); | |||
// Database class for DB operations. These work, they are NOT been tampered with. | |||
// Do not change this class. | |||
class MyDB extends SQLite3 | |||
{ | |||
function __construct() | |||
{ | |||
$this->open('./dbase/comments.db'); | |||
} | |||
function savecomment($parent_id, $name, $email, $comment) | |||
{ | |||
$this->exec("INSERT INTO comments (parent_id, author, email, comment, published) values(" . $parent_id . ", '" . $name . "', '" . $email . "', '" . $comment . "', 1);"); | |||
$rowid = $this->lastInsertRowID(); | |||
$res = $this->query("select hierarchy from comments where id=" . $parent_id); | |||
$hierarchy = $res->fetchArray()['hierarchy']; | |||
$nh = $hierarchy . "-" . $rowid; | |||
$this->exec("update comments set hierarchy='" . $nh . "' where id=" . $rowid); | |||
} | |||
} | |||
// cleanup the user input. Courtesy of w3schools. This function is correct | |||
function test_input($data) | |||
{ | |||
$data = trim($data); | |||
$data = stripslashes($data); | |||
$data = htmlspecialchars($data); | |||
return $data; | |||
} | |||
//Validate the name, set error and return to index if necessary. | |||
// only letters and spaces are allowed`; | |||
function validate_name($name) | |||
{ | |||
$name = test_input($name); | |||
if (!preg_match("/^[a-zA-Z ]*$/", $name)) { | |||
// https://www.w3schools.com/php/func_regex_preg_match.asp | |||
... | |||
} | |||
} | |||
// Validate the email, set error message and return to index if necessary | |||
function validate_email($email) | |||
{ | |||
$email = test_input($email); | |||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { | |||
// https://www.w3schools.com/php/php_form_url_email.asp | |||
... | |||
} | |||
return $email; | |||
} | |||
// comments should be checked for javascript and url, | |||
// but we just convert all non alphanumerics to url encoding to prevent | |||
// sql injection | |||
// we set cookies for the name and emailaddress | |||
// likely, the same user might be entering more comments | |||
setcookie("commentname", $_POST['name'], time() + 3600); | |||
setcookie("commentemail", $_POST['email'], time() + 3600); | |||
// new database object | |||
$db = new MyDB(); | |||
// validate the user input | |||
$name = validate_name($_POST['name']); | |||
$email = validate_email($_POST['email']); | |||
$comment = validate_comment($_POST['comment']); | |||
// parent_id = stored id. | |||
if (isset($_SESSION['parent_id'])) { | |||
$parent_id = $_SESSION['parent_id']; | |||
} else { | |||
$parent_id = 0; | |||
} | |||
// save in database and clean up | |||
if ($db => savecomment($parent_id, $name, $email, $comment)) { | |||
session_unset(); | |||
session_destroy(); | |||
} | |||
?> | |||
<html> | |||
<head> | |||
<link rel="stylesheet" href="./css/bootstrap.min.css"> | |||
<link rel="stylesheet" href="./style/style.css"> | |||
<script src="./js/bootstrap.min.js"></script> | |||
</head> | |||
<body> | |||
<div id="wrapwrap"> | |||
<div class="container"> | |||
<div id="header" class="row"> | |||
<h1>Examen PHP: < Vul hier je naam in > </h1> | |||
</div> | |||
<div id="main" class="row"> | |||
<h1>Thank you for your comment</h1> | |||
<hr/> | |||
<a href="index.php">Return to homepage</a> | |||
</div> | |||
</div> | |||
</html> |
@@ -0,0 +1,5 @@ | |||
#wrapwrap { | |||
margin-left: auto; | |||
margin-right: auto; | |||
width: 60%; | |||
} |