PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.13.3
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.13.3
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 / Tracker / Response.php
matomo / app / core / Tracker Last commit date
Db 3 years ago Handler 5 years ago TableLogAction 5 years ago Visit 5 years ago Action.php 4 years ago ActionPageview.php 5 years ago Cache.php 4 years ago Db.php 4 years ago Failures.php 4 years ago FingerprintSalt.php 4 years ago GoalManager.php 4 years ago Handler.php 5 years ago IgnoreCookie.php 4 years ago LogTable.php 5 years ago Model.php 5 years ago PageUrl.php 3 years ago Request.php 3 years ago RequestProcessor.php 5 years ago RequestSet.php 4 years ago Response.php 4 years ago ScheduledTasksRunner.php 5 years ago Settings.php 3 years ago TableLogAction.php 5 years ago TrackerCodeGenerator.php 3 years ago TrackerConfig.php 3 years ago Visit.php 4 years ago VisitExcluded.php 3 years ago VisitInterface.php 5 years ago Visitor.php 5 years ago VisitorNotFoundInDb.php 5 years ago VisitorRecognizer.php 4 years ago
Response.php
241 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 *
9 */
10
11 namespace Piwik\Tracker;
12
13 use Exception;
14 use Piwik\Common;
15 use Piwik\Config;
16 use Piwik\Profiler;
17 use Piwik\Timer;
18 use Piwik\Tracker;
19 use Piwik\Tracker\Db as TrackerDb;
20 use Piwik\Url;
21
22 class Response
23 {
24 private $timer;
25
26 private $content;
27
28 public function init(Tracker $tracker)
29 {
30 ob_start(); // we use ob_start only because of Common::printDebug, we should actually not really use ob_start
31
32 if ($tracker->isDebugModeEnabled() && TrackerConfig::getConfigValue('enable_sql_profiler')) {
33 $this->timer = new Timer();
34
35 TrackerDb::enableProfiling();
36 }
37 }
38
39 public function getOutput()
40 {
41 $this->outputAccessControlHeaders();
42
43 if (is_null($this->content) && ob_get_level() > 0) {
44 $this->content = ob_get_clean();
45 }
46
47 return $this->content;
48 }
49
50 /**
51 * Echos an error message & other information, then exits.
52 *
53 * @param Tracker $tracker
54 * @param Exception $e
55 * @param int $statusCode eg 500
56 */
57 public function outputException(Tracker $tracker, Exception $e, $statusCode)
58 {
59 Common::sendResponseCode($statusCode);
60 $this->logExceptionToErrorLog($e);
61
62 if ($tracker->isDebugModeEnabled()) {
63 Common::sendHeader('Content-Type: text/html; charset=utf-8');
64 $trailer = '<span style="color: #888888">Backtrace:<br /><pre>' . $e->getTraceAsString() . '</pre></span>';
65 $headerPage = file_get_contents(PIWIK_INCLUDE_PATH . '/plugins/Morpheus/templates/simpleLayoutHeader.tpl');
66 $footerPage = file_get_contents(PIWIK_INCLUDE_PATH . '/plugins/Morpheus/templates/simpleLayoutFooter.tpl');
67 $headerPage = str_replace('{$HTML_TITLE}', 'Matomo &rsaquo; Error', $headerPage);
68
69 echo $headerPage . '<p>' . $this->getMessageFromException($e) . '</p>' . $trailer . $footerPage;
70 } else {
71 $this->outputApiResponse($tracker);
72 }
73 }
74
75 public function outputResponse(Tracker $tracker)
76 {
77 if (!$tracker->shouldRecordStatistics()) {
78 Common::sendResponseCode(503);
79 $this->outputApiResponse($tracker);
80 Common::printDebug("Logging disabled, display transparent logo");
81 } elseif (!$tracker->hasLoggedRequests()) {
82 if (!$this->isHttpGetRequest() || !empty($_GET) || !empty($_POST)) {
83 Common::sendResponseCode(400);
84 }
85 Common::printDebug("Empty request => Matomo page");
86 echo "This resource is part of Matomo. Keep full control of your data with the leading free and open source <a href='https://matomo.org' target='_blank' rel='noopener noreferrer nofollow'>web analytics & conversion optimisation platform</a>.<br>\n";
87 echo "This file is the endpoint for the Matomo tracking API. If you want to access the Matomo UI or use the Reporting API, please use <a href='index.php'>index.php</a> instead.";
88 } else {
89 $this->outputApiResponse($tracker);
90 Common::printDebug("Nothing to notice => default behaviour");
91 }
92
93 Common::printDebug("End of the page.");
94
95 if (
96 $tracker->isDebugModeEnabled()
97 && $tracker->isDatabaseConnected()
98 && TrackerDb::isProfilingEnabled()
99 ) {
100 $db = Tracker::getDatabase();
101 $db->recordProfiling();
102 Profiler::displayDbTrackerProfile($db);
103 }
104
105 if ($tracker->isDebugModeEnabled()) {
106 Common::printDebug($_COOKIE);
107 Common::printDebug((string)$this->timer);
108 }
109 }
110
111 private function outputAccessControlHeaders()
112 {
113 if (!$this->isHttpGetRequest()) {
114 $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '*';
115 Common::sendHeader('Access-Control-Allow-Origin: ' . $origin);
116 Common::sendHeader('Access-Control-Allow-Credentials: true');
117 }
118 }
119
120 private function isHttpGetRequest()
121 {
122 $requestMethod = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
123
124 return strtoupper($requestMethod) === 'GET';
125 }
126
127 private function getOutputBuffer()
128 {
129 return ob_get_contents();
130 }
131
132 protected function hasAlreadyPrintedOutput()
133 {
134 return strlen($this->getOutputBuffer()) > 0;
135 }
136
137 private function outputApiResponse(Tracker $tracker)
138 {
139 if ($tracker->isDebugModeEnabled()) {
140 return;
141 }
142
143 if ($this->hasAlreadyPrintedOutput()) {
144 return;
145 }
146
147 $request = $_GET + $_POST;
148
149 if ($this->isHttpGetRequest()) {
150 Common::sendHeader('Cache-Control: no-store');
151 }
152
153 if (array_key_exists('send_image', $request) && $request['send_image'] === '0') {
154 Common::sendResponseCode(204);
155 return;
156 }
157
158 // Check for a custom tracking image
159 $customImage = Config::getInstance()->Tracker['custom_image'];
160 if (!empty($customImage) && $this->outputCustomImage($customImage)) {
161 return;
162 }
163
164 // No custom image defined, so output the default 1x1 base64 transparent gif
165 $this->outputTransparentGif();
166 }
167
168 /**
169 * Output a 1px x 1px transparent gif
170 */
171 private function outputTransparentGif()
172 {
173 $transGifBase64 = "R0lGODlhAQABAIAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
174 Common::sendHeader('Content-Type: image/gif');
175
176 echo base64_decode($transGifBase64);
177 }
178
179 /**
180 * Output a custom tracking image
181 *
182 * @param string $customImage The custom image setting specified in the config
183 *
184 * @return bool True if the custom image was successfully output, else false
185 */
186 private function outputCustomImage(string $customImage): bool
187 {
188 $supportedMimeTypes = ['image/png', 'image/gif', 'image/jpeg'];
189
190 $img = null;
191 $size = null;
192
193 if (strlen($customImage) > 2 && substr($customImage, -2) == '==') {
194 // Base64 image string
195 $img = base64_decode($customImage);
196 $size = getimagesizefromstring($img);
197 } elseif (is_file($customImage) && is_readable($customImage)) {
198 // Image file
199 $img = file_get_contents($customImage);
200 $size = getimagesize($customImage); // imagesize is used to get the mime type
201 }
202
203 // Must have valid image data and a valid mime type to proceed
204 if ($img && $size && isset($size['mime']) && in_array($size['mime'], $supportedMimeTypes)) {
205 Common::sendHeader('Content-Type: ' . $size['mime']);
206 echo $img;
207 return true;
208 }
209
210 return false;
211 }
212
213 /**
214 * Gets the error message to output when a tracking request fails.
215 *
216 * @param Exception $e
217 * @return string
218 */
219 protected function getMessageFromException($e)
220 {
221 // Note: duplicated from FormDatabaseSetup.isAccessDenied
222 // Avoid leaking the username/db name when access denied
223 if ($e->getCode() == 1044 || $e->getCode() == 42000) {
224 return "Error while connecting to the Matomo database - please check your credentials in config/config.ini.php file";
225 }
226
227 if (Common::isPhpCliMode()) {
228 return $e->getMessage() . "\n" . $e->getTraceAsString();
229 }
230
231 return $e->getMessage();
232 }
233
234 protected function logExceptionToErrorLog($e)
235 {
236 $hostname = Url::getRFCValidHostname();
237 $hostStr = $hostname ? "[$hostname]" : '-';
238 error_log(sprintf("$hostStr Error in Matomo (tracker): %s", str_replace("\n", " ", $this->getMessageFromException($e))));
239 }
240 }
241