1
0
قرینه از https://github.com/matomo-org/matomo.git synced 2025-08-22 06:57:53 +00:00
Files
matomo/plugins/Diagnostics/Diagnostic/DatabaseAbilitiesCheck.php
caddoo 55b28a4dc5 Block installation if installation is older than 3 days (#22750)
* Block installation if installation is older than 3 days

* Extend installation UI tests

* Move installation expiration logic out of constructor

* Update installation expiration error page

* Update expected screenshots

* Update FAQ link

---------

Co-authored-by: Marc Neudert <marc@innocraft.com>
2024-11-25 18:02:07 +01:00

220 خطوط
8.4 KiB
PHP

<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik\Plugins\Diagnostics\Diagnostic;
use Piwik\Common;
use Piwik\Config;
use Piwik\Db;
use Piwik\DbHelper;
use Piwik\SettingsPiwik;
use Piwik\Translation\Translator;
use Piwik\Url;
/**
* Check if Piwik can use LOAD DATA INFILE.
*/
class DatabaseAbilitiesCheck implements Diagnostic
{
/**
* @var Translator
*/
private $translator;
public function __construct(Translator $translator)
{
$this->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<br/><br/>' .
$this->translator->translate('Diagnostics_DatabaseUtf8mb4CharsetAvailableButNotUsed', '<code>' . PIWIK_INCLUDE_PATH . '/console core:convert-to-utf8mb4</code>') .
'<br/><br/>' .
$this->translator->translate('Diagnostics_DatabaseUtf8Requirement', ['<27>',
'<a href="' . Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/how-to-update/how-to-convert-the-database-to-utf8mb4-charset/') . '" rel="noreferrer noopener" target="_blank">', '</a>']) .
'<br/>'
);
}
return new DiagnosticResultItem(
DiagnosticResult::STATUS_WARNING,
'UTF8mb4 charset<br/><br/>' .
$this->translator->translate('Diagnostics_DatabaseUtf8mb4CharsetRecommended') .
'<br/><br/>' .
$this->translator->translate('Diagnostics_DatabaseUtf8Requirement', ['<27>',
'<a href="' . Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/how-to-update/how-to-convert-the-database-to-utf8mb4-charset/') . '" rel="noreferrer noopener" target="_blank">', '</a>']) .
'<br/>'
);
}
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<br/><br/>%s<br/><br/>%s<br/>',
$this->translator->translate('Diagnostics_DatabaseCollationNotConfigured'),
$this->translator->translate('Diagnostics_DatabaseCollationConnection', [$collationConnection])
);
if ('' !== $collationCharset) {
$message .= $this->translator->translate('Diagnostics_DatabaseCollationCharset', [$collationCharset]) . '<br/>';
}
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", "<br/>", $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<br/>%s<br/>%s',
$this->translator->translate('Installation_LoadDataInfileUnavailableHelp', array(
'LOAD DATA INFILE',
'FILE',
)),
$this->translator->translate('Installation_LoadDataInfileRecommended')
);
if ($errorMessage) {
$comment .= sprintf(
'<br/><strong>%s:</strong> %s<br/>%s',
$this->translator->translate('General_Error'),
$errorMessage,
'Troubleshooting: <a target="_blank" rel="noreferrer noopener" href="' . Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/troubleshooting/faq_194') . '">FAQ on matomo.org</a>'
);
}
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 .= '<br/>' . $this->translator->translate('Diagnostics_MysqlTemporaryTablesWarning');
$comment .= '<br/>Troubleshooting: <a target="_blank" rel="noreferrer noopener" href="' . Url::addCampaignParametersToMatomoLink('https://matomo.org/faq/how-to-install/faq_23484/') . '">FAQ on matomo.org</a>';
}
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 .= '<br/>' . $this->translator->translate('Diagnostics_MysqlTransactionLevel');
} else {
$level->restorePreviousStatus();
}
return new DiagnosticResultItem($status, $comment);
}
}