Compare commits
10 Commits
e97f7ba291
...
9d33bf21e6
Author | SHA1 | Date | |
---|---|---|---|
|
9d33bf21e6 | ||
|
8c3aab8c3d | ||
|
9691de3b8f | ||
|
d40b4d6754 | ||
|
2de5e2072a | ||
|
0990e971a0 | ||
|
71009bd737 | ||
|
4a2f1bbd51 | ||
|
6491b7d6bd | ||
|
fc91f7697c |
14
TODO.md
Normal file
14
TODO.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# TODO
|
||||||
|
|
||||||
|
- [ ] [Random sentences](https://www.andistips.com/php-get-a-random-item-from-an-array/)
|
||||||
|
- [ ] Login
|
||||||
|
- [ ] Forgotten password
|
||||||
|
- [ ] Welcome
|
||||||
|
- [ ] Styling
|
||||||
|
- [ ] Vegetables
|
||||||
|
- [ ] Login
|
||||||
|
- [ ] Index
|
||||||
|
- [ ] Forgotten password
|
||||||
|
- [ ] Sign up
|
||||||
|
- [ ] JavaScript
|
||||||
|
- [ ] Lists on the same page and edits too
|
@ -61,15 +61,16 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
// CUPBOARD
|
// CUPBOARD
|
||||||
if (empty(trim($_POST["cupboard"]))) {
|
if (empty(trim($_POST["cupboard"]))) {
|
||||||
$cupboard = null;
|
$cupboard = null;
|
||||||
} else if (is_numeric(trim($_POST["cupboard"]))) {
|
} else {
|
||||||
$cupboard_id = trim($_POST["cupboard"]);
|
$cupboard = trim($_POST["cupboard"]);
|
||||||
if (does_cupboard_exist_from_id($cupboard_id)) {
|
foreach (get_users_cupboards_array() as $cupboards) {
|
||||||
$cupboard = trim($_POST["cupboard"]);
|
if ($cupboards["public_id"] === trim($_POST["cupboard"])) {
|
||||||
} else {
|
$cupboard = $cupboards["id"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($cupboard === "") {
|
||||||
$cupboard_err = "Unknown cupboard.";
|
$cupboard_err = "Unknown cupboard.";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$cupboard_err = "Cupboard id isn't int.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
@ -78,14 +79,10 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
// INSERTION IN DATABASE IF CORRECT
|
// INSERTION IN DATABASE IF CORRECT
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
if (empty($product_name_err) && empty($description_err) && empty($expiration_date_err) && empty($cupboard_err)) {
|
if (empty($product_name_err) && empty($description_err) && empty($expiration_date_err) && empty($cupboard_err)) {
|
||||||
|
if (!add_product($product_name, $description, $expiration_date, $cupboard)) {
|
||||||
|
|
||||||
|
|
||||||
if (!add_product($product_name, $description, $expiration_date, $cupboard_id)) {
|
|
||||||
echo "Error. Something went wrong.";
|
echo "Error. Something went wrong.";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
echo $product_name_err;
|
echo $product_name_err;
|
||||||
echo $description_err;
|
echo $description_err;
|
||||||
echo $expiration_date_err;
|
echo $expiration_date_err;
|
||||||
@ -100,7 +97,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
$cupboard_list = "";
|
$cupboard_list = "";
|
||||||
foreach (get_users_cupboards_array() as $row) {
|
foreach (get_users_cupboards_array() as $row) {
|
||||||
$cupboard_list = $cupboard_list . "<option value=\""
|
$cupboard_list = $cupboard_list . "<option value=\""
|
||||||
. htmlspecialchars($row["id"]) . "\">"
|
. htmlspecialchars($row["public_id"]) . "\">"
|
||||||
. htmlspecialchars($row["name"]) . "</option>\n";
|
. htmlspecialchars($row["name"]) . "</option>\n";
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
73
assets/css/common.css
Normal file
73
assets/css/common.css
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css?family=Noto+Sans&display=swap');
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Montserrat&display=swap');
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');
|
||||||
|
|
||||||
|
body {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.montserrat {
|
||||||
|
font-family: 'Montserrat', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lato {
|
||||||
|
font-family: 'Lato', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noto-sans {
|
||||||
|
font-family: 'Noto Sans', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.white {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bold-900 {
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center30left {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 35%;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-evenly {
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-vertical-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-vertical-stretch {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-content-stretch {
|
||||||
|
align-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.halo-hover {
|
||||||
|
transition: all 500ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.halo-hover:hover {
|
||||||
|
transition: all 500ms;
|
||||||
|
box-shadow: 0 0 100px white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.width50P {
|
||||||
|
width: 50%;
|
||||||
|
}
|
86
assets/css/index.css
Normal file
86
assets/css/index.css
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
body {
|
||||||
|
background: rgb(2, 0, 36);
|
||||||
|
background: -moz-linear-gradient(140deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 30%, rgba(0, 111, 131, 1) 100%);
|
||||||
|
background: -webkit-linear-gradient(140deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 30%, rgba(0, 111, 131, 1) 100%);
|
||||||
|
background: linear-gradient(140deg, rgba(2, 0, 36, 1) 0%, rgba(9, 9, 121, 1) 30%, rgba(0, 111, 131, 1) 100%);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#020024", endColorstr="#006f83", GradientType=1);
|
||||||
|
background-size: 400% 400%;
|
||||||
|
animation: gradientBG 15s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradientBG {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#indexTitle {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 40%;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login {
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
top: 35px;
|
||||||
|
right: 35px;
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loginButton {
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
padding: 12px;
|
||||||
|
border: solid white;
|
||||||
|
border-radius: 15px;
|
||||||
|
transition: all 500ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loginButton:hover {
|
||||||
|
transition: all 500ms;
|
||||||
|
color: #546a7b;
|
||||||
|
background-color: #fdfdff;
|
||||||
|
box-shadow: 0 0 100px white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Very small devices (portrait phone, 575 and down) */
|
||||||
|
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
#title {
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
#subtitle {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small devices (landscape phones, 576px and up)*/
|
||||||
|
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
#title {
|
||||||
|
font-size: 5em;
|
||||||
|
}
|
||||||
|
#subtitle {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Large devices (desktops, 992px and up)*/
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
#title {
|
||||||
|
font-size: 7em;
|
||||||
|
}
|
||||||
|
#subtitle {
|
||||||
|
font-size: 2.5em;
|
||||||
|
}
|
||||||
|
}
|
195
assets/css/login.css
Normal file
195
assets/css/login.css
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#title {
|
||||||
|
font-size: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-family: "Exo", sans-serif;
|
||||||
|
background: rgb(111, 48, 153);
|
||||||
|
background: -moz-linear-gradient(145deg, rgba(111, 48, 153, 1) 0%, rgba(235, 18, 18, 1) 50%, rgba(255, 168, 62, 1) 100%);
|
||||||
|
background: -webkit-linear-gradient(145deg, rgba(111, 48, 153, 1) 0%, rgba(235, 18, 18, 1) 50%, rgba(255, 168, 62, 1) 100%);
|
||||||
|
background: linear-gradient(145deg, rgba(111, 48, 153, 1) 0%, rgba(235, 18, 18, 1) 50%, rgba(255, 168, 62, 1) 100%);
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#6f3099", endColorstr="#ffa83e", GradientType=1);
|
||||||
|
background-size: 400% 400%;
|
||||||
|
animation: gradientBG 15s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.form-control {
|
||||||
|
border: none;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 40px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-family: 'Work Sans', sans-serif;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 1.25em;
|
||||||
|
margin: 5px 5px;
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-button {
|
||||||
|
display: inline-block;
|
||||||
|
border: none;
|
||||||
|
border-radius: 40px;
|
||||||
|
padding: 10px 25px;
|
||||||
|
font-family: 'Work Sans' sans-serif;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
transition: all 250ms;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-button:hover {
|
||||||
|
transition: all 250ms;
|
||||||
|
background-color: darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.other-buttons {
|
||||||
|
background-color: darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container {
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradientBG {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-error {
|
||||||
|
-webkit-animation: shake-horizontal 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
|
||||||
|
animation: shake-horizontal 0.8s cubic-bezier(0.455, 0.030, 0.515, 0.955) both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake-horizontal {
|
||||||
|
0%, 100% {
|
||||||
|
-webkit-transform: translateX(0);
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
10%, 30%, 50%, 70% {
|
||||||
|
-webkit-transform: translateX(-10px);
|
||||||
|
transform: translateX(-10px);
|
||||||
|
}
|
||||||
|
20%, 40%, 60% {
|
||||||
|
-webkit-transform: translateX(10px);
|
||||||
|
transform: translateX(10px);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
-webkit-transform: translateX(8px);
|
||||||
|
transform: translateX(8px);
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
-webkit-transform: translateX(-8px);
|
||||||
|
transform: translateX(-8px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Very small devices (portrait phone, 575 and down) */
|
||||||
|
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
#title {
|
||||||
|
font-size: 3.5em;
|
||||||
|
}
|
||||||
|
input.form-control {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.center30left {
|
||||||
|
top: 50%;
|
||||||
|
left: 35px;
|
||||||
|
right: 35px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small devices (landscape phones, 576px and up)*/
|
||||||
|
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.center30left {
|
||||||
|
top: 50%;
|
||||||
|
left: 35px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Large devices (desktops, 992px and up)*/
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.center30left {
|
||||||
|
top: 50%;
|
||||||
|
left: 35%;
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom checkbox container */
|
||||||
|
|
||||||
|
.checkbox-container input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-container input:checked+.checkmark {
|
||||||
|
background-color: #2196fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-container:hover .checkmark {
|
||||||
|
background-color: darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-container input:checked+.checkmark:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
height: 5px;
|
||||||
|
width: 9px;
|
||||||
|
border-left: 2px solid white;
|
||||||
|
border-bottom: 2px solid white;
|
||||||
|
top: 45%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-container {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 30px;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 24px;
|
||||||
|
user-select: none;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-container .checkmark {
|
||||||
|
display: inline-block;
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
background-color: white;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#register-email, #lost-email {
|
||||||
|
width: 100%;
|
||||||
|
}
|
53
assets/css/reset.css
Normal file
53
assets/css/reset.css
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/* http://meyerweb.com/eric/tools/css/reset/ */
|
||||||
|
/* v1.0 | 20080212 */
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
vertical-align: baseline;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember to define focus styles! */
|
||||||
|
:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remember to highlight inserts somehow! */
|
||||||
|
ins {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
del {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tables still need 'cellspacing="0"' in the markup */
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
75
assets/css/welcome.css
Normal file
75
assets/css/welcome.css
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
h1 {
|
||||||
|
font-size: 3.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header {
|
||||||
|
position: absolute;
|
||||||
|
top: 25px;
|
||||||
|
left: 35px;
|
||||||
|
right: 35px;
|
||||||
|
z-index: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 7px;
|
||||||
|
padding: 10px 25px;
|
||||||
|
transition: all 250ms;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-violet {
|
||||||
|
background-color: rgb(169, 89, 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-violet:hover {
|
||||||
|
transition: all 250ms;
|
||||||
|
background-color: rgb(145, 47, 184);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-red {
|
||||||
|
background-color: #EC7063;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-red:hover {
|
||||||
|
transition: all, 250ms;
|
||||||
|
background-color: rgb(211, 59, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-blue {
|
||||||
|
background-color: rgb(59, 140, 233);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-blue:hover {
|
||||||
|
transition: all, 250ms;
|
||||||
|
background-color: rgb(51, 104, 202);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dark {
|
||||||
|
background-color: #424949;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dark:hover {
|
||||||
|
transition: all, 250ms;
|
||||||
|
background-color: #282b2b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-green {
|
||||||
|
background-color: #2ECC71;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-green:hover {
|
||||||
|
transition: all, 250ms;
|
||||||
|
background-color: rgb(20, 172, 53);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-image: radial-gradient( circle farthest-corner at 10% 20%, rgba(90, 92, 106, 1) 0%, rgba(32, 45, 58, 1) 81.3%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#buttonList, #buttonList2 {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
9
assets/php/confg.json.example
Normal file
9
assets/php/confg.json.example
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"host":"localhost",
|
||||||
|
"dbname": "db",
|
||||||
|
"user": "user",
|
||||||
|
"password": "pass",
|
||||||
|
"kind": "mysql",
|
||||||
|
"gmail_username":"example@gmail.com",
|
||||||
|
"gmail_password": "myawesomepassword123"
|
||||||
|
}
|
10
assets/php/copyright.php
Normal file
10
assets/php/copyright.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<!--
|
||||||
|
PAGE CODED BY :
|
||||||
|
__ _____ __ __ ______ ____ __ __ ______ __ __ ______ ______
|
||||||
|
/\ \ /\ __`\/\ \/\ \/\__ _\/\ _`\ /\ \/\ \/\ _ \/\ \ /\ \ /\ _ \/\__ _\
|
||||||
|
\ \ \ \ \ \/\ \ \ \ \ \/_/\ \/\ \,\L\_\ \ \ \ \ \ \ \L\ \ \ \ \ \ \ \ \ \L\ \/_/\ \/
|
||||||
|
\ \ \ __\ \ \ \ \ \ \ \ \ \ \ \ \/_\__ \ \ \ \ \ \ \ __ \ \ \ __\ \ \ __\ \ __ \ \ \ \
|
||||||
|
\ \ \L\ \\ \ \_\ \ \ \_\ \ \_\ \__/\ \L\ \ \ \ \_/ \ \ \/\ \ \ \L\ \\ \ \L\ \\ \ \/\ \ \ \ \
|
||||||
|
\ \____/ \ \_____\ \_____\/\_____\ `\____\ \ `\___/\ \_\ \_\ \____/ \ \____/ \ \_\ \_\ \ \_\
|
||||||
|
\/___/ \/_____/\/_____/\/_____/\/_____/ `\/__/ \/_/\/_/\/___/ \/___/ \/_/\/_/ \/_/
|
||||||
|
-->
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"host":"localhost",
|
|
||||||
"dbname": "db",
|
|
||||||
"user": "user",
|
|
||||||
"password": "pass",
|
|
||||||
"kind": "mysql"
|
|
||||||
}
|
|
39
assets/php/phpmailer/Exception.php
Normal file
39
assets/php/phpmailer/Exception.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPMailer Exception class.
|
||||||
|
* PHP Version 5.5.
|
||||||
|
*
|
||||||
|
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||||
|
*
|
||||||
|
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||||
|
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||||
|
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||||
|
* @author Brent R. Matzelle (original founder)
|
||||||
|
* @copyright 2012 - 2017 Marcus Bointon
|
||||||
|
* @copyright 2010 - 2012 Jim Jagielski
|
||||||
|
* @copyright 2004 - 2009 Andy Prevost
|
||||||
|
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||||
|
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPMailer\PHPMailer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPMailer exception handler.
|
||||||
|
*
|
||||||
|
* @author Marcus Bointon <phpmailer@synchromedia.co.uk>
|
||||||
|
*/
|
||||||
|
class Exception extends \Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Prettify error message output.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function errorMessage()
|
||||||
|
{
|
||||||
|
return '<strong>' . htmlspecialchars($this->getMessage()) . "</strong><br />\n";
|
||||||
|
}
|
||||||
|
}
|
138
assets/php/phpmailer/OAuth.php
Normal file
138
assets/php/phpmailer/OAuth.php
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPMailer - PHP email creation and transport class.
|
||||||
|
* PHP Version 5.5.
|
||||||
|
*
|
||||||
|
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||||
|
*
|
||||||
|
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||||
|
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||||
|
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||||
|
* @author Brent R. Matzelle (original founder)
|
||||||
|
* @copyright 2012 - 2015 Marcus Bointon
|
||||||
|
* @copyright 2010 - 2012 Jim Jagielski
|
||||||
|
* @copyright 2004 - 2009 Andy Prevost
|
||||||
|
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||||
|
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPMailer\PHPMailer;
|
||||||
|
|
||||||
|
use League\OAuth2\Client\Grant\RefreshToken;
|
||||||
|
use League\OAuth2\Client\Provider\AbstractProvider;
|
||||||
|
use League\OAuth2\Client\Token\AccessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth - OAuth2 authentication wrapper class.
|
||||||
|
* Uses the oauth2-client package from the League of Extraordinary Packages.
|
||||||
|
*
|
||||||
|
* @see http://oauth2-client.thephpleague.com
|
||||||
|
*
|
||||||
|
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||||
|
*/
|
||||||
|
class OAuth
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* An instance of the League OAuth Client Provider.
|
||||||
|
*
|
||||||
|
* @var AbstractProvider
|
||||||
|
*/
|
||||||
|
protected $provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current OAuth access token.
|
||||||
|
*
|
||||||
|
* @var AccessToken
|
||||||
|
*/
|
||||||
|
protected $oauthToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user's email address, usually used as the login ID
|
||||||
|
* and also the from address when sending email.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $oauthUserEmail = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The client secret, generated in the app definition of the service you're connecting to.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $oauthClientSecret = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The client ID, generated in the app definition of the service you're connecting to.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $oauthClientId = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The refresh token, used to obtain new AccessTokens.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $oauthRefreshToken = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth constructor.
|
||||||
|
*
|
||||||
|
* @param array $options Associative array containing
|
||||||
|
* `provider`, `userName`, `clientSecret`, `clientId` and `refreshToken` elements
|
||||||
|
*/
|
||||||
|
public function __construct($options)
|
||||||
|
{
|
||||||
|
$this->provider = $options['provider'];
|
||||||
|
$this->oauthUserEmail = $options['userName'];
|
||||||
|
$this->oauthClientSecret = $options['clientSecret'];
|
||||||
|
$this->oauthClientId = $options['clientId'];
|
||||||
|
$this->oauthRefreshToken = $options['refreshToken'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new RefreshToken.
|
||||||
|
*
|
||||||
|
* @return RefreshToken
|
||||||
|
*/
|
||||||
|
protected function getGrant()
|
||||||
|
{
|
||||||
|
return new RefreshToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a new AccessToken.
|
||||||
|
*
|
||||||
|
* @return AccessToken
|
||||||
|
*/
|
||||||
|
protected function getToken()
|
||||||
|
{
|
||||||
|
return $this->provider->getAccessToken(
|
||||||
|
$this->getGrant(),
|
||||||
|
['refresh_token' => $this->oauthRefreshToken]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a base64-encoded OAuth token.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOauth64()
|
||||||
|
{
|
||||||
|
// Get a new token if it's not available or has expired
|
||||||
|
if (null === $this->oauthToken || $this->oauthToken->hasExpired()) {
|
||||||
|
$this->oauthToken = $this->getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64_encode(
|
||||||
|
'user=' .
|
||||||
|
$this->oauthUserEmail .
|
||||||
|
"\001auth=Bearer " .
|
||||||
|
$this->oauthToken .
|
||||||
|
"\001\001"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
4770
assets/php/phpmailer/PHPMailer.php
Normal file
4770
assets/php/phpmailer/PHPMailer.php
Normal file
File diff suppressed because it is too large
Load Diff
419
assets/php/phpmailer/POP3.php
Normal file
419
assets/php/phpmailer/POP3.php
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PHPMailer POP-Before-SMTP Authentication Class.
|
||||||
|
* PHP Version 5.5.
|
||||||
|
*
|
||||||
|
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||||
|
*
|
||||||
|
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||||
|
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||||
|
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||||
|
* @author Brent R. Matzelle (original founder)
|
||||||
|
* @copyright 2012 - 2019 Marcus Bointon
|
||||||
|
* @copyright 2010 - 2012 Jim Jagielski
|
||||||
|
* @copyright 2004 - 2009 Andy Prevost
|
||||||
|
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||||
|
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PHPMailer\PHPMailer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PHPMailer POP-Before-SMTP Authentication Class.
|
||||||
|
* Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.
|
||||||
|
* 1) This class does not support APOP authentication.
|
||||||
|
* 2) Opening and closing lots of POP3 connections can be quite slow. If you need
|
||||||
|
* to send a batch of emails then just perform the authentication once at the start,
|
||||||
|
* and then loop through your mail sending script. Providing this process doesn't
|
||||||
|
* take longer than the verification period lasts on your POP3 server, you should be fine.
|
||||||
|
* 3) This is really ancient technology; you should only need to use it to talk to very old systems.
|
||||||
|
* 4) This POP3 class is deliberately lightweight and incomplete, implementing just
|
||||||
|
* enough to do authentication.
|
||||||
|
* If you want a more complete class there are other POP3 classes for PHP available.
|
||||||
|
*
|
||||||
|
* @author Richard Davey (original author) <rich@corephp.co.uk>
|
||||||
|
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||||
|
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||||
|
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||||
|
*/
|
||||||
|
class POP3
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The POP3 PHPMailer Version number.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const VERSION = '6.1.3';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default POP3 port number.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const DEFAULT_PORT = 110;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default timeout in seconds.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
const DEFAULT_TIMEOUT = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug display level.
|
||||||
|
* Options: 0 = no, 1+ = yes.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $do_debug = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POP3 mail server hostname.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POP3 port number.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POP3 Timeout Value in seconds.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $tval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POP3 username.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POP3 password.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource handle for the POP3 connection socket.
|
||||||
|
*
|
||||||
|
* @var resource
|
||||||
|
*/
|
||||||
|
protected $pop_conn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are we connected?
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $connected = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error container.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $errors = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Line break constant.
|
||||||
|
*/
|
||||||
|
const LE = "\r\n";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple static wrapper for all-in-one POP before SMTP.
|
||||||
|
*
|
||||||
|
* @param string $host The hostname to connect to
|
||||||
|
* @param int|bool $port The port number to connect to
|
||||||
|
* @param int|bool $timeout The timeout value
|
||||||
|
* @param string $username
|
||||||
|
* @param string $password
|
||||||
|
* @param int $debug_level
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function popBeforeSmtp(
|
||||||
|
$host,
|
||||||
|
$port = false,
|
||||||
|
$timeout = false,
|
||||||
|
$username = '',
|
||||||
|
$password = '',
|
||||||
|
$debug_level = 0
|
||||||
|
) {
|
||||||
|
$pop = new self();
|
||||||
|
|
||||||
|
return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate with a POP3 server.
|
||||||
|
* A connect, login, disconnect sequence
|
||||||
|
* appropriate for POP-before SMTP authorisation.
|
||||||
|
*
|
||||||
|
* @param string $host The hostname to connect to
|
||||||
|
* @param int|bool $port The port number to connect to
|
||||||
|
* @param int|bool $timeout The timeout value
|
||||||
|
* @param string $username
|
||||||
|
* @param string $password
|
||||||
|
* @param int $debug_level
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0)
|
||||||
|
{
|
||||||
|
$this->host = $host;
|
||||||
|
// If no port value provided, use default
|
||||||
|
if (false === $port) {
|
||||||
|
$this->port = static::DEFAULT_PORT;
|
||||||
|
} else {
|
||||||
|
$this->port = (int) $port;
|
||||||
|
}
|
||||||
|
// If no timeout value provided, use default
|
||||||
|
if (false === $timeout) {
|
||||||
|
$this->tval = static::DEFAULT_TIMEOUT;
|
||||||
|
} else {
|
||||||
|
$this->tval = (int) $timeout;
|
||||||
|
}
|
||||||
|
$this->do_debug = $debug_level;
|
||||||
|
$this->username = $username;
|
||||||
|
$this->password = $password;
|
||||||
|
// Reset the error log
|
||||||
|
$this->errors = [];
|
||||||
|
// connect
|
||||||
|
$result = $this->connect($this->host, $this->port, $this->tval);
|
||||||
|
if ($result) {
|
||||||
|
$login_result = $this->login($this->username, $this->password);
|
||||||
|
if ($login_result) {
|
||||||
|
$this->disconnect();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We need to disconnect regardless of whether the login succeeded
|
||||||
|
$this->disconnect();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to a POP3 server.
|
||||||
|
*
|
||||||
|
* @param string $host
|
||||||
|
* @param int|bool $port
|
||||||
|
* @param int $tval
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function connect($host, $port = false, $tval = 30)
|
||||||
|
{
|
||||||
|
// Are we already connected?
|
||||||
|
if ($this->connected) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//On Windows this will raise a PHP Warning error if the hostname doesn't exist.
|
||||||
|
//Rather than suppress it with @fsockopen, capture it cleanly instead
|
||||||
|
set_error_handler([$this, 'catchWarning']);
|
||||||
|
|
||||||
|
if (false === $port) {
|
||||||
|
$port = static::DEFAULT_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to the POP3 server
|
||||||
|
$this->pop_conn = fsockopen(
|
||||||
|
$host, // POP3 Host
|
||||||
|
$port, // Port #
|
||||||
|
$errno, // Error Number
|
||||||
|
$errstr, // Error Message
|
||||||
|
$tval
|
||||||
|
); // Timeout (seconds)
|
||||||
|
// Restore the error handler
|
||||||
|
restore_error_handler();
|
||||||
|
|
||||||
|
// Did we connect?
|
||||||
|
if (false === $this->pop_conn) {
|
||||||
|
// It would appear not...
|
||||||
|
$this->setError(
|
||||||
|
"Failed to connect to server $host on port $port. errno: $errno; errstr: $errstr"
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase the stream time-out
|
||||||
|
stream_set_timeout($this->pop_conn, $tval, 0);
|
||||||
|
|
||||||
|
// Get the POP3 server response
|
||||||
|
$pop3_response = $this->getResponse();
|
||||||
|
// Check for the +OK
|
||||||
|
if ($this->checkResponse($pop3_response)) {
|
||||||
|
// The connection is established and the POP3 server is talking
|
||||||
|
$this->connected = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log in to the POP3 server.
|
||||||
|
* Does not support APOP (RFC 2828, 4949).
|
||||||
|
*
|
||||||
|
* @param string $username
|
||||||
|
* @param string $password
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function login($username = '', $password = '')
|
||||||
|
{
|
||||||
|
if (!$this->connected) {
|
||||||
|
$this->setError('Not connected to POP3 server');
|
||||||
|
}
|
||||||
|
if (empty($username)) {
|
||||||
|
$username = $this->username;
|
||||||
|
}
|
||||||
|
if (empty($password)) {
|
||||||
|
$password = $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the Username
|
||||||
|
$this->sendString("USER $username" . static::LE);
|
||||||
|
$pop3_response = $this->getResponse();
|
||||||
|
if ($this->checkResponse($pop3_response)) {
|
||||||
|
// Send the Password
|
||||||
|
$this->sendString("PASS $password" . static::LE);
|
||||||
|
$pop3_response = $this->getResponse();
|
||||||
|
if ($this->checkResponse($pop3_response)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the POP3 server.
|
||||||
|
*/
|
||||||
|
public function disconnect()
|
||||||
|
{
|
||||||
|
$this->sendString('QUIT');
|
||||||
|
//The QUIT command may cause the daemon to exit, which will kill our connection
|
||||||
|
//So ignore errors here
|
||||||
|
try {
|
||||||
|
@fclose($this->pop_conn);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
//Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a response from the POP3 server.
|
||||||
|
*
|
||||||
|
* @param int $size The maximum number of bytes to retrieve
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getResponse($size = 128)
|
||||||
|
{
|
||||||
|
$response = fgets($this->pop_conn, $size);
|
||||||
|
if ($this->do_debug >= 1) {
|
||||||
|
echo 'Server -> Client: ', $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send raw data to the POP3 server.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function sendString($string)
|
||||||
|
{
|
||||||
|
if ($this->pop_conn) {
|
||||||
|
if ($this->do_debug >= 2) { //Show client messages when debug >= 2
|
||||||
|
echo 'Client -> Server: ', $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fwrite($this->pop_conn, $string, strlen($string));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the POP3 server response.
|
||||||
|
* Looks for for +OK or -ERR.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function checkResponse($string)
|
||||||
|
{
|
||||||
|
if (strpos($string, '+OK') !== 0) {
|
||||||
|
$this->setError("Server reported an error: $string");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an error to the internal error store.
|
||||||
|
* Also display debug output if it's enabled.
|
||||||
|
*
|
||||||
|
* @param string $error
|
||||||
|
*/
|
||||||
|
protected function setError($error)
|
||||||
|
{
|
||||||
|
$this->errors[] = $error;
|
||||||
|
if ($this->do_debug >= 1) {
|
||||||
|
echo '<pre>';
|
||||||
|
foreach ($this->errors as $e) {
|
||||||
|
print_r($e);
|
||||||
|
}
|
||||||
|
echo '</pre>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of error messages, if any.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getErrors()
|
||||||
|
{
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POP3 connection error handler.
|
||||||
|
*
|
||||||
|
* @param int $errno
|
||||||
|
* @param string $errstr
|
||||||
|
* @param string $errfile
|
||||||
|
* @param int $errline
|
||||||
|
*/
|
||||||
|
protected function catchWarning($errno, $errstr, $errfile, $errline)
|
||||||
|
{
|
||||||
|
$this->setError(
|
||||||
|
'Connecting to the POP3 server raised a PHP warning:' .
|
||||||
|
"errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
1370
assets/php/phpmailer/SMTP.php
Normal file
1370
assets/php/phpmailer/SMTP.php
Normal file
File diff suppressed because it is too large
Load Diff
55
assets/php/send_email.php
Normal file
55
assets/php/send_email.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
//Import PHPMailer classes into the global namespace
|
||||||
|
use PHPMailer\PHPMailer\PHPMailer;
|
||||||
|
use PHPMailer\PHPMailer\SMTP;
|
||||||
|
use PHPMailer\PHPMailer\Exception;
|
||||||
|
|
||||||
|
require_once("./assets/php/phpmailer/Exception.php");
|
||||||
|
require_once("./assets/php/phpmailer/PHPMailer.php");
|
||||||
|
require_once("./assets/php/phpmailer/SMTP.php");
|
||||||
|
|
||||||
|
function send_email($to, $subject, $body, $alt_body, $to_first_name, $to_last_name)
|
||||||
|
{
|
||||||
|
$config_array = json_decode(file_get_contents("config.json", true));
|
||||||
|
|
||||||
|
if (!isset($alt_body)) {
|
||||||
|
$alt_body = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
//Create a new PHPMailer instance
|
||||||
|
$mail = new PHPMailer;
|
||||||
|
//Tell PHPMailer to use SMTP
|
||||||
|
$mail->isSMTP();
|
||||||
|
//Enable SMTP debugging
|
||||||
|
// SMTP::DEBUG_OFF = off (for production use)
|
||||||
|
// SMTP::DEBUG_CLIENT = client messages
|
||||||
|
// SMTP::DEBUG_SERVER = client and server messages
|
||||||
|
$mail->SMTPDebug = SMTP::DEBUG_OFF;
|
||||||
|
//Set the hostname of the mail server
|
||||||
|
$mail->Host = 'smtp.gmail.com';
|
||||||
|
//Set the SMTP port number - 587 for authenticated TLS, a.k.a. RFC4409 SMTP submission
|
||||||
|
$mail->Port = 587;
|
||||||
|
//Set the encryption mechanism to use - STARTTLS or SMTPS
|
||||||
|
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||||
|
//Whether to use SMTP authentication
|
||||||
|
$mail->SMTPAuth = true;
|
||||||
|
//Username to use for SMTP authentication - use full email address for gmail
|
||||||
|
$mail->Username = $config_array->{"gmail_username"};
|
||||||
|
//Password to use for SMTP authentication
|
||||||
|
$mail->Password = $config_array->{"gmail_password"};
|
||||||
|
//Set who the message is to be sent from
|
||||||
|
$mail->setFrom($config_array->{"gmail_username"}, 'Food Inventory');
|
||||||
|
//Set an alternative reply-to address
|
||||||
|
$mail->addAddress($to, $to_first_name . " " . $to_last_name);
|
||||||
|
//Set the subject line
|
||||||
|
$mail->Subject = $subject;
|
||||||
|
$mail->Body = $body;
|
||||||
|
//Replace the plain text body with one created manually
|
||||||
|
$mail->AltBody = $alt_body;
|
||||||
|
//send the message, check for errors
|
||||||
|
return ($mail->send());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
$SESSION_COOKIE_NAME = "connection_id";
|
$SESSION_COOKIE_NAME = "connection_id";
|
||||||
$MAX_COOKIE_LIFE = 86400 * 30; // 30 days max
|
$MAX_COOKIE_LIFE = 86400 * 30; // 30 days max
|
||||||
|
$MAX_RESET_TOKEN_LIFE = 1200; // 20 minutes max
|
||||||
|
$MAX_TOKENS = 3;
|
||||||
$MINIMAL_PASSWORD_LENGTH = 8;
|
$MINIMAL_PASSWORD_LENGTH = 8;
|
||||||
|
|
||||||
$config_array = json_decode(file_get_contents("config.json", true));
|
$config_array = json_decode(file_get_contents("config.json", true));
|
||||||
@ -202,7 +204,6 @@ function add_user($email, $first_name, $last_name, $clear_password)
|
|||||||
return $query->execute();
|
return $query->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function change_user_password($user_id, $new_clear_password)
|
function change_user_password($user_id, $new_clear_password)
|
||||||
{
|
{
|
||||||
global $PDO;
|
global $PDO;
|
||||||
@ -230,13 +231,16 @@ function add_cupboard($name, $description)
|
|||||||
return $query->execute();
|
return $query->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
function does_cupboard_exist_from_id($id)
|
function is_users_cupboard($cupboard_public_id)
|
||||||
{
|
{
|
||||||
global $PDO;
|
global $PDO;
|
||||||
|
|
||||||
$sql = "SELECT id FROM cupboards WHERE id = :id;";
|
$sql = "SELECT cupboards.public_id FROM cupboards
|
||||||
|
INNER JOIN accounts ON cupboards.owner_id = accounts.id
|
||||||
|
WHERE cupboards.public_id = :public_id AND accounts.id = :accounts_id;";
|
||||||
$query = $PDO->prepare($sql);
|
$query = $PDO->prepare($sql);
|
||||||
$query->bindValue(":id", $id);
|
$query->bindValue(":public_id", $cupboard_public_id);
|
||||||
|
$query->bindValue(":accounts_id", get_user_info_from_session_id("id"));
|
||||||
|
|
||||||
if ($query->execute()) {
|
if ($query->execute()) {
|
||||||
return ($query->rowCount() === 1);
|
return ($query->rowCount() === 1);
|
||||||
@ -283,7 +287,7 @@ function get_users_products_array()
|
|||||||
products.id AS id, products.name AS name, products.description AS description,
|
products.id AS id, products.name AS name, products.description AS description,
|
||||||
cupboards.id AS cupboard_id, cupboards.name AS cupboard_name,
|
cupboards.id AS cupboard_id, cupboards.name AS cupboard_name,
|
||||||
cupboards.description AS cupboard_description, expiration_date,
|
cupboards.description AS cupboard_description, expiration_date,
|
||||||
added_date, products.public_id AS public_id
|
added_date, products.public_id AS public_id, cupboards.public_id AS cupboard_public_id
|
||||||
FROM products
|
FROM products
|
||||||
LEFT JOIN cupboards ON products.cupboard_id = cupboards.id
|
LEFT JOIN cupboards ON products.cupboard_id = cupboards.id
|
||||||
WHERE products.owner_id = :owner_id;";
|
WHERE products.owner_id = :owner_id;";
|
||||||
@ -358,7 +362,8 @@ function update_product(
|
|||||||
$product_public_id,
|
$product_public_id,
|
||||||
$new_name,
|
$new_name,
|
||||||
$new_description,
|
$new_description,
|
||||||
$new_expiration_date
|
$new_expiration_date,
|
||||||
|
$new_cupboard_id
|
||||||
) {
|
) {
|
||||||
global $PDO;
|
global $PDO;
|
||||||
|
|
||||||
@ -367,7 +372,8 @@ function update_product(
|
|||||||
ON products.owner_id = accounts.id
|
ON products.owner_id = accounts.id
|
||||||
SET products.name = :new_name,
|
SET products.name = :new_name,
|
||||||
products.description = :new_description,
|
products.description = :new_description,
|
||||||
products.expiration_date = :new_expiration_date
|
products.expiration_date = :new_expiration_date,
|
||||||
|
products.cupboard_id = :new_cupboard_id
|
||||||
WHERE products.public_id = :id
|
WHERE products.public_id = :id
|
||||||
AND products.owner_id = :owner_id;";
|
AND products.owner_id = :owner_id;";
|
||||||
$query = $PDO->prepare($sql);
|
$query = $PDO->prepare($sql);
|
||||||
@ -379,6 +385,11 @@ function update_product(
|
|||||||
} else {
|
} else {
|
||||||
$query->bindValue(":new_expiration_date", $new_expiration_date);
|
$query->bindValue(":new_expiration_date", $new_expiration_date);
|
||||||
}
|
}
|
||||||
|
if ($new_cupboard_id === null) {
|
||||||
|
$query->bindValue(":new_cupboard_id", $new_cupboard_id, PDO::PARAM_INT);
|
||||||
|
} else {
|
||||||
|
$query->bindValue(":new_cupboard_id", $new_cupboard_id);
|
||||||
|
}
|
||||||
$query->bindValue(":id", $product_public_id);
|
$query->bindValue(":id", $product_public_id);
|
||||||
$query->bindValue(":owner_id", get_user_info_from_session_id("id"));
|
$query->bindValue(":owner_id", get_user_info_from_session_id("id"));
|
||||||
|
|
||||||
@ -408,3 +419,134 @@ function update_cupboard(
|
|||||||
|
|
||||||
return $query->execute();
|
return $query->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clean_old_reset_tokens()
|
||||||
|
{
|
||||||
|
global $PDO;
|
||||||
|
|
||||||
|
$sql = "DELETE FROM reset_password WHERE token_eol < CURRENT_TIMESTAMP();";
|
||||||
|
$query = $PDO->prepare($sql);
|
||||||
|
return $query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_reset_token_valid($token)
|
||||||
|
{
|
||||||
|
global $PDO;
|
||||||
|
$sql = "SELECT * FROM reset_password WHERE token = :token;";
|
||||||
|
$query = $PDO->prepare($sql);
|
||||||
|
|
||||||
|
$query->bindValue(":token", $token);
|
||||||
|
|
||||||
|
if ($query->execute()) {
|
||||||
|
foreach ($query as $row) {
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_reset_token($token)
|
||||||
|
{
|
||||||
|
global $PDO;
|
||||||
|
$sql = "DELETE FROM reset_password WHERE token = :token;";
|
||||||
|
|
||||||
|
$query = $PDO->prepare($sql);
|
||||||
|
$query->bindValue(":token", $token);
|
||||||
|
|
||||||
|
return $query->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_user_id_from_reset_token($token)
|
||||||
|
{
|
||||||
|
global $PDO;
|
||||||
|
|
||||||
|
$sql = "SELECT accounts.id AS id FROM accounts INNER JOIN reset_password
|
||||||
|
ON accounts.id = reset_password.user_id WHERE token = :token;";
|
||||||
|
|
||||||
|
$query = $PDO->prepare($sql);
|
||||||
|
$query->bindValue(":token", $token);
|
||||||
|
if ($query->execute()) {
|
||||||
|
if ($row = $query->fetch()) {
|
||||||
|
return $row["id"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_token_count_from_email($email)
|
||||||
|
{
|
||||||
|
global $PDO;
|
||||||
|
|
||||||
|
$sql = "SELECT token FROM reset_password
|
||||||
|
INNER JOIN accounts ON reset_password.user_id = accounts.id
|
||||||
|
WHERE accounts.email = :email;";
|
||||||
|
|
||||||
|
$query = $PDO->prepare($sql);
|
||||||
|
$query->bindValue(":email", $email);
|
||||||
|
if ($query->execute()) {
|
||||||
|
return $query->rowCount();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generate_reset_password_token($email)
|
||||||
|
{
|
||||||
|
global $PDO, $MAX_RESET_TOKEN_LIFE, $MAX_TOKENS;
|
||||||
|
$user_id = get_user_id_from_email($email);
|
||||||
|
if (
|
||||||
|
is_numeric($user_id)
|
||||||
|
&& get_token_count_from_email($email) < $MAX_TOKENS
|
||||||
|
) {
|
||||||
|
$random_token = generate_random_string();
|
||||||
|
$sql = "INSERT INTO reset_password(token, token_eol, user_id)
|
||||||
|
VALUES(:token, :token_eol, :user_id);";
|
||||||
|
$query = $PDO->prepare($sql);
|
||||||
|
$query->bindValue(":token", $random_token);
|
||||||
|
$query->bindValue(
|
||||||
|
":token_eol",
|
||||||
|
date('Y-m-d H:i:s', strtotime("now + $MAX_RESET_TOKEN_LIFE seconds")),
|
||||||
|
PDO::PARAM_STR
|
||||||
|
);
|
||||||
|
$query->bindValue(":user_id", $user_id);
|
||||||
|
if ($query->execute()) {
|
||||||
|
return $random_token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_email_message($link, $first_name)
|
||||||
|
{
|
||||||
|
global $MAX_RESET_TOKEN_LIFE, $MAX_TOKENS;
|
||||||
|
$email = "Hey $first_name,<br>";
|
||||||
|
$email .= "<br>";
|
||||||
|
$email .= "Looks like you asked for a password reset, if so please click the link below (under " . $MAX_RESET_TOKEN_LIFE / 60 . " minutes from now) and reset you password on our website:<br>";
|
||||||
|
$email .= $link . "<br>";
|
||||||
|
$email .= "<br>";
|
||||||
|
$email .= "If it wasn't you who requested this, you can just ignore this message, and nothing will be done.<br>";
|
||||||
|
$email .= "<br>";
|
||||||
|
$email .= "Please remember that each link expires after " . $MAX_RESET_TOKEN_LIFE / 60 . " minutes, so this one will expire exactly at " . date('Y-m-d H:i:s', strtotime("now + $MAX_RESET_TOKEN_LIFE seconds")) . ".<br>";
|
||||||
|
$email .= "You can generate $MAX_TOKENS at maximum. So if you ever want to generate one more after this limit, you'd have to wait for the previous links to be deactivated.<br>";
|
||||||
|
$email .= "<br>";
|
||||||
|
$email .= "Thanks,<br>";
|
||||||
|
$email .= "The Food Inventory system";
|
||||||
|
return ["html" => $email, "alt" => str_replace("<br>", "\n", $email)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_user_info_from_email($email)
|
||||||
|
{
|
||||||
|
global $PDO;
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM accounts WHERE email = :email;";
|
||||||
|
|
||||||
|
$query = $PDO->prepare($sql);
|
||||||
|
$query->bindValue(":email", $email);
|
||||||
|
|
||||||
|
if ($query->execute()) {
|
||||||
|
foreach ($query as $row) {
|
||||||
|
return $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
122
forgotten-password.php
Normal file
122
forgotten-password.php
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
// Include util functions
|
||||||
|
require_once("./assets/php/utils.php");
|
||||||
|
require_once("./assets/php/send_email.php");
|
||||||
|
|
||||||
|
clean_old_reset_tokens();
|
||||||
|
disconnect();
|
||||||
|
|
||||||
|
$password1_err = $password2_err = $mode = $submit_message = $link = "";
|
||||||
|
|
||||||
|
|
||||||
|
if (isset($_GET["token"]) && is_reset_token_valid($_GET["token"])) {
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["password1"]) && isset($_POST["password2"])) {
|
||||||
|
if (empty(trim($_POST["password1"])) || strlen($_POST["password1"]) < $MINIMAL_PASSWORD_LENGTH) {
|
||||||
|
$password1_err = "The password is too short.";
|
||||||
|
} else if ($_POST["password1"] !== $_POST["password2"]) {
|
||||||
|
$password2_err = "Passwords didn't match.";
|
||||||
|
} else {
|
||||||
|
if (change_user_password(get_user_id_from_reset_token($_GET["token"]), $_POST["password1"])) {
|
||||||
|
delete_reset_token($_GET["token"]);
|
||||||
|
header("Location: login.php");
|
||||||
|
} else {
|
||||||
|
$password1_err = $password2_err = "There were an error while changing your password.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
$_SERVER["REQUEST_METHOD"] === "POST" && (!isset($_POST["password1"]) || !isset($_POST["password2"]) || empty(trim($_POST["password1"])) || empty(trim($_POST["password1"])))
|
||||||
|
) {
|
||||||
|
$password1_err = "Please input a new password.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_POST["email"])) {
|
||||||
|
$token = generate_reset_password_token($_POST["email"]);
|
||||||
|
if ($token !== false) {
|
||||||
|
$link = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST']
|
||||||
|
. explode('?', $_SERVER['REQUEST_URI'], 2)[0] . "?token=$token";
|
||||||
|
$row = get_user_info_from_email($_POST["email"]);
|
||||||
|
$email_array = get_email_message($link, $row["first_name"]);
|
||||||
|
if ($row !== false) {
|
||||||
|
send_email(
|
||||||
|
$_POST["email"],
|
||||||
|
"Forgot your password? Let's get you a new one!",
|
||||||
|
$email_array["html"],
|
||||||
|
$email_array["alt"],
|
||||||
|
$row["first_name"],
|
||||||
|
$row["last_name"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$submit_message = "If your e-mail address was correct, you should check your inbox.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<!-- TODO : ADD SEO STUFF -->
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<link href="/assets/css/reset.css" rel="stylesheet">
|
||||||
|
<link href="/assets/css/common.css" rel="stylesheet">
|
||||||
|
<link href="/assets/css/login.css" rel="stylesheet">
|
||||||
|
<title>Food inventory - Forgotten password</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="center30left white">
|
||||||
|
<h2 class="montserrat" id="title">Need to reset?</h2>
|
||||||
|
<?php if (isset($_GET["token"]) && is_reset_token_valid($_GET["token"])) {
|
||||||
|
?>
|
||||||
|
<form action="<?php echo htmlspecialchars($_SERVER["REQUEST_URI"]); ?>" method="post">
|
||||||
|
<div class="flex-container flex-evenly">
|
||||||
|
<input type="password" name="password1" class="form-control halo-hover <?php echo (!empty($password1_err)) ? 'has-error' : ''; ?>" placeholder="Password">
|
||||||
|
<input type="password" name="password2" class="form-control halo-hover <?php echo (!empty($password2_err)) ? 'has-error' : ''; ?>" placeholder="Confirm password">
|
||||||
|
</div>
|
||||||
|
<div class="flex-container flex-evenly">
|
||||||
|
<div class="error">
|
||||||
|
<?php
|
||||||
|
if (!empty($password1_err)) echo $password1_err;
|
||||||
|
else echo $password2_err;
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group flex-container flex-vertical-center flex-evenly">
|
||||||
|
<input type="submit" class="halo-hover login-button" value="Reset">
|
||||||
|
<a href="/" class="login-button halo-hover other-buttons">Main page</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
|
if ($submit_message === "") {
|
||||||
|
?>
|
||||||
|
<form action="<?php echo htmlspecialchars($_SERVER["REQUEST_URI"]); ?>" method="post">
|
||||||
|
<div class="flex-container flex-evenly">
|
||||||
|
<input type="email" name="email" class="form-control halo-hover" value="" placeholder="E-mail" required id="lost-email">
|
||||||
|
</div>
|
||||||
|
<div class="flex-container flex-evenly">
|
||||||
|
<div class="error">
|
||||||
|
<?php
|
||||||
|
if (!empty($password1_err)) echo $password1_err;
|
||||||
|
else echo $password2_err;
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group flex-container flex-vertical-center flex-evenly">
|
||||||
|
<input type="submit" class="halo-hover login-button" value="Reset">
|
||||||
|
<a href="/" class="login-button halo-hover other-buttons">Main page</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
|
echo "<p class=\"error\">" . $submit_message . "</p>\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
35
index.php
Normal file
35
index.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once("./assets/php/utils.php")
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<?php include_once("./assets/php/copyright.php"); ?>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<!-- TODO : ADD SEO STUFF -->
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<link href="/assets/css/reset.css" rel="stylesheet">
|
||||||
|
<link href="/assets/css/common.css" rel="stylesheet">
|
||||||
|
<link href="/assets/css/index.css" rel="stylesheet">
|
||||||
|
<title>Food inventory</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="indexTitle">
|
||||||
|
<h1 class="montserrat white bold-900 big" id="title">Food inventory</h1>
|
||||||
|
<h2 class="white bold-900 noto-sans" id="subtitle">Keep an eye on your food.</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="noto-sans" id="login">
|
||||||
|
<a class="white" href="/login.php" id="loginButton">
|
||||||
|
<?php echo is_connected() ? "Account\n" : "Connection\n"; ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -23,11 +23,18 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["edit"])) {
|
|||||||
$edit_description = $cupboard["description"];
|
$edit_description = $cupboard["description"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($edit_id === "") {
|
||||||
|
$erreur = "<p>Unknown cupboard.</p>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["edit_completed"])) {
|
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["edit_completed"])) {
|
||||||
if (isset($_POST["name"]) && isset($_POST["description"])) {
|
if (isset($_POST["name"]) && isset($_POST["description"])) {
|
||||||
if (!update_cupboard($_POST["edit_completed"], $_POST["name"], $_POST["description"])) {
|
if (!update_cupboard(
|
||||||
|
$_POST["edit_completed"],
|
||||||
|
$_POST["name"],
|
||||||
|
$_POST["description"]
|
||||||
|
)) {
|
||||||
$erreur = "<p>Something went wrong. Try again later.</p>";
|
$erreur = "<p>Something went wrong. Try again later.</p>";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -79,6 +86,7 @@ foreach (get_users_cupboards_array() as $row) {
|
|||||||
<label>Description : </label><input type="text" name="description" value="<?php echo $edit_description; ?>">
|
<label>Description : </label><input type="text" name="description" value="<?php echo $edit_description; ?>">
|
||||||
<button type="publish" name="edit_completed" value="<?php echo $edit_id; ?>">Valider</button>
|
<button type="publish" name="edit_completed" value="<?php echo $edit_id; ?>">Valider</button>
|
||||||
</form>
|
</form>
|
||||||
|
<br>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
require_once("./assets/php/utils.php");
|
require_once("./assets/php/utils.php");
|
||||||
|
|
||||||
$erreur = $edit_id = $edit_name = $edit_description = $edit_expiration = "";
|
$erreur = $edit_id = $edit_name = $edit_description = $edit_expiration = $edit_cupboard = "";
|
||||||
|
|
||||||
if (!is_connected()) {
|
if (!is_connected()) {
|
||||||
header("location: login.php");
|
header("location: login.php");
|
||||||
@ -22,13 +22,36 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["edit"])) {
|
|||||||
$edit_name = $product["name"];
|
$edit_name = $product["name"];
|
||||||
$edit_description = $product["description"];
|
$edit_description = $product["description"];
|
||||||
$edit_expiration = $product["expiration_date"];
|
$edit_expiration = $product["expiration_date"];
|
||||||
|
$edit_cupboard = $product["cupboard_public_id"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($edit_id === "") {
|
||||||
|
$erreur = "<p>Unknown product.</>p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
$cupboard_list = "";
|
||||||
|
foreach (get_users_cupboards_array() as $row) {
|
||||||
|
$cupboard_list = $cupboard_list . "<option value=\""
|
||||||
|
. htmlspecialchars($row["public_id"]) . "\"";
|
||||||
|
if ($row["public_id"] === $edit_cupboard) $cupboard_list = $cupboard_list . " selected ";
|
||||||
|
$cupboard_list = $cupboard_list . ">"
|
||||||
|
. htmlspecialchars($row["name"]) . "</option>\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["edit_completed"])) {
|
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST["edit_completed"])) {
|
||||||
if (isset($_POST["name"]) && isset($_POST["description"]) && isset($_POST["expiration"])) {
|
if (isset($_POST["name"]) && isset($_POST["description"]) && isset($_POST["expiration"]) && isset($_POST["cupboard"])) {
|
||||||
if (!update_product($_POST["edit_completed"], $_POST["name"], $_POST["description"], empty(trim($_POST["expiration"])) ? null : $_POST["expiration"])) {
|
$cupboard_id = null;
|
||||||
|
foreach (get_users_cupboards_array() as $cupboards) {
|
||||||
|
if ($cupboards["public_id"] === $_POST["cupboard"]) $cupboard_id = $cupboards["id"];
|
||||||
|
}
|
||||||
|
if (!update_product(
|
||||||
|
$_POST["edit_completed"],
|
||||||
|
$_POST["name"],
|
||||||
|
$_POST["description"],
|
||||||
|
empty(trim($_POST["expiration"])) ? null : $_POST["expiration"],
|
||||||
|
$cupboard_id
|
||||||
|
)) {
|
||||||
$erreur = "<p>Something went wrong. Try again later.</p>";
|
$erreur = "<p>Something went wrong. Try again later.</p>";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -49,10 +72,10 @@ foreach (get_users_products_array() as $row) {
|
|||||||
. "</td><td>"
|
. "</td><td>"
|
||||||
. htmlspecialchars($row["cupboard_name"] !== NULL ? $row["cupboard_name"] : "-")
|
. htmlspecialchars($row["cupboard_name"] !== NULL ? $row["cupboard_name"] : "-")
|
||||||
. "</td><td>"
|
. "</td><td>"
|
||||||
. "<form method='post'><button type='publish' name='edit' value='"
|
. "<form method='post'><button type='publish' name='edit' value='"
|
||||||
. $row["public_id"] . "'>Editer</button></form>"
|
. $row["public_id"] . "'>Editer</button></form>"
|
||||||
. "</td><td>"
|
. "</td><td>"
|
||||||
. "<form method='post'><button type='publish' name='delete' value='"
|
. "<form method='post'><button type='publish' name='delete' value='"
|
||||||
. $row["public_id"] . "'>Delete</button></form>"
|
. $row["public_id"] . "'>Delete</button></form>"
|
||||||
. "</td><tr>\n";
|
. "</td><tr>\n";
|
||||||
}
|
}
|
||||||
@ -90,8 +113,14 @@ foreach (get_users_products_array() as $row) {
|
|||||||
<label>Nom : </label><input type="text" name="name" value="<?php echo $edit_name; ?>">
|
<label>Nom : </label><input type="text" name="name" value="<?php echo $edit_name; ?>">
|
||||||
<label>Description : </label><input type="text" name="description" value="<?php echo $edit_description; ?>">
|
<label>Description : </label><input type="text" name="description" value="<?php echo $edit_description; ?>">
|
||||||
<label>Expiration : </label><input type="date" name="expiration" value="<?php echo $edit_expiration; ?>">
|
<label>Expiration : </label><input type="date" name="expiration" value="<?php echo $edit_expiration; ?>">
|
||||||
|
<label>Cupboard:</label>
|
||||||
|
<select name="cupboard">
|
||||||
|
<option value=""></option>
|
||||||
|
<?php echo $cupboard_list; ?>
|
||||||
|
</select>
|
||||||
<button type="publish" name="edit_completed" value="<?php echo $edit_id; ?>">Valider</button>
|
<button type="publish" name="edit_completed" value="<?php echo $edit_id; ?>">Valider</button>
|
||||||
</form>
|
</form>
|
||||||
|
<br>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
57
login.php
57
login.php
@ -54,46 +54,47 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
<?php include_once("./assets/php/copyright.php"); ?>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Login</title>
|
<!-- TODO : ADD SEO STUFF -->
|
||||||
<style type="text/css">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
body {
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
font: 14px sans-serif;
|
<link href="/assets/css/reset.css" rel="stylesheet">
|
||||||
}
|
<link href="/assets/css/common.css" rel="stylesheet">
|
||||||
|
<link href="/assets/css/login.css" rel="stylesheet">
|
||||||
.wrapper {
|
<title>Food inventory - Login</title>
|
||||||
width: 350px;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<div class="center30left white">
|
||||||
<h2>Login</h2>
|
<h2 class="montserrat" id="title">Welcome back</h2>
|
||||||
<p>Please fill in your credentials to login.</p>
|
|
||||||
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
|
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
|
||||||
<div class="form-group <?php echo (!empty($username_err)) ? 'has-error' : ''; ?>">
|
<div class="flex-container flex-evenly">
|
||||||
<label>Username</label>
|
<input type="email" name="username" class="form-control halo-hover <?php echo (!empty($username_err)) ? 'has-error' : ''; ?>" value="<?php echo $username; ?>" placeholder="Username">
|
||||||
<input type="text" name="username" class="form-control" value="<?php echo $username; ?>">
|
<input type="password" name="password" class="form-control halo-hover <?php echo (!empty($password_err)) ? 'has-error' : ''; ?>" placeholder="Password">
|
||||||
<span class="help-block"><?php echo $username_err; ?></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group <?php echo (!empty($password_err)) ? 'has-error' : ''; ?>">
|
<div class="flex-container flex-evenly">
|
||||||
<label>Password</label>
|
<div class="error">
|
||||||
<input type="password" name="password" class="form-control">
|
<?php
|
||||||
<span class="help-block"><?php echo $password_err; ?></span>
|
if (!empty($username_err)) echo $username_err; else echo $password_err;
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="remember-me flex-container">
|
||||||
<label>Remember me</label>
|
<label class="checkbox-container">Remember me
|
||||||
<input type="checkbox" name="stay_loggedin"/>
|
<input type="checkbox" name="stay_loggedin" />
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group flex-container flex-vertical-center flex-evenly">
|
||||||
<input type="submit" class="btn btn-primary" value="Login">
|
<input type="submit" class="halo-hover login-button" value="Login">
|
||||||
|
<a href="register.php" class="login-button halo-hover other-buttons">Register</a>
|
||||||
|
<a href="forgotten-password.php" class="login-button halo-hover other-buttons">Forgotten password?</a>
|
||||||
|
<a href="/" class="login-button halo-hover other-buttons">Main page</a>
|
||||||
</div>
|
</div>
|
||||||
<p>Don't have an account? <a href="register.php">Sign up now</a>.</p>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
75
register.php
75
register.php
@ -47,7 +47,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
|
|
||||||
if (empty(trim($_POST["first_name"]))) {
|
if (empty(trim($_POST["first_name"]))) {
|
||||||
$first_name_err = "Please input your first name.";
|
$first_name_err = "Please input your first name.";
|
||||||
} else if (strlen(trim($_POST["first_name"])) > 255){
|
} else if (strlen(trim($_POST["first_name"])) > 255) {
|
||||||
$first_name_err = "Too long.";
|
$first_name_err = "Too long.";
|
||||||
} else {
|
} else {
|
||||||
$first_name = trim($_POST["first_name"]);
|
$first_name = trim($_POST["first_name"]);
|
||||||
@ -55,7 +55,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
|
|
||||||
if (empty(trim($_POST["last_name"]))) {
|
if (empty(trim($_POST["last_name"]))) {
|
||||||
$last_name_err = "Please input your last name.";
|
$last_name_err = "Please input your last name.";
|
||||||
} else if (strlen(trim($_POST["last_name"])) > 255){
|
} else if (strlen(trim($_POST["last_name"])) > 255) {
|
||||||
$last_name_err = "Too long.";
|
$last_name_err = "Too long.";
|
||||||
} else {
|
} else {
|
||||||
$last_name = trim($_POST["last_name"]);
|
$last_name = trim($_POST["last_name"]);
|
||||||
@ -82,55 +82,46 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Sign Up</title>
|
<!-- TODO : ADD SEO STUFF -->
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<style type="text/css">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
body {
|
<link href="/assets/css/reset.css" rel="stylesheet">
|
||||||
font: 14px sans-serif;
|
<link href="/assets/css/common.css" rel="stylesheet">
|
||||||
}
|
<link href="/assets/css/login.css" rel="stylesheet">
|
||||||
|
<title>Food invetory - Register</title>
|
||||||
.wrapper {
|
|
||||||
width: 350px;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<div class="center30left white">
|
||||||
<h2>Sign Up</h2>
|
<h2 class="montserrat" id="title">Nice to meet you</h2>
|
||||||
<p>Please fill this form to create an account.</p>
|
|
||||||
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
|
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
|
||||||
<div class="form-group <?php echo (!empty($username_err)) ? 'has-error' : ''; ?>">
|
<div class="flex-container flex-content-stretch">
|
||||||
<label>Username</label>
|
<input type="email" name="username" class="form-control halo-hover <?php echo (!empty($username_err)) ? 'has-error' : ''; ?>" value="<?php echo $username; ?>" placeholder="E-mail" id="register-email">
|
||||||
<input type="text" name="username" class="form-control" value="<?php echo $username; ?>">
|
|
||||||
<span class="help-block"><?php echo $username_err; ?></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group <?php echo (!empty($first_name_err)) ? 'has-error' : ''; ?>">
|
<div class="flex-container flex-content-stretch flex-space-between">
|
||||||
<label>First name</label>
|
<input type="text" placeholder="First name" name="first_name" class="form-control halo-hover <?php echo (!empty($first_name_err)) ? 'has-error' : ''; ?>" value="<?php echo $first_name; ?>">
|
||||||
<input type="text" name="first_name" class="form-control" value="<?php echo $first_name; ?>">
|
<input type="text" placeholder="Last name" name="last_name" class="form-control halo-hover <?php echo (!empty($last_name_err)) ? 'has-error' : ''; ?>" value="<?php echo $last_name; ?>">
|
||||||
<span class="help-block"><?php echo $first_name_err; ?></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group <?php echo (!empty($last_name_err)) ? 'has-error' : ''; ?>">
|
<div class="flex-container flex-content-stretch flex-space-between">
|
||||||
<label>Last name</label>
|
<input type="password" placeholder="Password" name="password" class="form-control halo-hover <?php echo (!empty($password_err)) ? 'has-error' : ''; ?>" value="<?php echo $password; ?>">
|
||||||
<input type="text" name="last_name" class="form-control" value="<?php echo $last_name; ?>">
|
<input type="password" placeholder="Confirm password" name="confirm_password" class="form-control halo-hover <?php echo (!empty($confirm_password_err)) ? 'has-error' : ''; ?>" value="<?php echo $confirm_password; ?>">
|
||||||
<span class="help-block"><?php echo $last_name_err; ?></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group <?php echo (!empty($password_err)) ? 'has-error' : ''; ?>">
|
<div class="flex-container flex-evenly">
|
||||||
<label>Password</label>
|
<div class="error">
|
||||||
<input type="password" name="password" class="form-control" value="<?php echo $password; ?>">
|
<?php
|
||||||
<span class="help-block"><?php echo $password_err; ?></span>
|
if (!empty($username_err)) echo $username_err;
|
||||||
|
else if (!empty($first_name_err)) echo $first_name_err;
|
||||||
|
else if (!empty($last_name_err)) echo $last_name_err;
|
||||||
|
else if (!empty($password_err)) echo $password_err;
|
||||||
|
else echo $confirm_password_err;
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group <?php echo (!empty($confirm_password_err)) ? 'has-error' : ''; ?>">
|
<div class="form-group flex-container flex-vertical-center flex-space-between">
|
||||||
<label>Confirm Password</label>
|
<input type="submit" class="halo-hover login-button" value="Submit">
|
||||||
<input type="password" name="confirm_password" class="form-control" value="<?php echo $confirm_password; ?>">
|
<a href="login.php" class="login-button halo-hover other-buttons">Already registered? Login!</a>
|
||||||
<span class="help-block"><?php echo $confirm_password_err; ?></span>
|
<a href="/" class="login-button halo-hover other-buttons">Main page</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<input type="submit" class="btn btn-primary" value="Submit">
|
|
||||||
<input type="reset" class="btn btn-default" value="Reset">
|
|
||||||
</div>
|
|
||||||
<p>Already have an account? <a href="login.php">Login here</a>.</p>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
48
welcome.php
48
welcome.php
@ -13,32 +13,34 @@ if (!is_connected()) {
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Welcome</title>
|
<!-- TODO : ADD SEO STUFF -->
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<style type="text/css">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
body {
|
<link href="/assets/css/reset.css" rel="stylesheet">
|
||||||
font: 14px sans-serif;
|
<link href="/assets/css/common.css" rel="stylesheet">
|
||||||
text-align: center;
|
<link href="/assets/css/welcome.css" rel="stylesheet">
|
||||||
}
|
<title>Food inventory - Welcome</title>
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body class="white">
|
||||||
<div class="page-header">
|
<div id="header">
|
||||||
<h1>Hi, <b><?php echo htmlspecialchars(get_user_info_from_session_id("first_name")); ?></b>. Welcome to food-inventory.</h1>
|
<h1 class="montserrat">Hi, <b><?php echo htmlspecialchars(get_user_info_from_session_id("first_name")); ?></b>. Welcome to food-inventory.</h1>
|
||||||
|
<div class="flex-container flex-evenly" id="buttonList">
|
||||||
|
<a href="reset-password.php" class="button lato white btn-violet">Reset Your Password</a>
|
||||||
|
<a href="logout.php" class="button lato white btn-red">Sign Out of Your Account</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex-container flex-evenly" id="buttonList2">
|
||||||
|
<div class="flex-container flex-evenly width50P">
|
||||||
|
<a href="list-cupboards.php" class="button lato white btn-blue">List cupboards</a>
|
||||||
|
<a href="list-products.php" class="button lato white btn-blue">List products</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex-container flex-evenly width50P">
|
||||||
|
<a href="add-cupboard.php" class="button lato white btn-green">Add cupboard</a>
|
||||||
|
<a href="add-product.php" class="button lato white btn-green">Add product</a>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
|
||||||
<a href="reset-password.php" class="btn btn-warning">Reset Your Password</a>
|
|
||||||
<a href="logout.php" class="btn btn-danger">Sign Out of Your Account</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a href="list-cupboards.php" class="btn btn-info">List cupboards</a>
|
|
||||||
<a href="list-products.php" class="btn btn-info">List products</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a href="add-cupboard.php" class="btn btn-info">Add cupboard</a>
|
|
||||||
<a href="add-product.php" class="btn btn-info">Add product</a>
|
|
||||||
</p>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user