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