PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.4.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.4.2
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 / Updates / 4.0.0-b1.php
matomo / app / core / Updates Last commit date
3.12.0-b1.php 5 years ago 3.12.0-b7.php 5 years ago 4.0.0-b1.php 5 years ago 4.0.0-b3.php 5 years ago 4.0.0-rc3.php 5 years ago 4.0.0-rc4.php 5 years ago 4.0.1-b1.php 5 years ago 4.0.4-b1.php 5 years ago 4.1.2-b1.php 5 years ago 4.1.2-b2.php 5 years ago 4.3.0-b3.php 5 years ago 4.3.0-b4.php 5 years ago 4.3.0-rc2.php 5 years ago 4.4.0-b1.php 5 years ago
4.0.0-b1.php
315 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
10 namespace Piwik\Updates;
11
12 use Piwik\DataAccess\TableMetadata;
13 use Piwik\Updater\Migration\Custom as CustomMigration;
14 use Piwik\Db;
15 use Piwik\DbHelper;
16 use Piwik\Plugin\Manager;
17 use Piwik\Plugins\CoreAdminHome\Commands\MigrateTokenAuths;
18 use Piwik\Plugins\CoreHome\Columns\Profilable;
19 use Piwik\Plugins\CoreHome\Columns\VisitorSecondsSinceFirst;
20 use Piwik\Plugins\CoreHome\Columns\VisitorSecondsSinceOrder;
21 use Piwik\Plugins\Installation\ServerFilesGenerator;
22 use Piwik\Plugins\PagePerformance\Columns\TimeDomCompletion;
23 use Piwik\Plugins\PagePerformance\Columns\TimeDomProcessing;
24 use Piwik\Plugins\PagePerformance\Columns\TimeNetwork;
25 use Piwik\Plugins\PagePerformance\Columns\TimeOnLoad;
26 use Piwik\Plugins\PagePerformance\Columns\TimeServer;
27 use Piwik\Plugins\PagePerformance\Columns\TimeTransfer;
28 use Piwik\Plugins\UsersManager\Model;
29 use Piwik\Common;
30 use Piwik\Config;
31 use Piwik\Plugins\UserCountry\LocationProvider;
32 use Piwik\Plugins\VisitorInterest\Columns\VisitorSecondsSinceLast;
33 use Piwik\SettingsPiwik;
34 use Piwik\Updater;
35 use Piwik\Updates as PiwikUpdates;
36 use Piwik\Updater\Migration\Factory as MigrationFactory;
37
38 /**
39 * Update for version 4.0.0-b1.
40 */
41 class Updates_4_0_0_b1 extends PiwikUpdates
42 {
43 /**
44 * @var MigrationFactory
45 */
46 private $migration;
47
48 public function __construct(MigrationFactory $factory)
49 {
50 $this->migration = $factory;
51 }
52
53 public function getMigrations(Updater $updater)
54 {
55 $tableMetadata = new TableMetadata();
56
57 $columnsToAdd = [];
58
59 $migrations = [];
60
61 $domain = Config::getLocalConfigPath() === Config::getDefaultLocalConfigPath() ? '' : Config::getHostname();
62 $domainArg = !empty($domain) ? "--matomo-domain=". escapeshellarg($domain) . " " : '';
63 $toString = sprintf('./console %score:matomo4-migrate-token-auths', $domainArg);
64 $custom = new CustomMigration(array(MigrateTokenAuths::class, 'migrate'), $toString);
65
66 $migrations[] = $custom;
67
68 // invalidations table
69 $migrations[] = $this->migration->db->createTable('archive_invalidations', [
70 'idinvalidation' => 'BIGINT UNSIGNED NOT NULL AUTO_INCREMENT',
71 'idarchive' => 'INTEGER UNSIGNED NULL',
72 'name' => 'VARCHAR(255) NOT NULL',
73 'idsite' => 'INTEGER NOT NULL',
74 'date1' => 'DATE NOT NULL',
75 'date2' => 'DATE NOT NULL',
76 'period' => 'TINYINT UNSIGNED NOT NULL',
77 'ts_invalidated' => 'DATETIME NOT NULL',
78 'status' => 'TINYINT(1) UNSIGNED DEFAULT 0',
79 'report' => 'VARCHAR(255) NULL',
80 ], ['idinvalidation']);
81
82 $migrations[] = $this->migration->db->addIndex('archive_invalidations', ['idsite', 'date1', 'period'], 'index_idsite_dates_period_name');
83
84 $migrations[] = $this->migration->db->dropColumn('user', 'alias');
85
86 // prevent possible duplicates when shorting session id
87 $migrations[] = $this->migration->db->sql('DELETE FROM `' . Common::prefixTable('session') . '` WHERE length(id) > 190');
88
89 $migrations[] = $this->migration->db->changeColumnType('session', 'id', 'VARCHAR(191)');
90 $migrations[] = $this->migration->db->changeColumnType('site_url', 'url', 'VARCHAR(190)');
91 $migrations[] = $this->migration->db->changeColumnType('option', 'option_name', 'VARCHAR(191)');
92
93 $migrations[] = $this->migration->db->changeColumnType('log_action', 'name', 'VARCHAR(4096)');
94 $migrations[] = $this->migration->db->changeColumnType('log_conversion', 'url', 'VARCHAR(4096)');
95 $migrations[] = $this->migration->db->changeColumn('log_link_visit_action', 'interaction_position', 'pageview_position', 'MEDIUMINT UNSIGNED DEFAULT NULL');
96
97 $customTrackerPluginActive = false;
98 if (in_array('CustomPiwikJs', Config::getInstance()->Plugins['Plugins'])) {
99 $customTrackerPluginActive = true;
100 }
101
102 $migrations[] = $this->migration->plugin->activate('BulkTracking');
103 $migrations[] = $this->migration->plugin->deactivate('CustomPiwikJs');
104 $migrations[] = $this->migration->plugin->uninstall('CustomPiwikJs');
105
106 if ($customTrackerPluginActive) {
107 $migrations[] = $this->migration->plugin->activate('CustomJsTracker');
108 }
109
110 // Prepare all installed tables for utf8mb4 conversions. e.g. make some indexed fields smaller so they don't exceed the maximum key length
111 $allTables = DbHelper::getTablesInstalled();
112
113 foreach ($allTables as $table) {
114 if (preg_match('/archive_/', $table) == 1) {
115 $tableNameUnprefixed = Common::unprefixTable($table);
116 $migrations[] = $this->migration->db->changeColumnType($tableNameUnprefixed, 'name', 'VARCHAR(190)');
117 }
118 }
119
120 // Move the site search fields of log_visit out of custom variables into their own fields
121 $columnsToAdd['log_link_visit_action']['search_cat'] = 'VARCHAR(200) NULL';
122 $columnsToAdd['log_link_visit_action']['search_count'] = 'INTEGER(10) UNSIGNED NULL';
123
124 // replace days to ... dimensions w/ seconds dimensions
125 foreach (['log_visit', 'log_conversion'] as $table) {
126 $columnsToAdd[$table]['visitor_seconds_since_first'] = VisitorSecondsSinceFirst::COLUMN_TYPE;
127 $columnsToAdd[$table]['visitor_seconds_since_order'] = VisitorSecondsSinceOrder::COLUMN_TYPE;
128 }
129 $columnsToAdd['log_visit']['visitor_seconds_since_last'] = VisitorSecondsSinceLast::COLUMN_TYPE;
130 $columnsToAdd['log_visit']['profilable'] = Profilable::COLUMN_TYPE;
131 $columnsToAdd['log_link_visit_action'][TimeDomCompletion::COLUMN_NAME] = TimeDomCompletion::COLUMN_TYPE;
132 $columnsToAdd['log_link_visit_action'][TimeDomProcessing::COLUMN_NAME] = TimeDomProcessing::COLUMN_TYPE;
133 $columnsToAdd['log_link_visit_action'][TimeNetwork::COLUMN_NAME] = TimeNetwork::COLUMN_TYPE;
134 $columnsToAdd['log_link_visit_action'][TimeOnLoad::COLUMN_NAME] = TimeOnLoad::COLUMN_TYPE;
135 $columnsToAdd['log_link_visit_action'][TimeServer::COLUMN_NAME] = TimeServer::COLUMN_TYPE;
136 $columnsToAdd['log_link_visit_action'][TimeTransfer::COLUMN_NAME] = TimeTransfer::COLUMN_TYPE;
137
138 $columnsToMaybeAdd = ['revenue', 'revenue_discount', 'revenue_shipping', 'revenue_subtotal', 'revenue_tax'];
139 $columnsLogConversion = $tableMetadata->getColumns(Common::prefixTable('log_conversion'));
140 foreach ($columnsToMaybeAdd as $columnToMaybeAdd) {
141 if (!in_array($columnToMaybeAdd, $columnsLogConversion, true)) {
142 $columnsToAdd['log_conversion'][$columnToMaybeAdd] = 'DOUBLE NULL DEFAULT NULL';
143 }
144 }
145
146 foreach ($columnsToAdd as $table => $columns) {
147 $migrations[] = $this->migration->db->addColumns($table, $columns);
148
149 foreach ($columns as $columnName => $columnType) {
150 $optionKey = 'version_' . $table . '.' . $columnName;
151 $optionValue = $columnType;
152
153 if ($table == 'log_visit' && isset($columnsToAdd['log_conversion'][$columnName])) {
154 $optionValue .= '1'; // column is in log_conversion too
155 }
156
157 $migrations[] = $this->migration->db->sql("INSERT IGNORE INTO `" . Common::prefixTable('option')
158 . "` (option_name, option_value) VALUES ('$optionKey', '$optionValue')");
159 }
160 }
161
162 if (Manager::getInstance()->isPluginInstalled('CustomVariables')) {
163 $visitActionTable = Common::prefixTable('log_link_visit_action');
164 $migrations[] = $this->migration->db->sql("UPDATE $visitActionTable SET search_cat = if(custom_var_k4 = '_pk_scat', custom_var_v4, search_cat), search_count = if(custom_var_k5 = '_pk_scount', custom_var_v5, search_count) WHERE custom_var_k4 = '_pk_scat' or custom_var_k5 = '_pk_scount'");
165 }
166
167 if ($this->usesGeoIpLegacyLocationProvider()) {
168 // activate GeoIp2 plugin for users still using GeoIp2 Legacy (others might have it disabled on purpose)
169 $migrations[] = $this->migration->plugin->activate('GeoIp2');
170 }
171
172 // remove old options
173 $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")');
174
175 // init seconds_to_... columns
176 $logVisitColumns = $tableMetadata->getColumns(Common::prefixTable('log_visit'));
177 $hasDaysColumnInVisit = in_array('visitor_days_since_first', $logVisitColumns);
178
179 if ($hasDaysColumnInVisit) {
180 $migrations[] = $this->migration->db->sql("UPDATE " . Common::prefixTable('log_visit')
181 . " SET visitor_seconds_since_first = visitor_days_since_first * 86400,
182 visitor_seconds_since_order = visitor_days_since_order * 86400,
183 visitor_seconds_since_last = visitor_days_since_last * 86400");
184 }
185
186 $logConvColumns = $tableMetadata->getColumns(Common::prefixTable('log_conversion'));
187 $hasDaysColumnInConv = in_array('visitor_days_since_first', $logConvColumns);
188
189 if ($hasDaysColumnInConv) {
190 $migrations[] = $this->migration->db->sql("UPDATE " . Common::prefixTable('log_conversion')
191 . " SET visitor_seconds_since_first = visitor_days_since_first * 86400,
192 visitor_seconds_since_order = visitor_days_since_order * 86400");
193 }
194
195 // remove old days_to_... columns
196 $migrations[] = $this->migration->db->dropColumns('log_visit', [
197 'config_gears',
198 'config_director',
199 'visitor_days_since_first',
200 'visitor_days_since_order',
201 'visitor_days_since_last',
202 ]);
203 $migrations[] = $this->migration->db->dropColumns('log_conversion', [
204 'visitor_days_since_first',
205 'visitor_days_since_order',
206 ]);
207
208 $config = Config::getInstance();
209
210 if (!empty($config->mail['type']) && $config->mail['type'] === 'Crammd5') {
211 $migrations[] = $this->migration->config->set('mail', 'type', 'Cram-md5');
212 }
213
214 // keep piwik_ignore for existing installs
215 $migrations[] = $this->migration->config->set('Tracker', 'ignore_visits_cookie_name', 'piwik_ignore');
216
217 $migrations[] = $this->migration->plugin->activate('PagePerformance');
218 if (!Manager::getInstance()->isPluginActivated('CustomDimensions')) {
219 $migrations[] = $this->migration->plugin->activate('CustomDimensions');
220 }
221
222 $configTableLimit = Config::getInstance()->getFromLocalConfig('General')['datatable_archiving_maximum_rows_custom_variables'] ?? null;
223 $configSubTableLimit = Config::getInstance()->getFromLocalConfig('General')['datatable_archiving_maximum_rows_subtable_custom_variables'] ?? null;
224
225 if ($configTableLimit) {
226 $migrations[] = $this->migration->config->set('General', 'datatable_archiving_maximum_rows_custom_dimensions', $configTableLimit);
227 }
228 if ($configSubTableLimit) {
229 $migrations[] = $this->migration->config->set('General', 'datatable_archiving_maximum_rows_subtable_custom_dimensions', $configSubTableLimit);
230 }
231
232 return $migrations;
233 }
234
235 public function doUpdate(Updater $updater)
236 {
237 $salt = SettingsPiwik::getSalt();
238 $sessions = Db::fetchAll('SELECT id from ' . Common::prefixTable('session'));
239
240 foreach ($sessions as $session) {
241 if (!empty($session['id']) && mb_strlen($session['id']) != 128) {
242 $bind = [ hash('sha512', $session['id'] . $salt), $session['id'] ];
243 try {
244 Db::query(sprintf('UPDATE %s SET id = ? WHERE id = ?', Common::prefixTable('session')), $bind);
245 } catch (\Exception $e) {
246 // ignore possible duplicate key errors
247 }
248 }
249 }
250
251 $updater->executeMigrations(__FILE__, $this->getMigrations($updater));
252
253 if ($this->usesGeoIpLegacyLocationProvider()) {
254 // switch to default provider if GeoIp Legacy was still in use
255 LocationProvider::setCurrentProvider(LocationProvider\DefaultProvider::ID);
256 }
257
258 // eg the case when not updating from most recent Matomo 3.X and when not using the UI updater
259 // afterwards the should receive a notification that the plugins are outdated
260 self::ensureCorePluginsThatWereMovedToMarketplaceCanBeUpdated();
261 ServerFilesGenerator::createFilesForSecurity();
262 }
263
264 public static function ensureCorePluginsThatWereMovedToMarketplaceCanBeUpdated()
265 {
266 $plugins = ['Provider', 'CustomVariables'];
267 $pluginManager = Manager::getInstance();
268 foreach ($plugins as $plugin) {
269 if ($pluginManager->isPluginThirdPartyAndBogus($plugin)) {
270 $pluginDir = Manager::getPluginDirectory($plugin);
271
272 if (is_dir($pluginDir) &&
273 file_exists($pluginDir . '/' . $plugin . '.php')
274 && !file_exists($pluginDir . '/plugin.json')
275 && is_writable($pluginDir)) {
276 file_put_contents($pluginDir . '/plugin.json', '{
277 "name": "'.$plugin.'",
278 "description": "'.$plugin.'",
279 "version": "3.14.1",
280 "theme": false,
281 "require": {
282 "piwik": ">=3.0.0,<4.0.0-b1"
283 },
284 "authors": [
285 {
286 "name": "Matomo",
287 "email": "hello@matomo.org",
288 "homepage": "https:\/\/matomo.org"
289 }
290 ],
291 "homepage": "https:\/\/matomo.org",
292 "license": "GPL v3+",
293 "keywords": ["'.$plugin.'"]
294 }');
295 // otherwise cached information might be used and it won't be loaded otherwise within same request
296 $pluginObj = $pluginManager->loadPlugin($plugin);
297 $pluginObj->reloadPluginInformation();
298 $pluginManager->unloadPlugin($pluginObj); // prevent any events being posted to it somehow
299 }
300 }
301 }
302 }
303
304 protected function usesGeoIpLegacyLocationProvider()
305 {
306 $currentProvider = LocationProvider::getCurrentProviderId();
307
308 return in_array($currentProvider, [
309 'geoip_pecl',
310 'geoip_php',
311 'geoip_serverbased',
312 ]);
313 }
314 }
315