translator = $translator;
}
public function execute()
{
if (!SettingsPiwik::isMatomoInstalled()) {
// Skip the diagnostic if Matomo is being installed
return [];
}
$result = new DiagnosticResult($this->translator->translate('Installation_DatabaseAbilities'));
$result->addItem($this->checkUtf8mb4Charset());
$result->addItem($this->checkCollation());
if (Config::getInstance()->General['enable_load_data_infile']) {
$result->addItem($this->checkLoadDataInfile());
}
$result->addItem($this->checkTemporaryTables());
$result->addItem($this->checkTransactionLevel());
$databaseVersion = Db::fetchOne('SELECT VERSION();');
if (strpos(strtolower($databaseVersion), 'mariadb') !== false && Config\DatabaseConfig::getConfigValue('schema') !== 'Mariadb') {
$comment = $this->translator->translate('Diagnostics_MariaDbNotConfigured');
$result->addItem(new DiagnosticResultItem(DiagnosticResult::STATUS_INFORMATIONAL, $comment));
}
return [$result];
}
protected function checkUtf8mb4Charset()
{
$dbSettings = new Db\Settings();
$charset = $dbSettings->getUsedCharset();
if (DbHelper::getDefaultCharset() === 'utf8mb4' && $charset === 'utf8mb4') {
return new DiagnosticResultItem(DiagnosticResult::STATUS_OK, 'UTF8mb4 charset');
}
if (DbHelper::getDefaultCharset() === 'utf8mb4') {
return new DiagnosticResultItem(
DiagnosticResult::STATUS_WARNING,
'UTF8mb4 charset
' .
$this->translator->translate('Diagnostics_DatabaseUtf8mb4CharsetAvailableButNotUsed', '' . PIWIK_INCLUDE_PATH . '/console core:convert-to-utf8mb4') .
'
' .
$this->translator->translate('Diagnostics_DatabaseUtf8Requirement', ['�',
Url::getExternalLinkTag('https://matomo.org/faq/how-to-update/how-to-convert-the-database-to-utf8mb4-charset/'), '']) .
'
'
);
}
return new DiagnosticResultItem(
DiagnosticResult::STATUS_WARNING,
'UTF8mb4 charset
' .
$this->translator->translate('Diagnostics_DatabaseUtf8mb4CharsetRecommended') .
'
' .
$this->translator->translate('Diagnostics_DatabaseUtf8Requirement', ['�',
Url::getExternalLinkTag('https://matomo.org/faq/how-to-update/how-to-convert-the-database-to-utf8mb4-charset/'), '']) .
'
'
);
}
protected function checkCollation(): DiagnosticResultItem
{
$dbSettings = new Db\Settings();
$collation = $dbSettings->getUsedCollation();
if ('' !== $collation) {
return new DiagnosticResultItem(DiagnosticResult::STATUS_OK, 'Connection collation');
}
$collationConnection = Db::get()->fetchOne('SELECT @@collation_connection');
$collationCharset = DbHelper::getDefaultCollationForCharset($dbSettings->getUsedCharset());
$message = sprintf(
'Connection collation
%s
%s
',
$this->translator->translate('Diagnostics_DatabaseCollationNotConfigured'),
$this->translator->translate('Diagnostics_DatabaseCollationConnection', [$collationConnection])
);
if ('' !== $collationCharset) {
$message .= $this->translator->translate('Diagnostics_DatabaseCollationCharset', [$collationCharset]) . '
';
}
return new DiagnosticResultItem(DiagnosticResult::STATUS_WARNING, $message);
}
protected function checkLoadDataInfile()
{
$optionTable = Common::prefixTable('option');
$testOptionNames = array('test_system_check1', 'test_system_check2');
$loadDataInfile = false;
$errorMessage = null;
try {
$loadDataInfile = Db\BatchInsert::tableInsertBatch(
$optionTable,
array('option_name', 'option_value'),
array(
array($testOptionNames[0], '1'),
array($testOptionNames[1], '2'),
),
$throwException = true,
$charset = 'latin1'
);
} catch (\Exception $ex) {
$errorMessage = str_replace("\n", "
", $ex->getMessage());
}
// delete the temporary rows that were created
Db::exec("DELETE FROM `$optionTable` WHERE option_name IN ('" . implode("','", $testOptionNames) . "')");
if ($loadDataInfile) {
return new DiagnosticResultItem(DiagnosticResult::STATUS_OK, 'LOAD DATA INFILE');
}
$comment = sprintf(
'LOAD DATA INFILE
%s
%s',
$this->translator->translate('Installation_LoadDataInfileUnavailableHelp', array(
'LOAD DATA INFILE',
'FILE',
)),
$this->translator->translate('Installation_LoadDataInfileRecommended')
);
if ($errorMessage) {
$comment .= sprintf(
'
%s: %s
%s',
$this->translator->translate('General_Error'),
$errorMessage,
'Troubleshooting: ' . Url::getExternalLinkTag('https://matomo.org/faq/troubleshooting/faq_194') . 'FAQ on matomo.org'
);
}
return new DiagnosticResultItem(DiagnosticResult::STATUS_WARNING, $comment);
}
protected function checkTemporaryTables()
{
$status = DiagnosticResult::STATUS_OK;
$comment = 'CREATE TEMPORARY TABLES';
try {
// create a temporary table
Db::exec("CREATE TEMPORARY TABLE `piwik_test_table_temp` (
id INT,
val VARCHAR(5) NULL,
PRIMARY KEY (id)
)");
// insert an entry into the new temporary table
Db::exec('INSERT INTO `piwik_test_table_temp` (`id`, `val`) VALUES ("1", "val1");');
for ($i = 0; $i < 5; $i++) {
// try reading the entry a few times to ensure it doesn't fail, which might be possible when using load balanced databases
$result = Db::fetchRow('SELECT * FROM `piwik_test_table_temp` WHERE `id` = 1');
if (empty($result)) {
throw new \Exception('read failed');
}
}
} catch (\Exception $e) {
$status = DiagnosticResult::STATUS_ERROR;
$comment .= '
' . $this->translator->translate('Diagnostics_MysqlTemporaryTablesWarning');
$comment .= '
Troubleshooting: ' . Url::getExternalLinkTag('https://matomo.org/faq/how-to-install/faq_23484/') . 'FAQ on matomo.org';
}
return new DiagnosticResultItem($status, $comment);
}
protected function checkTransactionLevel()
{
$status = DiagnosticResult::STATUS_OK;
$comment = 'Changing transaction isolation level';
$level = new Db\TransactionLevel(Db::getReader());
if (!$level->setTransactionLevelForNonLockingReads()) {
$status = DiagnosticResult::STATUS_WARNING;
$comment .= '
' . $this->translator->translate('Diagnostics_MysqlTransactionLevel');
} else {
$level->restorePreviousStatus();
}
return new DiagnosticResultItem($status, $comment);
}
}