PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.1.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.1.2
5.13.0 5.12.1 5.12.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
657 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 INDEX index_ip_address(ip_address),
341 PRIMARY KEY(`id_brute_force_log`)
342 ) ENGINE=$engine DEFAULT CHARSET=$charset
343 ",
344
345 'tracking_failure' => "CREATE TABLE {$prefixTables}tracking_failure (
346 `idsite` BIGINT(20) UNSIGNED NOT NULL ,
347 `idfailure` SMALLINT UNSIGNED NOT NULL ,
348 `date_first_occurred` DATETIME NOT NULL ,
349 `request_url` MEDIUMTEXT NOT NULL ,
350 PRIMARY KEY(`idsite`, `idfailure`)
351 ) ENGINE=$engine DEFAULT CHARSET=$charset
352 ",
353 'locks' => "CREATE TABLE `{$prefixTables}locks` (
354 `key` VARCHAR(".Lock::MAX_KEY_LEN.") NOT NULL,
355 `value` VARCHAR(255) NULL DEFAULT NULL,
356 `expiry_time` BIGINT UNSIGNED DEFAULT 9999999999,
357 PRIMARY KEY (`key`)
358 ) ENGINE=$engine DEFAULT CHARSET=$charset
359 ",
360 );
361
362 return $tables;
363 }
364
365 /**
366 * Get the SQL to create a specific Piwik table
367 *
368 * @param string $tableName
369 * @throws Exception
370 * @return string SQL
371 */
372 public function getTableCreateSql($tableName)
373 {
374 $tables = DbHelper::getTablesCreateSql();
375
376 if (!isset($tables[$tableName])) {
377 throw new Exception("The table '$tableName' SQL creation code couldn't be found.");
378 }
379
380 return $tables[$tableName];
381 }
382
383 /**
384 * Names of all the prefixed tables in piwik
385 * Doesn't use the DB
386 *
387 * @return array Table names
388 */
389 public function getTablesNames()
390 {
391 $aTables = array_keys($this->getTablesCreateSql());
392 $prefixTables = $this->getTablePrefix();
393
394 $return = array();
395 foreach ($aTables as $table) {
396 $return[] = $prefixTables . $table;
397 }
398
399 return $return;
400 }
401
402 /**
403 * Get list of installed columns in a table
404 *
405 * @param string $tableName The name of a table.
406 *
407 * @return array Installed columns indexed by the column name.
408 */
409 public function getTableColumns($tableName)
410 {
411 $db = $this->getDb();
412
413 $allColumns = $db->fetchAll("SHOW COLUMNS FROM " . $tableName);
414
415 $fields = array();
416 foreach ($allColumns as $column) {
417 $fields[trim($column['Field'])] = $column;
418 }
419
420 return $fields;
421 }
422
423 /**
424 * Get list of tables installed (including tables defined by deactivated plugins)
425 *
426 * @param bool $forceReload Invalidate cache
427 * @return array installed Tables
428 */
429 public function getTablesInstalled($forceReload = true)
430 {
431 if (is_null($this->tablesInstalled)
432 || $forceReload === true
433 ) {
434 $db = $this->getDb();
435 $prefixTables = $this->getTablePrefixEscaped();
436
437 $allTables = $this->getAllExistingTables($prefixTables);
438
439 // all the tables to be installed
440 $allMyTables = $this->getTablesNames();
441
442 /**
443 * Triggered when detecting which tables have already been created by Matomo.
444 * This should be used by plugins to define it's database tables. Table names need to be added prefixed.
445 *
446 * **Example**
447 *
448 * Piwik::addAction('Db.getTablesInstalled', function(&$allTablesInstalled) {
449 * $allTablesInstalled = 'log_custom';
450 * });
451 * @param array $result
452 */
453 if (count($allTables)) {
454 Manager::getInstance()->loadPlugins(Manager::getAllPluginsNames());
455 Piwik::postEvent('Db.getTablesInstalled', [&$allMyTables]);
456 Manager::getInstance()->unloadPlugins();
457 Manager::getInstance()->loadActivatedPlugins();
458 }
459
460 // we get the intersection between all the tables in the DB and the tables to be installed
461 $tablesInstalled = array_intersect($allMyTables, $allTables);
462
463 // at this point we have the static list of core tables, but let's add the monthly archive tables
464 $allArchiveNumeric = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "archive_numeric%'");
465 $allArchiveBlob = $db->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "archive_blob%'");
466
467 $allTablesReallyInstalled = array_merge($tablesInstalled, $allArchiveNumeric, $allArchiveBlob);
468
469 $allTablesReallyInstalled = array_unique($allTablesReallyInstalled);
470
471 $this->tablesInstalled = $allTablesReallyInstalled;
472 }
473
474 return $this->tablesInstalled;
475 }
476
477 /**
478 * Checks whether any table exists
479 *
480 * @return bool True if tables exist; false otherwise
481 */
482 public function hasTables()
483 {
484 return count($this->getTablesInstalled()) != 0;
485 }
486
487 /**
488 * Create database
489 *
490 * @param string $dbName Name of the database to create
491 */
492 public function createDatabase($dbName = null)
493 {
494 if (is_null($dbName)) {
495 $dbName = $this->getDbName();
496 }
497
498 $dbName = str_replace('`', '', $dbName);
499 $charset = DbHelper::getDefaultCharset();
500
501 Db::exec("CREATE DATABASE IF NOT EXISTS `" . $dbName . "` DEFAULT CHARACTER SET ".$charset);
502 }
503
504 /**
505 * Creates a new table in the database.
506 *
507 * @param string $nameWithoutPrefix The name of the table without any piwik prefix.
508 * @param string $createDefinition The table create definition, see the "MySQL CREATE TABLE" specification for
509 * more information.
510 * @throws \Exception
511 */
512 public function createTable($nameWithoutPrefix, $createDefinition)
513 {
514 $dbSettings = new Db\Settings();
515 $charset = $dbSettings->getUsedCharset();
516
517 $statement = sprintf("CREATE TABLE IF NOT EXISTS `%s` ( %s ) ENGINE=%s DEFAULT CHARSET=%s ;",
518 Common::prefixTable($nameWithoutPrefix),
519 $createDefinition,
520 $this->getTableEngine(),
521 $charset);
522
523 try {
524 Db::exec($statement);
525 } catch (Exception $e) {
526 // mysql code error 1050:table already exists
527 // see bug #153 https://github.com/piwik/piwik/issues/153
528 if (!$this->getDb()->isErrNo($e, '1050')) {
529 throw $e;
530 }
531 }
532 }
533
534 /**
535 * Drop database
536 */
537 public function dropDatabase($dbName = null)
538 {
539 $dbName = $dbName ?: $this->getDbName();
540 $dbName = str_replace('`', '', $dbName);
541 Db::exec("DROP DATABASE IF EXISTS `" . $dbName . "`");
542 }
543
544 /**
545 * Create all tables
546 */
547 public function createTables()
548 {
549 $db = $this->getDb();
550 $prefixTables = $this->getTablePrefix();
551
552 $tablesAlreadyInstalled = $this->getAllExistingTables($prefixTables);
553 $tablesToCreate = $this->getTablesCreateSql();
554 unset($tablesToCreate['archive_blob']);
555 unset($tablesToCreate['archive_numeric']);
556
557 foreach ($tablesToCreate as $tableName => $tableSql) {
558 $tableName = $prefixTables . $tableName;
559 if (!in_array($tableName, $tablesAlreadyInstalled)) {
560 $db->query($tableSql);
561 }
562 }
563 }
564
565 /**
566 * Creates an entry in the User table for the "anonymous" user.
567 */
568 public function createAnonymousUser()
569 {
570 $now = Date::factory('now')->getDatetime();
571 // The anonymous user is the user that is assigned by default
572 // note that the token_auth value is anonymous, which is assigned by default as well in the Login plugin
573 $db = $this->getDb();
574 $db->query("INSERT IGNORE INTO " . Common::prefixTable("user") . "
575 (`login`, `password`, `email`, `twofactor_secret`, `superuser_access`, `date_registered`, `ts_password_modified`)
576 VALUES ( 'anonymous', '', 'anonymous@example.org', '', 0, '$now', '$now' );");
577
578 $model = new Model();
579 $model->addTokenAuth('anonymous', 'anonymous', 'anonymous default token', $now);
580 }
581
582 /**
583 * Records the Matomo version a user used when installing this Matomo for the first time
584 */
585 public function recordInstallVersion()
586 {
587 if (!self::getInstallVersion()) {
588 Option::set(self::OPTION_NAME_MATOMO_INSTALL_VERSION, Version::VERSION);
589 }
590 }
591
592 /**
593 * Returns which Matomo version was used to install this Matomo for the first time.
594 */
595 public function getInstallVersion()
596 {
597 Option::clearCachedOption(self::OPTION_NAME_MATOMO_INSTALL_VERSION);
598 $version = Option::get(self::OPTION_NAME_MATOMO_INSTALL_VERSION);
599 if (!empty($version)) {
600 return $version;
601 }
602 }
603
604 /**
605 * Truncate all tables
606 */
607 public function truncateAllTables()
608 {
609 $tables = $this->getAllExistingTables();
610 foreach ($tables as $table) {
611 Db::query("TRUNCATE `$table`");
612 }
613 }
614
615 private function getTablePrefix()
616 {
617 return $this->getDbSettings()->getTablePrefix();
618 }
619
620 private function getTableEngine()
621 {
622 return $this->getDbSettings()->getEngine();
623 }
624
625 private function getDb()
626 {
627 return Db::get();
628 }
629
630 private function getDbSettings()
631 {
632 return new Db\Settings();
633 }
634
635 private function getDbName()
636 {
637 return $this->getDbSettings()->getDbName();
638 }
639
640 private function getAllExistingTables($prefixTables = false)
641 {
642 if (empty($prefixTables)) {
643 $prefixTables = $this->getTablePrefixEscaped();
644 }
645
646 return Db::get()->fetchCol("SHOW TABLES LIKE '" . $prefixTables . "%'");
647 }
648
649 private function getTablePrefixEscaped()
650 {
651 $prefixTables = $this->getTablePrefix();
652 // '_' matches any character; force it to be literal
653 $prefixTables = str_replace('_', '\_', $prefixTables);
654 return $prefixTables;
655 }
656 }
657