Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Error;
|
||||
|
||||
class ApiError
|
||||
{
|
||||
/*
|
||||
* Auth-Fehler
|
||||
*/
|
||||
const CODE_UNAUTHORIZED = 7411; // (Erster) Besuch ohne Authorization-Header
|
||||
const CODE_DIGEST_HEADER_INCOMPLETE = 7412; // Digest-Header unvollständig; benötigte Teile fehlen
|
||||
const CODE_API_ACCOUNT_MISSING = 7413; // Es ist überhaupt kein API-Account angelegt oder aktiv
|
||||
const CODE_API_ACCOUNT_INVALID = 7414; // Verwendeter API-Account ist nicht (mehr?) gültig oder aktiv
|
||||
//const CODE_DIGEST_VALIDDATION_FAILED = 7415; // Prüfung ist fehlgeschlagen // Momentan nicht möglich da es mehrere Accounts mit dem gleichen Benutzernamen geben kann.
|
||||
const CODE_DIGEST_NONCE_INVALID = 7416; // Serverkey ist nicht vorhanden, oder schon länger abgelaufen (daher gelöscht)
|
||||
const CODE_DIGEST_NONCE_EXPIRED = 7417; // Serverkey ist abgelaufen
|
||||
const CODE_AUTH_USERNAME_EMPTY = 7418; // Benutzername wurde leer übergeben
|
||||
const CODE_AUTH_TYPE_NOT_ALLOWED = 7419; // Authorization-Header vorhanden, aber kein Digest
|
||||
const CODE_DIGEST_NC_NOT_MATCHING = 7420; // NonceCount (nc) passt nicht
|
||||
const CODE_API_ACCOUNT_PERMISSION_MISSING = 7421; // Api account has not the correct permissions
|
||||
|
||||
/*
|
||||
* Routing-Fehler
|
||||
*/
|
||||
const CODE_ROUTE_NOT_FOUND = 7431;
|
||||
const CODE_METHOD_NOT_ALLOWED = 7432;
|
||||
const CODE_API_METHOD_NOT_FOUND = 7433;
|
||||
|
||||
/*
|
||||
* Endpoint-Fehler
|
||||
*/
|
||||
const CODE_BAD_REQUEST = 7451; // API-Benutzer hat beim Request einen Fehler gemacht; Diesen Fehler nur verwenden
|
||||
// wenns nicht anders geht. Besser einen konkreteren Code verwenden bzw. anlegen. Benutzer kann mit diesem Fehler
|
||||
// nichts anfangen.
|
||||
|
||||
const CODE_RESOURCE_NOT_FOUND = 7452; // API-Resource wurde nicht gefunden; zb wenn gesuchte ID nicht existiert
|
||||
const CODE_VALIDATION_ERROR = 7453; // Fehler bei der Validierung von Eingabedaten (nur bei PUT oder POST)
|
||||
const CODE_INVALID_ARGUMENT = 7454; // Argument (z.B. Suchparameter) enthält ungültige Werte
|
||||
const CODE_MALFORMED_REQUEST_BODY = 7455; // JSON oder XML konnte nicht dekodiert werden
|
||||
const CODE_CONTENT_TYPE_NOT_SUPPORTED = 7456; // Request-Body wurde mit unbekanntem Content-Type abgeschickt
|
||||
|
||||
/*
|
||||
* Webserver falsch konfiguriert (Vermutlich Nginx oder FastCGI falsch konfiguriert)
|
||||
* @see https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
|
||||
*/
|
||||
const CODE_WEBSERVER_MISCONFIGURED = 7481; // Fehlkonfiguration im Webserver (nicht genauer beschrieben). Diesen
|
||||
// Fehler-Code nicht verwenden! Besser einen konkreteren Fehlercode verwenden bzw. hinzufügen.
|
||||
|
||||
const CODE_WEBSERVER_PATHINFO_INVALID = 7482; // $_SERVER['PATH_INFO'] ist nicht vorhanden oder leer, obwohl der
|
||||
// Request darauf hindeutet dass PATH_INFO gefüllt sein sollte.
|
||||
// Nginx bzw. FastCGI sehr wahrscheinlich falsch konfiguriert.
|
||||
|
||||
/*
|
||||
* Sonstige Fehler
|
||||
*/
|
||||
const CODE_UNEXPECTED_ERROR = 7499; // Schwerer Fehler; z.B. ungefangene Exception oder Fatal Error (unsere Schuld)
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Error;
|
||||
|
||||
use Exception;
|
||||
use PDOException;
|
||||
use Xentral\Core\LegacyConfig\Exception\LegacyConfigExceptionInterface;
|
||||
|
||||
/**
|
||||
* @see /www/api/index.php
|
||||
*/
|
||||
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 array $errorTypeTranslations */
|
||||
private $errorTypeTranslations = [
|
||||
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 void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
register_shutdown_function([$this, 'onShutdown']);
|
||||
|
||||
// Use own error output function
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_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)) {
|
||||
|
||||
$content = [
|
||||
'error' => [
|
||||
'code' => ApiError::CODE_UNEXPECTED_ERROR,
|
||||
'message' => 'Unexpected error',
|
||||
'http_code' => 500,
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->isDebugModeActive()) {
|
||||
$errorType = $this->translateErrorType($code);
|
||||
$content['debug'] = [
|
||||
'error' => [
|
||||
'message' => $errorType . ': ' . $message,
|
||||
'file' => $file,
|
||||
'line' => $line,
|
||||
'code' => $code,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode($content);
|
||||
exit; // Necessary for E_RECOVERABLE_ERROR
|
||||
}
|
||||
|
||||
return true; // Don't execute PHP internal error handler
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Exception $exception
|
||||
*/
|
||||
public function handleException($exception)
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
if ($exception instanceof PDOException) {
|
||||
if ($exception->getCode() === 'HY000') {
|
||||
// "HY000: General error: 1364 Field 'xxxxx' doesn't have a default value"
|
||||
if (strpos($exception->getMessage(), 'SQLSTATE[HY000]: General error: 1364') !== false) {
|
||||
$errors[] = str_replace('SQLSTATE[HY000]: General error: 1364 ', '', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
// 42S22: Column not found
|
||||
if ($exception->getCode() === '42S22') {
|
||||
$errors[] = str_replace('SQLSTATE[42S22]: Column not found: 1054 ', '', $exception->getMessage());
|
||||
}
|
||||
// 1049: Unknown database
|
||||
if ($exception->getCode() === 1049) {
|
||||
$errors[] = str_replace('SQLSTATE[HY000] [1049] ', 'DatabaseException: ', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if ($exception instanceof LegacyConfigExceptionInterface) {
|
||||
$errors[] = $exception->getMessage();
|
||||
}
|
||||
|
||||
$content = [
|
||||
'error' => [
|
||||
'code' => ApiError::CODE_UNEXPECTED_ERROR,
|
||||
'message' => 'Unexpected error',
|
||||
'http_code' => 500,
|
||||
'errors' => $errors,
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->isDebugModeActive()) {
|
||||
$content['debug'] = [
|
||||
'error' => [
|
||||
'message' => 'Unhandled exception: ' . $exception->getMessage(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'code' => $exception->getCode(),
|
||||
'trace' => $exception->getTrace(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode($content);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://secure.php.net/manual/en/errorfunc.constants.php
|
||||
*
|
||||
* @param int $type
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function translateErrorType($type)
|
||||
{
|
||||
$type = (int)$type;
|
||||
|
||||
if (!isset($this->errorTypeTranslations[$type])) {
|
||||
return 'Unknown Error';
|
||||
}
|
||||
|
||||
return $this->errorTypeTranslations[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isErrorTypeHaltingExecution($type)
|
||||
{
|
||||
return in_array((int)$type, self::THROWABLE_ERROR_TYPES, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isDebugModeActive()
|
||||
{
|
||||
return defined('DEBUG_MODE') && (int)DEBUG_MODE === 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user