Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorSam <8619576+samjf@users.noreply.github.com>2022-04-11 12:32:52 +0300
committerGitHub <noreply@github.com>2022-04-11 12:32:52 +0300
commite6182097f4a9005de69f34f82c3f76b5c6162473 (patch)
tree5b3dbf39461c64f81aefad15f544b81ca7946862 /core
parentf8267dfed779e06f7483d9d952700e8c819cafba (diff)
Add the request hostname to error & exception logs (#18996)
* Add the hostname to the tracker exception log so multi-tenant domains are easier to debug * Add hostname to error log to help with debugging * use Url::getHost and add method to Url class instead * apply PSR12 code formatting Co-authored-by: sgiehl <stefan@matomo.org>
Diffstat (limited to 'core')
-rw-r--r--core/ExceptionHandler.php32
-rw-r--r--core/Tracker/Response.php14
-rw-r--r--core/Url.php57
-rw-r--r--core/testMinimumPhpVersion.php34
4 files changed, 95 insertions, 42 deletions
diff --git a/core/ExceptionHandler.php b/core/ExceptionHandler.php
index 4a61495a85..ca549622b5 100644
--- a/core/ExceptionHandler.php
+++ b/core/ExceptionHandler.php
@@ -1,4 +1,5 @@
<?php
+
/**
* Matomo - free/libre analytics platform
*
@@ -6,6 +7,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
+
namespace Piwik;
use DI\DependencyException;
@@ -25,7 +27,7 @@ class ExceptionHandler
{
public static function setUp()
{
- set_exception_handler(array('Piwik\ExceptionHandler', 'handleException'));
+ set_exception_handler(['Piwik\ExceptionHandler', 'handleException']);
}
/**
@@ -97,7 +99,7 @@ class ExceptionHandler
try {
echo self::getErrorResponse($exception);
- } catch(Exception $e) {
+ } catch (Exception $e) {
// When there are failures while generating the HTML error response itself,
// we simply print out the error message instead.
echo $exception->getMessage();
@@ -118,11 +120,9 @@ class ExceptionHandler
$isHtmlMessage = method_exists($ex, 'isHtmlMessage') && $ex->isHtmlMessage();
if (!$isHtmlMessage && Request::isApiRequest($_GET)) {
-
$outputFormat = strtolower(Common::getRequestVar('format', 'xml', 'string', $_GET + $_POST));
$response = new ResponseBuilder($outputFormat);
return $response->getResponseException($ex);
-
} elseif (!$isHtmlMessage) {
$message = Common::sanitizeInputValue($message);
}
@@ -150,8 +150,20 @@ class ExceptionHandler
// be written to the application log instead
$writeErrorLog = !($ex instanceof \Piwik\Exception\NotSupportedBrowserException);
- $result = Piwik_GetErrorMessagePage($message, $debugTrace, true, true, $logoHeaderUrl,
- $logoFaviconUrl, null, $writeErrorLog);
+ $hostname = Url::getRFCValidHostname();
+ $hostStr = $hostname ? "[$hostname] " : '- ';
+
+ $result = Piwik_GetErrorMessagePage(
+ $message,
+ $debugTrace,
+ true,
+ true,
+ $logoHeaderUrl,
+ $logoFaviconUrl,
+ null,
+ $hostStr,
+ $writeErrorLog
+ );
try {
/**
@@ -163,7 +175,7 @@ class ExceptionHandler
* @param string &$result The HTML of the error page.
* @param Exception $ex The Exception displayed in the error page.
*/
- Piwik::postEvent('FrontController.modifyErrorPage', array(&$result, $ex));
+ Piwik::postEvent('FrontController.modifyErrorPage', [&$result, $ex]);
} catch (ContainerDoesNotExistException $ex) {
// this can happen when an error occurs before the Piwik environment is created
}
@@ -171,17 +183,17 @@ class ExceptionHandler
return $result;
}
- private static function logException($exception, $loglevel=Log::ERROR)
+ private static function logException($exception, $loglevel = Log::ERROR)
{
try {
switch ($loglevel) {
- case(Log::DEBUG):
+ case (Log::DEBUG):
StaticContainer::get(LoggerInterface::class)->debug('Uncaught exception: {exception}', [
'exception' => $exception,
'ignoreInScreenWriter' => true,
]);
break;
- case(Log::ERROR):
+ case (Log::ERROR):
default:
StaticContainer::get(LoggerInterface::class)->error('Uncaught exception: {exception}', [
'exception' => $exception,
diff --git a/core/Tracker/Response.php b/core/Tracker/Response.php
index 9e1a63c846..e99feb8b38 100644
--- a/core/Tracker/Response.php
+++ b/core/Tracker/Response.php
@@ -1,4 +1,5 @@
<?php
+
/**
* Matomo - free/libre analytics platform
*
@@ -6,6 +7,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
+
namespace Piwik\Tracker;
use Exception;
@@ -15,6 +17,7 @@ use Piwik\Profiler;
use Piwik\Timer;
use Piwik\Tracker;
use Piwik\Tracker\Db as TrackerDb;
+use Piwik\Url;
class Response
{
@@ -89,7 +92,8 @@ class Response
Common::printDebug("End of the page.");
- if ($tracker->isDebugModeEnabled()
+ if (
+ $tracker->isDebugModeEnabled()
&& $tracker->isDatabaseConnected()
&& TrackerDb::isProfilingEnabled()
) {
@@ -190,7 +194,7 @@ class Response
// Base64 image string
$img = base64_decode($customImage);
$size = getimagesizefromstring($img);
- } else if (is_file($customImage) && is_readable($customImage)) {
+ } elseif (is_file($customImage) && is_readable($customImage)) {
// Image file
$img = file_get_contents($customImage);
$size = getimagesize($customImage); // imagesize is used to get the mime type
@@ -198,7 +202,7 @@ class Response
// Must have valid image data and a valid mime type to proceed
if ($img && $size && isset($size['mime']) && in_array($size['mime'], $supportedMimeTypes)) {
- Common::sendHeader('Content-Type: '.$size['mime']);
+ Common::sendHeader('Content-Type: ' . $size['mime']);
echo $img;
return true;
}
@@ -229,6 +233,8 @@ class Response
protected function logExceptionToErrorLog($e)
{
- error_log(sprintf("Error in Matomo (tracker): %s", str_replace("\n", " ", $this->getMessageFromException($e))));
+ $hostname = Url::getRFCValidHostname();
+ $hostStr = $hostname ? "[$hostname]" : '-';
+ error_log(sprintf("$hostStr Error in Matomo (tracker): %s", str_replace("\n", " ", $this->getMessageFromException($e))));
}
}
diff --git a/core/Url.php b/core/Url.php
index c027538cdb..abe1c82006 100644
--- a/core/Url.php
+++ b/core/Url.php
@@ -1,4 +1,5 @@
<?php
+
/**
* Matomo - free/libre analytics platform
*
@@ -6,6 +7,7 @@
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
+
namespace Piwik;
use Exception;
@@ -129,7 +131,8 @@ class Url
$url = '';
// insert extra path info if proxy_uri_header is set and enabled
- if (isset(Config::getInstance()->General['proxy_uri_header'])
+ if (
+ isset(Config::getInstance()->General['proxy_uri_header'])
&& Config::getInstance()->General['proxy_uri_header'] == 1
&& !empty($_SERVER['HTTP_X_FORWARDED_URI'])
) {
@@ -209,7 +212,8 @@ class Url
public static function isValidHost($host = false): bool
{
// only do trusted host check if it's enabled
- if (isset(Config::getInstance()->General['enable_trusted_host_check'])
+ if (
+ isset(Config::getInstance()->General['enable_trusted_host_check'])
&& Config::getInstance()->General['enable_trusted_host_check'] == 0
) {
return true;
@@ -277,12 +281,13 @@ class Url
protected static function saveHostsnameInConfig($host, $domain, $key)
{
- if (Piwik::hasUserSuperUserAccess()
+ if (
+ Piwik::hasUserSuperUserAccess()
&& file_exists(Config::getLocalConfigPath())
) {
$config = Config::getInstance()->$domain;
if (!is_array($host)) {
- $host = array($host);
+ $host = [$host];
}
$host = array_filter($host);
if (empty($host)) {
@@ -340,6 +345,21 @@ class Url
}
/**
+ * Returns the valid hostname (according to RFC standards) as a string; else it will return false if it isn't valid.
+ * If the hostname isn't supplied it will default to using Url::getHost
+ * Note: this will not verify if the hostname is trusted.
+ * @param $hostname
+ * @return false|string
+ */
+ public static function getRFCValidHostname($hostname = null)
+ {
+ if (empty($hostname)) {
+ $hostname = self::getHost(false);
+ }
+ return filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
+ }
+
+ /**
* Sets the host. Useful for CLI scripts, eg. core:archive command
*
* @param $host string
@@ -363,7 +383,7 @@ class Url
*/
public static function getCurrentHost($default = 'unknown', $checkTrustedHost = true)
{
- $hostHeaders = array();
+ $hostHeaders = [];
$config = Config::getInstance()->General;
if (isset($config['proxy_host_headers'])) {
@@ -371,7 +391,7 @@ class Url
}
if (!is_array($hostHeaders)) {
- $hostHeaders = array();
+ $hostHeaders = [];
}
$host = self::getHost($checkTrustedHost);
@@ -390,7 +410,8 @@ class Url
public static function getCurrentQueryString()
{
$url = '';
- if (isset($_SERVER['QUERY_STRING'])
+ if (
+ isset($_SERVER['QUERY_STRING'])
&& !empty($_SERVER['QUERY_STRING'])
) {
$url .= "?" . $_SERVER['QUERY_STRING'];
@@ -491,7 +512,8 @@ class Url
private static function redirectToUrlNoExit($url)
{
- if (UrlHelper::isLookLikeUrl($url)
+ if (
+ UrlHelper::isLookLikeUrl($url)
|| strpos($url, 'index.php') === 0
) {
Common::sendResponseCode(302);
@@ -568,13 +590,13 @@ class Url
// handle host name mangling
$requestUri = isset($_SERVER['SCRIPT_URI']) ? $_SERVER['SCRIPT_URI'] : '';
$parseRequest = @parse_url($requestUri);
- $hosts = array(self::getHost(), self::getCurrentHost());
+ $hosts = [self::getHost(), self::getCurrentHost()];
if (!empty($parseRequest['host'])) {
$hosts[] = $parseRequest['host'];
}
// drop port numbers from hostnames and IP addresses
- $hosts = array_map(array('self', 'getHostSanitized'), $hosts);
+ $hosts = array_map(['self', 'getHostSanitized'], $hosts);
$disableHostCheck = Config::getInstance()->General['enable_trusted_host_check'] == 0;
// compare scheme and host
@@ -583,7 +605,7 @@ class Url
return !empty($host)
&& ($disableHostCheck || in_array($host, $hosts))
&& !empty($parsedUrl['scheme'])
- && in_array($parsedUrl['scheme'], array('http', 'https'));
+ && in_array($parsedUrl['scheme'], ['http', 'https']);
}
/**
@@ -650,12 +672,12 @@ class Url
$config = @Config::getInstance()->$domain;
if (!isset($config[$key])) {
- return array();
+ return [];
}
$hosts = $config[$key];
if (!is_array($hosts)) {
- return array();
+ return [];
}
return $hosts;
}
@@ -735,7 +757,7 @@ class Url
*/
public static function getLocalHostnames()
{
- return array('localhost', '127.0.0.1', '::1', '[::1]', '[::]', '0000::1', '0177.0.0.1', '2130706433', '[0:0:0:0:0:ffff:127.0.0.1]');
+ return ['localhost', '127.0.0.1', '::1', '[::1]', '[::]', '0000::1', '0177.0.0.1', '2130706433', '[0:0:0:0:0:ffff:127.0.0.1]'];
}
/**
@@ -769,10 +791,10 @@ class Url
return 'http';
}
- if ((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === true))
+ if (
+ (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] === true))
|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
) {
-
return 'https';
}
return 'http';
@@ -796,7 +818,8 @@ class Url
{
$host = @$_SERVER['SERVER_NAME'];
if (!empty($host)) {
- if (strpos($host, ':') === false
+ if (
+ strpos($host, ':') === false
&& !empty($_SERVER['SERVER_PORT'])
&& $_SERVER['SERVER_PORT'] != 80
&& $_SERVER['SERVER_PORT'] != 443
diff --git a/core/testMinimumPhpVersion.php b/core/testMinimumPhpVersion.php
index 70fa5310bf..efeb530f68 100644
--- a/core/testMinimumPhpVersion.php
+++ b/core/testMinimumPhpVersion.php
@@ -1,4 +1,5 @@
<?php
+
/**
* Matomo - free/libre analytics platform
*
@@ -61,12 +62,12 @@ if ($minimumPhpInvalid) {
$composerInstall = "Download and run <a href=\"https://getcomposer.org/Composer-Setup.exe\"><b>Composer-Setup.exe</b></a>, it will install the latest Composer version and set up your PATH so that you can just call composer from any directory in your command line. "
. " <br>Then run this command in a terminal in the matomo directory: <br> $ php composer.phar install ";
}
- $piwik_errorMessage .= "<p>It appears the <a href='https://getcomposer.org/' rel='noreferrer noopener' target='_blank'>composer</a> tool is not yet installed. You can install Composer in a few easy steps:\n\n".
- "<br/>" . $composerInstall.
- " This will initialize composer for Matomo and download libraries we use in vendor/* directory.".
+ $piwik_errorMessage .= "<p>It appears the <a href='https://getcomposer.org/' rel='noreferrer noopener' target='_blank'>composer</a> tool is not yet installed. You can install Composer in a few easy steps:\n\n" .
+ "<br/>" . $composerInstall .
+ " This will initialize composer for Matomo and download libraries we use in vendor/* directory." .
"\n\n<br/><br/>Then reload this page to access your analytics reports." .
"\n\n<br/><br/>For more information check out this FAQ: <a href='https://matomo.org/faq/how-to-install/faq_18271/' rel='noreferrer noopener' target='_blank'>How do I use Matomo from the Git repository?</a>." .
- "\n\n<br/><br/>Note: if for some reasons you cannot install composer, instead install the latest Matomo release from ".
+ "\n\n<br/><br/>Note: if for some reasons you cannot install composer, instead install the latest Matomo release from " .
"<a href='https://builds.matomo.org/piwik.zip' rel='noreferrer noopener'>builds.matomo.org</a>.</p>";
}
}
@@ -83,7 +84,8 @@ if (!function_exists('Piwik_GetErrorMessagePage')) {
*/
function Piwik_ShouldPrintBackTraceWithMessage()
{
- if (class_exists('\Piwik\SettingsServer')
+ if (
+ class_exists('\Piwik\SettingsServer')
&& class_exists('\Piwik\Common')
&& \Piwik\SettingsServer::isArchivePhpTriggered()
&& \Piwik\Common::isPhpCliMode()
@@ -109,14 +111,23 @@ if (!function_exists('Piwik_GetErrorMessagePage')) {
* @param bool $optionalLinkBack If true, displays a link to go back
* @param bool|string $logoUrl The URL to the logo to use.
* @param bool|string $faviconUrl The URL to the favicon to use.
+ * @param string $errorLogPrefix String to prepend to the error in log file
* @param bool $writeErrorLog If true then a webserver error log will be written, defaults to true
* @return string
*/
- function Piwik_GetErrorMessagePage($message, $optionalTrace = false, $optionalLinks = false, $optionalLinkBack = false,
- $logoUrl = false, $faviconUrl = false, $isCli = null, bool $writeErrorLog = true)
- {
+ function Piwik_GetErrorMessagePage(
+ $message,
+ $optionalTrace = false,
+ $optionalLinks = false,
+ $optionalLinkBack = false,
+ $logoUrl = false,
+ $faviconUrl = false,
+ $isCli = null,
+ $errorLogPrefix = '',
+ bool $writeErrorLog = true
+ ) {
if ($writeErrorLog) {
- error_log(sprintf("Error in Matomo: %s", str_replace("\n", " ", strip_tags($message))));
+ error_log(sprintf("${errorLogPrefix}Error in Matomo: %s", str_replace("\n", " ", strip_tags($message))));
}
if (!headers_sent()) {
@@ -130,7 +141,8 @@ if (!function_exists('Piwik_GetErrorMessagePage')) {
}
// We return only an HTML fragment for AJAX requests
- if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])
+ if (
+ isset($_SERVER['HTTP_X_REQUESTED_WITH'])
&& (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest')
) {
return "<div class='alert alert-danger'><strong>Error:</strong> $message</div>";
@@ -182,7 +194,7 @@ if (!function_exists('Piwik_GetErrorMessagePage')) {
. ' ' . $optionalLinks;
- $message = str_replace(array("<br />", "<br>", "<br/>", "</p>"), "\n", $message);
+ $message = str_replace(["<br />", "<br>", "<br/>", "</p>"], "\n", $message);
$message = str_replace("\t", "", $message);
$message = strip_tags($message);