PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / ArchiveProcessor / Rules.php
matomo / app / core / ArchiveProcessor Last commit date
ArchivingStatus.php 5 years ago Loader.php 5 years ago Parameters.php 5 years ago PluginsArchiver.php 5 years ago PluginsArchiverException.php 5 years ago Rules.php 5 years ago
Rules.php
356 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\ArchiveProcessor;
10
11 use Exception;
12 use Piwik\Common;
13 use Piwik\Config;
14 use Piwik\DataAccess\ArchiveWriter;
15 use Piwik\DataAccess\Model;
16 use Piwik\Date;
17 use Piwik\Log;
18 use Piwik\Option;
19 use Piwik\Piwik;
20 use Piwik\Plugin\Manager;
21 use Piwik\Plugins\CoreAdminHome\Controller;
22 use Piwik\Segment;
23 use Piwik\SettingsPiwik;
24 use Piwik\SettingsServer;
25 use Piwik\Site;
26 use Piwik\Tracker\Cache;
27
28 /**
29 * This class contains Archiving rules/logic which are used when creating and processing Archives.
30 *
31 */
32 class Rules
33 {
34 const OPTION_TODAY_ARCHIVE_TTL = 'todayArchiveTimeToLive';
35
36 const OPTION_BROWSER_TRIGGER_ARCHIVING = 'enableBrowserTriggerArchiving';
37
38 const FLAG_TABLE_PURGED = 'lastPurge_';
39
40 /** Flag that will forcefully disable the archiving process (used in tests only) */
41 public static $archivingDisabledByTests = false;
42
43 /**
44 * Returns the name of the archive field used to tell the status of an archive, (ie,
45 * whether the archive was created successfully or not).
46 *
47 * @param array $idSites
48 * @param Segment $segment
49 * @param string $periodLabel
50 * @param string $plugin
51 * @return string
52 */
53 public static function getDoneStringFlagFor(array $idSites, $segment, $periodLabel, $plugin)
54 {
55 if (!empty($plugin)
56 && !self::shouldProcessReportsAllPlugins($idSites, $segment, $periodLabel)
57 ) {
58 return self::getDoneFlagArchiveContainsOnePlugin($segment, $plugin);
59 }
60 return self::getDoneFlagArchiveContainsAllPlugins($segment);
61 }
62
63 public static function shouldProcessReportsAllPlugins(array $idSites, Segment $segment, $periodLabel)
64 {
65 if (self::isRequestingToAndAbleToForceArchiveSinglePlugin()) {
66 return false;
67 }
68
69 if ($segment->isEmpty() && ($periodLabel != 'range' || SettingsServer::isArchivePhpTriggered())) {
70 return true;
71 }
72
73 return self::isSegmentPreProcessed($idSites, $segment);
74 }
75
76 /**
77 * @param $idSites
78 * @return array
79 */
80 public static function getSegmentsToProcess($idSites)
81 {
82 $knownSegmentsToArchiveAllSites = SettingsPiwik::getKnownSegmentsToArchive();
83
84 $segmentsToProcess = $knownSegmentsToArchiveAllSites;
85 foreach ($idSites as $idSite) {
86 $segmentForThisWebsite = SettingsPiwik::getKnownSegmentsToArchiveForSite($idSite);
87 $segmentsToProcess = array_merge($segmentsToProcess, $segmentForThisWebsite);
88 }
89 $segmentsToProcess = array_unique($segmentsToProcess);
90 return $segmentsToProcess;
91 }
92
93 public static function getDoneFlagArchiveContainsOnePlugin(Segment $segment, $plugin)
94 {
95 return 'done' . $segment->getHash() . '.' . $plugin ;
96 }
97
98 public static function getDoneFlagArchiveContainsAllPlugins(Segment $segment)
99 {
100 return 'done' . $segment->getHash();
101 }
102
103 /**
104 * Return done flags used to tell how the archiving process for a specific archive was completed,
105 *
106 * @param array $plugins
107 * @param $segment
108 * @return array
109 */
110 public static function getDoneFlags(array $plugins, Segment $segment)
111 {
112 $doneFlags = array();
113 $doneAllPlugins = self::getDoneFlagArchiveContainsAllPlugins($segment);
114 $doneFlags[$doneAllPlugins] = $doneAllPlugins;
115
116 $plugins = array_unique($plugins);
117 foreach ($plugins as $plugin) {
118 $doneOnePlugin = self::getDoneFlagArchiveContainsOnePlugin($segment, $plugin);
119 $doneFlags[$plugin] = $doneOnePlugin;
120 }
121 return $doneFlags;
122 }
123
124 public static function getMinTimeProcessedForInProgressArchive(
125 Date $dateStart, \Piwik\Period $period, Segment $segment, Site $site)
126 {
127 $todayArchiveTimeToLive = self::getPeriodArchiveTimeToLiveDefault($period->getLabel());
128
129 $now = time();
130 $minimumArchiveTime = $now - $todayArchiveTimeToLive;
131
132 $idSites = array($site->getId());
133 $isArchivingDisabled = Rules::isArchivingDisabledFor($idSites, $segment, $period->getLabel());
134 if ($isArchivingDisabled) {
135 if ($period->getNumberOfSubperiods() == 0
136 && $dateStart->getTimestamp() <= $now
137 ) {
138 // Today: accept any recent enough archive
139 $minimumArchiveTime = false;
140 } else {
141 // This week, this month, this year:
142 // accept any archive that was processed today after 00:00:01 this morning
143 $timezone = $site->getTimezone();
144 $minimumArchiveTime = Date::factory(Date::factory('now', $timezone)->getDateStartUTC())->setTimezone($timezone)->getTimestamp();
145 }
146 }
147 return $minimumArchiveTime;
148 }
149
150 public static function setTodayArchiveTimeToLive($timeToLiveSeconds)
151 {
152 $timeToLiveSeconds = (int)$timeToLiveSeconds;
153 if ($timeToLiveSeconds <= 0) {
154 throw new Exception(Piwik::translate('General_ExceptionInvalidArchiveTimeToLive'));
155 }
156 Option::set(self::OPTION_TODAY_ARCHIVE_TTL, $timeToLiveSeconds, $autoLoad = true);
157 }
158
159 public static function getTodayArchiveTimeToLive()
160 {
161 $uiSettingIsEnabled = Controller::isGeneralSettingsAdminEnabled();
162
163 if ($uiSettingIsEnabled) {
164 $timeToLive = Option::get(self::OPTION_TODAY_ARCHIVE_TTL);
165 if ($timeToLive !== false) {
166 return $timeToLive;
167 }
168 }
169 return self::getTodayArchiveTimeToLiveDefault();
170 }
171
172 public static function getPeriodArchiveTimeToLiveDefault($periodLabel)
173 {
174 if (empty($periodLabel) || strtolower($periodLabel) === 'day') {
175 return self::getTodayArchiveTimeToLive();
176 }
177
178 $config = Config::getInstance();
179 $general = $config->General;
180
181 $key = sprintf('time_before_%s_archive_considered_outdated', $periodLabel);
182 if (isset($general[$key]) && is_numeric($general[$key]) && $general[$key] > 0) {
183 return $general[$key];
184 }
185
186 return self::getTodayArchiveTimeToLive();
187 }
188
189 public static function getTodayArchiveTimeToLiveDefault()
190 {
191 return Config::getInstance()->General['time_before_today_archive_considered_outdated'];
192 }
193
194 public static function isBrowserArchivingAvailableForSegments()
195 {
196 $generalConfig = Config::getInstance()->General;
197 return !$generalConfig['browser_archiving_disabled_enforce'];
198 }
199
200 public static function isArchivingEnabledFor(array $idSites, Segment $segment, $periodLabel)
201 {
202 return !self::isArchivingDisabledFor($idSites, $segment, $periodLabel);
203 }
204
205 public static function isArchivingDisabledFor(array $idSites, Segment $segment, $periodLabel)
206 {
207 $generalConfig = Config::getInstance()->General;
208
209 if ($periodLabel == 'range') {
210 if (!isset($generalConfig['archiving_range_force_on_browser_request'])
211 || $generalConfig['archiving_range_force_on_browser_request'] != false
212 ) {
213 return false;
214 }
215
216 Log::debug("Not forcing archiving for range period.");
217 $processOneReportOnly = false;
218
219 } else {
220 $processOneReportOnly = !self::shouldProcessReportsAllPlugins($idSites, $segment, $periodLabel);
221 }
222
223 $isArchivingEnabled = self::isRequestAuthorizedToArchive() && !self::$archivingDisabledByTests;
224
225 if ($processOneReportOnly) {
226 // When there is a segment, we disable archiving when browser_archiving_disabled_enforce applies
227 if (!$segment->isEmpty()
228 && !$isArchivingEnabled
229 && !self::isBrowserArchivingAvailableForSegments()
230 && !SettingsServer::isArchivePhpTriggered() // Only applies when we are not running core:archive command
231 ) {
232 Log::debug("Archiving is disabled because of config setting browser_archiving_disabled_enforce=1");
233 return true;
234 }
235
236 // Always allow processing one report
237 return false;
238 }
239
240 return !$isArchivingEnabled;
241 }
242
243 public static function isRequestAuthorizedToArchive(Parameters $params = null)
244 {
245 $isRequestAuthorizedToArchive = Rules::isBrowserTriggerEnabled() || SettingsServer::isArchivePhpTriggered();
246
247 if (!empty($params)) {
248 /**
249 * @ignore
250 *
251 * @params bool &$isRequestAuthorizedToArchive
252 * @params Parameters $params
253 */
254 Piwik::postEvent('Archiving.isRequestAuthorizedToArchive', [&$isRequestAuthorizedToArchive, $params]);
255 }
256
257 return $isRequestAuthorizedToArchive;
258 }
259
260 public static function isBrowserTriggerEnabled()
261 {
262 $uiSettingIsEnabled = Controller::isGeneralSettingsAdminEnabled();
263
264 if ($uiSettingIsEnabled) {
265 $browserArchivingEnabled = Option::get(self::OPTION_BROWSER_TRIGGER_ARCHIVING);
266 if ($browserArchivingEnabled !== false) {
267 return (bool)$browserArchivingEnabled;
268 }
269 }
270 return (bool)Config::getInstance()->General['enable_browser_archiving_triggering'];
271 }
272
273 public static function setBrowserTriggerArchiving($enabled)
274 {
275 if (!is_bool($enabled)) {
276 throw new Exception('Browser trigger archiving must be set to true or false.');
277 }
278 Option::set(self::OPTION_BROWSER_TRIGGER_ARCHIVING, (int)$enabled, $autoLoad = true);
279 Cache::clearCacheGeneral();
280 }
281
282 /**
283 * Returns true if the archiving process should skip the calculation of unique visitors
284 * across several sites. The `[General] enable_processing_unique_visitors_multiple_sites`
285 * INI config option controls the value of this variable.
286 *
287 * @return bool
288 */
289 public static function shouldSkipUniqueVisitorsCalculationForMultipleSites()
290 {
291 return Config::getInstance()->General['enable_processing_unique_visitors_multiple_sites'] != 1;
292 }
293
294 /**
295 * @param array $idSites
296 * @param Segment $segment
297 * @return bool
298 */
299 public static function isSegmentPreProcessed(array $idSites, Segment $segment)
300 {
301 $segmentsToProcess = self::getSegmentsToProcess($idSites);
302
303 if (empty($segmentsToProcess)) {
304 return false;
305 }
306 // If the requested segment is one of the segments to pre-process
307 // we ensure that any call to the API will trigger archiving of all reports for this segment
308 $segment = $segment->getString();
309
310 // Turns out the getString() above returns the URL decoded segment string
311 $segmentsToProcessUrlDecoded = array_map('urldecode', $segmentsToProcess);
312
313 return in_array($segment, $segmentsToProcess)
314 || in_array($segment, $segmentsToProcessUrlDecoded);
315 }
316
317 /**
318 * Returns done flag values allowed to be selected
319 *
320 * @return string[]
321 */
322 public static function getSelectableDoneFlagValues($includeInvalidated = true, Parameters $params = null, $checkAuthorizedToArchive = true)
323 {
324 $possibleValues = array(ArchiveWriter::DONE_OK, ArchiveWriter::DONE_OK_TEMPORARY);
325
326 if ($includeInvalidated) {
327 if (!$checkAuthorizedToArchive || !Rules::isRequestAuthorizedToArchive($params)) {
328 //If request is not authorized to archive then fetch also invalidated archives
329 $possibleValues[] = ArchiveWriter::DONE_INVALIDATED;
330 $possibleValues[] = ArchiveWriter::DONE_PARTIAL;
331 }
332 }
333
334 return $possibleValues;
335 }
336
337 public static function isRequestingToAndAbleToForceArchiveSinglePlugin()
338 {
339 if (!SettingsServer::isArchivePhpTriggered()) {
340 return false;
341 }
342
343 return !empty($_GET['pluginOnly']) || !empty($_POST['pluginOnly']);
344 }
345
346 public static function isActuallyForceArchivingSinglePlugin()
347 {
348 return Loader::getArchivingDepth() <= 1 && self::isRequestingToAndAbleToForceArchiveSinglePlugin();
349 }
350
351 public static function shouldProcessSegmentsWhenReArchivingReports()
352 {
353 return Config::getInstance()->General['rearchive_reports_in_past_exclude_segments'] != 1;
354 }
355 }
356