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