PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Db / Schema / Mysql.php
matomo / app / core / Db / Schema Last commit date
Mysql.php 5 years ago
Mysql.php
658 lines
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 */
9 namespace Piwik\Db\Schema;
10
11 use Exception;
12 use Piwik\Common;
13 use Piwik\Concurrency\Lock;
14 use Piwik\Date;
15 use Piwik\Db\SchemaInterface;
16 use Piwik\Db;
17 use Piwik\DbHelper;
18 use Piwik\Option;
19 use Piwik\Piwik;
20 use Piwik\Plugin\Manager;
21 use Piwik\Plugins\UsersManager\Model;
22 use Piwik\Version;
23
24 /**
25 * MySQL schema
26 */
27 class 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 TEXT,
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)) {
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 ;",
519 Common::prefixTable($nameWithoutPrefix),
520 $createDefinition,
521 $this->getTableEngine(),
522 $charset);
523
524 try {
525 Db::exec($statement);
526 } catch (Exception $e) {
527 // mysql code error 1050:table already exists
528 // see bug #153 https://github.com/piwik/piwik/issues/153
529 if (!$this->getDb()->isErrNo($e, '1050')) {
530 throw $e;
531 }
532 }
533 }
534
535 /**
536 * Drop database
537 */
538 public function dropDatabase($dbName = null)
539 {
540 $dbName = $dbName ?: $this->getDbName();
541 $dbName = str_replace('`', '', $dbName);
542 Db::exec("DROP DATABASE IF EXISTS `" . $dbName . "`");
543 }
544
545 /**
546 * Create all tables
547 */
548 public function createTables()
549 {
550 $db = $this->getDb();
551 $prefixTables = $this->getTablePrefix();
552
553 $tablesAlreadyInstalled = $this->getAllExistingTables($prefixTables);
554 $tablesToCreate = $this->getTablesCreateSql();
555 unset($tablesToCreate['archive_blob']);
556 unset($tablesToCreate['archive_numeric']);
557
558 foreach ($tablesToCreate as $tableName => $tableSql) {
559 $tableName = $prefixTables . $tableName;
560 if (!in_array($tableName, $tablesAlreadyInstalled)) {
561 $db->query($tableSql);
562 }
563 }
564 }
565
566 /**
567 * Creates an entry in the User table for the "anonymous" user.
568 */
569 public function createAnonymousUser()
570 {
571 $now = Date::factory('now')->getDatetime();
572 // The anonymous user is the user that is assigned by default
573 // note that the token_auth value is anonymous, which is assigned by default as well in the Login plugin
574 $db = $this->getDb();
575 $db->query("INSERT IGNORE INTO " . Common::prefixTable("user") . "
576 (`login`, `password`, `email`, `twofactor_secret`, `superuser_access`, `date_registered`, `ts_password_modified`)
577 VALUES ( 'anonymous', '', 'anonymous@example.org', '', 0, '$now', '$now' );");
578
579 $model = new Model();
580 $model->addTokenAuth('anonymous', 'anonymous', 'anonymous default token', $now);
581 }
582
583 /**
584 * Records the Matomo version a user used when installing this Matomo for the first time
585 */
586 public function recordInstallVersion()
587 {
588 if (!self::getInstallVersion()) {
589 Option::set(self::OPTION_NAME_MATOMO_INSTALL_VERSION, Version::VERSION);
590 }
591 }
592
593 /**
594 * Returns which Matomo version was used to install this Matomo for the first time.
595 */
596 public function getInstallVersion()
597 {
598 Option::clearCachedOption(self::OPTION_NAME_MATOMO_INSTALL_VERSION);
599 $version = Option::get(self::OPTION_NAME_MATOMO_INSTALL_VERSION);
600 if (!empty($version)) {
601 return $version;
602 }
603 }
604
605 /**
606 * Truncate all tables
607 */
608 public function truncateAllTables()
609 {
610 $tables = $this->getAllExistingTables();
611 foreach ($tables as $table) {
612 Db::query("TRUNCATE `$table`");
613 }
614 }
615
616 private function getTablePrefix()
617 {
618 return $this->getDbSettings()->getTablePrefix();
619 }
620
621 private function getTableEngine()
622 {
623 return $this->getDbSettings()->getEngine();
624 }
625
626 private function getDb()
627 {
628 return Db::get();
629 }
630
631 private function getDbSettings()
632 {
633 return new Db\Settings();
634 }
635
636 private function getDbName()
637 {
638 return $this->getDbSettings()->getDbName();
639 }
640
641 private function getAllExistingTables($prefixTables = false)
642 {
643 if (empty($prefixTables)) {
644 $prefixTables = $this->getTablePrefixEscaped();
645 }
646
647 return Db::get()->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "%'");
648 }
649
650 private function getTablePrefixEscaped()
651 {
652 $prefixTables = $this->getTablePrefix();
653 // '_' matches any character; force it to be literal
654 $prefixTables = str_replace('_', '\_', $prefixTables);
655 return $prefixTables;
656 }
657 }
658