Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rwxr-xr-xconfig/global.ini.php2
-rw-r--r--core/DataAccess/ArchiveTableCreator.php10
-rw-r--r--core/DataAccess/Model.php8
-rw-r--r--core/Db/Adapter/Mysqli.php2
-rw-r--r--core/Db/Adapter/Pdo/Mysql.php2
-rw-r--r--core/Db/Adapter/Pdo/Pgsql.php2
-rw-r--r--core/Db/Schema/Mysql.php101
-rw-r--r--core/Db/Settings.php16
-rw-r--r--core/DbHelper.php49
-rw-r--r--core/Option.php18
-rw-r--r--core/Tracker/Request.php11
-rw-r--r--core/Updater/Migration/Config/Factory.php48
-rw-r--r--core/Updater/Migration/Config/Set.php56
-rw-r--r--core/Updater/Migration/Factory.php9
-rw-r--r--core/Updates/4.0.0-b1.php31
-rw-r--r--plugins/CoreUpdater/Commands/ConvertToUtf8mb4.php141
-rw-r--r--plugins/CoreUpdater/SystemSettings.php26
-rw-r--r--plugins/CoreUpdater/Tasks.php28
-rw-r--r--plugins/CoreUpdater/lang/en.json5
m---------plugins/CustomAlerts0
m---------plugins/CustomDimensions0
-rw-r--r--plugins/DBStats/tests/UI/expected-screenshots/DBStats_admin_page.png4
-rw-r--r--plugins/Dashboard/Dashboard.php13
-rw-r--r--plugins/Diagnostics/Diagnostic/DatabaseAbilitiesCheck.php31
-rw-r--r--plugins/Diagnostics/lang/en.json3
-rw-r--r--plugins/Diagnostics/tests/UI/expected-screenshots/Diagnostics_page.png4
-rw-r--r--plugins/ExampleLogTables/Dao/CustomUserLog.php2
-rw-r--r--plugins/ExampleLogTables/ExampleLogTables.php19
-rw-r--r--plugins/Installation/Controller.php4
-rw-r--r--plugins/LanguagesManager/LanguagesManager.php13
-rw-r--r--plugins/PrivacyManager/PrivacyManager.php16
m---------plugins/QueuedTracking0
-rw-r--r--plugins/ScheduledReports/ScheduledReports.php12
-rw-r--r--plugins/SegmentEditor/SegmentEditor.php15
m---------plugins/TagManager0
-rw-r--r--tests/PHPUnit/Integration/Tracker/RequestTest.php15
-rw-r--r--tests/PHPUnit/Integration/Updater/Migration/FactoryTest.php8
-rw-r--r--tests/PHPUnit/System/BackwardsCompatibility1XTest.php11
-rw-r--r--tests/PHPUnit/System/UrlNormalizationTest.php2
-rw-r--r--tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmentedRef__Actions.getPageUrls_day.xml6
-rw-r--r--tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmented__Actions.getPageUrls_day.xml6
-rw-r--r--tests/PHPUnit/System/expected/test_UrlNormalization_urls__Actions.getPageUrls_day.xml6
-rw-r--r--tests/PHPUnit/System/expected/test_Utf8mb4__Live.getLastVisitsDetails_year.xml22
-rw-r--r--tests/PHPUnit/Unit/DataAccess/ArchiveTableCreatorTest.php6
45 files changed, 670 insertions, 114 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e232b6398..f9a4f6d090 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -60,6 +60,7 @@ The Product Changelog at **[matomo.org/changelog](https://matomo.org/changelog)*
* Zend_Mail has been removed. `Piwik\Mail` is now an independet class.
* PHPMailer is now used for sending mails in `\Piwik\Mail\Transport` and can be replaced using DI.
* Various methods in `Piwik\Mail` have been removed or changed their signature.
+* Added new event `Db.getTablesInstalled`, plugins should use to register the tables they create.
## Matomo 3.13.5
diff --git a/config/global.ini.php b/config/global.ini.php
index 8a76434ca8..0097c19187 100755
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -67,7 +67,7 @@ port = 3306
adapter = PDO\MYSQL
type = InnoDB
schema = Mysql
-charset = utf8
+charset = utf8mb4
enable_ssl = 0
ssl_ca =
ssl_cert =
diff --git a/core/DataAccess/ArchiveTableCreator.php b/core/DataAccess/ArchiveTableCreator.php
index 2ab74db2cc..98225673d2 100644
--- a/core/DataAccess/ArchiveTableCreator.php
+++ b/core/DataAccess/ArchiveTableCreator.php
@@ -11,7 +11,6 @@ namespace Piwik\DataAccess;
use Piwik\Common;
use Piwik\Date;
-use Piwik\DbHelper;
class ArchiveTableCreator
{
@@ -63,15 +62,16 @@ class ArchiveTableCreator
self::$tablesAlreadyInstalled = null;
}
- public static function refreshTableList($forceReload = false)
+ public static function refreshTableList()
{
- self::$tablesAlreadyInstalled = DbHelper::getTablesInstalled($forceReload);
+ self::$tablesAlreadyInstalled = self::getModel()->getInstalledArchiveTables();
}
/**
* Returns all table names archive_*
*
* @param string $type The type of table to return. Either `self::NUMERIC_TABLE` or `self::BLOB_TABLE`.
+ * @param bool $forceReload
* @return array
*/
public static function getTablesArchivesInstalled($type = null, $forceReload = false)
@@ -79,11 +79,11 @@ class ArchiveTableCreator
if (is_null(self::$tablesAlreadyInstalled)
|| $forceReload
) {
- self::refreshTableList($forceReload);
+ self::refreshTableList();
}
if (empty($type)) {
- $tableMatchRegex = '/archive_(numeric|blob)_/';
+ return self::$tablesAlreadyInstalled;
} else {
$tableMatchRegex = '/archive_' . preg_quote($type) . '_/';
}
diff --git a/core/DataAccess/Model.php b/core/DataAccess/Model.php
index 20bf53a129..47e69431c8 100644
--- a/core/DataAccess/Model.php
+++ b/core/DataAccess/Model.php
@@ -382,6 +382,14 @@ class Model
}
}
+ public function getInstalledArchiveTables()
+ {
+ $allArchiveNumeric = Db::get()->fetchCol("SHOW TABLES LIKE '" . Common::prefixTable('archive_numeric%') . "'");
+ $allArchiveBlob = Db::get()->fetchCol("SHOW TABLES LIKE '" . Common::prefixTable('archive_blob%') ."'");
+
+ return array_merge($allArchiveBlob, $allArchiveNumeric);
+ }
+
public function allocateNewArchiveId($numericTable)
{
$sequence = new Sequence($numericTable);
diff --git a/core/Db/Adapter/Mysqli.php b/core/Db/Adapter/Mysqli.php
index a34b38433f..a47f5bb4eb 100644
--- a/core/Db/Adapter/Mysqli.php
+++ b/core/Db/Adapter/Mysqli.php
@@ -234,7 +234,7 @@ class Mysqli extends Zend_Db_Adapter_Mysqli implements AdapterInterface
public function isConnectionUTF8()
{
$charset = mysqli_character_set_name($this->_connection);
- return $charset === 'utf8';
+ return strpos($charset, 'utf8') === 0;
}
/**
diff --git a/core/Db/Adapter/Pdo/Mysql.php b/core/Db/Adapter/Pdo/Mysql.php
index 18e6db18c1..6127276419 100644
--- a/core/Db/Adapter/Pdo/Mysql.php
+++ b/core/Db/Adapter/Pdo/Mysql.php
@@ -243,7 +243,7 @@ class Mysql extends Zend_Db_Adapter_Pdo_Mysql implements AdapterInterface
}
$charset = $charsetInfo[0]['Value'];
- return $charset === 'utf8';
+ return strpos($charset, 'utf8') === 0;
}
/**
diff --git a/core/Db/Adapter/Pdo/Pgsql.php b/core/Db/Adapter/Pdo/Pgsql.php
index 2976533390..ac9f527f47 100644
--- a/core/Db/Adapter/Pdo/Pgsql.php
+++ b/core/Db/Adapter/Pdo/Pgsql.php
@@ -158,7 +158,7 @@ class Pgsql extends Zend_Db_Adapter_Pdo_Pgsql implements AdapterInterface
public function isConnectionUTF8()
{
$charset = $this->fetchOne('SHOW client_encoding');
- return strtolower($charset) === 'utf8';
+ return strpos(strtolower($charset), 'utf8') === 0;
}
/**
diff --git a/core/Db/Schema/Mysql.php b/core/Db/Schema/Mysql.php
index e26d0e68f8..bcb1b60627 100644
--- a/core/Db/Schema/Mysql.php
+++ b/core/Db/Schema/Mysql.php
@@ -16,6 +16,8 @@ use Piwik\Db\SchemaInterface;
use Piwik\Db;
use Piwik\DbHelper;
use Piwik\Option;
+use Piwik\Piwik;
+use Piwik\Plugin\Manager;
use Piwik\Plugins\UsersManager\Model;
use Piwik\Version;
@@ -38,6 +40,8 @@ class Mysql implements SchemaInterface
{
$engine = $this->getTableEngine();
$prefixTables = $this->getTablePrefix();
+ $dbSettings = new Db\Settings();
+ $charset = $dbSettings->getUsedCharset();
$tables = array(
'user' => "CREATE TABLE {$prefixTables}user (
@@ -49,13 +53,13 @@ class Mysql implements SchemaInterface
date_registered TIMESTAMP NULL,
ts_password_modified TIMESTAMP NULL,
PRIMARY KEY(login)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'user_token_auth' => "CREATE TABLE {$prefixTables}user_token_auth (
idusertokenauth BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
login VARCHAR(100) NOT NULL,
description VARCHAR(".Model::MAX_LENGTH_TOKEN_DESCRIPTION.") NOT NULL,
- password VARCHAR(255) NOT NULL,
+ password VARCHAR(191) NOT NULL,
hash_algo VARCHAR(30) NOT NULL,
system_token TINYINT(1) NOT NULL DEFAULT 0,
last_used DATETIME NULL,
@@ -63,7 +67,7 @@ class Mysql implements SchemaInterface
date_expired DATETIME NULL,
PRIMARY KEY(idusertokenauth),
UNIQUE KEY uniq_password(password)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'twofactor_recovery_code' => "CREATE TABLE {$prefixTables}twofactor_recovery_code (
@@ -71,7 +75,7 @@ class Mysql implements SchemaInterface
login VARCHAR(100) NOT NULL,
recovery_code VARCHAR(40) NOT NULL,
PRIMARY KEY(idrecoverycode)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'access' => "CREATE TABLE {$prefixTables}access (
@@ -81,7 +85,7 @@ class Mysql implements SchemaInterface
access VARCHAR(50) NULL,
PRIMARY KEY(idaccess),
INDEX index_loginidsite (login, idsite)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'site' => "CREATE TABLE {$prefixTables}site (
@@ -104,7 +108,7 @@ class Mysql implements SchemaInterface
keep_url_fragment TINYINT NOT NULL DEFAULT 0,
creator_login VARCHAR(100) NULL,
PRIMARY KEY(idsite)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'plugin_setting' => "CREATE TABLE {$prefixTables}plugin_setting (
@@ -116,7 +120,7 @@ class Mysql implements SchemaInterface
`idplugin_setting` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (idplugin_setting),
INDEX(plugin_name, user_login)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'site_setting' => "CREATE TABLE {$prefixTables}site_setting (
@@ -128,14 +132,14 @@ class Mysql implements SchemaInterface
`idsite_setting` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (idsite_setting),
INDEX(idsite, plugin_name)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'site_url' => "CREATE TABLE {$prefixTables}site_url (
idsite INTEGER(10) UNSIGNED NOT NULL,
- url VARCHAR(255) NOT NULL,
+ url VARCHAR(190) NOT NULL,
PRIMARY KEY(idsite, url)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'goal' => "CREATE TABLE `{$prefixTables}goal` (
@@ -152,7 +156,7 @@ class Mysql implements SchemaInterface
`deleted` tinyint(4) NOT NULL default '0',
`event_value_as_revenue` tinyint(4) NOT NULL default '0',
PRIMARY KEY (`idsite`,`idgoal`)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'logger_message' => "CREATE TABLE {$prefixTables}logger_message (
@@ -162,7 +166,7 @@ class Mysql implements SchemaInterface
level VARCHAR(16) NULL,
message TEXT NULL,
PRIMARY KEY(idlogger_message)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'log_action' => "CREATE TABLE {$prefixTables}log_action (
@@ -173,7 +177,7 @@ class Mysql implements SchemaInterface
url_prefix TINYINT(2) NULL,
PRIMARY KEY(idaction),
INDEX index_type_hash (type, hash)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'log_visit' => "CREATE TABLE {$prefixTables}log_visit (
@@ -187,7 +191,7 @@ class Mysql implements SchemaInterface
INDEX index_idsite_config_datetime (idsite, config_id, visit_last_action_time),
INDEX index_idsite_datetime (idsite, visit_last_action_time),
INDEX index_idsite_idvisitor (idsite, idvisitor)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'log_conversion_item' => "CREATE TABLE `{$prefixTables}log_conversion_item` (
@@ -208,7 +212,7 @@ class Mysql implements SchemaInterface
deleted TINYINT(1) UNSIGNED NOT NULL,
PRIMARY KEY(idvisit, idorder, idaction_sku),
INDEX index_idsite_servertime ( idsite, server_time )
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'log_conversion' => "CREATE TABLE `{$prefixTables}log_conversion` (
@@ -226,7 +230,7 @@ class Mysql implements SchemaInterface
PRIMARY KEY (idvisit, idgoal, buster),
UNIQUE KEY unique_idsite_idorder (idsite, idorder),
INDEX index_idsite_datetime ( idsite, server_time )
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'log_link_visit_action' => "CREATE TABLE {$prefixTables}log_link_visit_action (
@@ -239,7 +243,7 @@ class Mysql implements SchemaInterface
custom_float DOUBLE NULL DEFAULT NULL,
PRIMARY KEY(idlink_va),
INDEX index_idvisit(idvisit)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'log_profiling' => "CREATE TABLE {$prefixTables}log_profiling (
@@ -249,30 +253,30 @@ class Mysql implements SchemaInterface
idprofiling BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (idprofiling),
UNIQUE KEY query(query(100))
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'option' => "CREATE TABLE `{$prefixTables}option` (
- option_name VARCHAR( 255 ) NOT NULL,
+ option_name VARCHAR( 191 ) NOT NULL,
option_value LONGTEXT NOT NULL,
autoload TINYINT NOT NULL DEFAULT '1',
PRIMARY KEY ( option_name ),
INDEX autoload( autoload )
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'session' => "CREATE TABLE {$prefixTables}session (
- id VARCHAR( 255 ) NOT NULL,
+ id VARCHAR( 191 ) NOT NULL,
modified INTEGER,
lifetime INTEGER,
data TEXT,
PRIMARY KEY ( id )
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'archive_numeric' => "CREATE TABLE {$prefixTables}archive_numeric (
idarchive INTEGER UNSIGNED NOT NULL,
- name VARCHAR(255) NOT NULL,
+ name VARCHAR(190) NOT NULL,
idsite INTEGER UNSIGNED NULL,
date1 DATE NULL,
date2 DATE NULL,
@@ -282,12 +286,12 @@ class Mysql implements SchemaInterface
PRIMARY KEY(idarchive, name),
INDEX index_idsite_dates_period(idsite, date1, date2, period, ts_archived),
INDEX index_period_archived(period, ts_archived)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'archive_blob' => "CREATE TABLE {$prefixTables}archive_blob (
idarchive INTEGER UNSIGNED NOT NULL,
- name VARCHAR(255) NOT NULL,
+ name VARCHAR(190) NOT NULL,
idsite INTEGER UNSIGNED NULL,
date1 DATE NULL,
date2 DATE NULL,
@@ -296,7 +300,7 @@ class Mysql implements SchemaInterface
value MEDIUMBLOB NULL,
PRIMARY KEY(idarchive, name),
INDEX index_period_archived(period, ts_archived)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'archive_invalidations' => "CREATE TABLE `{$prefixTables}archive_invalidations` (
@@ -311,14 +315,14 @@ class Mysql implements SchemaInterface
status TINYINT(1) UNSIGNED DEFAULT 0,
PRIMARY KEY(idinvalidation),
INDEX index_idsite_dates_period_name(idsite, date1, period, name)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'sequence' => "CREATE TABLE {$prefixTables}sequence (
`name` VARCHAR(120) NOT NULL,
`value` BIGINT(20) UNSIGNED NOT NULL ,
PRIMARY KEY(`name`)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'brute_force_log' => "CREATE TABLE {$prefixTables}brute_force_log (
@@ -327,7 +331,7 @@ class Mysql implements SchemaInterface
`attempted_at` datetime NOT NULL,
INDEX index_ip_address(ip_address),
PRIMARY KEY(`id_brute_force_log`)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'tracking_failure' => "CREATE TABLE {$prefixTables}tracking_failure (
@@ -336,14 +340,14 @@ class Mysql implements SchemaInterface
`date_first_occurred` DATETIME NOT NULL ,
`request_url` MEDIUMTEXT NOT NULL ,
PRIMARY KEY(`idsite`, `idfailure`)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
'locks' => "CREATE TABLE `{$prefixTables}locks` (
`key` VARCHAR(".Lock::MAX_KEY_LEN.") NOT NULL,
`value` VARCHAR(255) NULL DEFAULT NULL,
`expiry_time` BIGINT UNSIGNED DEFAULT 9999999999,
PRIMARY KEY (`key`)
- ) ENGINE=$engine DEFAULT CHARSET=utf8
+ ) ENGINE=$engine DEFAULT CHARSET=$charset
",
);
@@ -409,7 +413,7 @@ class Mysql implements SchemaInterface
}
/**
- * Get list of tables installed
+ * Get list of tables installed (including tables defined by deactivated plugins)
*
* @param bool $forceReload Invalidate cache
* @return array installed Tables
@@ -427,6 +431,24 @@ class Mysql implements SchemaInterface
// all the tables to be installed
$allMyTables = $this->getTablesNames();
+ /**
+ * Triggered when detecting which tables have already been created by Matomo.
+ * This should be used by plugins to define it's database tables. Table names need to be added prefixed.
+ *
+ * **Example**
+ *
+ * Piwik::addAction('Db.getTablesInstalled', function(&$allTablesInstalled) {
+ * $allTablesInstalled = 'log_custom';
+ * });
+ * @param array $result
+ */
+ if (count($allTables)) {
+ Manager::getInstance()->loadPlugins(Manager::getAllPluginsNames());
+ Piwik::postEvent('Db.getTablesInstalled', [&$allMyTables]);
+ Manager::getInstance()->unloadPlugins();
+ Manager::getInstance()->loadActivatedPlugins();
+ }
+
// we get the intersection between all the tables in the DB and the tables to be installed
$tablesInstalled = array_intersect($allMyTables, $allTables);
@@ -436,6 +458,8 @@ class Mysql implements SchemaInterface
$allTablesReallyInstalled = array_merge($tablesInstalled, $allArchiveNumeric, $allArchiveBlob);
+ $allTablesReallyInstalled = array_unique($allTablesReallyInstalled);
+
$this->tablesInstalled = $allTablesReallyInstalled;
}
@@ -464,8 +488,9 @@ class Mysql implements SchemaInterface
}
$dbName = str_replace('`', '', $dbName);
+ $charset = DbHelper::getDefaultCharset();
- Db::exec("CREATE DATABASE IF NOT EXISTS `" . $dbName . "` DEFAULT CHARACTER SET utf8");
+ Db::exec("CREATE DATABASE IF NOT EXISTS `" . $dbName . "` DEFAULT CHARACTER SET ".$charset);
}
/**
@@ -478,10 +503,14 @@ class Mysql implements SchemaInterface
*/
public function createTable($nameWithoutPrefix, $createDefinition)
{
- $statement = sprintf("CREATE TABLE IF NOT EXISTS `%s` ( %s ) ENGINE=%s DEFAULT CHARSET=utf8 ;",
+ $dbSettings = new Db\Settings();
+ $charset = $dbSettings->getUsedCharset();
+
+ $statement = sprintf("CREATE TABLE IF NOT EXISTS `%s` ( %s ) ENGINE=%s DEFAULT CHARSET=%s ;",
Common::prefixTable($nameWithoutPrefix),
$createDefinition,
- $this->getTableEngine());
+ $this->getTableEngine(),
+ $charset);
try {
Db::exec($statement);
@@ -512,7 +541,7 @@ class Mysql implements SchemaInterface
$db = $this->getDb();
$prefixTables = $this->getTablePrefix();
- $tablesAlreadyInstalled = $this->getTablesInstalled();
+ $tablesAlreadyInstalled = $this->getAllExistingTables($prefixTables);
$tablesToCreate = $this->getTablesCreateSql();
unset($tablesToCreate['archive_blob']);
unset($tablesToCreate['archive_numeric']);
diff --git a/core/Db/Settings.php b/core/Db/Settings.php
index dfdbb7ae6d..f931249bb1 100644
--- a/core/Db/Settings.php
+++ b/core/Db/Settings.php
@@ -10,13 +10,6 @@ namespace Piwik\Db;
use Piwik\Db;
-/**
- * Schema abstraction
- *
- * Note: no relation to the ZF proposals for Zend_Db_Schema_Manager
- *
- * @method static \Piwik\Db\Schema getInstance()
- */
class Settings
{
public function getEngine()
@@ -34,11 +27,14 @@ class Settings
return $this->getDbSetting('dbname');
}
+ public function getUsedCharset()
+ {
+ return strtolower($this->getDbSetting('charset'));
+ }
+
private function getDbSetting($key)
{
$dbInfos = Db::getDatabaseConfig();
- $engine = $dbInfos[$key];
-
- return $engine;
+ return $dbInfos[$key];
}
}
diff --git a/core/DbHelper.php b/core/DbHelper.php
index 4d93ea43f3..e025db4a1a 100644
--- a/core/DbHelper.php
+++ b/core/DbHelper.php
@@ -205,6 +205,55 @@ class DbHelper
}
/**
+ * Returns the default database charset to use
+ *
+ * Returns utf8mb4 if supported, with fallback to utf8
+ *
+ * @return string
+ * @throws Tracker\Db\DbException
+ */
+ public static function getDefaultCharset()
+ {
+ $result = Db::get()->fetchRow("SHOW CHARACTER SET LIKE 'utf8mb4'");
+
+ if (empty($result)) {
+ return 'utf8'; // charset not available
+ }
+
+ $result = Db::get()->fetchRow("SHOW VARIABLES LIKE 'character_set_database'");
+
+ if (!empty($result) && $result['Value'] === 'utf8mb4') {
+ return 'utf8mb4'; // database has utf8mb4 charset, so assume it can be used
+ }
+
+ $result = Db::get()->fetchRow("SHOW VARIABLES LIKE 'innodb_file_per_table'");
+
+ if (empty($result) || $result['Value'] !== 'ON') {
+ return 'utf8'; // innodb_file_per_table is required for utf8mb4
+ }
+
+ return 'utf8mb4';
+ }
+
+ /**
+ * Returns sql queries to convert all installed tables to utf8mb4
+ *
+ * @return array
+ */
+ public static function getUtf8mb4ConversionQueries()
+ {
+ $allTables = DbHelper::getTablesInstalled();
+
+ $queries = [];
+
+ foreach ($allTables as $table) {
+ $queries[] = "ALTER TABLE `$table` CONVERT TO CHARACTER SET utf8mb4;";
+ }
+
+ return $queries;
+ }
+
+ /**
* Get the SQL to create Piwik tables
*
* @return array array of strings containing SQL
diff --git a/core/Option.php b/core/Option.php
index d342f678ba..be6bdef8f4 100644
--- a/core/Option.php
+++ b/core/Option.php
@@ -8,6 +8,8 @@
*/
namespace Piwik;
+use Piwik\Container\StaticContainer;
+
/**
* Convenient key-value storage for user specified options and temporary
* data that needs to be persisted beyond one request.
@@ -163,6 +165,7 @@ class Option
protected function clearCachedOptionByName($name)
{
+ $name = $this->trimOptionNameIfNeeded($name);
if (isset($this->all[$name])) {
unset($this->all[$name]);
}
@@ -170,6 +173,7 @@ class Option
protected function getValue($name)
{
+ $name = $this->trimOptionNameIfNeeded($name);
$this->autoload();
if (isset($this->all[$name])) {
return $this->all[$name];
@@ -185,6 +189,7 @@ class Option
protected function setValue($name, $value, $autoLoad = 0)
{
$autoLoad = (int)$autoLoad;
+ $name = $this->trimOptionNameIfNeeded($name);
$sql = 'UPDATE `' . Common::prefixTable('option') . '` SET option_value = ?, autoload = ? WHERE option_name = ?';
$bind = array($value, $autoLoad, $name);
@@ -209,6 +214,7 @@ class Option
protected function deleteValue($name, $value)
{
+ $name = $this->trimOptionNameIfNeeded($name);
$sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name = ?';
$bind[] = $name;
@@ -224,6 +230,7 @@ class Option
protected function deleteNameLike($name, $value = null)
{
+ $name = $this->trimOptionNameIfNeeded($name);
$sql = 'DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?';
$bind[] = $name;
@@ -239,6 +246,7 @@ class Option
protected function getNameLike($name)
{
+ $name = $this->trimOptionNameIfNeeded($name);
$sql = 'SELECT option_name, option_value FROM `' . Common::prefixTable('option') . '` WHERE option_name LIKE ?';
$bind = array($name);
$rows = Db::fetchAll($sql, $bind);
@@ -272,4 +280,14 @@ class Option
$this->loaded = true;
}
+
+ private function trimOptionNameIfNeeded($name)
+ {
+ if (strlen($name) > 191) {
+ StaticContainer::get('Psr\Log\LoggerInterface')->debug("Option name '$name' is too long and was trimmed to 191 chars");
+ $name = substr($name, 0, 191);
+ }
+
+ return $name;
+ }
}
diff --git a/core/Tracker/Request.php b/core/Tracker/Request.php
index 48fecc103b..77c5795804 100644
--- a/core/Tracker/Request.php
+++ b/core/Tracker/Request.php
@@ -13,6 +13,7 @@ use Piwik\Common;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\Cookie;
+use Piwik\DbHelper;
use Piwik\Exception\InvalidRequestParameterException;
use Piwik\Exception\UnexpectedWebsiteFoundException;
use Piwik\IP;
@@ -87,13 +88,19 @@ class Request
}
}
- // check for 4byte utf8 characters in all tracking params and replace them with �
- // @TODO Remove as soon as our database tables use utf8mb4 instead of utf8
+ // check for 4byte utf8 characters in all tracking params and replace them with � if not support by database
$this->params = $this->replaceUnsupportedUtf8Chars($this->params);
}
protected function replaceUnsupportedUtf8Chars($value, $key=false)
{
+ $dbSettings = new \Piwik\Db\Settings();
+ $charset = $dbSettings->getUsedCharset();
+
+ if ('utf8mb4' === $charset) {
+ return $value; // no need to replace anything if utf8mb4 is supported
+ }
+
if (is_string($value) && preg_match('/[\x{10000}-\x{10FFFF}]/u', $value)) {
Common::printDebug("Unsupported character detected in $key. Replacing with \xEF\xBF\xBD");
return preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $value);
diff --git a/core/Updater/Migration/Config/Factory.php b/core/Updater/Migration/Config/Factory.php
new file mode 100644
index 0000000000..9db3f2e59d
--- /dev/null
+++ b/core/Updater/Migration/Config/Factory.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Updater\Migration\Config;
+
+use Piwik\Container\StaticContainer;
+
+/**
+ * Provides config migrations.
+ *
+ * @api
+ */
+class Factory
+{
+ /**
+ * @var \DI\Container
+ */
+ private $container;
+
+ /**
+ * @ignore
+ */
+ public function __construct()
+ {
+ $this->container = StaticContainer::getContainer();
+ }
+
+ /**
+ * Sets a configuration to the Matomo config file
+ *
+ * @param string $section
+ * @param string $key
+ * @param string $value
+ * @return Set
+ */
+ public function set($section, $key, $value)
+ {
+ return $this->container->make('Piwik\Updater\Migration\Config\Set', array(
+ 'section' => $section,
+ 'key' => $key,
+ 'value' => $value,
+ ));
+ }
+}
diff --git a/core/Updater/Migration/Config/Set.php b/core/Updater/Migration/Config/Set.php
new file mode 100644
index 0000000000..d3f547bb3e
--- /dev/null
+++ b/core/Updater/Migration/Config/Set.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+namespace Piwik\Updater\Migration\Config;
+
+use Piwik\Config;
+use Piwik\Updater\Migration;
+
+/**
+ * Sets the given configuration to Matomo config value
+ */
+class Set extends Migration
+{
+ /**
+ * @var string
+ */
+ private $section;
+
+ /**
+ * @var string
+ */
+ private $key;
+
+ /**
+ * @var string
+ */
+ private $value;
+
+
+ public function __construct($section, $key, $value)
+ {
+ $this->section = $section;
+ $this->key = $key;
+ $this->value = $value;
+ }
+
+ public function __toString()
+ {
+ $domain = Config::getLocalConfigPath() == Config::getDefaultLocalConfigPath() ? '' : Config::getHostname();
+ $domainArg = !empty($domain) ? "--matomo-domain=\"$domain\" " : '';
+
+ return sprintf('./console %sconfig:set --section="%s" --key="%s" --value="%s"', $domainArg, $this->section, $this->key, $this->value);
+ }
+
+ public function exec()
+ {
+ $config = Config::getInstance();
+ $config->{$this->section}[$this->key] = $this->value;
+ $config->forceSave();
+ }
+
+}
diff --git a/core/Updater/Migration/Factory.php b/core/Updater/Migration/Factory.php
index b95ebfae29..4859198006 100644
--- a/core/Updater/Migration/Factory.php
+++ b/core/Updater/Migration/Factory.php
@@ -9,6 +9,7 @@ namespace Piwik\Updater\Migration;
use Piwik\Updater\Migration\Db\Factory as DbFactory;
use Piwik\Updater\Migration\Plugin\Factory as PluginFactory;
+use Piwik\Updater\Migration\Config\Factory as ConfigFactory;
/**
* Migration factory to create various migrations that implement the Migration interface.
@@ -28,11 +29,17 @@ class Factory
public $plugin;
/**
+ * @var ConfigFactory
+ */
+ public $config;
+
+ /**
* @ignore
*/
- public function __construct(DbFactory $dbFactory, PluginFactory $pluginFactory)
+ public function __construct(DbFactory $dbFactory, PluginFactory $pluginFactory, ConfigFactory $configFactory)
{
$this->db = $dbFactory;
$this->plugin = $pluginFactory;
+ $this->config = $configFactory;
}
}
diff --git a/core/Updates/4.0.0-b1.php b/core/Updates/4.0.0-b1.php
index 44fe57dd0f..00b0ed41bd 100644
--- a/core/Updates/4.0.0-b1.php
+++ b/core/Updates/4.0.0-b1.php
@@ -46,7 +46,7 @@ class Updates_4_0_0_b1 extends PiwikUpdates
'idusertokenauth' => 'BIGINT UNSIGNED NOT NULL AUTO_INCREMENT',
'login' => 'VARCHAR(100) NOT NULL',
'description' => 'VARCHAR('.Model::MAX_LENGTH_TOKEN_DESCRIPTION.') NOT NULL',
- 'password' => 'VARCHAR(255) NOT NULL',
+ 'password' => 'VARCHAR(191) NOT NULL',
'system_token' => 'TINYINT(1) NOT NULL DEFAULT 0',
'hash_algo' => 'VARCHAR(30) NOT NULL',
'last_used' => 'DATETIME NULL',
@@ -87,6 +87,20 @@ class Updates_4_0_0_b1 extends PiwikUpdates
$migrations[] = $this->migration->plugin->activate('CustomJsTracker');
}
+ // Prepare all installed tables for utf8mb4 conversions. e.g. make some indexed fields smaller so they don't exceed the maximum key length
+ $allTables = DbHelper::getTablesInstalled();
+
+ $migrations[] = $this->migration->db->changeColumnType('session', 'id', 'VARCHAR(191)');
+ $migrations[] = $this->migration->db->changeColumnType('site_url', 'url', 'VARCHAR(190)');
+ $migrations[] = $this->migration->db->changeColumnType('option', 'option_name', 'VARCHAR(191)');
+
+ foreach ($allTables as $table) {
+ if (preg_match('/archive_/', $table) == 1) {
+ $tableNameUnprefixed = Common::unprefixTable($table);
+ $migrations[] = $this->migration->db->changeColumnType($tableNameUnprefixed, 'name', 'VARCHAR(190)');
+ }
+ }
+
// Move the site search fields of log_visit out of custom variables into their own fields
$migrations[] = $this->migration->db->addColumn('log_link_visit_action', 'search_cat', 'VARCHAR(200) NULL');
$migrations[] = $this->migration->db->addColumn('log_link_visit_action', 'search_count', 'INTEGER(10) UNSIGNED NULL');
@@ -102,6 +116,13 @@ class Updates_4_0_0_b1 extends PiwikUpdates
// remove old options
$migrations[] = $this->migration->db->sql('DELETE FROM `' . Common::prefixTable('option') . '` WHERE option_name IN ("geoip.updater_period", "geoip.loc_db_url", "geoip.isp_db_url", "geoip.org_db_url")');
+
+ $config = Config::getInstance();
+
+ if (!empty($config->mail['type']) && $config->mail['type'] === 'Crammd5') {
+ $migrations[] = $this->migration->config->set('mail', 'type', 'Cram-md5');
+ }
+
return $migrations;
}
@@ -113,14 +134,6 @@ class Updates_4_0_0_b1 extends PiwikUpdates
// switch to default provider if GeoIp Legacy was still in use
LocationProvider::setCurrentProvider(LocationProvider\DefaultProvider::ID);
}
-
- // @todo migrate that to a config migration. See utf8mb4 branch
- $config = Config::getInstance();
-
- if (!empty($config->mail['type']) && $config->mail['type'] === 'Crammd5') {
- $config->mail['type'] === 'Cram-md5';
- $config->forceSave();
- }
}
protected function usesGeoIpLegacyLocationProvider()
diff --git a/plugins/CoreUpdater/Commands/ConvertToUtf8mb4.php b/plugins/CoreUpdater/Commands/ConvertToUtf8mb4.php
new file mode 100644
index 0000000000..141b71470c
--- /dev/null
+++ b/plugins/CoreUpdater/Commands/ConvertToUtf8mb4.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\CoreUpdater\Commands;
+
+use Piwik\Config;
+use Piwik\Db;
+use Piwik\DbHelper;
+use Piwik\Piwik;
+use Piwik\Plugin\ConsoleCommand;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+
+/**
+ * @package CoreUpdater
+ */
+class ConvertToUtf8mb4 extends ConsoleCommand
+{
+ protected function configure()
+ {
+ $this->setName('core:convert-to-utf8mb4');
+
+ $this->setDescription('Converts the database to utf8mb4');
+
+ $this->addOption('show', null, InputOption::VALUE_NONE, Piwik::translate('Show all commands / queries only.'));
+ $this->addOption('yes', null, InputOption::VALUE_NONE, Piwik::translate('CoreUpdater_ConsoleParameterDescription'));
+ $this->addOption('keep-tracking', null, InputOption::VALUE_NONE, 'Do not disable tracking while conversion is running');
+ }
+
+ public function isEnabled()
+ {
+ $dbSettings = new Db\Settings();
+ $charset = $dbSettings->getUsedCharset();
+
+ return $charset !== 'utf8mb4';
+ }
+
+ /**
+ * Execute command like: ./console core:convert-to-utf8mb4 --yes
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $yes = $input->getOption('yes');
+ $keepTracking = $input->getOption('keep-tracking');
+ $show = $input->getOption('show');
+
+ $queries = DbHelper::getUtf8mb4ConversionQueries();
+
+ if ($show) {
+ $this->showCommands($queries, $keepTracking, $output);
+ return;
+ }
+
+ $output->writeln("This command will convert all Matomo database tables to utf8mb4.\n");
+
+ if (DbHelper::getDefaultCharset() !== 'utf8mb4') {
+ $this->writeSuccessMessage($output, array('Your database does not support utf8mb4'));
+ return;
+ }
+
+ if (!$keepTracking) {
+ $output->writeln("Tracking will be disabled during this process.\n");
+ }
+
+ $output->writeln('If you want to see what this command is going to do use the --show option.');
+
+ if (!$yes) {
+ $yes = $this->askForUpdateConfirmation($input, $output);
+ }
+
+ if ($yes) {
+
+ if (!$keepTracking) {
+ $output->writeln("\n" . Piwik::translate('Disabling Matomo Tracking'));
+ $config = Config::getInstance();
+ $config->Tracker['record_statistics'] = '0';
+ $config->forceSave();
+ }
+
+ $output->writeln("\n" . Piwik::translate('CoreUpdater_ConsoleStartingDbUpgrade'));
+
+ foreach ($queries as $query) {
+ $output->write("\n" . 'Executing ' . $query . '... ');
+ Db::get()->exec($query);
+ $output->write(' done.');
+ }
+
+ $output->writeln("\n" . 'Updating used database charset in config.ini.php.');
+ $config = Config::getInstance();
+ $config->database['charset'] = 'utf8mb4';
+
+ if (!$keepTracking) {
+ $output->writeln("\n" . Piwik::translate('Enabling Matomo Tracking'));
+ $config->Tracker['record_statistics'] = '1';
+ }
+
+ $config->forceSave();
+
+ $this->writeSuccessMessage($output, array('Conversion to utf8mb4 successful.'));
+
+ } else {
+ $this->writeSuccessMessage($output, array('Database conversion skipped.'));
+ }
+ }
+
+ protected function showCommands($queries, $keepTracking, OutputInterface $output)
+ {
+ $output->writeln("To manually convert all Matomo database tables to utf8mb4 follow these steps.");
+ if (!$keepTracking) {
+ $output->writeln('');
+ $output->writeln('** Disable Matomo Tracking with this command: **');
+ $output->writeln('./console config:set --section=Tracker --key=record_statistics --value=0');
+ }
+ $output->writeln('');
+ $output->writeln('** Execute the following database queries: **');
+ $output->writeln(implode("\n", $queries));
+ $output->writeln('');
+ $output->writeln('** Change configured database charset to utf8mb4 with this command: **');
+ $output->writeln('./console config:set --section=database --key=charset --value=utf8mb4');
+ if (!$keepTracking) {
+ $output->writeln('');
+ $output->writeln('** Enable Matomo Tracking again with this command: **');
+ $output->writeln('./console config:set --section=Tracker --key=record_statistics --value=1');
+ }
+ }
+
+ private function askForUpdateConfirmation(InputInterface $input, OutputInterface $output)
+ {
+ $helper = $this->getHelper('question');
+ $question = new ConfirmationQuestion('<comment>Execute updates? (y/N) </comment>', false);
+
+ return $helper->ask($input, $output, $question);
+ }
+}
diff --git a/plugins/CoreUpdater/SystemSettings.php b/plugins/CoreUpdater/SystemSettings.php
index 8bf13a03b9..e8de1fb493 100644
--- a/plugins/CoreUpdater/SystemSettings.php
+++ b/plugins/CoreUpdater/SystemSettings.php
@@ -8,6 +8,8 @@
namespace Piwik\Plugins\CoreUpdater;
+use Piwik\Db\Settings;
+use Piwik\DbHelper;
use Piwik\Piwik;
use Piwik\Plugin\ReleaseChannels;
use Piwik\Plugins\CoreAdminHome\Controller as CoreAdminController;
@@ -31,6 +33,9 @@ class SystemSettings extends \Piwik\Settings\Plugin\SystemSettings
/** @var Setting */
public $sendPluginUpdateEmail;
+ /** @var Setting */
+ public $updateToUtf8mb4;
+
/**
* @var ReleaseChannels
*/
@@ -54,6 +59,12 @@ class SystemSettings extends \Piwik\Settings\Plugin\SystemSettings
$isWritable = $isWritable && PluginUpdateCommunication::canBeEnabled();
$this->sendPluginUpdateEmail = $this->createSendPluginUpdateEmail();
$this->sendPluginUpdateEmail->setIsWritableByCurrentUser($isWritable);
+
+ $isWritable = Piwik::hasUserSuperUserAccess() && CoreAdminController::isGeneralSettingsAdminEnabled();
+ $dbSettings = new Settings();
+ if ($isWritable && $dbSettings->getUsedCharset() !== 'utf8mb4' && DbHelper::getDefaultCharset() === 'utf8mb4') {
+ $this->updateToUtf8mb4 = $this->createUpdateToUtf8mb4();
+ }
}
private function createReleaseChannel()
@@ -104,4 +115,19 @@ class SystemSettings extends \Piwik\Settings\Plugin\SystemSettings
});
}
+ private function createUpdateToUtf8mb4()
+ {
+ return $this->makeSetting('update_to_utf8mb4', $default = false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
+ $field->introduction = Piwik::translate('CoreUpdater_ConvertToUtf8mb4');
+ $field->title = Piwik::translate('CoreUpdater_TriggerDatabaseConversion');
+ $field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
+ $field->inlineHelp = Piwik::translate('CoreUpdater_Utf8mb4ConversionHelp', [
+ '�',
+ '<code>' . PIWIK_INCLUDE_PATH . '/console core:convert-to-utf8mb4</code>',
+ '<a href="https://matomo.org/faq/how-to-update/how-to-convert-the-database-to-utf8mb4-charset/" rel="noreferrer noopener" target="_blank">',
+ '</a>'
+ ]);
+ });
+ }
+
}
diff --git a/plugins/CoreUpdater/Tasks.php b/plugins/CoreUpdater/Tasks.php
index 7998a83925..f3ecae955d 100644
--- a/plugins/CoreUpdater/Tasks.php
+++ b/plugins/CoreUpdater/Tasks.php
@@ -8,11 +8,23 @@
*/
namespace Piwik\Plugins\CoreUpdater;
+use Piwik\Config;
+use Piwik\Container\StaticContainer;
+use Piwik\Db;
+use Piwik\DbHelper;
+
class Tasks extends \Piwik\Plugin\Tasks
{
public function schedule()
{
$this->daily('sendNotificationIfUpdateAvailable', null, self::LOWEST_PRIORITY);
+
+ $dbSettings = new \Piwik\Db\Settings();
+ $settings = StaticContainer::get('Piwik\Plugins\CoreUpdater\SystemSettings');
+
+ if ($dbSettings->getUsedCharset() !== 'utf8mb4' && DbHelper::getDefaultCharset() === 'utf8mb4' && $settings->updateToUtf8mb4->getValue()) {
+ $this->daily('convertToUtf8mb4', null, self::HIGHEST_PRIORITY);
+ }
}
public function sendNotificationIfUpdateAvailable()
@@ -22,4 +34,20 @@ class Tasks extends \Piwik\Plugin\Tasks
$coreUpdateCommunication->sendNotificationIfUpdateAvailable();
}
}
+
+ public function convertToUtf8mb4()
+ {
+ $queries = DbHelper::getUtf8mb4ConversionQueries();
+
+ foreach ($queries as $query) {
+ Db::get()->exec($query);
+ }
+
+ $config = Config::getInstance();
+ $config->database['charset'] = 'utf8mb4';
+ $config->forceSave();
+
+ $settings = StaticContainer::get('Piwik\Plugins\CoreUpdater\SystemSettings');
+ $settings->updateToUtf8mb4->setValue(false);
+ }
} \ No newline at end of file
diff --git a/plugins/CoreUpdater/lang/en.json b/plugins/CoreUpdater/lang/en.json
index bc703116b8..728706f1c4 100644
--- a/plugins/CoreUpdater/lang/en.json
+++ b/plugins/CoreUpdater/lang/en.json
@@ -91,6 +91,9 @@
"YouMustDownloadPackageOrFixPermissions": "Matomo is unable to overwrite your current installation. You can either fix the directory\/file permissions, or download the package and install version %s manually:",
"YourDatabaseIsOutOfDate": "Your Matomo database is out-of-date, and must be upgraded before you can continue.",
"ViewVersionChangelog": "View the changelog for this version:",
- "ReceiveEmailBecauseIsSuperUser": "You receive this email because you are a Super User on the Matomo at: %s"
+ "ReceiveEmailBecauseIsSuperUser": "You receive this email because you are a Super User on the Matomo at: %s",
+ "ConvertToUtf8mb4": "Convert database to UTF8mb4 charset",
+ "TriggerDatabaseConversion": "Trigger database conversion in background",
+ "Utf8mb4ConversionHelp": "Your database is currently not using utf8mb4 charset. This makes it impossible to store 4-byte characters, such as emojis, less common characters of asian languages, various historic scripts or mathematical symbols. Those are currently replaced with %1$s.<br /><br />Your database supports the utf8mb4 charset and it would be possible to convert it.<br /><br />If you are able to run console commands we recommend using this command: %2$s<br /><br />Alternatively you can enable the conversion here. It will then be triggered automatically as a scheduled task in the background.<br /><br />Attention: Converting the database might take up to a couple of hours depending on the database size. As tracking might not work during this process, we do not recommend to use the trigger for bigger instances.<br /><br />You can find more information about this topic in this %3$sFAQ%4$s."
}
}
diff --git a/plugins/CustomAlerts b/plugins/CustomAlerts
-Subproject 63b7cdd5cb374cc40e7fb0857d215f66a48d8bc
+Subproject 8e17d3977e2c9443ea0b51f6ec40e90f89fa56f
diff --git a/plugins/CustomDimensions b/plugins/CustomDimensions
-Subproject aeb7231db7746aa77e94c2f0b0bc2633fa50bc5
+Subproject 10665789dc16cf7bef9513891df4c6fd1353352
diff --git a/plugins/DBStats/tests/UI/expected-screenshots/DBStats_admin_page.png b/plugins/DBStats/tests/UI/expected-screenshots/DBStats_admin_page.png
index 0775f88f58..728709e0bc 100644
--- a/plugins/DBStats/tests/UI/expected-screenshots/DBStats_admin_page.png
+++ b/plugins/DBStats/tests/UI/expected-screenshots/DBStats_admin_page.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f91af708ab6062666dcfe4486b507ab61df96b4d799e32f28df3afe4c77ec10d
-size 225637
+oid sha256:7ba1a11dba92cd190560f4c556f5dcc3de90588346db5c45a6e98d954b15b69e
+size 228111
diff --git a/plugins/Dashboard/Dashboard.php b/plugins/Dashboard/Dashboard.php
index 8eeec660c6..652bad1b4f 100644
--- a/plugins/Dashboard/Dashboard.php
+++ b/plugins/Dashboard/Dashboard.php
@@ -32,10 +32,21 @@ class Dashboard extends \Piwik\Plugin
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'Widget.addWidgetConfigs' => 'addWidgetConfigs',
'Category.addSubcategories' => 'addSubcategories',
- 'Widgetize.shouldEmbedIframeEmpty' => 'shouldEmbedIframeEmpty'
+ 'Widgetize.shouldEmbedIframeEmpty' => 'shouldEmbedIframeEmpty',
+ 'Db.getTablesInstalled' => 'getTablesInstalled'
);
}
+ /**
+ * Register the new tables, so Matomo knows about them.
+ *
+ * @param array $allTablesInstalled
+ */
+ public function getTablesInstalled(&$allTablesInstalled)
+ {
+ $allTablesInstalled[] = Common::prefixTable('user_dashboard');
+ }
+
public function shouldEmbedIframeEmpty(&$shouldEmbedEmpty, $controllerName, $actionName)
{
if ($controllerName == 'Dashboard' && $actionName == 'index') {
diff --git a/plugins/Diagnostics/Diagnostic/DatabaseAbilitiesCheck.php b/plugins/Diagnostics/Diagnostic/DatabaseAbilitiesCheck.php
index f867bcce67..563c904bcc 100644
--- a/plugins/Diagnostics/Diagnostic/DatabaseAbilitiesCheck.php
+++ b/plugins/Diagnostics/Diagnostic/DatabaseAbilitiesCheck.php
@@ -10,6 +10,7 @@ namespace Piwik\Plugins\Diagnostics\Diagnostic;
use Piwik\Common;
use Piwik\Config;
use Piwik\Db;
+use Piwik\DbHelper;
use Piwik\Translation\Translator;
/**
@@ -37,6 +38,8 @@ class DatabaseAbilitiesCheck implements Diagnostic
$result = new DiagnosticResult($this->translator->translate('Installation_DatabaseAbilities'));
+ $result->addItem($this->checkUtf8mb4Charset());
+
if (Config::getInstance()->General['enable_load_data_infile']) {
$result->addItem($this->checkLoadDataInfile());
}
@@ -47,6 +50,34 @@ class DatabaseAbilitiesCheck implements Diagnostic
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', ['�', '<a href="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', ['�', '<a href="https://matomo.org/faq/how-to-update/how-to-convert-the-database-to-utf8mb4-charset/" rel="noreferrer noopener" target="_blank">', '</a>']) .
+ '<br/>'
+ );
+ }
+
protected function checkLoadDataInfile()
{
$optionTable = Common::prefixTable('option');
diff --git a/plugins/Diagnostics/lang/en.json b/plugins/Diagnostics/lang/en.json
index 741126d70b..cf7f935f23 100644
--- a/plugins/Diagnostics/lang/en.json
+++ b/plugins/Diagnostics/lang/en.json
@@ -9,6 +9,9 @@
"HideUnchanged": "If you want to see only changed values you can %1$shide all unchanged values%2$s.",
"Sections": "Sections",
"DatabaseReaderConnection": "Database Reader Connection",
+ "DatabaseUtf8Requirement": "This is required to be able to store 4-byte UTF8 characters. Unless utf8mb4 is available special characters, such as emojis, less common characters of asian languages, various historic scripts or mathematical symbols will be replaced with %1$s. You can read more details about this topic in %2$sthis FAQ%3$s.",
+ "DatabaseUtf8mb4CharsetRecommended": "Your database doesn't support utf8mb4 charset yet.",
+ "DatabaseUtf8mb4CharsetAvailableButNotUsed": "Your database supports utf8mb4 charset, but your database tables have not been converted yet. You can do this by executing the command %1$s or activating the automatic conversion in General Settings.",
"CronArchivingLastRunCheck": "Last Successful Archiving Completion",
"CronArchivingHasNotRun": "Archiving has not yet run successfully.",
"CronArchivingHasNotRunInAWhile": "Archiving last ran successfully on %1$s which is %2$s ago.",
diff --git a/plugins/Diagnostics/tests/UI/expected-screenshots/Diagnostics_page.png b/plugins/Diagnostics/tests/UI/expected-screenshots/Diagnostics_page.png
index 28a561a3e6..eb8d9abcdd 100644
--- a/plugins/Diagnostics/tests/UI/expected-screenshots/Diagnostics_page.png
+++ b/plugins/Diagnostics/tests/UI/expected-screenshots/Diagnostics_page.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d1982392882b95083955e07a3b2a49ae09f877db360e7e120f157221277eeaf5
-size 204436
+oid sha256:16f6eb7a77e36b275e3293d82b29a7c304587ac1dbf0064f641b2aadaa0915f8
+size 206667
diff --git a/plugins/ExampleLogTables/Dao/CustomUserLog.php b/plugins/ExampleLogTables/Dao/CustomUserLog.php
index 50f3016301..ecdfd96f6f 100644
--- a/plugins/ExampleLogTables/Dao/CustomUserLog.php
+++ b/plugins/ExampleLogTables/Dao/CustomUserLog.php
@@ -25,7 +25,7 @@ class CustomUserLog
public function install()
{
DbHelper::createTable($this->table, "
- `user_id` VARCHAR(200) NOT NULL,
+ `user_id` VARCHAR(191) NOT NULL,
`gender` VARCHAR(30) NOT NULL,
`group` VARCHAR(30) NOT NULL,
PRIMARY KEY (user_id)");
diff --git a/plugins/ExampleLogTables/ExampleLogTables.php b/plugins/ExampleLogTables/ExampleLogTables.php
index caf83d594b..ed7ada493f 100644
--- a/plugins/ExampleLogTables/ExampleLogTables.php
+++ b/plugins/ExampleLogTables/ExampleLogTables.php
@@ -8,11 +8,19 @@
*/
namespace Piwik\Plugins\ExampleLogTables;
+use Piwik\Common;
use Piwik\Plugins\ExampleLogTables\Dao\CustomUserLog;
use Piwik\Plugins\ExampleLogTables\Dao\CustomGroupLog;
class ExampleLogTables extends \Piwik\Plugin
{
+ public function registerEvents()
+ {
+ return [
+ 'Db.getTablesInstalled' => 'getTablesInstalled'
+ ];
+ }
+
public function install()
{
// Install custom log table [disabled as example only]
@@ -23,4 +31,15 @@ class ExampleLogTables extends \Piwik\Plugin
// $userLog = new CustomGroupLog();
// $userLog->install();
}
+
+ /**
+ * Register the new tables, so Matomo knows about them.
+ *
+ * @param array $allTablesInstalled
+ */
+ public function getTablesInstalled(&$allTablesInstalled)
+ {
+ $allTablesInstalled[] = Common::prefixTable('log_group');
+ $allTablesInstalled[] = Common::prefixTable('log_custom');
+ }
} \ No newline at end of file
diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php
index b7dbd5a60a..4452c914b4 100644
--- a/plugins/Installation/Controller.php
+++ b/plugins/Installation/Controller.php
@@ -598,9 +598,7 @@ class Controller extends \Piwik\Plugin\ControllerAdmin
$config->General['installation_in_progress'] = 1;
$config->database = $dbInfos;
- if (!DbHelper::isDatabaseConnectionUTF8()) {
- $config->database['charset'] = 'utf8';
- }
+ $config->database['charset'] = DbHelper::getDefaultCharset();
$config->forceSave();
diff --git a/plugins/LanguagesManager/LanguagesManager.php b/plugins/LanguagesManager/LanguagesManager.php
index 71f67910ff..b73dfff640 100644
--- a/plugins/LanguagesManager/LanguagesManager.php
+++ b/plugins/LanguagesManager/LanguagesManager.php
@@ -39,10 +39,21 @@ class LanguagesManager extends \Piwik\Plugin
'Platform.initialized' => 'initLanguage',
'UsersManager.deleteUser' => 'deleteUserLanguage',
'Template.topBar' => 'addLanguagesManagerToOtherTopBar',
- 'Template.jsGlobalVariables' => 'jsGlobalVariables'
+ 'Template.jsGlobalVariables' => 'jsGlobalVariables',
+ 'Db.getTablesInstalled' => 'getTablesInstalled'
);
}
+ /**
+ * Register the new tables, so Matomo knows about them.
+ *
+ * @param array $allTablesInstalled
+ */
+ public function getTablesInstalled(&$allTablesInstalled)
+ {
+ $allTablesInstalled[] = Common::prefixTable('user_language');
+ }
+
public function getJsFiles(&$jsFiles)
{
$jsFiles[] = "plugins/LanguagesManager/angularjs/languageselector/languageselector.directive.js";
diff --git a/plugins/PrivacyManager/PrivacyManager.php b/plugins/PrivacyManager/PrivacyManager.php
index b107f20189..96d659eb58 100644
--- a/plugins/PrivacyManager/PrivacyManager.php
+++ b/plugins/PrivacyManager/PrivacyManager.php
@@ -24,6 +24,7 @@ use Piwik\Piwik;
use Piwik\Plugin;
use Piwik\Plugins\Goals\Archiver;
use Piwik\Plugins\Installation\FormDefaultSettings;
+use Piwik\Plugins\PrivacyManager\Model\LogDataAnonymizations;
use Piwik\Site;
use Piwik\Tracker\Cache;
use Piwik\Tracker\GoalManager;
@@ -182,11 +183,22 @@ class PrivacyManager extends Plugin
'Tracker.setVisitorIp' => array($this->ipAnonymizer, 'setVisitorIpAddress'),
'Installation.defaultSettingsForm.init' => 'installationFormInit',
'Installation.defaultSettingsForm.submit' => 'installationFormSubmit',
- 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'Template.pageFooter' => 'renderPrivacyPolicyLinks',
+ 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
+ 'Template.pageFooter' => 'renderPrivacyPolicyLinks',
+ 'Db.getTablesInstalled' => 'getTablesInstalled'
);
}
+ /**
+ * Register the new tables, so Matomo knows about them.
+ *
+ * @param array $allTablesInstalled
+ */
+ public function getTablesInstalled(&$allTablesInstalled)
+ {
+ $allTablesInstalled[] = Common::prefixTable(LogDataAnonymizations::getDbTableName());
+ }
+
public function isTrackerPlugin()
{
return true;
diff --git a/plugins/QueuedTracking b/plugins/QueuedTracking
-Subproject 3bb2ec92d755afa276e8555fae36bf8b4ed8db0
+Subproject 154a0ca633c139408146dfa9a9996a3cb309d18
diff --git a/plugins/ScheduledReports/ScheduledReports.php b/plugins/ScheduledReports/ScheduledReports.php
index a2c62b2700..05bb43ef78 100644
--- a/plugins/ScheduledReports/ScheduledReports.php
+++ b/plugins/ScheduledReports/ScheduledReports.php
@@ -96,9 +96,21 @@ class ScheduledReports extends \Piwik\Plugin
'SegmentEditor.update' => 'segmentUpdated',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
'Request.getRenamedModuleAndAction' => 'renameDeprecatedModuleAndAction',
+ 'Db.getTablesInstalled' => 'getTablesInstalled'
);
}
+ /**
+ * Register the new tables, so Matomo knows about them.
+ *
+ * @param array $allTablesInstalled
+ */
+ public function getTablesInstalled(&$allTablesInstalled)
+ {
+ $allTablesInstalled[] = Common::prefixTable('report');
+ $allTablesInstalled[] = Common::prefixTable('report_subscriptions');
+ }
+
public function renameDeprecatedModuleAndAction(&$module, &$action)
{
if($module == 'PDFReports') {
diff --git a/plugins/SegmentEditor/SegmentEditor.php b/plugins/SegmentEditor/SegmentEditor.php
index 38a49443ad..d5beb44ab2 100644
--- a/plugins/SegmentEditor/SegmentEditor.php
+++ b/plugins/SegmentEditor/SegmentEditor.php
@@ -48,11 +48,22 @@ class SegmentEditor extends \Piwik\Plugin
'Template.nextToCalendar' => 'getSegmentEditorHtml',
'System.addSystemSummaryItems' => 'addSystemSummaryItems',
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys',
- 'Visualization.onNoData' => 'onNoData',
- 'Archive.noArchivedData' => 'onNoArchiveData',
+ 'Visualization.onNoData' => 'onNoData',
+ 'Archive.noArchivedData' => 'onNoArchiveData',
+ 'Db.getTablesInstalled' => 'getTablesInstalled'
);
}
+ /**
+ * Register the new tables, so Matomo knows about them.
+ *
+ * @param array $allTablesInstalled
+ */
+ public function getTablesInstalled(&$allTablesInstalled)
+ {
+ $allTablesInstalled[] = Common::prefixTable('segment');
+ }
+
public function addSystemSummaryItems(&$systemSummary)
{
$storedSegments = StaticContainer::get('Piwik\Plugins\SegmentEditor\Services\StoredSegmentService');
diff --git a/plugins/TagManager b/plugins/TagManager
-Subproject 2105be36d15030f632efd60d71b761f6e1a5f8f
+Subproject bb8cc3b28952b6f3a7891b5b10737f603d46374
diff --git a/tests/PHPUnit/Integration/Tracker/RequestTest.php b/tests/PHPUnit/Integration/Tracker/RequestTest.php
index 33026de7c9..501cd981bb 100644
--- a/tests/PHPUnit/Integration/Tracker/RequestTest.php
+++ b/tests/PHPUnit/Integration/Tracker/RequestTest.php
@@ -9,6 +9,7 @@
namespace Piwik\Tests\Integration\Tracker;
use Matomo\Network\IPUtils;
+use Piwik\Config;
use Piwik\Piwik;
use Piwik\Plugins\CustomVariables\CustomVariables;
use Piwik\Plugins\UsersManager\API;
@@ -447,12 +448,24 @@ class RequestTest extends IntegrationTestCase
* @group invalidChars
* @dataProvider getInvalidCharacterUrls
*/
- public function testInvalidCharacterRemoval($url, $expectedUrl)
+ public function testInvalidCharacterRemovalForUtf8($url, $expectedUrl)
{
+ Config::getInstance()->database['charset'] = 'utf8';
$request = $this->buildRequest(array('url' => $url));
$this->assertEquals($expectedUrl, $request->getParam('url'));
}
+ /**
+ * @group invalidChars
+ * @dataProvider getInvalidCharacterUrls
+ */
+ public function test4ByteCharacterRemainForUtf8mb4($url, $expectedUrl)
+ {
+ Config::getInstance()->database['charset'] = 'utf8mb4';
+ $request = $this->buildRequest(array('url' => $url));
+ $this->assertEquals($url, $request->getParam('url'));
+ }
+
public function getInvalidCharacterUrls()
{
return array(
diff --git a/tests/PHPUnit/Integration/Updater/Migration/FactoryTest.php b/tests/PHPUnit/Integration/Updater/Migration/FactoryTest.php
index cfe1b303ad..ae27537181 100644
--- a/tests/PHPUnit/Integration/Updater/Migration/FactoryTest.php
+++ b/tests/PHPUnit/Integration/Updater/Migration/FactoryTest.php
@@ -12,6 +12,7 @@ use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
use Piwik\Updater\Migration;
use Piwik\Updater\Migration\Db\Factory as DbFactory;
use Piwik\Updater\Migration\Plugin\Factory as PluginFactory;
+use Piwik\Updater\Migration\Config\Factory as ConfigFactory;
/**
* @group Core
@@ -29,7 +30,7 @@ class FactoryTest extends IntegrationTestCase
{
parent::setUp();
- $this->factory = new Migration\Factory(new DbFactory(), new PluginFactory());
+ $this->factory = new Migration\Factory(new DbFactory(), new PluginFactory(), new ConfigFactory());
}
public function test_db_holdsDatabaseFactory()
@@ -42,4 +43,9 @@ class FactoryTest extends IntegrationTestCase
$this->assertTrue($this->factory->plugin instanceof PluginFactory);
}
+ public function test_plugin_holdsConfigFactory()
+ {
+ $this->assertTrue($this->factory->config instanceof ConfigFactory);
+ }
+
}
diff --git a/tests/PHPUnit/System/BackwardsCompatibility1XTest.php b/tests/PHPUnit/System/BackwardsCompatibility1XTest.php
index 30b1489bfb..e2157ac3a9 100644
--- a/tests/PHPUnit/System/BackwardsCompatibility1XTest.php
+++ b/tests/PHPUnit/System/BackwardsCompatibility1XTest.php
@@ -9,6 +9,7 @@ namespace Piwik\Tests\System;
use Piwik\Common;
use Piwik\Db;
+use Piwik\Plugin\Manager;
use Piwik\Plugins\VisitFrequency\API as VisitFrequencyApi;
use Piwik\Tests\Framework\TestCase\SystemTestCase;
use Piwik\Tests\Fixtures\SqlDump;
@@ -24,15 +25,19 @@ class BackwardsCompatibility1XTest extends SystemTestCase
{
const FIXTURE_LOCATION = '/tests/resources/piwik-1.13-dump.sql';
+ /** @var SqlDump $fixture */
public static $fixture = null; // initialized below class
public static function setUpBeforeClass(): void
{
parent::setUpBeforeClass();
- // note: not sure why I have to manually install plugin
- \Piwik\Plugin\Manager::getInstance()->loadPlugin('CustomAlerts')->install();
- \Piwik\Plugin\Manager::getInstance()->loadPlugin('CustomDimensions')->install();
+ $installedPlugins = Manager::getInstance()->getInstalledPluginsName();
+
+ // ensure all plugins are installed correctly (some plugins database tables would be missing otherwise)
+ foreach ($installedPlugins as $installedPlugin) {
+ \Piwik\Plugin\Manager::getInstance()->loadPlugin($installedPlugin)->install();
+ }
$result = Fixture::updateDatabase();
if ($result === false) {
diff --git a/tests/PHPUnit/System/UrlNormalizationTest.php b/tests/PHPUnit/System/UrlNormalizationTest.php
index ca7e60175c..3b1fc15107 100644
--- a/tests/PHPUnit/System/UrlNormalizationTest.php
+++ b/tests/PHPUnit/System/UrlNormalizationTest.php
@@ -110,7 +110,7 @@ class UrlNormalizationTest extends SystemTestCase
array('name' => 'example.org/foo/bar2.html', 'url_prefix' => 3),
array('name' => 'example.org/foo/bar3.html', 'url_prefix' => 1),
array('name' => 'my.url/ꟽ碌㒧䊶亄ﶆⅅขκもኸόσशμεޖृ', 'url_prefix' => 1),
- array('name' => 'make.wordpress.org/?emoji=�l&param=test', 'url_prefix' => 2),
+ array('name' => 'make.wordpress.org/?emoji=😎l&param=test', 'url_prefix' => 2),
array('name' => 'example.org/foo/bar4.html', 'url_prefix' => 2),
);
$this->assertEquals($expected, $urls, "normalization went wrong");
diff --git a/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmentedRef__Actions.getPageUrls_day.xml b/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmentedRef__Actions.getPageUrls_day.xml
index 9f90d4f076..b0e0e5763b 100644
--- a/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmentedRef__Actions.getPageUrls_day.xml
+++ b/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmentedRef__Actions.getPageUrls_day.xml
@@ -95,7 +95,7 @@
</subtable>
</row>
<row>
- <label>/?emoji=�l&amp;param=test</label>
+ <label>/?emoji=😎l&amp;param=test</label>
<nb_visits>1</nb_visits>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_hits>1</nb_hits>
@@ -109,8 +109,8 @@
<avg_time_on_page>0</avg_time_on_page>
<bounce_rate>0%</bounce_rate>
<exit_rate>0%</exit_rate>
- <url>https://make.wordpress.org/?emoji=�l&amp;param=test</url>
- <segment>pageUrl==https%253A%252F%252Fmake.wordpress.org%252F%253Femoji%253D%25EF%25BF%25BDl%2526param%253Dtest</segment>
+ <url>https://make.wordpress.org/?emoji=😎l&amp;param=test</url>
+ <segment>pageUrl==https%253A%252F%252Fmake.wordpress.org%252F%253Femoji%253D%25F0%259F%2598%258El%2526param%253Dtest</segment>
</row>
<row>
<label>/ꟽ碌㒧䊶亄ﶆⅅขκもኸόσशμεޖृ</label>
diff --git a/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmented__Actions.getPageUrls_day.xml b/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmented__Actions.getPageUrls_day.xml
index 9f90d4f076..b0e0e5763b 100644
--- a/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmented__Actions.getPageUrls_day.xml
+++ b/tests/PHPUnit/System/expected/test_UrlNormalization_pagesSegmented__Actions.getPageUrls_day.xml
@@ -95,7 +95,7 @@
</subtable>
</row>
<row>
- <label>/?emoji=�l&amp;param=test</label>
+ <label>/?emoji=😎l&amp;param=test</label>
<nb_visits>1</nb_visits>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_hits>1</nb_hits>
@@ -109,8 +109,8 @@
<avg_time_on_page>0</avg_time_on_page>
<bounce_rate>0%</bounce_rate>
<exit_rate>0%</exit_rate>
- <url>https://make.wordpress.org/?emoji=�l&amp;param=test</url>
- <segment>pageUrl==https%253A%252F%252Fmake.wordpress.org%252F%253Femoji%253D%25EF%25BF%25BDl%2526param%253Dtest</segment>
+ <url>https://make.wordpress.org/?emoji=😎l&amp;param=test</url>
+ <segment>pageUrl==https%253A%252F%252Fmake.wordpress.org%252F%253Femoji%253D%25F0%259F%2598%258El%2526param%253Dtest</segment>
</row>
<row>
<label>/ꟽ碌㒧䊶亄ﶆⅅขκもኸόσशμεޖृ</label>
diff --git a/tests/PHPUnit/System/expected/test_UrlNormalization_urls__Actions.getPageUrls_day.xml b/tests/PHPUnit/System/expected/test_UrlNormalization_urls__Actions.getPageUrls_day.xml
index 9f90d4f076..b0e0e5763b 100644
--- a/tests/PHPUnit/System/expected/test_UrlNormalization_urls__Actions.getPageUrls_day.xml
+++ b/tests/PHPUnit/System/expected/test_UrlNormalization_urls__Actions.getPageUrls_day.xml
@@ -95,7 +95,7 @@
</subtable>
</row>
<row>
- <label>/?emoji=�l&amp;param=test</label>
+ <label>/?emoji=😎l&amp;param=test</label>
<nb_visits>1</nb_visits>
<nb_uniq_visitors>1</nb_uniq_visitors>
<nb_hits>1</nb_hits>
@@ -109,8 +109,8 @@
<avg_time_on_page>0</avg_time_on_page>
<bounce_rate>0%</bounce_rate>
<exit_rate>0%</exit_rate>
- <url>https://make.wordpress.org/?emoji=�l&amp;param=test</url>
- <segment>pageUrl==https%253A%252F%252Fmake.wordpress.org%252F%253Femoji%253D%25EF%25BF%25BDl%2526param%253Dtest</segment>
+ <url>https://make.wordpress.org/?emoji=😎l&amp;param=test</url>
+ <segment>pageUrl==https%253A%252F%252Fmake.wordpress.org%252F%253Femoji%253D%25F0%259F%2598%258El%2526param%253Dtest</segment>
</row>
<row>
<label>/ꟽ碌㒧䊶亄ﶆⅅขκもኸόσशμεޖृ</label>
diff --git a/tests/PHPUnit/System/expected/test_Utf8mb4__Live.getLastVisitsDetails_year.xml b/tests/PHPUnit/System/expected/test_Utf8mb4__Live.getLastVisitsDetails_year.xml
index 3aa91520d2..c282465a49 100644
--- a/tests/PHPUnit/System/expected/test_Utf8mb4__Live.getLastVisitsDetails_year.xml
+++ b/tests/PHPUnit/System/expected/test_Utf8mb4__Live.getLastVisitsDetails_year.xml
@@ -15,34 +15,34 @@
<itemDetails>
<row>
- <itemSKU>sku �</itemSKU>
- <itemName>name �</itemName>
- <itemCategory>category �</itemCategory>
+ <itemSKU>sku 🛸</itemSKU>
+ <itemName>name 🛩</itemName>
+ <itemCategory>category 🛤</itemCategory>
<price>95</price>
<quantity>1</quantity>
<categories>
- <row>category �</row>
+ <row>category 🛤</row>
</categories>
</row>
</itemDetails>
<icon>plugins/Morpheus/images/ecommerceAbandonedCart.png</icon>
<iconSVG>plugins/Morpheus/images/ecommerceAbandonedCart.svg</iconSVG>
<title>Abandoned Cart</title>
- <subtitle>$100 revenue - 1 items: name �)</subtitle>
+ <subtitle>$100 revenue - 1 items: name 🛩)</subtitle>
</row>
<row>
<type>action</type>
- <url>http://example.org/foo/�.html</url>
- <pageTitle>incredible �</pageTitle>
+ <url>http://example.org/foo/🙙.html</url>
+ <pageTitle>incredible 🚜</pageTitle>
<pageIdAction>2</pageIdAction>
<pageId>1</pageId>
<bandwidth />
<pageviewPosition>1</pageviewPosition>
- <title>incredible �</title>
- <subtitle>http://example.org/foo/�.html</subtitle>
+ <title>incredible 🚜</title>
+ <subtitle>http://example.org/foo/🙙.html</subtitle>
<icon />
<iconSVG>plugins/Morpheus/images/action.svg</iconSVG>
@@ -81,9 +81,9 @@
<referrerType>search</referrerType>
<referrerTypeName>Search Engines</referrerTypeName>
<referrerName>Google</referrerName>
- <referrerKeyword>�</referrerKeyword>
+ <referrerKeyword>😡</referrerKeyword>
<referrerKeywordPosition />
- <referrerUrl>http://www.google.com/search?q=�</referrerUrl>
+ <referrerUrl>http://www.google.com/search?q=😡</referrerUrl>
<referrerSearchEngineUrl>http://google.com</referrerSearchEngineUrl>
<referrerSearchEngineIcon>plugins/Morpheus/icons/dist/searchEngines/google.com.png</referrerSearchEngineIcon>
<referrerSocialNetworkUrl />
diff --git a/tests/PHPUnit/Unit/DataAccess/ArchiveTableCreatorTest.php b/tests/PHPUnit/Unit/DataAccess/ArchiveTableCreatorTest.php
index 565045a915..6743b167f9 100644
--- a/tests/PHPUnit/Unit/DataAccess/ArchiveTableCreatorTest.php
+++ b/tests/PHPUnit/Unit/DataAccess/ArchiveTableCreatorTest.php
@@ -24,12 +24,9 @@ class ArchiveTableCreatorTest extends \PHPUnit\Framework\TestCase
$this->tables = array(
'archive_numeric_2015_02',
'archive_blob_2015_05',
- 'garbage',
'archive_numeric_2014_03',
'archive_blob_2015_01',
'archive_blob_2015_02',
- 'aslkdfjsd',
- 'prefixed_archive_numeric_2012_01',
);
}
@@ -69,7 +66,6 @@ class ArchiveTableCreatorTest extends \PHPUnit\Framework\TestCase
array(
'archive_numeric_2015_02',
'archive_numeric_2014_03',
- 'prefixed_archive_numeric_2012_01',
),
),
@@ -86,7 +82,6 @@ class ArchiveTableCreatorTest extends \PHPUnit\Framework\TestCase
'archive_numeric_2014_03',
'archive_blob_2015_01',
'archive_blob_2015_02',
- 'prefixed_archive_numeric_2012_01',
),
),
@@ -98,7 +93,6 @@ class ArchiveTableCreatorTest extends \PHPUnit\Framework\TestCase
'archive_numeric_2014_03',
'archive_blob_2015_01',
'archive_blob_2015_02',
- 'prefixed_archive_numeric_2012_01',
),
),
);