PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.2
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 / Tracker.php
matomo / app / core Last commit date
API 5 years ago Access 5 years ago Application 5 years ago Archive 5 years ago ArchiveProcessor 5 years ago Archiver 5 years ago AssetManager 5 years ago Auth 5 years ago Category 5 years ago CliMulti 5 years ago Columns 5 years ago Composer 5 years ago Concurrency 5 years ago Config 5 years ago Container 5 years ago CronArchive 5 years ago DataAccess 5 years ago DataFiles 5 years ago DataTable 5 years ago Db 5 years ago DeviceDetector 5 years ago Email 5 years ago Exception 5 years ago Http 5 years ago Intl 5 years ago Mail 5 years ago Measurable 5 years ago Menu 5 years ago Metrics 5 years ago Notification 5 years ago Period 5 years ago Plugin 5 years ago ProfessionalServices 5 years ago Report 5 years ago ReportRenderer 5 years ago Scheduler 5 years ago Segment 5 years ago Session 5 years ago Settings 5 years ago Tracker 5 years ago Translation 5 years ago UpdateCheck 5 years ago Updater 5 years ago Updates 5 years ago Validators 5 years ago View 5 years ago ViewDataTable 5 years ago Visualization 5 years ago Widget 5 years ago .htaccess 6 years ago Access.php 5 years ago Archive.php 5 years ago ArchiveProcessor.php 5 years ago AssetManager.php 5 years ago Auth.php 5 years ago AuthResult.php 5 years ago BaseFactory.php 5 years ago Cache.php 5 years ago CacheId.php 5 years ago CliMulti.php 5 years ago Common.php 5 years ago Config.php 5 years ago Console.php 5 years ago Context.php 5 years ago Cookie.php 5 years ago CronArchive.php 5 years ago DataArray.php 5 years ago DataTable.php 5 years ago Date.php 5 years ago Db.php 5 years ago DbHelper.php 5 years ago Development.php 5 years ago ErrorHandler.php 5 years ago EventDispatcher.php 5 years ago ExceptionHandler.php 5 years ago FileIntegrity.php 5 years ago Filechecks.php 5 years ago Filesystem.php 5 years ago FrontController.php 5 years ago Http.php 5 years ago IP.php 5 years ago Log.php 5 years ago LogDeleter.php 5 years ago Mail.php 5 years ago Metrics.php 5 years ago NoAccessException.php 5 years ago Nonce.php 5 years ago Notification.php 5 years ago NumberFormatter.php 5 years ago Option.php 5 years ago Period.php 5 years ago Piwik.php 5 years ago Plugin.php 5 years ago Profiler.php 5 years ago ProxyHeaders.php 5 years ago ProxyHttp.php 5 years ago QuickForm2.php 5 years ago RankingQuery.php 5 years ago ReportRenderer.php 5 years ago Segment.php 5 years ago Sequence.php 5 years ago Session.php 5 years ago SettingsPiwik.php 5 years ago SettingsServer.php 5 years ago Singleton.php 5 years ago Site.php 5 years ago TCPDF.php 5 years ago Theme.php 5 years ago Timer.php 5 years ago Tracker.php 5 years ago Twig.php 5 years ago Unzip.php 5 years ago UpdateCheck.php 5 years ago Updater.php 5 years ago UpdaterErrorException.php 5 years ago Updates.php 5 years ago Url.php 5 years ago UrlHelper.php 5 years ago Version.php 5 years ago View.php 5 years ago bootstrap.php 5 years ago dispatch.php 5 years ago testMinimumPhpVersion.php 5 years ago
Tracker.php
362 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;
10
11 use Exception;
12 use Piwik\Container\StaticContainer;
13 use Piwik\Plugins\BulkTracking\Tracker\Requests;
14 use Piwik\Plugins\PrivacyManager\Config as PrivacyManagerConfig;
15 use Piwik\Tracker\Db as TrackerDb;
16 use Piwik\Tracker\Db\DbException;
17 use Piwik\Tracker\Handler;
18 use Piwik\Tracker\Request;
19 use Piwik\Tracker\RequestSet;
20 use Piwik\Tracker\TrackerConfig;
21 use Piwik\Tracker\Visit;
22 use Piwik\Plugin\Manager as PluginManager;
23 use Psr\Log\LoggerInterface;
24
25 /**
26 * Class used by the logging script piwik.php called by the javascript tag.
27 * Handles the visitor and their actions on the website, saves the data in the DB,
28 * saves information in the cookie, etc.
29 *
30 * We try to include as little files as possible (no dependency on 3rd party modules).
31 */
32 class Tracker
33 {
34 /**
35 * @var Db
36 */
37 private static $db = null;
38
39 // We use hex ID that are 16 chars in length, ie. 64 bits IDs
40 const LENGTH_HEX_ID_STRING = 16;
41 const LENGTH_BINARY_ID = 8;
42
43 public static $initTrackerMode = false;
44
45 private $countOfLoggedRequests = 0;
46 protected $isInstalled = null;
47
48 /**
49 * @var LoggerInterface
50 */
51 private $logger;
52
53 public function __construct()
54 {
55 $this->logger = StaticContainer::get(LoggerInterface::class);
56 }
57
58 public function isDebugModeEnabled()
59 {
60 return array_key_exists('PIWIK_TRACKER_DEBUG', $GLOBALS) && $GLOBALS['PIWIK_TRACKER_DEBUG'] === true;
61 }
62
63 public function shouldRecordStatistics()
64 {
65 $record = TrackerConfig::getConfigValue('record_statistics') != 0;
66
67 if (!$record) {
68 $this->logger->debug('Tracking is disabled in the config.ini.php via record_statistics=0');
69 }
70
71 return $record && $this->isInstalled();
72 }
73
74 public static function loadTrackerEnvironment()
75 {
76 SettingsServer::setIsTrackerApiRequest();
77 if (empty($GLOBALS['PIWIK_TRACKER_DEBUG'])) {
78 $GLOBALS['PIWIK_TRACKER_DEBUG'] = self::isDebugEnabled();
79 }
80 if (!empty($GLOBALS['PIWIK_TRACKER_DEBUG']) && !Common::isPhpCliMode()) {
81 Common::sendHeader('Content-Type: text/plain');
82 }
83 PluginManager::getInstance()->loadTrackerPlugins();
84 }
85
86 private function init()
87 {
88 $this->handleFatalErrors();
89
90 if ($this->isDebugModeEnabled()) {
91 ErrorHandler::registerErrorHandler();
92 ExceptionHandler::setUp();
93
94 $this->logger->debug("Debug enabled - Input parameters: {params}", [
95 'params' => var_export($_GET + $_POST, true),
96 ]);
97 }
98 }
99
100 public function isInstalled()
101 {
102 if (is_null($this->isInstalled)) {
103 $this->isInstalled = SettingsPiwik::isMatomoInstalled();
104 }
105
106 return $this->isInstalled;
107 }
108
109 public function main(Handler $handler, RequestSet $requestSet)
110 {
111 try {
112 $this->init();
113 $handler->init($this, $requestSet);
114
115 $this->track($handler, $requestSet);
116 } catch (Exception $e) {
117 StaticContainer::get(LoggerInterface::class)->debug("Tracker encountered an exception: {ex}", [$e]);
118
119 $handler->onException($this, $requestSet, $e);
120 }
121
122 Piwik::postEvent('Tracker.end');
123 $response = $handler->finish($this, $requestSet);
124
125 $this->disconnectDatabase();
126
127 return $response;
128 }
129
130 public function track(Handler $handler, RequestSet $requestSet)
131 {
132 if (!$this->shouldRecordStatistics()) {
133 return;
134 }
135
136 $requestSet->initRequestsAndTokenAuth();
137
138 if ($requestSet->hasRequests()) {
139 $handler->onStartTrackRequests($this, $requestSet);
140 $handler->process($this, $requestSet);
141 $handler->onAllRequestsTracked($this, $requestSet);
142 }
143 }
144
145 /**
146 * @param Request $request
147 * @return array
148 */
149 public function trackRequest(Request $request)
150 {
151 if ($request->isEmptyRequest()) {
152 $this->logger->debug('The request is empty');
153 } else {
154 $this->logger->debug('Current datetime: {date}', [
155 'date' => date("Y-m-d H:i:s", $request->getCurrentTimestamp()),
156 ]);
157
158 $visit = Visit\Factory::make();
159 $visit->setRequest($request);
160 $visit->handle();
161 }
162
163 // increment successfully logged request count. make sure to do this after try-catch,
164 // since an excluded visit is considered 'successfully logged'
165 ++$this->countOfLoggedRequests;
166 }
167
168 /**
169 * Used to initialize core Piwik components on a piwik.php request
170 * Eg. when cache is missed and we will be calling some APIs to generate cache
171 */
172 public static function initCorePiwikInTrackerMode()
173 {
174 if (SettingsServer::isTrackerApiRequest()
175 && self::$initTrackerMode === false
176 ) {
177 self::$initTrackerMode = true;
178 require_once PIWIK_INCLUDE_PATH . '/core/Option.php';
179
180 Access::getInstance();
181 Config::getInstance();
182
183 try {
184 Db::get();
185 } catch (Exception $e) {
186 Db::createDatabaseObject();
187 }
188
189 PluginManager::getInstance()->loadCorePluginsDuringTracker();
190 }
191 }
192
193 public static function restoreTrackerPlugins()
194 {
195 if (SettingsServer::isTrackerApiRequest() && Tracker::$initTrackerMode) {
196 Plugin\Manager::getInstance()->loadTrackerPlugins();
197 }
198 }
199
200 public function getCountOfLoggedRequests()
201 {
202 return $this->countOfLoggedRequests;
203 }
204
205 public function setCountOfLoggedRequests($numLoggedRequests)
206 {
207 $this->countOfLoggedRequests = $numLoggedRequests;
208 }
209
210 public function hasLoggedRequests()
211 {
212 return 0 !== $this->countOfLoggedRequests;
213 }
214
215 public function isDatabaseConnected()
216 {
217 return !is_null(self::$db);
218 }
219
220 public static function getDatabase()
221 {
222 if (is_null(self::$db)) {
223 try {
224 self::$db = TrackerDb::connectPiwikTrackerDb();
225 } catch (Exception $e) {
226 throw new DbException($e->getMessage(), $e->getCode());
227 }
228 }
229
230 return self::$db;
231 }
232
233 protected function disconnectDatabase()
234 {
235 if ($this->isDatabaseConnected()) { // note: I think we do this only for the tests
236 self::$db->disconnect();
237 self::$db = null;
238 }
239 }
240
241 // for tests
242 public static function disconnectCachedDbConnection()
243 {
244 // code redundancy w/ above is on purpose; above disconnectDatabase depends on method that can potentially be overridden
245 if (!is_null(self::$db)) {
246 self::$db->disconnect();
247 self::$db = null;
248 }
249 }
250
251 public static function setTestEnvironment($args = null, $requestMethod = null)
252 {
253 if (is_null($args)) {
254 $requests = new Requests();
255 $args = $requests->getRequestsArrayFromBulkRequest($requests->getRawBulkRequest());
256 $args = $_GET + $args;
257 }
258
259 if (is_null($requestMethod) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
260 $requestMethod = $_SERVER['REQUEST_METHOD'];
261 } elseif (is_null($requestMethod)) {
262 $requestMethod = 'GET';
263 }
264
265 // Do not run scheduled tasks during tests
266 if (!defined('DEBUG_FORCE_SCHEDULED_TASKS')) {
267 TrackerConfig::setConfigValue('scheduled_tasks_min_interval', 0);
268 }
269
270 // if nothing found in _GET/_POST and we're doing a POST, assume bulk request. in which case,
271 // we have to bypass authentication
272 if (empty($args) && $requestMethod == 'POST') {
273 TrackerConfig::setConfigValue('tracking_requests_require_authentication', 0);
274 }
275
276 // Tests can force the use of 3rd party cookie for ID visitor
277 if (Common::getRequestVar('forceEnableFingerprintingAcrossWebsites', false, null, $args) == 1) {
278 TrackerConfig::setConfigValue('enable_fingerprinting_across_websites', 1);
279 }
280
281 // Tests can simulate the tracker API maintenance mode
282 if (Common::getRequestVar('forceEnableTrackerMaintenanceMode', false, null, $args) == 1) {
283 TrackerConfig::setConfigValue('record_statistics', 0);
284 }
285
286 // Tests can force the use of 3rd party cookie for ID visitor
287 if (Common::getRequestVar('forceUseThirdPartyCookie', false, null, $args) == 1) {
288 TrackerConfig::setConfigValue('use_third_party_id_cookie', 1);
289 }
290
291 // Tests using window_look_back_for_visitor
292 if (Common::getRequestVar('forceLargeWindowLookBackForVisitor', false, null, $args) == 1
293 // also look for this in bulk requests (see fake_logs_replay.log)
294 || strpos(json_encode($args, true), '"forceLargeWindowLookBackForVisitor":"1"') !== false
295 ) {
296 TrackerConfig::setConfigValue('window_look_back_for_visitor', 2678400);
297 }
298
299 // Tests can force the enabling of IP anonymization
300 if (Common::getRequestVar('forceIpAnonymization', false, null, $args) == 1) {
301 self::getDatabase(); // make sure db is initialized
302
303 $privacyConfig = new PrivacyManagerConfig();
304 $privacyConfig->ipAddressMaskLength = 2;
305
306 \Piwik\Plugins\PrivacyManager\IPAnonymizer::activate();
307
308 \Piwik\Tracker\Cache::deleteTrackerCache();
309 Filesystem::clearPhpCaches();
310 }
311
312 $pluginsDisabled = array('Provider');
313
314 // Disable provider plugin, because it is so slow to do many reverse ip lookups
315 PluginManager::getInstance()->setTrackerPluginsNotToLoad($pluginsDisabled);
316 }
317
318 protected function loadTrackerPlugins()
319 {
320 try {
321 $pluginManager = PluginManager::getInstance();
322 $pluginsTracker = $pluginManager->loadTrackerPlugins();
323
324 $this->logger->debug("Loading plugins: { {plugins} }", [
325 'plugins' => implode(", ", $pluginsTracker),
326 ]);
327 } catch (Exception $e) {
328 $this->logger->error('Error loading tracker plugins: {exception}', [
329 'exception' => $e,
330 ]);
331 }
332 }
333
334 private function handleFatalErrors()
335 {
336 register_shutdown_function(function () { // TODO: add a log here
337 $lastError = error_get_last();
338 if (!empty($lastError) && $lastError['type'] == E_ERROR) {
339 Common::sendResponseCode(500);
340 }
341 });
342 }
343
344 private static function isDebugEnabled()
345 {
346 try {
347 $debug = (bool) TrackerConfig::getConfigValue('debug');
348 if ($debug) {
349 return true;
350 }
351
352 $debugOnDemand = (bool) TrackerConfig::getConfigValue('debug_on_demand');
353 if ($debugOnDemand) {
354 return (bool) Common::getRequestVar('debug', false);
355 }
356 } catch (Exception $e) {
357 }
358
359 return false;
360 }
361 }
362