1<?php 2/** 3 * Matomo - free/libre analytics platform 4 * 5 * @link https://matomo.org 6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later 7 * 8 */ 9namespace Piwik\Db\Schema; 10 11use Exception; 12use Piwik\Common; 13use Piwik\Concurrency\Lock; 14use Piwik\Date; 15use Piwik\Db\SchemaInterface; 16use Piwik\Db; 17use Piwik\DbHelper; 18use Piwik\Option; 19use Piwik\Piwik; 20use Piwik\Plugin\Manager; 21use Piwik\Plugins\UsersManager\Model; 22use Piwik\Version; 23 24/** 25 * MySQL schema 26 */ 27class Mysql implements SchemaInterface 28{ 29 const OPTION_NAME_MATOMO_INSTALL_VERSION = 'install_version'; 30 const MAX_TABLE_NAME_LENGTH = 64; 31 32 private $tablesInstalled = null; 33 34 /** 35 * Get the SQL to create Piwik tables 36 * 37 * @return array array of strings containing SQL 38 */ 39 public function getTablesCreateSql() 40 { 41 $engine = $this->getTableEngine(); 42 $prefixTables = $this->getTablePrefix(); 43 $dbSettings = new Db\Settings(); 44 $charset = $dbSettings->getUsedCharset(); 45 46 $tables = array( 47 'user' => "CREATE TABLE {$prefixTables}user ( 48 login VARCHAR(100) NOT NULL, 49 password VARCHAR(255) NOT NULL, 50 email VARCHAR(100) NOT NULL, 51 twofactor_secret VARCHAR(40) NOT NULL DEFAULT '', 52 superuser_access TINYINT(2) unsigned NOT NULL DEFAULT '0', 53 date_registered TIMESTAMP NULL, 54 ts_password_modified TIMESTAMP NULL, 55 PRIMARY KEY(login) 56 ) ENGINE=$engine DEFAULT CHARSET=$charset 57 ", 58 'user_token_auth' => "CREATE TABLE {$prefixTables}user_token_auth ( 59 idusertokenauth BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 60 login VARCHAR(100) NOT NULL, 61 description VARCHAR(".Model::MAX_LENGTH_TOKEN_DESCRIPTION.") NOT NULL, 62 password VARCHAR(191) NOT NULL, 63 hash_algo VARCHAR(30) NOT NULL, 64 system_token TINYINT(1) NOT NULL DEFAULT 0, 65 last_used DATETIME NULL, 66 date_created DATETIME NOT NULL, 67 date_expired DATETIME NULL, 68 PRIMARY KEY(idusertokenauth), 69 UNIQUE KEY uniq_password(password) 70 ) ENGINE=$engine DEFAULT CHARSET=$charset 71 ", 72 73 'twofactor_recovery_code' => "CREATE TABLE {$prefixTables}twofactor_recovery_code ( 74 idrecoverycode BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 75 login VARCHAR(100) NOT NULL, 76 recovery_code VARCHAR(40) NOT NULL, 77 PRIMARY KEY(idrecoverycode) 78 ) ENGINE=$engine DEFAULT CHARSET=$charset 79 ", 80 81 'access' => "CREATE TABLE {$prefixTables}access ( 82 idaccess INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, 83 login VARCHAR(100) NOT NULL, 84 idsite INTEGER UNSIGNED NOT NULL, 85 access VARCHAR(50) NULL, 86 PRIMARY KEY(idaccess), 87 INDEX index_loginidsite (login, idsite) 88 ) ENGINE=$engine DEFAULT CHARSET=$charset 89 ", 90 91 'site' => "CREATE TABLE {$prefixTables}site ( 92 idsite INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, 93 name VARCHAR(90) NOT NULL, 94 main_url VARCHAR(255) NOT NULL, 95 ts_created TIMESTAMP NULL, 96 ecommerce TINYINT DEFAULT 0, 97 sitesearch TINYINT DEFAULT 1, 98 sitesearch_keyword_parameters TEXT NOT NULL, 99 sitesearch_category_parameters TEXT NOT NULL, 100 timezone VARCHAR( 50 ) NOT NULL, 101 currency CHAR( 3 ) NOT NULL, 102 exclude_unknown_urls TINYINT(1) DEFAULT 0, 103 excluded_ips TEXT NOT NULL, 104 excluded_parameters TEXT NOT NULL, 105 excluded_user_agents TEXT NOT NULL, 106 `group` VARCHAR(250) NOT NULL, 107 `type` VARCHAR(255) NOT NULL, 108 keep_url_fragment TINYINT NOT NULL DEFAULT 0, 109 creator_login VARCHAR(100) NULL, 110 PRIMARY KEY(idsite) 111 ) ENGINE=$engine DEFAULT CHARSET=$charset 112 ", 113 114 'plugin_setting' => "CREATE TABLE {$prefixTables}plugin_setting ( 115 `plugin_name` VARCHAR(60) NOT NULL, 116 `setting_name` VARCHAR(255) NOT NULL, 117 `setting_value` LONGTEXT NOT NULL, 118 `json_encoded` TINYINT UNSIGNED NOT NULL DEFAULT 0, 119 `user_login` VARCHAR(100) NOT NULL DEFAULT '', 120 `idplugin_setting` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 121 PRIMARY KEY (idplugin_setting), 122 INDEX(plugin_name, user_login) 123 ) ENGINE=$engine DEFAULT CHARSET=$charset 124 ", 125 126 'site_setting' => "CREATE TABLE {$prefixTables}site_setting ( 127 idsite INTEGER(10) UNSIGNED NOT NULL, 128 `plugin_name` VARCHAR(60) NOT NULL, 129 `setting_name` VARCHAR(255) NOT NULL, 130 `setting_value` LONGTEXT NOT NULL, 131 `json_encoded` TINYINT UNSIGNED NOT NULL DEFAULT 0, 132 `idsite_setting` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 133 PRIMARY KEY (idsite_setting), 134 INDEX(idsite, plugin_name) 135 ) ENGINE=$engine DEFAULT CHARSET=$charset 136 ", 137 138 'site_url' => "CREATE TABLE {$prefixTables}site_url ( 139 idsite INTEGER(10) UNSIGNED NOT NULL, 140 url VARCHAR(190) NOT NULL, 141 PRIMARY KEY(idsite, url) 142 ) ENGINE=$engine DEFAULT CHARSET=$charset 143 ", 144 145 'goal' => "CREATE TABLE `{$prefixTables}goal` ( 146 `idsite` int(11) NOT NULL, 147 `idgoal` int(11) NOT NULL, 148 `name` varchar(50) NOT NULL, 149 `description` varchar(255) NOT NULL DEFAULT '', 150 `match_attribute` varchar(20) NOT NULL, 151 `pattern` varchar(255) NOT NULL, 152 `pattern_type` varchar(25) NOT NULL, 153 `case_sensitive` tinyint(4) NOT NULL, 154 `allow_multiple` tinyint(4) NOT NULL, 155 `revenue` DOUBLE NOT NULL, 156 `deleted` tinyint(4) NOT NULL default '0', 157 `event_value_as_revenue` tinyint(4) NOT NULL default '0', 158 PRIMARY KEY (`idsite`,`idgoal`) 159 ) ENGINE=$engine DEFAULT CHARSET=$charset 160 ", 161 162 'logger_message' => "CREATE TABLE {$prefixTables}logger_message ( 163 idlogger_message INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, 164 tag VARCHAR(50) NULL, 165 timestamp TIMESTAMP NULL, 166 level VARCHAR(16) NULL, 167 message TEXT NULL, 168 PRIMARY KEY(idlogger_message) 169 ) ENGINE=$engine DEFAULT CHARSET=$charset 170 ", 171 172 'log_action' => "CREATE TABLE {$prefixTables}log_action ( 173 idaction INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, 174 name VARCHAR(4096), 175 hash INTEGER(10) UNSIGNED NOT NULL, 176 type TINYINT UNSIGNED NULL, 177 url_prefix TINYINT(2) NULL, 178 PRIMARY KEY(idaction), 179 INDEX index_type_hash (type, hash) 180 ) ENGINE=$engine DEFAULT CHARSET=$charset 181 ", 182 183 'log_visit' => "CREATE TABLE {$prefixTables}log_visit ( 184 idvisit BIGINT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 185 idsite INTEGER(10) UNSIGNED NOT NULL, 186 idvisitor BINARY(8) NOT NULL, 187 visit_last_action_time DATETIME NOT NULL, 188 config_id BINARY(8) NOT NULL, 189 location_ip VARBINARY(16) NOT NULL, 190 PRIMARY KEY(idvisit), 191 INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time), 192 INDEX index_idsite_datetime (idsite, visit_last_action_time), 193 INDEX index_idsite_idvisitor (idsite, idvisitor) 194 ) ENGINE=$engine DEFAULT CHARSET=$charset 195 ", 196 197 'log_conversion_item' => "CREATE TABLE `{$prefixTables}log_conversion_item` ( 198 idsite int(10) UNSIGNED NOT NULL, 199 idvisitor BINARY(8) NOT NULL, 200 server_time DATETIME NOT NULL, 201 idvisit BIGINT(10) UNSIGNED NOT NULL, 202 idorder varchar(100) NOT NULL, 203 idaction_sku INTEGER(10) UNSIGNED NOT NULL, 204 idaction_name INTEGER(10) UNSIGNED NOT NULL, 205 idaction_category INTEGER(10) UNSIGNED NOT NULL, 206 idaction_category2 INTEGER(10) UNSIGNED NOT NULL, 207 idaction_category3 INTEGER(10) UNSIGNED NOT NULL, 208 idaction_category4 INTEGER(10) UNSIGNED NOT NULL, 209 idaction_category5 INTEGER(10) UNSIGNED NOT NULL, 210 price DOUBLE NOT NULL, 211 quantity INTEGER(10) UNSIGNED NOT NULL, 212 deleted TINYINT(1) UNSIGNED NOT NULL, 213 PRIMARY KEY(idvisit, idorder, idaction_sku), 214 INDEX index_idsite_servertime ( idsite, server_time ) 215 ) ENGINE=$engine DEFAULT CHARSET=$charset 216 ", 217 218 'log_conversion' => "CREATE TABLE `{$prefixTables}log_conversion` ( 219 idvisit BIGINT(10) unsigned NOT NULL, 220 idsite int(10) unsigned NOT NULL, 221 idvisitor BINARY(8) NOT NULL, 222 server_time datetime NOT NULL, 223 idaction_url INTEGER(10) UNSIGNED default NULL, 224 idlink_va BIGINT(10) UNSIGNED default NULL, 225 idgoal int(10) NOT NULL, 226 buster int unsigned NOT NULL, 227 idorder varchar(100) default NULL, 228 items SMALLINT UNSIGNED DEFAULT NULL, 229 url VARCHAR(4096) NOT NULL, 230 revenue DOUBLE default NULL, 231 revenue_shipping DOUBLE default NULL, 232 revenue_subtotal DOUBLE default NULL, 233 revenue_tax DOUBLE default NULL, 234 revenue_discount DOUBLE default NULL, 235 PRIMARY KEY (idvisit, idgoal, buster), 236 UNIQUE KEY unique_idsite_idorder (idsite, idorder), 237 INDEX index_idsite_datetime ( idsite, server_time ) 238 ) ENGINE=$engine DEFAULT CHARSET=$charset 239 ", 240 241 'log_link_visit_action' => "CREATE TABLE {$prefixTables}log_link_visit_action ( 242 idlink_va BIGINT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 243 idsite int(10) UNSIGNED NOT NULL, 244 idvisitor BINARY(8) NOT NULL, 245 idvisit BIGINT(10) UNSIGNED NOT NULL, 246 idaction_url_ref INTEGER(10) UNSIGNED NULL DEFAULT 0, 247 idaction_name_ref INTEGER(10) UNSIGNED NULL, 248 custom_float DOUBLE NULL DEFAULT NULL, 249 pageview_position MEDIUMINT UNSIGNED DEFAULT NULL, 250 PRIMARY KEY(idlink_va), 251 INDEX index_idvisit(idvisit) 252 ) ENGINE=$engine DEFAULT CHARSET=$charset 253 ", 254 255 'log_profiling' => "CREATE TABLE {$prefixTables}log_profiling ( 256 query TEXT NOT NULL, 257 count INTEGER UNSIGNED NULL, 258 sum_time_ms FLOAT NULL, 259 idprofiling BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 260 PRIMARY KEY (idprofiling), 261 UNIQUE KEY query(query(100)) 262 ) ENGINE=$engine DEFAULT CHARSET=$charset 263 ", 264 265 'option' => "CREATE TABLE `{$prefixTables}option` ( 266 option_name VARCHAR( 191 ) NOT NULL, 267 option_value LONGTEXT NOT NULL, 268 autoload TINYINT NOT NULL DEFAULT '1', 269 PRIMARY KEY ( option_name ), 270 INDEX autoload( autoload ) 271 ) ENGINE=$engine DEFAULT CHARSET=$charset 272 ", 273 274 'session' => "CREATE TABLE {$prefixTables}session ( 275 id VARCHAR( 191 ) NOT NULL, 276 modified INTEGER, 277 lifetime INTEGER, 278 data MEDIUMTEXT, 279 PRIMARY KEY ( id ) 280 ) ENGINE=$engine DEFAULT CHARSET=$charset 281 ", 282 283 'archive_numeric' => "CREATE TABLE {$prefixTables}archive_numeric ( 284 idarchive INTEGER UNSIGNED NOT NULL, 285 name VARCHAR(190) NOT NULL, 286 idsite INTEGER UNSIGNED NULL, 287 date1 DATE NULL, 288 date2 DATE NULL, 289 period TINYINT UNSIGNED NULL, 290 ts_archived DATETIME NULL, 291 value DOUBLE NULL, 292 PRIMARY KEY(idarchive, name), 293 INDEX index_idsite_dates_period(idsite, date1, date2, period, ts_archived), 294 INDEX index_period_archived(period, ts_archived) 295 ) ENGINE=$engine DEFAULT CHARSET=$charset 296 ", 297 298 'archive_blob' => "CREATE TABLE {$prefixTables}archive_blob ( 299 idarchive INTEGER UNSIGNED NOT NULL, 300 name VARCHAR(190) NOT NULL, 301 idsite INTEGER UNSIGNED NULL, 302 date1 DATE NULL, 303 date2 DATE NULL, 304 period TINYINT UNSIGNED NULL, 305 ts_archived DATETIME NULL, 306 value MEDIUMBLOB NULL, 307 PRIMARY KEY(idarchive, name), 308 INDEX index_period_archived(period, ts_archived) 309 ) ENGINE=$engine DEFAULT CHARSET=$charset 310 ", 311 312 'archive_invalidations' => "CREATE TABLE `{$prefixTables}archive_invalidations` ( 313 idinvalidation BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 314 idarchive INTEGER UNSIGNED NULL, 315 name VARCHAR(255) NOT NULL, 316 idsite INTEGER UNSIGNED NOT NULL, 317 date1 DATE NOT NULL, 318 date2 DATE NOT NULL, 319 period TINYINT UNSIGNED NOT NULL, 320 ts_invalidated DATETIME NULL, 321 ts_started DATETIME NULL, 322 status TINYINT(1) UNSIGNED DEFAULT 0, 323 `report` VARCHAR(255) NULL, 324 PRIMARY KEY(idinvalidation), 325 INDEX index_idsite_dates_period_name(idsite, date1, period) 326 ) ENGINE=$engine DEFAULT CHARSET=$charset 327 ", 328 329 'sequence' => "CREATE TABLE {$prefixTables}sequence ( 330 `name` VARCHAR(120) NOT NULL, 331 `value` BIGINT(20) UNSIGNED NOT NULL , 332 PRIMARY KEY(`name`) 333 ) ENGINE=$engine DEFAULT CHARSET=$charset 334 ", 335 336 'brute_force_log' => "CREATE TABLE {$prefixTables}brute_force_log ( 337 `id_brute_force_log` bigint(11) NOT NULL AUTO_INCREMENT, 338 `ip_address` VARCHAR(60) DEFAULT NULL, 339 `attempted_at` datetime NOT NULL, 340 `login` VARCHAR(100) NULL, 341 INDEX index_ip_address(ip_address), 342 PRIMARY KEY(`id_brute_force_log`) 343 ) ENGINE=$engine DEFAULT CHARSET=$charset 344 ", 345 346 'tracking_failure' => "CREATE TABLE {$prefixTables}tracking_failure ( 347 `idsite` BIGINT(20) UNSIGNED NOT NULL , 348 `idfailure` SMALLINT UNSIGNED NOT NULL , 349 `date_first_occurred` DATETIME NOT NULL , 350 `request_url` MEDIUMTEXT NOT NULL , 351 PRIMARY KEY(`idsite`, `idfailure`) 352 ) ENGINE=$engine DEFAULT CHARSET=$charset 353 ", 354 'locks' => "CREATE TABLE `{$prefixTables}locks` ( 355 `key` VARCHAR(".Lock::MAX_KEY_LEN.") NOT NULL, 356 `value` VARCHAR(255) NULL DEFAULT NULL, 357 `expiry_time` BIGINT UNSIGNED DEFAULT 9999999999, 358 PRIMARY KEY (`key`) 359 ) ENGINE=$engine DEFAULT CHARSET=$charset 360 ", 361 ); 362 363 return $tables; 364 } 365 366 /** 367 * Get the SQL to create a specific Piwik table 368 * 369 * @param string $tableName 370 * @throws Exception 371 * @return string SQL 372 */ 373 public function getTableCreateSql($tableName) 374 { 375 $tables = DbHelper::getTablesCreateSql(); 376 377 if (!isset($tables[$tableName])) { 378 throw new Exception("The table '$tableName' SQL creation code couldn't be found."); 379 } 380 381 return $tables[$tableName]; 382 } 383 384 /** 385 * Names of all the prefixed tables in piwik 386 * Doesn't use the DB 387 * 388 * @return array Table names 389 */ 390 public function getTablesNames() 391 { 392 $aTables = array_keys($this->getTablesCreateSql()); 393 $prefixTables = $this->getTablePrefix(); 394 395 $return = array(); 396 foreach ($aTables as $table) { 397 $return[] = $prefixTables . $table; 398 } 399 400 return $return; 401 } 402 403 /** 404 * Get list of installed columns in a table 405 * 406 * @param string $tableName The name of a table. 407 * 408 * @return array Installed columns indexed by the column name. 409 */ 410 public function getTableColumns($tableName) 411 { 412 $db = $this->getDb(); 413 414 $allColumns = $db->fetchAll("SHOW COLUMNS FROM " . $tableName); 415 416 $fields = array(); 417 foreach ($allColumns as $column) { 418 $fields[trim($column['Field'])] = $column; 419 } 420 421 return $fields; 422 } 423 424 /** 425 * Get list of tables installed (including tables defined by deactivated plugins) 426 * 427 * @param bool $forceReload Invalidate cache 428 * @return array installed Tables 429 */ 430 public function getTablesInstalled($forceReload = true) 431 { 432 if (is_null($this->tablesInstalled) 433 || $forceReload === true 434 ) { 435 $db = $this->getDb(); 436 $prefixTables = $this->getTablePrefixEscaped(); 437 438 $allTables = $this->getAllExistingTables($prefixTables); 439 440 // all the tables to be installed 441 $allMyTables = $this->getTablesNames(); 442 443 /** 444 * Triggered when detecting which tables have already been created by Matomo. 445 * This should be used by plugins to define it's database tables. Table names need to be added prefixed. 446 * 447 * **Example** 448 * 449 * Piwik::addAction('Db.getTablesInstalled', function(&$allTablesInstalled) { 450 * $allTablesInstalled = 'log_custom'; 451 * }); 452 * @param array $result 453 */ 454 if (count($allTables) && empty($GLOBALS['DISABLE_GET_TABLES_INSTALLED_EVENTS_FOR_TEST'])) { 455 Manager::getInstance()->loadPlugins(Manager::getAllPluginsNames()); 456 Piwik::postEvent('Db.getTablesInstalled', [&$allMyTables]); 457 Manager::getInstance()->unloadPlugins(); 458 Manager::getInstance()->loadActivatedPlugins(); 459 } 460 461 // we get the intersection between all the tables in the DB and the tables to be installed 462 $tablesInstalled = array_intersect($allMyTables, $allTables); 463 464 // at this point we have the static list of core tables, but let's add the monthly archive tables 465 $allArchiveNumeric = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "archive_numeric%'"); 466 $allArchiveBlob = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "archive_blob%'"); 467 468 $allTablesReallyInstalled = array_merge($tablesInstalled, $allArchiveNumeric, $allArchiveBlob); 469 470 $allTablesReallyInstalled = array_unique($allTablesReallyInstalled); 471 472 $this->tablesInstalled = $allTablesReallyInstalled; 473 } 474 475 return $this->tablesInstalled; 476 } 477 478 /** 479 * Checks whether any table exists 480 * 481 * @return bool True if tables exist; false otherwise 482 */ 483 public function hasTables() 484 { 485 return count($this->getTablesInstalled()) != 0; 486 } 487 488 /** 489 * Create database 490 * 491 * @param string $dbName Name of the database to create 492 */ 493 public function createDatabase($dbName = null) 494 { 495 if (is_null($dbName)) { 496 $dbName = $this->getDbName(); 497 } 498 499 $dbName = str_replace('`', '', $dbName); 500 $charset = DbHelper::getDefaultCharset(); 501 502 Db::exec("CREATE DATABASE IF NOT EXISTS `" . $dbName . "` DEFAULT CHARACTER SET ".$charset); 503 } 504 505 /** 506 * Creates a new table in the database. 507 * 508 * @param string $nameWithoutPrefix The name of the table without any piwik prefix. 509 * @param string $createDefinition The table create definition, see the "MySQL CREATE TABLE" specification for 510 * more information. 511 * @throws \Exception 512 */ 513 public function createTable($nameWithoutPrefix, $createDefinition) 514 { 515 $dbSettings = new Db\Settings(); 516 $charset = $dbSettings->getUsedCharset(); 517 518 $statement = sprintf("CREATE TABLE IF NOT EXISTS `%s` ( %s ) ENGINE=%s DEFAULT CHARSET=%s %s;", 519 Common::prefixTable($nameWithoutPrefix), 520 $createDefinition, 521 $this->getTableEngine(), 522 $charset, 523 $dbSettings->getRowFormat()); 524 525 try { 526 Db::exec($statement); 527 } catch (Exception $e) { 528 // mysql code error 1050:table already exists 529 // see bug #153 https://github.com/piwik/piwik/issues/153 530 if (!$this->getDb()->isErrNo($e, '1050')) { 531 throw $e; 532 } 533 } 534 } 535 536 /** 537 * Drop database 538 */ 539 public function dropDatabase($dbName = null) 540 { 541 $dbName = $dbName ?: $this->getDbName(); 542 $dbName = str_replace('`', '', $dbName); 543 Db::exec("DROP DATABASE IF EXISTS `" . $dbName . "`"); 544 } 545 546 /** 547 * Create all tables 548 */ 549 public function createTables() 550 { 551 $db = $this->getDb(); 552 $prefixTables = $this->getTablePrefix(); 553 554 $tablesAlreadyInstalled = $this->getAllExistingTables($prefixTables); 555 $tablesToCreate = $this->getTablesCreateSql(); 556 unset($tablesToCreate['archive_blob']); 557 unset($tablesToCreate['archive_numeric']); 558 559 foreach ($tablesToCreate as $tableName => $tableSql) { 560 $tableName = $prefixTables . $tableName; 561 if (!in_array($tableName, $tablesAlreadyInstalled)) { 562 $db->query($tableSql); 563 } 564 } 565 } 566 567 /** 568 * Creates an entry in the User table for the "anonymous" user. 569 */ 570 public function createAnonymousUser() 571 { 572 $now = Date::factory('now')->getDatetime(); 573 // The anonymous user is the user that is assigned by default 574 // note that the token_auth value is anonymous, which is assigned by default as well in the Login plugin 575 $db = $this->getDb(); 576 $db->query("INSERT IGNORE INTO " . Common::prefixTable("user") . " 577 (`login`, `password`, `email`, `twofactor_secret`, `superuser_access`, `date_registered`, `ts_password_modified`) 578 VALUES ( 'anonymous', '', 'anonymous@example.org', '', 0, '$now', '$now' );"); 579 580 $model = new Model(); 581 $model->addTokenAuth('anonymous', 'anonymous', 'anonymous default token', $now); 582 } 583 584 /** 585 * Records the Matomo version a user used when installing this Matomo for the first time 586 */ 587 public function recordInstallVersion() 588 { 589 if (!self::getInstallVersion()) { 590 Option::set(self::OPTION_NAME_MATOMO_INSTALL_VERSION, Version::VERSION); 591 } 592 } 593 594 /** 595 * Returns which Matomo version was used to install this Matomo for the first time. 596 */ 597 public function getInstallVersion() 598 { 599 Option::clearCachedOption(self::OPTION_NAME_MATOMO_INSTALL_VERSION); 600 $version = Option::get(self::OPTION_NAME_MATOMO_INSTALL_VERSION); 601 if (!empty($version)) { 602 return $version; 603 } 604 } 605 606 /** 607 * Truncate all tables 608 */ 609 public function truncateAllTables() 610 { 611 $tables = $this->getAllExistingTables(); 612 foreach ($tables as $table) { 613 Db::query("TRUNCATE `$table`"); 614 } 615 } 616 617 private function getTablePrefix() 618 { 619 return $this->getDbSettings()->getTablePrefix(); 620 } 621 622 private function getTableEngine() 623 { 624 return $this->getDbSettings()->getEngine(); 625 } 626 627 private function getDb() 628 { 629 return Db::get(); 630 } 631 632 private function getDbSettings() 633 { 634 return new Db\Settings(); 635 } 636 637 private function getDbName() 638 { 639 return $this->getDbSettings()->getDbName(); 640 } 641 642 private function getAllExistingTables($prefixTables = false) 643 { 644 if (empty($prefixTables)) { 645 $prefixTables = $this->getTablePrefixEscaped(); 646 } 647 648 return Db::get()->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "%'"); 649 } 650 651 private function getTablePrefixEscaped() 652 { 653 $prefixTables = $this->getTablePrefix(); 654 // '_' matches any character; force it to be literal 655 $prefixTables = str_replace('_', '\_', $prefixTables); 656 return $prefixTables; 657 } 658} 659