Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*
*********************************************************************/

declare(strict_types=1);

namespace ILIAS\Init\ErrorHandling\Http;

use ilUtil;
use Throwable;
use DateTimeZone;
use PDOException;
use ilGlobalTemplate;
use DateTimeImmutable;
use ILIAS\DI\Container;
use ILIAS\HTTP\StatusCode;
use ILIAS\HTTP\Response\ResponseHeader;

class ErrorPageResponder
{
public function handleError(
Container $dic,
int $http_status_code,
?string $error_lang_key = null,
?string $link_url = null,
?string $link_lang_key = null
): void {
$dic->globalScreen()->tool()->context()->claim()->external();

$dic->language()->loadLanguageModule('error');

$local_tpl = new ilGlobalTemplate('tpl.error.html', true, true);

if ($error_lang_key !== null) {
$local_tpl->setCurrentBlock('msg_box');
$local_tpl->setVariable(
'MESSAGE_BOX',
$dic->ui()->renderer()->render(
$dic->ui()->factory()->messageBox()->failure(
$dic->language()->txt($error_lang_key)
)
)
);
$local_tpl->parseCurrentBlock();
}

if ($link_url !== null && $link_lang_key !== null) {
$local_tpl->setCurrentBlock('ErrorLink');
$local_tpl->setVariable('TXT_LINK', $dic->language()->txt($link_lang_key));
$local_tpl->setVariable('LINK', ilUtil::secureUrl($link_url));
$local_tpl->parseCurrentBlock();
}

$dic->http()->saveResponse(
$dic->http()
->response()
->withStatus($http_status_code)
->withHeader(ResponseHeader::CONTENT_TYPE, 'text/html')
);

$dic->ui()->mainTemplate()->setContent($local_tpl->get());
$dic->ui()->mainTemplate()->printToStdout();

$dic->http()->close();
}

public function sendFallbackResponse(Throwable $e): never
{
if (defined('DEVMODE') && DEVMODE) {
throw $e;
}

if (!headers_sent()) {
http_response_code(StatusCode::HTTP_INTERNAL_SERVER_ERROR);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question is: Can we always assume that should result in an HTTP 502 status code?

header('Content-Type: text/plain; charset=UTF-8');
}

$incident_id = session_id() . '_' . (new \Random\Randomizer())->getInt(1, 9999);
$timestamp = (new DateTimeImmutable())
->setTimezone(new DateTimeZone('UTC'))
->format('Y-m-d\TH:i:s\Z');

echo "Internal Server Error\n";
echo "Incident: $incident_id\n";
echo "Timestamp: $timestamp\n";

if ($e instanceof PDOException) {
echo "Message: A database error occurred. Please contact the system administrator with the incident id.\n";
} else {
echo "Message: {$e->getMessage()}\n";
}

error_log(sprintf(
"[%s] INCIDENT %s — Uncaught %s: %s in %s:%d\nStack trace:\n%s\n",
$timestamp,
$incident_id,
get_class($e),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString()
));

exit(1);
}
}
72 changes: 13 additions & 59 deletions components/ILIAS/Init/resources/error.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,73 +20,27 @@

namespace ILIAS\Init;

use ilSession;
use Throwable;
use ILIAS\HTTP\StatusCode;
use ILIAS\Init\ErrorHandling\Http\ErrorPageResponder;

try {
require_once '../vendor/composer/vendor/autoload.php';

require_once __DIR__ . '/../artifacts/bootstrap_default.php';
entry_point('ILIAS Legacy Initialisation Adapter');

$DIC->globalScreen()->tool()->context()->claim()->external();

$lng->loadLanguageModule('error');
$txt = $lng->txt('error_back_to_repository');

$local_tpl = new \ilGlobalTemplate('tpl.error.html', true, true);
$local_tpl->setCurrentBlock('ErrorLink');
$local_tpl->setVariable('TXT_LINK', $txt);
$local_tpl->setVariable('LINK', \ilUtil::secureUrl(ILIAS_HTTP_PATH . '/ilias.php?baseClass=ilRepositoryGUI'));
$local_tpl->parseCurrentBlock();

\ilSession::clear('referer');
\ilSession::clear('message');

$DIC->http()->saveResponse(
$DIC->http()
->response()
->withStatus(500)
->withHeader(\ILIAS\HTTP\Response\ResponseHeader::CONTENT_TYPE, 'text/html')
(new ErrorPageResponder())->handleError(
$DIC,
StatusCode::HTTP_INTERNAL_SERVER_ERROR,
null,
ILIAS_HTTP_PATH . '/ilias.php?baseClass=ilRepositoryGUI',
'error_back_to_repository'
);

$tpl->setContent($local_tpl->get());
$tpl->printToStdout();

$DIC->http()->close();
} catch (\Throwable $e) {
if (\defined('DEVMODE') && DEVMODE) {
throw $e;
}

/*
* Since we are already in the `error.php` and an unexpected error occurred, we should not rely on the $DIC or any
* other components here and use "Vanilla PHP" instead to handle the error.
*/
if (!headers_sent()) {
http_response_code(500);
header('Content-Type: text/plain; charset=UTF-8');
}

$incident_id = session_id() . '_' . (new \Random\Randomizer())->getInt(1, 9999);
$timestamp = (new \DateTimeImmutable())->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d\TH:i:s\Z');

echo "Internal Server Error\n";
echo "Incident: $incident_id\n";
echo "Timestamp: $timestamp\n";
if ($e instanceof \PDOException) {
echo "Message: A database error occurred. Please contact the system administrator with the incident id.\n";
} else {
echo "Message: {$e->getMessage()}\n";
}

error_log(\sprintf(
"[%s] INCIDENT %s — Uncaught %s: %s in %s:%d\nStack trace:\n%s\n",
$timestamp,
$incident_id,
\get_class($e),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString()
));

exit(1);
} catch (Throwable $e) {
(new ErrorPageResponder())->sendFallbackResponse($e);
}
17 changes: 11 additions & 6 deletions components/ILIAS/Init/resources/ilias.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

declare(strict_types=1);

use ILIAS\HTTP\StatusCode;
use ILIAS\Init\ErrorHandling\Http\ErrorPageResponder;

if (!file_exists('../ilias.ini.php')) {
die('The ILIAS setup is not completed. Please run the setup routine.');
}
Expand All @@ -36,14 +39,16 @@
throw $e;
}

