Initial commit.
This commit is contained in:
commit
227c91963e
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/data
|
||||||
|
|
68
edit/inc/functions.php
Normal file
68
edit/inc/functions.php
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* This file contains all the main functions for the backend.
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Include functions from frontend.
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../inc/functions.php';
|
||||||
|
require_once __DIR__ . '/standardHTML.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for ensuring everything is in order in the backend.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ensureBackendEnv() {
|
||||||
|
|
||||||
|
if (session_status() != PHP_SESSION_ACTIVE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
include_once __DIR__ . "/../password_protect.php";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that checks all the indexes in the input array for their availability in $_GET or $_POST.
|
||||||
|
* If they exist in either, they are written to global variables.
|
||||||
|
*
|
||||||
|
* @param string[] $vars Input array containing indices, that may be contained in $_GET or $_POST.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function loadHttpToGlobals(array $vars) {
|
||||||
|
|
||||||
|
foreach ($vars as $var) {
|
||||||
|
if (isset($_GET[$var])) $GLOBALS[$var] = $_GET[$var];
|
||||||
|
else if (isset($_POST[$var])) $GLOBALS[$var] = $_POST[$var];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for loading the language.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
function loadLanguage():array {
|
||||||
|
|
||||||
|
if (isset($_GET['lan'])) $_SESSION['lan'] = $lan = $_GET['lan'];
|
||||||
|
else if (isset($_SESSION['lan'])) $lan = $_SESSION['lan'];
|
||||||
|
|
||||||
|
// Default to English
|
||||||
|
if (!isset($lan) or !file_exists(__DIR__ . "/translations/$lan.php")) {
|
||||||
|
$lan = "en";
|
||||||
|
}
|
||||||
|
|
||||||
|
include __DIR__ . "/../translations/$lan.php";
|
||||||
|
|
||||||
|
return $translations;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
163
edit/inc/standardHTML.php
Normal file
163
edit/inc/standardHTML.php
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Functions for forming the HTML output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the head element of an HTML page
|
||||||
|
*
|
||||||
|
* @param string $page Name / ID of the current page.
|
||||||
|
* @param string $title Title of the page.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function printBackendHead(string $page = "home", string $title = "Home"):string {
|
||||||
|
|
||||||
|
$output = '<!DOCTYPE html>
|
||||||
|
<html lang="en" id="' . $page . '">
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<title>' . $title . '</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="themes/imports.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="themes/default/default.css">
|
||||||
|
<meta http-equiv="content-type" content="text/html;charset=utf-8">';
|
||||||
|
|
||||||
|
$output .= '
|
||||||
|
<meta name="robots" content="none" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<script type="text/javascript" src="./js/newToolTip.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
';
|
||||||
|
|
||||||
|
if (isset($_SESSION['editHistory'])) {
|
||||||
|
$output .= "<p class='editLine ".$_SESSION['editHistory'][0]."'>".$_SESSION['editHistory'][1]."</p>";
|
||||||
|
unset($_SESSION['editHistory']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the header element of an HTML page.
|
||||||
|
*
|
||||||
|
* @param string $title Title of the page.
|
||||||
|
* @param string $helpText Additional help text for the page. Optional.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function printBackendHeader(string $title = "Home", string $helpText = ""):string {
|
||||||
|
|
||||||
|
$output = '
|
||||||
|
|
||||||
|
<header id="mainHeader">
|
||||||
|
|
||||||
|
<span id="toggleNavigation"></span>
|
||||||
|
<h1>' . $title . '</h1>
|
||||||
|
<span>
|
||||||
|
<span id="toggleTextBlocks"></span>';
|
||||||
|
if ($helpText) $output .= '
|
||||||
|
<span class="newToolTipTag" data-for="pageHelp" id="helpText">
|
||||||
|
<span>?</span>
|
||||||
|
<div class="newToolTip" id="tooltip_pageHelp" data-title="' . $title . '">
|
||||||
|
' . $helpText . '
|
||||||
|
</div>
|
||||||
|
</span>';
|
||||||
|
$output .= '
|
||||||
|
<span id="uploadFile"></span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</header>
|
||||||
|
';
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns HTML code for a help icon and its attached tooltip.
|
||||||
|
*
|
||||||
|
* @param string $tooltipName Name / ID of the tooltip to generate.
|
||||||
|
* @param string $title Title to print in the tooltip.
|
||||||
|
* @param string $helpText Text to print into the tooltip.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function generateHelpToolTip(string $tooltipName, string $title, string $helpText):string {
|
||||||
|
$output = '
|
||||||
|
<span class="newToolTipTag helpToolTip" data-for="' . $tooltipName . '">
|
||||||
|
<div class="newToolTip" id="tooltip_' . $tooltipName . '" data-title="' . $title . '">
|
||||||
|
' . $helpText . '
|
||||||
|
</div>
|
||||||
|
</span>';
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the navigation for the backend.
|
||||||
|
*
|
||||||
|
* @param string[] $translations Translation variable.
|
||||||
|
* @param integer[] $numbers Count of the given values.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function printBackendNav(array $translations, $numbers = []):string {
|
||||||
|
|
||||||
|
$output = '
|
||||||
|
|
||||||
|
<nav id="mainNav">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<span>' . $translations['edit'] . '</span>
|
||||||
|
<div>
|
||||||
|
<a href=".">' . $translations['start'] . '</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="pages.php">' . $translations['pages'] . '</a>
|
||||||
|
<a href="page.php"> + </a>';
|
||||||
|
if (isset($numbers['pages'])) $output .= '
|
||||||
|
<a href="users.php#listUsers">' . $numbers['pages'] . '</a>';
|
||||||
|
$output .= '
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="fileUpload.php">' . $translations['fileUpload'] . '</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>' . $translations['administration'] . '</span>
|
||||||
|
<div>
|
||||||
|
<a href="users.php#listUsers">' . $translations['users'] . '</a>
|
||||||
|
<a href="users.php#addUser"> + </a>';
|
||||||
|
if (isset($numbers['users'])) $output .= '
|
||||||
|
<a href="users.php#listUsers">' . $numbers['users'] . '</a>';
|
||||||
|
$output .= '
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
';
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the finishing elements of an HTML page.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function printBackendEnd():string {
|
||||||
|
|
||||||
|
$output = '
|
||||||
|
</body>
|
||||||
|
</html>';
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
47
edit/index.php
Normal file
47
edit/index.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Start page of the backend.
|
||||||
|
* Offers a dashboard.
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Require files and ensure environment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . "/inc/functions.php";
|
||||||
|
|
||||||
|
ensureEnvironment(); // Ensure existence of system files.
|
||||||
|
$translations = loadLanguage(); // Load translations.
|
||||||
|
ensureBackendEnv(); // Ensure session is started etc.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output
|
||||||
|
*/
|
||||||
|
|
||||||
|
echo printBackendHead($translations['start']);
|
||||||
|
echo printBackendHeader($translations['start'], $translations['helpStart']);
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<div id="mainWrapper">
|
||||||
|
';
|
||||||
|
|
||||||
|
echo printBackendNav($translations);
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<main>';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
echo '
|
||||||
|
</main>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
echo printBackendEnd();
|
||||||
|
|
||||||
|
?>
|
69
edit/js/newToolTip.js
Normal file
69
edit/js/newToolTip.js
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/**
|
||||||
|
* A simple implementation of a tooltip.
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for setting the alignment of an element.
|
||||||
|
*
|
||||||
|
* @param {Event} e Event triggering the execution of this function.
|
||||||
|
* @param {DOMElement} elem Dom element to position.
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
function getDirection(e, elem) {
|
||||||
|
|
||||||
|
if (window.innerHeight < e.clientY + elem.clientHeight) {
|
||||||
|
elem.style.top = "";
|
||||||
|
elem.style.bottom = (window.innerHeight - e.clientY) + "px";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elem.style.bottom = "";
|
||||||
|
elem.style.top = (e.clientY + 2) + "px";
|
||||||
|
}
|
||||||
|
if (window.innerWidth < e.clientX + elem.clientWidth) {
|
||||||
|
elem.style.left = "";
|
||||||
|
elem.style.right = (window.innerWidth - e.clientX) + "px";
|
||||||
|
} else {
|
||||||
|
elem.style.right = "";
|
||||||
|
elem.style.left = (e.clientX + 2) + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let triggers = document.getElementsByClassName("newToolTipTag");
|
||||||
|
for (let i = 0, max = triggers.length; i < max; i++) {
|
||||||
|
|
||||||
|
let trigger = triggers[i];
|
||||||
|
let dataTarget = trigger.getAttribute("data-for");
|
||||||
|
let target = document.getElementById("tooltip_" + dataTarget);
|
||||||
|
|
||||||
|
trigger.addEventListener("mouseover", function(e) {
|
||||||
|
let newMain = document.getElementById("newToolTipMain");
|
||||||
|
if (newMain !== null) return;
|
||||||
|
newMain = target.cloneNode(true);
|
||||||
|
newMain.id = "newToolTipMain";
|
||||||
|
document.getElementsByTagName("body")[0].appendChild(newMain);
|
||||||
|
newMain.classList.add("visible");
|
||||||
|
getDirection(e, newMain);
|
||||||
|
});
|
||||||
|
trigger.addEventListener("mousemove", function(e) {
|
||||||
|
let newMain = document.getElementById("newToolTipMain");
|
||||||
|
getDirection(e, newMain);
|
||||||
|
});
|
||||||
|
trigger.addEventListener("mouseout", function(e) {
|
||||||
|
let newMain = document.getElementById("newToolTipMain");
|
||||||
|
if (newMain.classList.contains("sticked")) return;
|
||||||
|
newMain.classList.remove("visible");
|
||||||
|
document.getElementsByTagName("body")[0].removeChild(newMain);
|
||||||
|
});
|
||||||
|
trigger.addEventListener("click", function(e) {
|
||||||
|
document.getElementById("newToolTipMain").classList.toggle("sticked");
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
40
edit/page.php
Normal file
40
edit/page.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* This page offers the opportunity to edit static pages.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Require files and ensure environment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . "/inc/functions.php";
|
||||||
|
|
||||||
|
ensureEnvironment(); // Ensure existence of system files.
|
||||||
|
$translations = loadLanguage(); // Load translations.
|
||||||
|
ensureBackendEnv(); // Ensure session is started etc.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output
|
||||||
|
*/
|
||||||
|
|
||||||
|
echo printBackendHead($translations['start']);
|
||||||
|
echo printBackendHeader($translations['start'], $translations['helpStart']);
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<div id="mainWrapper">
|
||||||
|
';
|
||||||
|
|
||||||
|
echo printBackendNav($translations);
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<main>';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
echo '
|
||||||
|
</main>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
echo printBackendEnd();
|
||||||
|
|
||||||
|
?>
|
9
edit/pages.php
Normal file
9
edit/pages.php
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* This page provides an overview over all static pages in the system.
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
179
edit/password_protect.php
Normal file
179
edit/password_protect.php
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Login script
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Load settings
|
||||||
|
|
||||||
|
// Demand HTTPS
|
||||||
|
if (!isset($_SERVER['HTTPS']) or $_SERVER['HTTPS'] != 'on') header("Location: ../");
|
||||||
|
|
||||||
|
// Get available login information
|
||||||
|
|
||||||
|
$loginInformation = json_decode(file_get_contents(__DIR__ . '/../data/users.json'), True);
|
||||||
|
define("loginLogFile", "/../data/logins.csv");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for printing the login page
|
||||||
|
*
|
||||||
|
* @param string $error_msg Error message to print. Optional.
|
||||||
|
* @param string $cssFile CSS file.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function showLoginPasswordProtect($error_msg = "", $cssFile = "themes/default/default.css") {
|
||||||
|
|
||||||
|
echo '<!DOCTYPE html>
|
||||||
|
<html id="loginPage">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Log In</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="' . $cssFile . '">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Log In</h1>';
|
||||||
|
if ($error_msg) echo '<p id="errorMsg">'.$error_msg.'</p>';
|
||||||
|
echo '
|
||||||
|
<form action="" method="POST">
|
||||||
|
<input type="text" name="username" placeholder="Username" required autofocus />
|
||||||
|
<input type="password" name="password" placeholder="Password" required />
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
';
|
||||||
|
|
||||||
|
die();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logout function: Unsets all relevant session variables.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function logout() {
|
||||||
|
$loginVariables = array("username", "userlevel", "userLastLogin", "userLang");
|
||||||
|
foreach ($loginVariables as $var) {
|
||||||
|
if (isset($_SESSION[$var])) unset($_SESSION[$var]);
|
||||||
|
}
|
||||||
|
header("Location: ../");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for Logging logins.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function logLogin() {
|
||||||
|
file_put_contents(loginLogFile, $_SESSION['username'].'|'.date("Y-m-d H:i:s").PHP_EOL, FILE_APPEND | LOCK_EX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent brute force attacks
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function preventBruteForce() {
|
||||||
|
|
||||||
|
if (!isset($_SESSION['loginattempt'])) $_SESSION['loginattempt'] = array();
|
||||||
|
|
||||||
|
$_SESSION['loginattempt'][] = date("Y-m-d H:i:s");
|
||||||
|
|
||||||
|
if (count($_SESSION['loginattempt']) > 3) {
|
||||||
|
|
||||||
|
$secondtolastattempt = strtotime($_SESSION['loginattempt'][count($_SESSION['loginattempt']) - 3]);
|
||||||
|
$lastattempt = strtotime($_SESSION['loginattempt'][count($_SESSION['loginattempt']) - 2]);
|
||||||
|
|
||||||
|
$logindelay = (intval(count($_SESSION['loginattempt'])) * 20);
|
||||||
|
$sincelastlogin = strtotime(date("Y-m-d H:i:s")) - $lastattempt;
|
||||||
|
|
||||||
|
if ($sincelastlogin < $logindelay) showLoginPasswordProtect("You failed logging in too often, try again in $logindelay seconds.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check for validity of username / password combination.
|
||||||
|
*
|
||||||
|
* @param mixed[] $loginInformation Array containing all login information.
|
||||||
|
* @param string $username Username to check.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function checkLoginValidity(array $loginInformation, $username) {
|
||||||
|
if (!isset($loginInformation[$username])) showLoginPasswordProtect("Incorrect username");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main part of the script
|
||||||
|
|
||||||
|
if (isset($_GET['logout'])) logout(); // Log out if so requested
|
||||||
|
|
||||||
|
// Check for expiry
|
||||||
|
|
||||||
|
else if (isset($_SESSION['username'])) {
|
||||||
|
|
||||||
|
checkLoginValidity($loginInformation, $_SESSION["username"]);
|
||||||
|
|
||||||
|
// Check for expiry of login
|
||||||
|
if (isset($_SESSION["userLastLogin"]) and strtotime(date("Y-m-d H:i:s")) - strtotime($_SESSION["userLastLogin"]) > 3600) logout();
|
||||||
|
|
||||||
|
// Renew last login time
|
||||||
|
$_SESSION["userLastLogin"] = date("Y-m-d H:i:s");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the corresponding POST vars are set, check for
|
||||||
|
|
||||||
|
else if (isset($_SERVER['PHP_AUTH_USER']) and isset($_SERVER['PHP_AUTH_PW'])) {
|
||||||
|
|
||||||
|
preventBruteForce();
|
||||||
|
checkLoginValidity($loginInformation, $_SERVER['PHP_AUTH_USER']);
|
||||||
|
|
||||||
|
if (password_verify($loginInformation[$_SERVER['PHP_AUTH_USER']]['password'], $_SERVER['PHP_AUTH_PW'])) showLoginPasswordProtect("Incorrect password");
|
||||||
|
|
||||||
|
// Set username
|
||||||
|
$_SESSION["username"] = $_SERVER['PHP_AUTH_USER'];
|
||||||
|
|
||||||
|
// Set last access time
|
||||||
|
$_SESSION["userLastLogin"] = date("Y-m-d H:i:s");
|
||||||
|
|
||||||
|
if (isset($_SESSION['loginattempt'])) unset($_SESSION['loginattempt']);
|
||||||
|
|
||||||
|
// Log login time
|
||||||
|
logLogin();
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (isset($_POST['username']) and isset($_POST['password'])) {
|
||||||
|
|
||||||
|
preventBruteForce();
|
||||||
|
checkLoginValidity($loginInformation, $_POST['username']);
|
||||||
|
if (password_verify($loginInformation[$_POST['username']]['password'], $_POST['username'])) showLoginPasswordProtect("Incorrect password");
|
||||||
|
|
||||||
|
// Set username
|
||||||
|
$_SESSION["username"] = $_POST['username'];
|
||||||
|
|
||||||
|
// Set last access time
|
||||||
|
$_SESSION["userLastLogin"] = date("Y-m-d H:i:s");
|
||||||
|
|
||||||
|
if (isset($_SESSION['loginattempt'])) unset($_SESSION['loginattempt']);
|
||||||
|
|
||||||
|
// Log login time
|
||||||
|
logLogin();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing happens, offer login page
|
||||||
|
|
||||||
|
else showLoginPasswordProtect();
|
||||||
|
|
||||||
|
// End script
|
||||||
|
|
||||||
|
unset($loginInformation); // Unset array containing login information
|
||||||
|
|
||||||
|
?>
|
186
edit/themes/default/default.css
Normal file
186
edit/themes/default/default.css
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
/**
|
||||||
|
* Default theme for the backend of md:cms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/****************************
|
||||||
|
* Load fonts
|
||||||
|
*/
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: sourceSansPro;
|
||||||
|
src: local('Source-Sans-Pro'), local('Source Sans Pro'),
|
||||||
|
url(./fonts/SourceSansPro-Regular.woff2) format('woff2'),
|
||||||
|
url(./fonts/SourceSansPro-Regular.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************
|
||||||
|
* General
|
||||||
|
*/
|
||||||
|
|
||||||
|
html { margin: 0; padding: 0; }
|
||||||
|
body { margin: 0; padding: 0; font-family: sourceSansPro; font-size: 1.15em; line-height: 1.5; }
|
||||||
|
|
||||||
|
* { box-sizing: border-box; z-index: 1; }
|
||||||
|
a { color: inherit; text-decoration: none; }
|
||||||
|
|
||||||
|
a.buttonLike { display: inline-block; }
|
||||||
|
|
||||||
|
a.buttonLike,
|
||||||
|
select,
|
||||||
|
button,
|
||||||
|
textarea,
|
||||||
|
input { padding: .6em .8em; background: #FAFAFA; border: 1px solid #CFD8DC; font-family: roboto; font-size: inherit;
|
||||||
|
border-radius: .3em; transition: background .1s, box-shadow .1s; box-sizing: border-box; }
|
||||||
|
button { padding: .6em; }
|
||||||
|
select { padding: .3em .8em; }
|
||||||
|
textarea { line-height: 1.4em; }
|
||||||
|
|
||||||
|
a.buttonLike:hover,
|
||||||
|
select:hover,
|
||||||
|
button:hover,
|
||||||
|
textarea:hover,
|
||||||
|
input:hover { background: #FFF; box-shadow: 1px 1px 3px #CFD8DC; }
|
||||||
|
|
||||||
|
a.buttonLike:focus,
|
||||||
|
select:focus,
|
||||||
|
button:focus,
|
||||||
|
textarea:focus,
|
||||||
|
input:focus { background: #FFF; box-shadow: 1px 1px 3px #607D8B; }
|
||||||
|
|
||||||
|
input[type="range"] { background: inherit; border: 0; }
|
||||||
|
|
||||||
|
table { width: 100%; border-collapse: collapse; }
|
||||||
|
th { text-align: left; }
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Tables for providing an overview.
|
||||||
|
*/
|
||||||
|
|
||||||
|
table.overviewtable { height: auto; }
|
||||||
|
table.overviewtable thead { position: sticky; top: 0px; border-bottom: 3px solid #D6D6D6; }
|
||||||
|
|
||||||
|
table.overviewtable th,
|
||||||
|
table.overviewtable td { padding: .35em; }
|
||||||
|
table.overviewtable tr th:first-child,
|
||||||
|
table.overviewtable tr td:first-child { padding-left: .7em; }
|
||||||
|
table.overviewtable tr th:last-child,
|
||||||
|
table.overviewtable tr td:last-child { padding-right: .7em; text-align: right; }
|
||||||
|
|
||||||
|
table.overviewtable tr { transition: background .4s; }
|
||||||
|
|
||||||
|
table.secondRowShaded tr:nth-child(2n):hover,
|
||||||
|
table.overviewtable tr:hover { background: #E0E0E0; }
|
||||||
|
|
||||||
|
table.overviewtable tr:nth-child(2n) { background: #F2F2F2; }
|
||||||
|
|
||||||
|
table.fullwidth { width: auto; table-layout: fixed; }
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Tables for adding something.
|
||||||
|
*/
|
||||||
|
|
||||||
|
table.obj_cha_maintable { width: 100%; margin: 2em 0; }
|
||||||
|
.withAside .obj_cha_maintable { width: calc(100%); margin: 0px; }
|
||||||
|
table.obj_cha_maintable th { width: 100px; padding-top: .5em; padding-right: .8em; color: #424242; vertical-align: top; font-weight: normal; text-align: left; }
|
||||||
|
table.obj_cha_maintable td > label { padding-top: .5em; }
|
||||||
|
table.obj_cha_maintable td { vertical-align: top; }
|
||||||
|
|
||||||
|
table.obj_cha_maintable td:last-child { text-align: center; padding-top: .5em; }
|
||||||
|
|
||||||
|
table.obj_cha_maintable td.twoInputs input { width: 50%; }
|
||||||
|
table.obj_cha_maintable select:only-child,
|
||||||
|
table.obj_cha_maintable button:only-child,
|
||||||
|
table.obj_cha_maintable input:only-child { width: 100%; }
|
||||||
|
table.obj_cha_maintable textarea:only-child { width: 100%; height: 14em; }
|
||||||
|
|
||||||
|
@media screen and (min-width:65em) {
|
||||||
|
table.obj_cha_maintable th { width: 16em; }
|
||||||
|
}
|
||||||
|
|
||||||
|
table.obj_cha_maintable td.shortInputLong input { width: 8em; }
|
||||||
|
table.obj_cha_maintable td.shortInputLong input:nth-child(2) { width: calc(100% - 9em); float: right; }
|
||||||
|
|
||||||
|
.obj_cha_maintable td:last-child { width: 3em; }
|
||||||
|
|
||||||
|
.helpToolTip { display: inline-block; padding: .1em .5em;
|
||||||
|
background: #DDD; border-radius: .2em; transition: background .4s, color .4s; }
|
||||||
|
.helpToolTip:before { content: "?"; }
|
||||||
|
.helpToolTip:hover { background: #C0CA33; color: #FFF; }
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Edit line
|
||||||
|
*/
|
||||||
|
|
||||||
|
p.editLine { animation: fade-in-and-vanish 2.4s; position: fixed; left: 0; top: 0;
|
||||||
|
display: block; width: 100%;
|
||||||
|
margin: 0; text-align: center; font-weight: bold; opacity: 0;
|
||||||
|
box-sizing: border-box; box-shadow: 0 1.5px 2px rgba(0,0,0,.06),0 1.5px 1.5px rgba(0,0,0,.06); z-index: 0; }
|
||||||
|
p.editLine.massiveEditLine { animation: fade-in-and-vanish-massive 2.4s; }
|
||||||
|
|
||||||
|
p.changesStored { background: #7CB342; color: #FFF; }
|
||||||
|
p.changesDeleted { background: #E53935; color: #FFF; }
|
||||||
|
p.changesAborted { background: #C62828; color: #FFF; }
|
||||||
|
|
||||||
|
|
||||||
|
/****************************
|
||||||
|
* Main Structuring Elements
|
||||||
|
*/
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Main Header
|
||||||
|
* Displays current position and offers access
|
||||||
|
*/
|
||||||
|
|
||||||
|
#mainHeader { display: table; width: 100%; border-bottom: 1px solid #D6D6D6; }
|
||||||
|
#mainHeader > * { display: table-cell; padding: .5rem; color: #666; vertical-align: middle; }
|
||||||
|
#mainHeader h1 { color: #333; }
|
||||||
|
|
||||||
|
#mainHeader > *:last-child { text-align: right; }
|
||||||
|
#mainHeader > *:last-child > * { display: inline-block; margin: 0 .5em; padding: .5rem 1rem;
|
||||||
|
background: #1976D2; color: #FFF; border-radius: .2em; transition: background .4s; }
|
||||||
|
|
||||||
|
#mainHeader #toggleNavigation { width: 3em; text-align: center; }
|
||||||
|
#mainHeader #toggleNavigation:before { content:'\2630'; }
|
||||||
|
|
||||||
|
#mainHeader #uploadFile:before { content:'\2630'; }
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Main wrapper
|
||||||
|
* Contains the navigation and the main part.
|
||||||
|
*/
|
||||||
|
|
||||||
|
div#mainWrapper { display: block; }
|
||||||
|
|
||||||
|
@media screen and (min-width: 75em) {
|
||||||
|
div#mainWrapper { display: table; width: 100%; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Main navigation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#mainNav { display: block; border: 1px solid #D6D6D6; border-width: 0; }
|
||||||
|
#mainNav > * { display: block; border-bottom: 1px solid #D6D6D6; }
|
||||||
|
|
||||||
|
#mainNav > * > span { display: block; padding: .7em 1em; font-weight: bold; transition: background .2s; }
|
||||||
|
#mainNav > * > span:hover { background: #F2F2F2; }
|
||||||
|
#mainNav > * > div { position: relative; }
|
||||||
|
|
||||||
|
#mainNav > * > div > *:first-child { position: relative; display: block; padding: .7em 1em; font-weight: bold; transition: background .2s; }
|
||||||
|
#mainNav > * > div > *:first-child:hover { background: #F2F2F2; }
|
||||||
|
|
||||||
|
#mainNav > * > div > *:not(:first-child) { position: absolute; right: 1em; top: 50%; transform: translate(0, -50%);
|
||||||
|
display: block; padding: .1em .5em; background: #EEE; color: #888; border-radius: 100%;
|
||||||
|
transition: background .4s, color .4s; }
|
||||||
|
#mainNav > * > div > *:not(:first-child):hover { background: #AAA; color: #000; }
|
||||||
|
|
||||||
|
@media screen and (min-width: 75em) {
|
||||||
|
#mainNav { display: table-cell; width: 250px; border-width: 0 1px 0 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Main part of the page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
main { padding: .5em 5em 3em 3em; }
|
BIN
edit/themes/default/fonts/SourceSansPro-Regular.ttf
Normal file
BIN
edit/themes/default/fonts/SourceSansPro-Regular.ttf
Normal file
Binary file not shown.
BIN
edit/themes/default/fonts/SourceSansPro-Regular.woff2
Normal file
BIN
edit/themes/default/fonts/SourceSansPro-Regular.woff2
Normal file
Binary file not shown.
37
edit/themes/imports.css
Normal file
37
edit/themes/imports.css
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* ========
|
||||||
|
| Notifications
|
||||||
|
|= ======== */
|
||||||
|
|
||||||
|
p.notifLine { animation: fade-in-and-vanish 2.4s; position: fixed; left: 0; top: 0; display: block; width: 100%;
|
||||||
|
margin: 0; background: rgba(0,0,0,.8); color: #FFF; text-align: center; font-weight: bold; opacity: 0;
|
||||||
|
box-sizing: border-box; box-shadow: 0 1.5px 2px rgba(0,0,0,.06),0 1.5px 1.5px rgba(0,0,0,.06); z-index: 0; }
|
||||||
|
|
||||||
|
/* ========
|
||||||
|
| New tooltip
|
||||||
|
|= ======== */
|
||||||
|
|
||||||
|
.newToolTip { position: fixed; display: none !important; min-width: 300px !important; max-width: 600px;
|
||||||
|
background: #FFF !important; text-align: left; font-size: .95rem;
|
||||||
|
border-radius: .2em; box-shadow: 1px 1px 4px #646464; z-index: 3000; white-space: initial !important; }
|
||||||
|
#newToolTipMain:before { content: attr(data-title); display: block; padding: .5em 1em;
|
||||||
|
background: #37474F; color: #FFF; }
|
||||||
|
#newToolTipMain > * { padding: .5rem 1rem !important; }
|
||||||
|
#newToolTipMain > table td { padding: .5rem 1em; vertical-align: top; }
|
||||||
|
#newToolTipMain.visible { display: block !important; }
|
||||||
|
|
||||||
|
#newToolTipMain img { max-width: 200px; max-height: 300px; }
|
||||||
|
|
||||||
|
/* ========
|
||||||
|
| Animations
|
||||||
|
|= ======== */
|
||||||
|
|
||||||
|
@keyframes fade-in-and-vanish {
|
||||||
|
0% { opacity: 0; z-index: 1000; }
|
||||||
|
5% { opacity: .4; }
|
||||||
|
15% { opacity: 1; padding: .8em; }
|
||||||
|
75% { opacity: 1; padding: .8em; }
|
||||||
|
85% { opacity: .4; transform: translateY(0px);}
|
||||||
|
99% { opacity: 0; transform: translateY(-30px);}
|
||||||
|
100% { opacity: 0; z-index: 0; }
|
||||||
|
}
|
||||||
|
|
34
edit/translations/en.php
Normal file
34
edit/translations/en.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?PHP
|
||||||
|
|
||||||
|
$translations = [
|
||||||
|
"submit" => "Submit",
|
||||||
|
"options" => "Options",
|
||||||
|
"start" => "Start",
|
||||||
|
"fileUpload" => "File Uploads",
|
||||||
|
"users" => "Users",
|
||||||
|
"pages" => "Pages",
|
||||||
|
"edit" => "Edit",
|
||||||
|
"administration" => "Administration",
|
||||||
|
|
||||||
|
"usersOverview" => "Overview of All Users",
|
||||||
|
"listUsers" => "List users",
|
||||||
|
"addUser" => "Add user",
|
||||||
|
"userAdded" => "Successfully added new user: ",
|
||||||
|
"username" => "Username",
|
||||||
|
"helpUsername" => "<p>Username of the user. The user logs in with his or her username.</p><p><b>Required.</b></p>",
|
||||||
|
"email" => "Email Address",
|
||||||
|
"helpEmail" => "<p>Email address of the user. This needs to be saved, to be able to contact the user later on.</p><p><b>Required.</b></p>",
|
||||||
|
"password" => "Password",
|
||||||
|
"passwordVerify" => "Password (Verification)",
|
||||||
|
"helpPassword" => "<p>Password of the user. The password needs to be at least 8 characters long.</p><p><b>Required.</b></p>",
|
||||||
|
"realName" => "Real name",
|
||||||
|
"helpRealName" => "<p>Full, real name of the user. The full name is displayed next to entries by that person.</p><p><b>Required.</b></p>",
|
||||||
|
"helpUsers" => "<p>On this page, you can see access an overview of all users. You can also add new users here.</p>",
|
||||||
|
"helpStart" => "<p>This is the start page of md:cms.</p>",
|
||||||
|
|
||||||
|
"requiredValueMissing" => "A required value is missing.",
|
||||||
|
"passwordsDoNotMatch" => "The passwords do not match.",
|
||||||
|
"passwordTooShort" => "The passwords is too short.",
|
||||||
|
];
|
||||||
|
|
||||||
|
?>
|
192
edit/users.php
Normal file
192
edit/users.php
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Start page of the backend.
|
||||||
|
* Offers a dashboard.
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Require files and ensure environment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once __DIR__ . "/inc/functions.php";
|
||||||
|
|
||||||
|
ensureEnvironment(); // Ensure existence of system files.
|
||||||
|
$translations = loadLanguage(); // Load translations.
|
||||||
|
ensureBackendEnv(); // Ensure session is started etc.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Check for vars.
|
||||||
|
loadHttpToGlobals(["task", "username", "realName", "email", "password", "passwordVerify"]);
|
||||||
|
|
||||||
|
if (!isset($users)) {
|
||||||
|
$users = json_decode(file_get_contents(__DIR__ . "/../data/users.json"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($task) and $task == "insert") { // Adding new users.
|
||||||
|
|
||||||
|
$redirectURL = "./users.php?" . write_common_vars(["username", "realName", "email"]) . "#addUser";
|
||||||
|
|
||||||
|
// Ensure all required values are set.
|
||||||
|
foreach (["username", "realName", "email", "password", "passwordVerify"] as $var) {
|
||||||
|
if (isset($$var)) continue;
|
||||||
|
|
||||||
|
$_SESSION["editHistory"] = ["changesAborted", $translations['requiredValueMissing']];
|
||||||
|
header('Location: ' . $redirectURL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the passwords match.
|
||||||
|
if ($password != $passwordVerify) {
|
||||||
|
$_SESSION["editHistory"] = ["changesAborted", $translations['passwordsDoNotMatch']];
|
||||||
|
header('Location: ' . $redirectURL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if passwords is too short.
|
||||||
|
if (strlen($password) < 8) {
|
||||||
|
$_SESSION["editHistory"] = ["changesAborted", $translations['passwordTooShort']];
|
||||||
|
header('Location: ' . $redirectURL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options for hashing.
|
||||||
|
$newUser = array(
|
||||||
|
|
||||||
|
"username" => $username,
|
||||||
|
"realName" => $realName,
|
||||||
|
"email" => $email,
|
||||||
|
"password" => password_hash("$password", PASSWORD_BCRYPT, ['cost' => 12]),
|
||||||
|
"created" => date("Y-m-d H:i:s"),
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
$users[$username] = $newUser;
|
||||||
|
|
||||||
|
// Store the users array.
|
||||||
|
file_put_contents(__DIR__ . "/../data/users.json", json_encode($users), LOCK_EX);
|
||||||
|
|
||||||
|
$_SESSION["editHistory"] = ["changesStored", $translations['userAdded'] . " $username"];
|
||||||
|
header('Location: ./users.php#addUser');
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output
|
||||||
|
*/
|
||||||
|
|
||||||
|
echo printBackendHead($translations['start']);
|
||||||
|
echo printBackendHeader($translations['usersOverview'], $translations['helpUsers']);
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<div id="mainWrapper">
|
||||||
|
';
|
||||||
|
|
||||||
|
echo printBackendNav($translations);
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<main>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="#listUsers" class="buttonLike">' . $translations['listUsers'] . '</a>
|
||||||
|
<a href="#addUser" class="buttonLike">' . $translations['addUser'] . '</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<section id="listUsers">
|
||||||
|
|
||||||
|
<form action="" method="POST">
|
||||||
|
<table class="obj_cha_maintable">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label for="username">' . $translations['username'] . '</label></th>
|
||||||
|
<td><input type="text" id="username" name="username" placeholder="' . $translations['username']. '"';
|
||||||
|
if (isset($username)) echo " value='$username'";
|
||||||
|
echo ' required /></td>
|
||||||
|
<td>' . generateHelpToolTip("helpUsername", $translations['username'], $translations['helpUsername']) . '</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label for="realName">' . $translations['realName'] . '</label></th>
|
||||||
|
<td><input type="text" id="realName" name="realName" placeholder="' . $translations['realName']. '"';
|
||||||
|
if (isset($realName)) echo " value='$realName'";
|
||||||
|
echo ' required /></td>
|
||||||
|
<td>' . generateHelpToolTip("helpRealName", $translations['realName'], $translations['helpRealName']) . '</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label for="userEmail">' . $translations['email'] . '</label></th>
|
||||||
|
<td><input type="email" id="userEmail" name="email" placeholder="' . $translations['email']. '"';
|
||||||
|
if (isset($email)) echo " value='$email'";
|
||||||
|
echo ' required /></td>
|
||||||
|
<td>' . generateHelpToolTip("helpEmail", $translations['email'], $translations['helpEmail']) . '</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label for="password">' . $translations['password'] . '</label></th>
|
||||||
|
<td><input type="password" id="password" name="password" placeholder="' . $translations['password']. '" required /></td>
|
||||||
|
<td>' . generateHelpToolTip("helpPassword", $translations['password'], $translations['helpPassword']) . '</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th><label for="passwordVerify">' . $translations['passwordVerify'] . '</label></th>
|
||||||
|
<td><input type="password" id="passwordVerify" name="passwordVerify" placeholder="' . $translations['passwordVerify']. '" required /></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<td><button type="submit">' . $translations['submit'] . '</button></td>
|
||||||
|
<td>
|
||||||
|
' . printHiddenInputs(['task' => 'insert'], 16) . '
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
|
||||||
|
<table class="overviewtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>' . $translations['username'] . '</th>
|
||||||
|
<th>' . $translations['realName'] . '</th>
|
||||||
|
<th>' . $translations['email'] . '</th>
|
||||||
|
<th>' . $translations['options'] . '</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
';
|
||||||
|
|
||||||
|
foreach ($users as $user) {
|
||||||
|
|
||||||
|
echo '
|
||||||
|
<tr>
|
||||||
|
<td><a href="user.php?t=' . urlencode($user['username']) . '">' . $user['username'] . '</a></td>
|
||||||
|
<td>' . $user['realName'] . '</td>
|
||||||
|
<td>' . $user['email'] . '</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
echo '
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
echo printBackendEnd();
|
||||||
|
|
||||||
|
?>
|
221
inc/functions.php
Normal file
221
inc/functions.php
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
<?PHP
|
||||||
|
/**
|
||||||
|
* Main file for functions.
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @author Joshua Ramon Enslin <joshua@jrenslin.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function ensureDir checks if a directory exists, and creates it if it does not yet.
|
||||||
|
*
|
||||||
|
* @param string $filepath File path.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ensureDir(string $filepath) {
|
||||||
|
if (!is_dir($filepath)) mkdir($filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function ensureJson checks that a JSON file exists. If not, it creates an empty one at the specified location.
|
||||||
|
*
|
||||||
|
* @param string $filepath File path to the JSON file.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ensureJson(string $filepath) {
|
||||||
|
|
||||||
|
if (!file_exists($filepath) or filesize($filepath) < 2) {
|
||||||
|
file_put_contents($filepath, "[]");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function for ensuring the existence of an appropriate environment.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function ensureEnvironment() {
|
||||||
|
|
||||||
|
// Enable error reporting
|
||||||
|
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set("display_errors", 1);
|
||||||
|
|
||||||
|
// Ensure existence of directories
|
||||||
|
|
||||||
|
foreach ([__DIR__ . "/../data", __DIR__ . "/../data/static", __DIR__ . "/../data/caches", __DIR__ . "/../js"] as $folder) {
|
||||||
|
ensureDir($folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure existence of settings files
|
||||||
|
|
||||||
|
foreach ([
|
||||||
|
__DIR__ . "/../data/settings.json",
|
||||||
|
__DIR__ . "/../data/caches/pages.json",
|
||||||
|
__DIR__ . "/../data/users.json",
|
||||||
|
] as $jsonFile) {
|
||||||
|
ensureJson($jsonFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function scanDirConts is a wrapper around scandir(), which removes [".", ".."].
|
||||||
|
*
|
||||||
|
* @param string $folder Folder to scan.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
function scanDirConts(string $folder):array {
|
||||||
|
return array_values(array_diff(scandir($folder), [".", "..", ".git"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function printHiddenInputs takes an array, in which each entry stands for a new hidden input field.
|
||||||
|
* The key to the entry stands for the name attribute, the value for the value attribute.
|
||||||
|
*
|
||||||
|
* @param array $array Associative array containing all the variable names and corresponding values to print
|
||||||
|
* @param int $indent Integer describing how far each line in the returned string should be indented.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function printHiddenInputs(array $array, int $indent = 0):string {
|
||||||
|
|
||||||
|
$output = '';
|
||||||
|
$indentString = PHP_EOL;
|
||||||
|
|
||||||
|
for ($i = 0; $i < $indent; $i++) $indentString .= ' ';
|
||||||
|
foreach ($array as $name => $value) {
|
||||||
|
$output .= $indentString . '<input type="hidden" name="'.$name.'" value="'.$value.'" />';
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function printHiddenInputsFromGlobalsSimple takes an array, in which each entry stands for a new hidden input field.
|
||||||
|
* The value stands for the name attribute of the input field and the key in $GLOBALS.
|
||||||
|
*
|
||||||
|
* @param array $array Input array.
|
||||||
|
* @param int $indent Number of spaces for indenting the output input fields in HTML. Optional.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function printHiddenInputsFromGlobalsSimple(array $array, int $indent = 0):string {
|
||||||
|
|
||||||
|
$output = '';
|
||||||
|
$indentString = PHP_EOL;
|
||||||
|
|
||||||
|
for ($i = 0; $i < $indent; $i++) $indentString .= ' ';
|
||||||
|
foreach ($array as $value) {
|
||||||
|
if (!isset($GLOBALS[$value])) continue;
|
||||||
|
$output .= $indentString . '<input type="hidden" name="'.$value.'" value="'.$GLOBALS[$value].'" />';
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function write_get_vars prints checks for GET variables specified in the input array and returns them as a single string.
|
||||||
|
* Useful for avoiding long blocks of links working to write meaningful links.
|
||||||
|
*
|
||||||
|
* @param string[] $input Input array: both simple and associative arrays are accepted.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function write_get_vars(array $input):string {
|
||||||
|
|
||||||
|
// Check if keys have been specified in the array (in Python terms, if it is a dict or a list).
|
||||||
|
// If keys are not specified, write new working variable $vars with keys equaling the value.
|
||||||
|
// $str is the string that will eventually be returned.
|
||||||
|
$vars = array();
|
||||||
|
$str = '';
|
||||||
|
|
||||||
|
if (isset($input[0])) {
|
||||||
|
foreach ($input as $value) $vars[$value] = $value;
|
||||||
|
}
|
||||||
|
else $vars = $input;
|
||||||
|
|
||||||
|
// For each of the variables specified in $vars, check if a corresponding GET variable is set.
|
||||||
|
// If so, add that to the return string.
|
||||||
|
// The key is used in place of the original GET variable's name ($value),
|
||||||
|
// because some pages may have the same GET variables carry different names.
|
||||||
|
foreach ($vars as $key => $value) {
|
||||||
|
if (isset($GLOBALS['_GET'][$value])) $str .= '&'.$key.'='.$GLOBALS['_GET'][$value];
|
||||||
|
}
|
||||||
|
return ($str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function write_post_vars prints checks for POST variables specified in the input
|
||||||
|
* array and returns them as a single string.
|
||||||
|
* Useful for avoiding long blocks of links working to write meaningful links.
|
||||||
|
*
|
||||||
|
* @param string[] $input Input array: both simple and associative arrays are accepted.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function write_post_vars(array $input):string {
|
||||||
|
|
||||||
|
// Check if keys have been specified in the array (in Python terms, if it is a dict or a list).
|
||||||
|
// If keys are not specified, write new working variable $vars with keys equaling the value.
|
||||||
|
// $str is the string that will eventually be returned.
|
||||||
|
$vars = array();
|
||||||
|
$str = '';
|
||||||
|
|
||||||
|
if (isset($input[0])) {
|
||||||
|
foreach ($input as $value) $vars[$value] = $value;
|
||||||
|
}
|
||||||
|
else $vars = $input;
|
||||||
|
|
||||||
|
// For each of the variables specified in $vars, check if a corresponding GET variable is set.
|
||||||
|
// If so, add that to the return string. The key is used in place of the original POST variable's name ($value),
|
||||||
|
// because some pages may have the same GET variables carry different names.
|
||||||
|
foreach ($vars as $key => $value) {
|
||||||
|
if (isset($GLOBALS['_POST'][$value])) $str .= '&'.$key.'='.$GLOBALS['_POST'][$value];
|
||||||
|
}
|
||||||
|
return ($str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function write_common_vars prints checks for global variables specified in the input
|
||||||
|
* array and returns them as a single string.
|
||||||
|
* Useful for avoiding long blocks of links working to write meaningful links.
|
||||||
|
*
|
||||||
|
* @param string[] $input Input array: both simple and associative arrays are accepted.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function write_common_vars(array $input):string {
|
||||||
|
|
||||||
|
// Check if keys have been specified in the array (in Python terms, if it is a dict or a list).
|
||||||
|
// If keys are not specified, write new working variable $vars with keys equaling the value.
|
||||||
|
// $str is the string that will eventually be returned.
|
||||||
|
$vars = array();
|
||||||
|
$str = '';
|
||||||
|
|
||||||
|
if (isset($input[0])) {
|
||||||
|
foreach ($input as $value) $vars[$value] = $value;
|
||||||
|
}
|
||||||
|
else $vars = $input;
|
||||||
|
|
||||||
|
// For each of the variables specified in $vars, check if a corresponding GET variable is set.
|
||||||
|
// If so, add that to the return string. The key is used in place of the original GET variable's name ($value),
|
||||||
|
// because some pages may have the same GET variables carry different names.
|
||||||
|
foreach ($vars as $key => $value) {
|
||||||
|
if (isset($GLOBALS[$value])) $str .= '&'.$key.'='.$GLOBALS[$value];
|
||||||
|
}
|
||||||
|
return ($str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
Reference in New Issue
Block a user