User tests: Successful: Unsuccessful:
This fix is when a plugin or template developer would like to create a custom 404 error page by using different names than the default "404.php".
For example, without this fix, the below example works only if in the template "protostar-test" I have the file "error.php" only. But, it's not working if I rename the file to "another-error404-page.php".
public static function renderCustom404ErrorPage($error)
{
$expectedClass = PHP_MAJOR_VERSION >= 7 ? '\Throwable' : '\Exception';
$isException = $error instanceof $expectedClass;
// In PHP 5, the $error object should be an instance of \Exception; PHP 7 should be a Throwable implementation
if ($isException)
{
try
{
// Try to log the error, but don't let the logging cause a fatal error
try
{
\JLog::add(
sprintf(
'Uncaught %1$s of type %2$s thrown. Stack trace: %3$s',
$expectedClass,
get_class($error),
$error->getTraceAsString()
),
\JLog::CRITICAL,
'error'
);
}
catch (\Throwable $e)
{
// Logging failed, don't make a stink about it though
}
catch (\Exception $e)
{
// Logging failed, don't make a stink about it though
}
$app = \JFactory::getApplication();
// If site is offline and it's a 404 error, just go to index (to see offline message, instead of 404)
if ($error->getCode() == '404' && $app->get('offline') == 1)
{
$app->redirect('index.php');
}
$attributes = array(
'charset' => 'utf-8',
'lineend' => 'unix',
'tab' => "\t",
'language' => 'en-GB',
'direction' => 'ltr',
);
// If there is a \JLanguage instance in \JFactory then let's pull the language and direction from its metadata
if (\JFactory::$language)
{
$attributes['language'] = \JFactory::getLanguage()->getTag();
$attributes['direction'] = \JFactory::getLanguage()->isRtl() ? 'rtl' : 'ltr';
}
$document = \JDocument::getInstance('error', $attributes);
if (!$document)
{
// We're probably in an CLI environment
jexit($error->getMessage());
}
// Get the current template from the application
$template = 'protostar-test'; //$app->getTemplate();
$app->set('theme', 'protostar-test');
// Push the error object into the document
$document->setError($error);
if (ob_get_contents())
{
ob_end_clean();
}
$document->setTitle(\JText::_('ERROR') . ': ' . $error->getCode());
$document_options = array(
'template' => $app->get('theme'),
'file' => $app->get('themeFile', 'another-error404-page.php'),
'directory' => JPATH_THEMES,
'params' => $app->get('themeParams'),
'debug' => JDEBUG,
);
$document->parse($document_options);
$data = $document->render(
false,
$document_options
);
// Do not allow cache
$app->allowCache(false);
// If nothing was rendered, just use the message from the Exception
if (empty($data))
{
$data = $error->getMessage();
}
$app->setBody($data);
echo $app->toString();
$app->close(0);
// This return is needed to ensure the test suite does not trigger the non-Exception handling below
return;
}
catch (\Throwable $e)
{
// Pass the error down
}
catch (\Exception $e)
{
// Pass the error down
}
}
// This isn't an Exception, we can't handle it.
if (!headers_sent())
{
header('HTTP/1.1 500 Internal Server Error');
}
$message = 'Error';
if ($isException)
{
// Make sure we do not display sensitive data in production environments
if (ini_get('display_errors'))
{
$message .= ': ';
if (isset($e))
{
$message .= $e->getMessage() . ': ';
}
$message .= $error->getMessage();
}
}
echo $message;
jexit(1);
}| Status | New | ⇒ | Pending |
| Category | ⇒ | Libraries |
I suspect you doing some hack to use own exception handler? :)
You also have to check $file exists, and always fallback to error.php.
But, if all that you want is to have an error layout per "status code", then you can just improve ErrorDocuemnt to check these files:
eg "Error 500" => search for error-500.php => or fallback to error.php
And as @ReLater already said, you need to provide a testing instruction. Little code snippet that anyone can copy/paste and run.
hmm RIPS also just reported an possible Remote File Inclusion issue following this changes here. So before this here get finalised & merged please tag the JSST for a final review. Thanks.
hmm RIPS also just reported an possible Remote File Inclusion issue following this changes here. So before this here get finalised & merged please tag the JSST for a final review. Thanks.
$params is not user supplied input, so can't see a RFI here. Do I miss anything?
$params is not user supplied input, so can't see a RFI here. Do I miss anything?
$params comes form here ($this->docOptions): https://github.com/joomla/joomla-cms/blob/staging/libraries/src/Application/CMSApplication.php#L1044
$this->docOptions['file'] comes from here: https://github.com/joomla/joomla-cms/blob/staging/libraries/src/Application/CMSApplication.php#L1016
And themeFile can be set via an input parameter:
joomla-cms/libraries/src/Application/AdministratorApplication.php
Lines 412 to 419 in d3b544e
So that option can be usersupplied (but still be CMD filtered) atleast in the core. I guess thats the thing that RIPS found. The question now is whether this is a issue or not.
as mentiond above we still have not got any info how to use it. i will close this PR.
| Status | Pending | ⇒ | Closed |
| Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2022-06-12 17:53:23 |
| Closed_By | ⇒ | zero-24 | |
| Labels |
Added:
?
?
Removed: ? |
||
Could you please provide a code snippet where we see how and where we have to define the
'file'inside $params. I have absolutely no idea how to test this pr in a "living Joomla".BTW: I personally wouldn't use 'file' but something more specific like 'errorTmpl'
(?????)
And I think this is a new feature. Joomla 3 has a feature lock. You should rebase the pr for Joomla 4.
(?????)