if (!str_contains($e->getMessage(), 'not given a baseclass') &&
!str_contains($e->getMessage(), 'not a baseclass')) {
throw new RuntimeException(sprintf('ilCtrl could not dispatch request: %s', $e->getMessage()), 0, $e);
}

$DIC->logger()->root()->error($e->getMessage());
$DIC->logger()->root()->error($e->getTraceAsString());
$DIC->ctrl()->redirectToURL(ilUtil::_getHttpPath());

(new ErrorPageResponder())->handleError(
$DIC,
StatusCode::HTTP_NOT_FOUND,
'http_404_not_found',
ILIAS_HTTP_PATH . '/ilias.php?baseClass=ilRepositoryGUI',
'error_back_to_repository'
);
}

$DIC['ilBench']->save();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

declare(strict_types=1);

use ILIAS\UICore\Exceptions\ilCtrlPathException;

/**
* Class ilCtrlExistingPath
*
Expand Down Expand Up @@ -56,7 +58,7 @@ protected function ensureValidCidPath(): void
$child_class = $this->structure->getClassNameByCid($child_cid);
$allowed_children = $this->structure->getChildrenByCid($parent_cid) ?? [];
if (null === $child_class || !in_array($child_class, $allowed_children, true)) {
throw new RuntimeException('ilCtrl: invalid ' . ilCtrlInterface::PARAM_CID_PATH . ' parameter requested.');
throw new ilCtrlPathException('ilCtrl: invalid ' . ilCtrlInterface::PARAM_CID_PATH . ' parameter requested.');
}
}
}
Expand Down
31 changes: 31 additions & 0 deletions components/ILIAS/UICore/exceptions/ilCtrlPathException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

/**
* This file is part of ILIAS, a powerful learning management system
* published by ILIAS open source e-Learning e.V.
*
* ILIAS is licensed with the GPL-3.0,
* see https://www.gnu.org/licenses/gpl-3.0.en.html
* You should have received a copy of said license along with the
* source code, too.
*
* If this is not the case or you just want to try ILIAS, you'll find
* us at:
* https://www.ilias.de
* https://github.com/ILIAS-eLearning
*
*********************************************************************/

declare(strict_types=1);

namespace ILIAS\UICore\Exceptions;

use ilCtrlException;

/**
* Thrown when ilCtrl encounters an invalid or unresolvable CID path during
* request dispatching
*/
class ilCtrlPathException extends ilCtrlException
{
}
2 changes: 2 additions & 0 deletions lang/ilias_de.lang
Original file line number Diff line number Diff line change
Expand Up @@ -9217,6 +9217,8 @@ ecs#:#ecs_wiki_export_enabled#:#Freigeben
ecs#:#ecs_wiki_export_obj_settings#:#Einstellungen für Wikifreigaben
error#:#error_back_to_repository#:#Zurück zum Magazin
error#:#error_sry_error#:#Es ist leider ein Fehler aufgetreten.
error#:#http_404_not_found#:#Die angeforderte Seite wurde nicht gefunden.
error#:#http_500_internal_server_error#:#Es ist ein interner Serverfehler aufgetreten.
etal#:#appointments#:#Sitzungen
etal#:#cal_type_tals#:#Gespräche
etal#:#change_date_of_series#:#Gesprächsserie anpassen
Expand Down
2 changes: 2 additions & 0 deletions lang/ilias_en.lang
Original file line number Diff line number Diff line change
Expand Up @@ -9190,6 +9190,8 @@ ecs#:#ecs_wiki_export_enabled#:#Release this Wiki
ecs#:#ecs_wiki_export_obj_settings#:#Wiki Release Settings
error#:#error_back_to_repository#:#Back to Repository
error#:#error_sry_error#:#Sorry, an error occurred.
error#:#http_404_not_found#:#The requested page could not be found.
error#:#http_500_internal_server_error#:#An internal server error occurred.
etal#:#appointments#:#Appointments
etal#:#cal_type_tals#:#Talks
etal#:#change_date_of_series#:#Change date of talk series
Expand Down
3 changes: 3 additions & 0 deletions templates/default/tpl.error.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<!-- BEGIN msg_box -->
{MESSAGE_BOX}
<!-- END msg_box -->
<!-- BEGIN ErrorLink -->
<!-- additional link e.g. by WebAccessChecker -->
<p>
Expand Down