Joshua Ramon Enslin
02df42a62d
Closes: #1 phpcs-errors:226 phpunit-status:successful phpstan-errors:207
383 lines
11 KiB
PHP
383 lines
11 KiB
PHP
<?PHP
|
|
/**
|
|
* Generic collection of functions used in CSVXML.
|
|
*
|
|
* @file
|
|
*
|
|
* @author
|
|
*/
|
|
declare(strict_types = 1);
|
|
|
|
// Set autoloader
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', "1");
|
|
spl_autoload_register("mdCsvxmlAutoloader");
|
|
set_exception_handler("mdExceptionHandler");
|
|
set_error_handler("mdErrorHandler", E_ALL);
|
|
|
|
require_once __DIR__ . '/../vendor/autoload.php';
|
|
|
|
/**
|
|
* Autoloader for museum-digital.org.
|
|
*
|
|
* @param string $className Name of the class to load.
|
|
*
|
|
* @return void
|
|
*/
|
|
function mdCsvxmlAutoloader(string $className):void {
|
|
|
|
$classDirs = [
|
|
__DIR__ . "/../classes/MDTlLoader",
|
|
__DIR__ . "/../classes/MD_STD",
|
|
__DIR__ . "/../classes/MDAllowedValueSets/src",
|
|
__DIR__ . "/../classes/MDExportFormats/src",
|
|
__DIR__ . "/../classes/MDErrorReporter",
|
|
__DIR__ . "/../classes/MDMailer/src",
|
|
__DIR__ . "/../conf",
|
|
__DIR__ . "/../classes/MDErrorReporter/exceptions/generic",
|
|
__DIR__ . "/../classes/MDErrorReporter/exceptions/page",
|
|
__DIR__ . "/../classes/MDErrorReporter/exceptions/updates",
|
|
];
|
|
|
|
foreach ($classDirs as $classDir) {
|
|
|
|
if (file_exists("$classDir/$className.php")) {
|
|
include "$classDir/$className.php";
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Own error handler: Set to enforce exit on any error.
|
|
*
|
|
* @param integer $errno Error number.
|
|
* @param string $string Error message.
|
|
* @param string $file File in which the error occured.
|
|
* @param integer $line Line number.
|
|
*
|
|
* @return void
|
|
*/
|
|
function mdErrorHandler(int $errno, string $string, string $file, int $line):void {
|
|
|
|
$getStr = [];
|
|
foreach ($_GET as $key => $value) {
|
|
if (is_array($value)) continue;
|
|
$getStr[] = $key . "=" . $value;
|
|
}
|
|
|
|
$userMsg = "";
|
|
if (isset($_SESSION['anmnam'])) $userMsg .= " User: " . $_SESSION["anmnam"];
|
|
if (isset($_SESSION['username'])) $userMsg .= " (" . $_SESSION["username"] . ")";
|
|
if ($userMsg) $userMsg = " |--" . $userMsg;
|
|
|
|
$errorMsg = "";
|
|
|
|
if (!empty($_SERVER) && !empty($_SERVER["HTTP_HOST"])) {
|
|
|
|
$errorPage = $_SERVER['PHP_SELF'] . "?" . implode("&", $getStr);
|
|
$errorPageFull = "https://" . $_SERVER["HTTP_HOST"] . $errorPage;
|
|
|
|
$errorMsg = "*$errno (<a href='https://www.google.de/search?q=php+" . str_replace(" ", "+", $string) . "'>$string</a>) at $file: line_ $line _";
|
|
$errorMsg .= $userMsg;
|
|
$errorMsg .= " |-- Error generating page: <a href='$errorPageFull'>$errorPage</a>";
|
|
$errorMsg .= " |-- Used RAM / Peak RAM / Allowed: " . MD_STD::human_filesize(memory_get_usage()) . " / " . MD_STD::human_filesize(memory_get_peak_usage()) . " / " . ini_get("memory_limit");
|
|
|
|
$errorMsg = str_replace(PHP_EOL, " ", $errorMsg);
|
|
|
|
error_log($errorMsg);
|
|
|
|
}
|
|
|
|
if ($errno == E_ERROR) exit;
|
|
|
|
}
|
|
|
|
/**
|
|
* Exception handler to also be able to handle custom exceptions.
|
|
*
|
|
* @param Throwable $exception Exception.
|
|
*
|
|
* @return void
|
|
*/
|
|
function mdExceptionHandler(Throwable $exception):void {
|
|
|
|
$formatErrorPage = function(string $errorMsg = "", string $versionName = "") :string {
|
|
|
|
if (PHP_SAPI === "cli") {
|
|
return $errorMsg . PHP_EOL;
|
|
}
|
|
|
|
$output = '<!DOCTYPE html>
|
|
<html id="errorPage">
|
|
<head>
|
|
<script src="js/loadCaches.min.js?2020013517" type="text/javascript" async></script>
|
|
<script src="js/applyCaches.min.js?2020013517" type="text/javascript"></script>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
|
|
<link rel="manifest" href="./manifest.webmanifest" />
|
|
<link rel="shortcut icon" sizes="16x16 32x32" href="./db_images_gestaltung/mdlogo-32px.png" />
|
|
<link rel="shortcut icon" sizes="64x64" href="./db_images_gestaltung/mdlogo-64px.png" />
|
|
<link rel="stylesheet" type="text/css" href="css/main.min.css?2020013517" />
|
|
<link rel="stylesheet" type="text/css" href="css/errorPage.css" />';
|
|
if (!empty($_SESSION['dark-theme'])) $output .= '
|
|
<link rel="stylesheet" type="text/css" href="css/dark-theme.css?2020013517" />';
|
|
$output .= '
|
|
<title>Error :: ';
|
|
$output .= $versionName;
|
|
$output .= '</title>
|
|
</head>
|
|
<body>
|
|
|
|
<main>
|
|
<img src="./db_images_gestaltung/mdlogo-256px.png" />
|
|
<p>' . $errorMsg . '</p>
|
|
|
|
<nav>
|
|
<a href="index.php?t=home">Home</a>
|
|
<a href="index.php?t=museum">Museum</a>
|
|
<a href="index.php?t=collection">Collection</a>
|
|
<a href="index.php?t=exhibitions_overview">Exhibition</a>
|
|
<a href="index.php?t=events">Event</a>
|
|
<a href="index.php?t=topics">Topics</a>
|
|
<a href="index.php?t=listen&sv=+&done=yes">Objects</a>
|
|
</nav>
|
|
<nav>
|
|
<a href="index.php?t=kontakt">Contact</a>
|
|
<a href="index.php?t=impressum">Impressum</a>
|
|
<a href="index.php?t=privacy">Privacy Policy</a>
|
|
</nav>
|
|
</main>
|
|
|
|
</body>
|
|
</html>';
|
|
|
|
return $output;
|
|
};
|
|
|
|
$errorReporter = new MDErrorReporter("md:csvxml", "bugs-csvxml@museum-digital.de");
|
|
$errorCategory = MDErrorReporter::categorizeError($exception);
|
|
|
|
http_response_code(404);
|
|
|
|
switch ($errorCategory) {
|
|
case MDErrorReporter::MD_ERROR_KNOWN:
|
|
|
|
if (isset($_GET["output"]) and $_GET['output'] === "json") {
|
|
header('Content-type: application/json');
|
|
$output = [
|
|
"status" => "Error",
|
|
"msg" => $exception->getMessage(),
|
|
];
|
|
echo MD_STD::json_encode($output);
|
|
exit;
|
|
}
|
|
|
|
echo $formatErrorPage($exception->getMessage(), "");
|
|
exit;
|
|
|
|
default:
|
|
$errorReporter->sendErrorReport($exception, "joshua@museum-digital.de");
|
|
echo $formatErrorPage("Uncaught exception ...<br />Our team has been notified and will get to fixing this error shortly.", "");
|
|
exit;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Function for generating the HTML head.
|
|
*
|
|
* @param string $injected Additional code to inject into the head, e.g. a
|
|
* reference to JS files.
|
|
*
|
|
* @return string
|
|
*/
|
|
function printHTMLHead(string $injected = ""):string {
|
|
|
|
$output = '<!DOCTYPE HTML>
|
|
<html lang="en">
|
|
<head>
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
|
|
|
|
<meta name="theme-color" content="#FFF" />
|
|
<link rel="stylesheet" type="text/css" href="assets/css/csvxml.min.css" />
|
|
<link rel="shortcut icon" sizes="128x128" href="assets/img/mdlogo-csvxml.svg" />
|
|
<script src="assets/js/csvxml-overview.min.js" type="text/javascript" defer></script>
|
|
|
|
<title>CSVXML :: museum-digital</title>
|
|
|
|
<meta name="keywords" content="Imports, museum-digital" />
|
|
';
|
|
|
|
$output .= $injected;
|
|
|
|
$output .= '
|
|
|
|
</head>
|
|
<body>
|
|
|
|
<h1>
|
|
<img src="assets/img/mdlogo-csvxml.svg" />
|
|
<span>museum-digital:csvxml</span>
|
|
</h1>
|
|
';
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function generateHelpTooltip returns a tooltip for hovering over using the common settings.
|
|
*
|
|
* @param string $identifier ID attribute of the tooltip.
|
|
* @param string $title Title of the tooltip.
|
|
* @param string $explica More in-depth explanation: body of the tooltip.
|
|
* @param boolean $setParagraph If set to true (default), the content of the tooltip will be put into a <p> element. Optional.
|
|
*
|
|
* @return array
|
|
*/
|
|
function generateHelpTooltip(string $identifier, string $title, string $explica, bool $setParagraph = true):array {
|
|
|
|
$outputTag = '<a class="newToolTipTag icons iconsHelp" data-for="' . $identifier . '" title="Help"></a>';
|
|
$output = '<span class="newToolTip" id="tooltip_' . $identifier . '" data-title="' . $title . '">';
|
|
if ($setParagraph) $output .= '<p class="toolTipCont">';
|
|
$output .= $explica;
|
|
if ($setParagraph) $output .= '</p>';
|
|
$output .= '</span>';
|
|
|
|
return [$output, $outputTag];
|
|
|
|
}
|
|
|
|
/**
|
|
* Outputs a DOMDocument with correct header and then aborts.
|
|
* Used mainly for debugging.
|
|
*
|
|
* @param DOMDocument $xmlDoc XML object.
|
|
*
|
|
* @return string
|
|
*/
|
|
function printDOMDocToXML(DOMDocument $xmlDoc):string {
|
|
|
|
return '<?xml version="1.0" encoding="UTF-8"?>' . $xmlDoc->saveXML($xmlDoc->documentElement);
|
|
|
|
}
|
|
|
|
/**
|
|
* Function for creating a DOMElement with a text node inside.
|
|
*
|
|
* @param DOMDocument $xmlDoc XML document.
|
|
* @param string $tag Tag.
|
|
* @param string $content Text content.
|
|
*
|
|
* @return DOMElement
|
|
*/
|
|
function createTextDomElement(DOMDocument $xmlDoc, string $tag, string $content):DOMElement {
|
|
|
|
try {
|
|
$element = $xmlDoc->createElement($tag);
|
|
}
|
|
catch (DOMException $e) {
|
|
echo "Error at " . __FILE__ . ", line #" . __LINE__ . PHP_EOL . "<br/>";
|
|
echo "Cannot create DOM element for $tag / $content";
|
|
exit;
|
|
}
|
|
|
|
$element->appendChild($xmlDoc->createTextNode($content));
|
|
|
|
return $element;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function for creating a DOMDocument record channel.
|
|
*
|
|
* @return array
|
|
*/
|
|
function getBlankRecordChannel():array {
|
|
|
|
$xmlDoc = new DOMDocument("1.0", "UTF-8");
|
|
$xmlMainElem = $xmlDoc->createElement("record");
|
|
$record_node = $xmlDoc->appendChild($xmlMainElem); //add RSS element to XML node
|
|
|
|
return [$xmlDoc, $record_node];
|
|
|
|
}
|
|
|
|
/**
|
|
* Function for removing a directory with all its contents.
|
|
*
|
|
* @param string $dir File path of the directory to remove.
|
|
*
|
|
* @return void
|
|
*/
|
|
function rrmdir(string $dir):void {
|
|
if (is_dir($dir)) {
|
|
$objects = scandir($dir);
|
|
foreach ($objects as $object) {
|
|
if ($object != "." && $object != "..") {
|
|
if (filetype($dir . "/" . $object) == "dir") rrmdir($dir . "/" . $object); else unlink($dir . "/" . $object);
|
|
}
|
|
}
|
|
reset($objects);
|
|
rmdir($dir);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Function for checking if two arrays have identical values / contents.
|
|
*
|
|
* @param array $arrayA First array to compare.
|
|
* @param array $arrayB Second array to compare.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function identical_values(array $arrayA, array $arrayB):bool {
|
|
sort($arrayA);
|
|
sort($arrayB);
|
|
return $arrayA == $arrayB;
|
|
|
|
}
|
|
|
|
/**
|
|
* Function for retrieving the anti-csrf token or generating it if need be.
|
|
*
|
|
* @return string
|
|
*/
|
|
function getAntiCsrfToken():string {
|
|
|
|
if (empty($_SESSION['csrf-token'])) {
|
|
$_SESSION['csrf-token'] = bin2hex(random_bytes(32));
|
|
}
|
|
|
|
return $_SESSION['csrf-token'];
|
|
|
|
}
|
|
|
|
/**
|
|
* Function for validating anti-csrf tokens. Each anti-csrf token is removed
|
|
* after use.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function validateAntiCsrfToken():bool {
|
|
|
|
$validity = false;
|
|
if (!empty($_POST['csrf-token'])
|
|
&& !empty($_SESSION['csrf-token'])
|
|
&& hash_equals($_SESSION['csrf-token'], $_POST['csrf-token']) === true
|
|
) {
|
|
$validity = true;
|
|
}
|
|
$_SESSION['csrf-token'] = null; unset($_SESSION['csrf-token']);
|
|
|
|
return $validity;
|
|
|
|
}
|
|
|