Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
+220
View File
@@ -0,0 +1,220 @@
<?php
namespace Xentral\Core\ErrorHandler;
use Throwable;
final class ErrorHandler
{
/** @var array Error types that halts execution */
const THROWABLE_ERROR_TYPES = [
E_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_error.php */
E_PARSE, /** @see http://www.bbminfo.com/Tutor/php_error_e_parse.php */
E_CORE_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_core_error.php */
E_COMPILE_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_compile_error.php */
E_USER_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_user_error.php */
E_RECOVERABLE_ERROR, /** @see http://www.bbminfo.com/Tutor/php_error_e_recoverable_error.php */
];
/** @var string[] */
private const DELETE_FILE_FOLDERS = [
'www/pages',
'www/lib/versandarten',
'www/lib/zahlungsweisen',
];
/**
* @return void
*/
public function register()
{
register_shutdown_function([$this, 'onShutdown']);
// Use own error output function
ini_set('display_errors', true);
set_error_handler([$this, 'handleError']);
set_exception_handler([$this, 'handleException']);
}
/**
* @return void
*/
public function onShutdown()
{
$error = error_get_last();
if ($error === null) {
return;
}
if ($this->isErrorTypeHaltingExecution((int)$error['type'])) {
// Try to free memory; in case of exhausted memory limit
@gc_enable();
@gc_collect_cycles();
$this->handleError((int)$error['type'], $error['message'], $error['file'], $error['line']);
}
}
/**
* @param int $code
* @param string $message
* @param string $file
* @param int $line
*
* @return bool
*/
public function handleError($code, $message, $file, $line)
{
if ($this->isErrorTypeHaltingExecution($code)) {
$type = (string)$this->translateErrorType($code);
$exception = new PhpErrorException(sprintf('%s: %s', $type, $message), (int)$code);
$exception->setFile($file);
$exception->setLine($line);
$this->handleException($exception);
die(); // Necessary for E_RECOVERABLE_ERROR
}
return true; // Don't execute PHP internal error handler
}
/**
* @param Throwable $exception
*/
public function handleException($exception)
{
$title = null;
if ($this->isIoncubeError($exception)) {
$title = $this->handleIoncubeError($exception);
}
$data = new ErrorPageData($exception, $title);
$renderer = new ErrorPageRenderer($data);
header('HTTP/1.1 500 Internal Server Error');
header('Content-Type: text/html; charset=utf-8');
echo $renderer->renderErrorPage();
}
/**
* @see https://secure.php.net/manual/en/errorfunc.constants.php
*
* @param int $type
*
* @return string|null
*/
private function translateErrorType($type)
{
$errors = [
E_ERROR => 'Fatal Error',
E_PARSE => 'Parse Error',
E_CORE_ERROR => 'Core Error',
E_COMPILE_ERROR => 'Compile Error',
E_USER_ERROR => 'Fatal User Error',
E_RECOVERABLE_ERROR => 'Recoverable Error',
];
return $errors[(int)$type];
}
/**
* @param int $type
*
* @return bool
*/
private function isErrorTypeHaltingExecution($type)
{
return in_array((int)$type, self::THROWABLE_ERROR_TYPES, true);
}
/**
* @param Throwable $exception
*
* @return bool
*/
private function isIoncubeError($exception)
{
if ((int)$exception->getCode() !== E_CORE_ERROR) {
return false;
}
if (strpos($exception->getMessage(), 'requires a license file.') !== false) {
return true;
}
if (strpos($exception->getMessage(), 'ionCube Encoder') !== false) {
return true;
}
return false;
}
/**
* @param Throwable $exception
*
* @return string|null
*/
private function handleIoncubeError($exception)
{
$file = $this->extractFileFromIoncubeError($exception);
if (empty($file)) {
return null;
}
if (!$this->isDeleteableFile($file)) {
return null;
}
@unlink($file);
if(is_file($file)) {
return sprintf('Es wurde eine alte Systemdatei gefunden die nicht manuell gelöscht werden konnte.
Bitte löschen Sie die Datei %s', $file);
}
return 'Es wurde eine alte Systemdatei gefunden und automatisch gelöscht.
Bitte führen Sie das Update nochmal durch dann sollte diese Meldung nicht mehr erscheinen.';
}
/**
* @param string $file
*
* @return bool
*/
private function isDeleteableFile(string $file)
{
if (!is_file($file)) {
return false;
}
$dir = dirname($file);
foreach (self::DELETE_FILE_FOLDERS as $folder) {
if (substr($dir, -strlen($folder)) === $folder) {
return true;
}
}
return false;
}
/**
* @example "<br>The encoded file <b>/var/www/xentral/www/pages/adresse.php</b> requires a license file.<br>"
* "The license file <b>/var/www/xentral/key.php</b> is corrupt."
*
* @param Throwable $exception
*
* @return string|null
*/
private function extractFileFromIoncubeError($exception)
{
$message = strip_tags($exception->getMessage());
$theFilePos = stripos($message, 'The File ');
if ($theFilePos === false) {
$theFilePos = strpos($message, 'The encoded file');
if ($theFilePos === false) {
return null;
}
$theFilePos += 16;
} else {
$theFilePos += 9;
}
$file = trim(substr($message, $theFilePos));
$file = explode(' ', $file);
return reset($file);
}
}
+431
View File
@@ -0,0 +1,431 @@
<?php
namespace Xentral\Core\ErrorHandler;
use JsonSerializable;
use Throwable;
final class ErrorPageData implements JsonSerializable
{
/** @var Throwable $exception */
private $exception;
/** @var string $title */
private $title;
/**
* @param Throwable $exception
* @param string|null $title
*/
public function __construct($exception, $title = null)
{
$this->exception = $exception;
$this->title = !empty($title) ? (string)$title : 'Xentral: Es ist ein unerwarteter Fehler aufgetreten!';
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @return array
*/
public function getData()
{
return [
'information' => $this->prepareSystemInformation(),
'exception' => $this->prepareExceptionStack($this->exception),
];
}
/**
* @return Throwable
*/
public function getException()
{
return $this->exception;
}
/**
* @return array
*/
public function jsonSerialize()
{
return $this->getData();
}
/**
* @param Throwable $exception
*
* @return array
*/
private function prepareExceptionStack($exception)
{
$stack = [];
$traces = $exception->getTrace();
foreach ($traces as $index => $trace) {
$stack[$index] = $trace;
unset($stack[$index]['args']);
}
return [
'message' => $exception->getMessage(),
'class' => get_class($exception),
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $stack,
'previous' => $exception->getPrevious() !== null ? $this->prepareExceptionStack($exception->getPrevious()) : null,
];
}
/**
* @return array
*/
private function prepareSystemInformation()
{
return [
'php' => [
'general' => $this->getPhpGeneralInformations(),
'settings' => $this->getPhpImportantSettings(),
'extensions' => $this->getPhpExtensions(),
],
'software' => $this->getSoftwareInformations(),
'env' => $this->getEnvironmentInformation(),
'server' => $this->getServerInformation(),
'request' => $this->getRequestInformation(),
];
}
/**
* @return array
*/
private function getEnvironmentInformation()
{
$scriptFile = isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : __FILE__;
try {
$fileOwner = !function_exists('posix_getpwuid')?null:@posix_getpwuid(@fileowner($scriptFile));
} catch (Throwable $e) {
$fileOwner = null;
}
try {
$fileGroup = !function_exists('posix_getgrgid')?null:@posix_getgrgid(@filegroup($scriptFile));
}
catch (Throwable $e) {
$fileGroup = null;
}
return [
'username' => !empty(@getenv('USER')) ? @getenv('USER') : @getenv('USERNAME'),
'home_dir' => @getenv('HOME'),
'document_root' => isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : null,
'script_filename' => isset($_SERVER['SCRIPT_FILENAME']) ? $_SERVER['SCRIPT_FILENAME'] : null,
'script_owner' => isset($fileOwner['name']) ? $fileOwner['name'] : null,
'script_group' => isset($fileGroup['name']) ? $fileGroup['name'] : null,
];
}
/**
* @return array
*/
private function getServerInformation()
{
return [
'software' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : null,
'signature' => isset($_SERVER['SERVER_SIGNATURE']) ? strip_tags(trim($_SERVER['SERVER_SIGNATURE'])) : null,
'addr' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : null,
'name' => isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : null,
'port' => isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : null,
];
}
/**
* @return array
*/
private function getRequestInformation()
{
return [
'is_https' => $this->isHttpsRequest(),
'is_ajax' => $this->isAjaxRequest(),
'time' => isset($_SERVER['REQUEST_TIME']) ? $_SERVER['REQUEST_TIME'] : null,
'method' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : null,
'scheme' => isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : null,
'uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null,
'referer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null,
'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null,
];
}
/**
* @return array
*/
private function getPhpGeneralInformations()
{
return [
'version' => PHP_VERSION,
'version_id' => PHP_VERSION_ID,
'version_major' => PHP_MAJOR_VERSION,
'version_minor' => PHP_MINOR_VERSION,
'version_release' => PHP_RELEASE_VERSION,
'server_api' => PHP_SAPI,
'binary_dir' => PHP_BINDIR,
'php_ini_dir' => php_ini_loaded_file(),
];
}
/**
* @return array
*/
private function getSoftwareInformations()
{
$version = '';
$version_revision = '';
$versionFile = dirname(dirname(dirname(__DIR__))) . '/version.php';
if (is_file($versionFile)) {
include $versionFile;
}
/** @var string $version Defined in version.php */
/** @var string $version_revision Defined in version.php */
return [
'xentral_version' => !empty($version) ? $version : null,
'xentral_revision' => !empty($version_revision) ? $version_revision : null,
'fpdf_version' => $this->getFpdfVersion(),
];
}
/**
* @return array
*/
private function getPhpImportantSettings()
{
return [
[
'setting' => 'max_execution_time',
'raw_value' => $this->getPhpMaxExecutionTimeValue(),
'int_value' => (int)$this->getPhpMaxExecutionTimeValue(),
],
[
'setting' => 'max_input_time',
'raw_value' => @ini_get('max_input_time'),
'int_value' => (int)@ini_get('max_input_time'),
],
[
'setting' => 'post_max_size',
'raw_value' => $this->getPostMaxSizeValue(),
'int_value' => (int)$this->convertPhpValueToBytes($this->getPostMaxSizeValue()),
],
[
'setting' => 'upload_max_filesize',
'raw_value' => @ini_get('upload_max_filesize'),
'int_value' => (int)$this->convertPhpValueToBytes(@ini_get('upload_max_filesize')),
],
[
'setting' => 'memory_limit',
'raw_value' => @ini_get('memory_limit'),
'int_value' => (int)$this->convertPhpValueToBytes(@ini_get('memory_limit')),
],
];
}
private function getPhpExtensions()
{
$extensionsLoaded = $this->getPhpExtensionsLoaded();
$extensionsDefined = $this->getPhpExtensionsDefined();
$extensionsOther = array_diff_key($extensionsLoaded, $extensionsDefined);
ksort($extensionsOther);
return [
'defined' => $this->getPhpExtensionsDefined(),
'other' => $extensionsOther,
];
}
private function getPhpExtensionsLoaded()
{
$extensions = get_loaded_extensions();
return array_combine($extensions, array_fill(0, count($extensions), true));
}
/**
* @return array
*/
private function getPhpExtensionsDefined()
{
$extensionsResult = [];
$extensionsCheck = $this->getPhpExtensionsDefinedCallbacks();
foreach ($extensionsCheck as $extension => $callback) {
$checkResult = $callback();
$extensionsResult[$extension] = $checkResult;
}
return $extensionsResult;
}
/**
* @return array
*/
private function getPhpExtensionsDefinedCallbacks()
{
return [
'mysqli' => function () {
return function_exists('mysqli_connect');
},
'mysqlnd' => function () {
return extension_loaded('mysqlnd');
},
'PDO' => function () {
return class_exists('\PDO');
},
'curl' => function () {
return function_exists('curl_init');
},
'xml' => function () {
return function_exists('simplexml_load_string');
},
'stream_socket_enable_crypto' => function () {
return function_exists('stream_socket_enable_crypto');
},
'fsocket' => function () {
return function_exists('fsockopen');
},
'openssl' => function () {
return function_exists('openssl_error_string');
},
'mbstring' => function () {
return function_exists('mb_encode_numericentity');
},
'json' => function () {
return function_exists('json_encode');
},
'iconv' => function () {
return function_exists('iconv');
},
'soap' => function () {
return class_exists('\SoapClient');
},
'imap' => function () {
return function_exists('imap_open');
},
'zip' => function () {
return class_exists('\ZipArchive');
},
'gd' => function () {
return function_exists('imagejpeg');
},
'ldap' => function () {
return function_exists('ldap_connect');
},
'ioncube' => function () {
if (!function_exists('ioncube_loader_version')) {
return false;
}
$ioncubeMajorVersion = (int)@ioncube_loader_version();
return $ioncubeMajorVersion >= 5;
},
];
}
/**
* @return bool
*/
private function isHttpsRequest()
{
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
return true;
}
if (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] === 'on') {
return true;
}
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
return true;
}
return false;
}
/**
* @return bool
*/
private function isAjaxRequest()
{
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}
/**
* @return string
*/
private function getPhpMaxExecutionTimeValue()
{
$maxExecutionTime = @ini_get('fastcgi_read_timeout'); // Nginx
if (empty($maxExecutionTime)) {
$maxExecutionTime = @ini_get('max_execution_time');
}
return $maxExecutionTime;
}
/**
* @return string
*/
private function getPostMaxSizeValue()
{
$postMaxSize = @ini_get('client_max_body_size');
if (empty($postMaxSize)) {
$postMaxSize = @ini_get('post_max_size');
}
return $postMaxSize;
}
/**
* @return int
*/
private function getFpdfVersion()
{
if (defined('USEFPDF3') && (bool)USEFPDF3 === true) {
return 3;
}
if (defined('USEFPDF2') && (bool)USEFPDF2 === true) {
return 2;
}
return 1;
}
/**
* Converts PHP size value to byte value; e.g. 64K => 65536 Bytes
*
* @param string $phpValue
*
* @return int
*/
private function convertPhpValueToBytes($phpValue)
{
$lastChar = strtoupper(substr(trim($phpValue), -1));
switch ($lastChar) {
case 'G':
$bytes = (int)$phpValue * 1024 * 1024 * 1024;
break;
case 'M':
$bytes = (int)$phpValue * 1024 * 1024;
break;
case 'K':
$bytes = (int)$phpValue * 1024;
break;
default:
$bytes = (int)$phpValue;
}
return $bytes;
}
}
@@ -0,0 +1,311 @@
<?php
namespace Xentral\Core\ErrorHandler;
final class ErrorPageRenderer
{
/** @var array REQUIRED_PHP_EXTENSIONS */
const REQUIRED_PHP_EXTENSIONS = [
'PDO', 'mysqli', 'mysqlnd', 'mbstring', 'curl', 'xml', 'zip', 'stream_socket_enable_crypto'
];
/** @var ErrorPageData $data */
private $data;
/**
* @param ErrorPageData $data
*/
public function __construct(ErrorPageData $data)
{
$this->data = $data;
}
/**
* @return string
*/
public function renderErrorPage()
{
$data = $this->data->getData();
$title = $this->data->getTitle();
$content = $this->renderPageHeader();
$content .= '<table>';
$content .= '<tr><td colspan="2" id="headline">';
$content .= '<h1>' . htmlspecialchars($title, ENT_QUOTES) . '</h1>';
$content .= '<h2>' . htmlspecialchars($data['exception']['message'], ENT_QUOTES) . '</h2>';
$content .= '</td></tr>';
$content .= '<tr>';
$content .= '<td width="20%" id="side">' . $this->renderInformationData($data['information']) . '</td>';
$content .= '<td width="80%" id="main">' . $this->renderExceptionData($data['exception']) . '</td>';
$content .= '</tr></table>';
$content .= $this->renderPageFooter();
return $content;
}
/**
* @return string
*/
private function renderPageHeader()
{
return <<<HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Unerwarteter Fehler</title>
<style type="text/css">
html { padding: 0; margin: 0; }
body { font-family: BlinkMacSystemFont, -apple-system, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, Helvetica, Arial, sans-serif; font-size: 12px; line-height: 1.6em; color: #48494B; background-color: #EEE; padding: 0; margin: 0; }
h1, h2, h3, h4, h5, h6 { padding: 0; margin: 0.5em 0 0.5em 0; font-weight: bold; }
p { padding: 0; margin: 0 0 .25em 0; }
a, a:link, a:visited, a:hover, a:active { text-decoration: none; }
#headline { padding: 24px 12px 18px 12px; background-color: #42B8C5; }
#headline h1 { color: #F5F5F5; font-size: 2rem; margin: 1rem 0; }
#headline h2 { color: #9CD6DB; font-size: 1.1rem; font-weight: normal; margin: 1rem 0; }
table { width: 100%; border-collapse: separate; border-spacing: 0; }
table td, table th { text-align: left; padding: 10px 0 10px 0; vertical-align: baseline; }
table th.head { padding: 5px 0 10px 0; background-color: #FFF; vertical-align: baseline; border-bottom: 2px solid #DBDBDB; }
table th.head h3 { margin: 3px 0; }
table td.trace { background-color: #F5F5F5; vertical-align: baseline; }
table.exception { margin-bottom: 20px; border-top: 2px solid #DBDBDB; }
table.exception td { border-bottom: 1px solid #DBDBDB; }
td.stacktrace { padding-top: 0; padding-bottom: 0; background-color: #FFF; }
td.stacktrace table { border-spacing: 0; }
table.exception a:link code, table.exception a:visited code { color: #42B8C5; }
table.exception a:hover code, table.exception a:active code { color: #2F9099; }
td.stacktrace tr:last-child td { border: none; }
#main { background-color: #FFF; padding: 2rem; }
#side { min-width: 240px; padding: 5px 15px; background-color: #E9ECEF; }
#side h1, #side h2, #side h3, #side h4, #side h5, #side h6 { color: #7A7A7A; font-weight: normal; text-transform: uppercase; margin: 1em 0 0.5em 0; }
.float-right { float: right; }
.separator { color: #999; }
.classname { color: #42B8C5; }
.namespace { }
.method { }
.number { display: inline-block; width: 20px; padding: 1px 6px; margin-right: 10px; text-align: center; background-color: #DBDBDB; border-radius: 5px; }
.errorclass { font-weight: bold; }
.errorfile { margin-left: 42px; }
code { font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace, serif; font-size: 12px; font-weight: normal; color: #42B8C5; padding: 3px 4px 1px 4px; background-color: #E9ECEF; }
code.success { color: #48494B; background-color: #9FF781; }
code.warning { color: #48494B; background-color: #F4FA58; }
code.error { color: #48494B; background-color: #FA5858; }
span.success { background-color: #9FF781; padding: 0 1px; }
span.warning { background-color: #F4FA58; padding: 0 1px; }
span.error { background-color: #FA5858; padding: 0 1px; }
</style>
</head>
<body>
HTML;
}
/**
* @return string
*/
private function renderPageFooter()
{
return '</body></html>';
}
/**
* @param array $exception
*
* @return string
*/
private function renderExceptionData($exception)
{
$content = '';
$content .= '<h3>' . $this->renderExceptionHeadline($exception['class']) . '</h3>';
$content .= '<table class="exception">';
$content .= '<tr><th class="head">';
$content .= '<h2>' . htmlspecialchars($exception['message'], ENT_QUOTES) . '</h2>';
$content .= "<div><a href='editor://open?file={$exception['file']}&line={$exception['line']}'>";
$content .= "<code>{$exception['file']}:{$exception['line']}</code>";
$content .= '</div>';
$content .= '</th></tr>';
if (!empty($exception['trace'])) {
$content .= '<tr><td class="stacktrace">';
$content .= $this->renderStackTrace($exception['trace']);
$content .= '</td></tr>';
}
$content .= '</table>';
// Render previous exceptions at the end
if ($exception['previous'] !== null) {
$content .= $this->renderExceptionData($exception['previous']);
}
return $content;
}
/**
* @param string $className Full-qualified class name
*
* @return string
*/
private function renderExceptionHeadline($className)
{
$classNameParts = explode('\\', $className);
$partsSize = count($classNameParts) - 1;
$headline = '';
foreach ($classNameParts as $index => $part) {
if ($index === $partsSize) {
$headline .= "<span class='classname'>{$part}</span>";
} else {
$headline .= "<span class='namespace'>{$part}</span>";
$headline .= " <small class='separator'>\</small> ";
}
}
return $headline;
}
/**
* @param $stackTrace
*
* @return string
*/
private function renderStackTrace($stackTrace)
{
$traceSize = count($stackTrace);
$content = '<table class="stacktrace">';
foreach ($stackTrace as $index => $trace) {
// @todo Einkommentieren wenn ErrorHandler erprobt und stabil
//if (isset($trace['class']) && $trace['class'] === ErrorHandler::class) {
// continue;
//}
$number = $traceSize - $index;
$editorLink = 'editor://open?file=' . urlencode($trace['file']) . '&line=' . urlencode($trace['line']);
$content .= '<tr>';
$content .= '<td>';
$content .= '<div class="errorclass">';
$content .= "<span class='number'>{$number}</span>";
$content .= "<span>{$trace['class']}</span>";
$content .= "<span class='method'><span>&rarr;</span>{$trace['function']}()</span>";
$content .= '</div>';
if (!empty($trace['file'])) {
$content .= "<div class='errorfile'><a href='{$editorLink}'>";
$content .= "<code>{$trace['file']}:{$trace['line']}</code>";
$content .= '</a></div>';
}
$content .= '</td>';
$content .= '</tr>';
}
$content .= '</table>';
return $content;
}
/**
* @param array $data
*
* @return string
*/
private function renderInformationData($data)
{
$content = "<h3>Systeminformationen</h3>\n";
$software = $data['software'];
$content .= "<h4>Software</h4>\n";
$content .= '<p>Xentral-Revision: <code>';
$content .= !empty($software['xentral_revision']) ? $software['xentral_revision'] : '--';
$content .= "</code></p>\n";
$content .= '<p>Xentral-Version: <code>';
$content .= !empty($software['xentral_version']) ? $software['xentral_version'] : '--';
$content .= "</code>\n";
$content .= '<p>FPDF-Version: <code>';
$content .= !empty($software['fpdf_version']) ? $software['fpdf_version'] : '--';
$content .= "</code>\n";
$general = $data['php']['general'];
$content .= "<h4>PHP</h4>\n";
$version = "{$general['version_major']}.{$general['version_minor']}.{$general['version_release']}";
$content .= "<p>Version: <code>{$version}</code> ({$general['version']})</p>\n";
$content .= "<p>Server-API: <code>{$general['server_api']}</code></p>\n";
$content .= "<p>Binary-Pfad: <code>{$general['binary_dir']}</code></p>\n";
$content .= "<p>php.ini: <code>{$general['php_ini_dir']}</code></p>\n";
$settings = $data['php']['settings'];
$content .= "<h4>PHP-Einstellungen:</h4>\n";
foreach ($settings as $setting) {
switch ($setting['setting']) {
case 'max_execution_time':
$cssClass = $setting['int_value'] <= 0 || $setting['int_value'] >= 30 ? '' : 'warning';
break;
case 'max_input_time':
$cssClass = $setting['int_value'] <= 0 || $setting['int_value'] >= 30 ? '' : 'warning';
break;
case 'post_max_size':
$cssClass = $setting['int_value'] >= 8 * 1024 * 1024 ? '' : 'warning';
break;
case 'upload_max_filesize':
$cssClass = $setting['int_value'] >= 8 * 1024 * 1024 ? '' : 'warning';
break;
case 'memory_limit':
$cssClass = $setting['int_value'] >= 256 * 1024 * 1024 ? '' : 'warning';
break;
default:
$cssClass = '';
break;
}
$content .= sprintf(
'<p><code class="%s">%s = %s</code></p>' . "\n",
$cssClass, $setting['setting'], $setting['raw_value']
);
}
$content .= "<h4>PHP-Erweiterungen</h4>\n";
$defined = $data['php']['extensions']['defined'];
$content .= '<h5>Benötigt</h5><p>';
foreach ($defined as $extension => $isAvailable) {
$failedCssClass = in_array($extension, self::REQUIRED_PHP_EXTENSIONS, true) ? 'error' : 'warning';
$cssClass = $isAvailable === true ? '' : $failedCssClass;
$content .= sprintf('<code class="%s">%s</code>', $cssClass, $extension) . ', ';
}
$content = substr_replace($content, '', -2);
$content .= "</p>\n";
/*$other = $data['php']['extensions']['other'];
$content .= "<h5>Sonstige</h5><p>";
foreach ($other as $extension => $available) {
$content .= sprintf('<code>%s</code>', $extension) . ', ';
}
$content = substr_replace($content, '', -2);
$content .= "</p>\n";*/
$env = $data['env'];
$content .= "<h4>Umgebung</h4>\n";
$content .= "<p>Username: <code>{$env['username']}</code></p>\n";
$content .= "<p>Home-Directory: <code>{$env['home_dir']}</code></p>\n";
$content .= "<p>Document-Root: <code>{$env['document_root']}</code></p>\n";
$content .= "<p>Script-Filename: <code>{$env['script_filename']}</code></p>\n";
if ($env['script_owner'] !== null) {
$content .= "<p>Script-Owner/-Group: <code>{$env['script_owner']}:{$env['script_group']}</code></p>\n";
}
$server = $data['server'];
$content .= "<h4>Webserver</h4>\n";
$content .= '<p>Software: <code>' . (!empty($server['software']) ? $server['software'] : '--') . "</code></p>\n";
$content .= '<p>Signatur: <code>' . (!empty($server['signature']) ? $server['signature'] : '--') . "</code></p>\n";
$content .= "<p>Host: <code>{$server['name']}</code> (<code>{$server['addr']}:{$server['port']}</code>)</p>\n";
$request = $data['request'];
$content .= "<h4>Request</h4>\n";
$content .= "<p>Schema: <code>{$request['scheme']}</code></p>\n";
$content .= "<p>Method/Uri: <code>{$request['method']} " . htmlspecialchars($request['uri']) . "</code></p>\n";
$content .= '<p>Referer: <code>' . (!empty($request['referer']) ? htmlspecialchars($request['referer']) : '--') . "</code></p>\n";
$content .= '<p>UserAgent: <code>' . (!empty($request['user_agent']) ? $request['user_agent'] : '--') . "</code></p>\n";
$content .= '<p>AJAX-Request: <code>' . ($request['is_ajax'] === true ? 'true' : 'false') . "</code></p>\n";
$content .= '<p>HTTPS-Request: <code>' . ($request['is_https'] === true ? 'true' : 'false') . "</code></p>\n";
$content .= "<p>Timestamp: <code>{$request['time']}</code></p>\n";
return $content;
}
}
@@ -0,0 +1,28 @@
<?php
namespace Xentral\Core\ErrorHandler;
use RuntimeException;
class PhpErrorException extends RuntimeException
{
/**
* @param string $file
*
* @return void
*/
public function setFile($file)
{
$this->file = $file;
}
/**
* @param int $line
*
* @return void
*/
public function setLine($line)
{
$this->line = $line;
}
}