PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
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 / View.php
matomo / app / core Last commit date
API 1 month ago Access 3 months ago Application 1 month ago Archive 1 month ago ArchiveProcessor 1 month ago Archiver 2 years ago AssetManager 1 month ago Auth 6 months ago Category 6 months ago Changes 1 month ago CliMulti 1 year ago Columns 1 month ago Concurrency 1 month ago Config 1 month ago Container 1 month ago CronArchive 3 months ago DataAccess 1 month ago DataFiles 2 years ago DataTable 2 weeks ago Db 2 weeks ago DeviceDetector 1 year ago Email 2 years ago Exception 4 months ago Http 4 months ago Intl 3 months ago Log 2 years ago Mail 1 year ago Measurable 6 months ago Menu 1 month ago Metrics 3 months ago Notification 6 months ago Period 1 month ago Plugin 2 weeks ago Policy 1 month ago ProfessionalServices 1 year ago Report 1 year ago ReportRenderer 3 months ago Request 3 months ago Scheduler 1 month ago Segment 1 month ago Session 2 weeks ago Settings 1 month ago Tracker 2 weeks ago Translation 1 month ago Twig 1 year ago UpdateCheck 3 months ago Updater 1 month ago Updates 2 days ago Validators 1 year ago View 1 month ago ViewDataTable 2 weeks ago Visualization 1 year ago Widget 1 month ago .htaccess 2 years ago Access.php 1 month ago Archive.php 1 month ago ArchiveProcessor.php 1 month ago AssetManager.php 1 month ago Auth.php 6 months ago AuthResult.php 6 months ago BaseFactory.php 2 years ago Cache.php 2 years ago CacheId.php 4 months ago CliMulti.php 1 month ago Common.php 2 weeks ago Config.php 1 month ago Console.php 3 months ago Context.php 2 years ago Cookie.php 1 year ago CronArchive.php 1 month ago DI.php 3 months ago DataArray.php 1 month ago DataTable.php 1 month ago Date.php 1 month ago Db.php 1 month ago DbHelper.php 1 month ago Development.php 1 year ago ErrorHandler.php 6 months ago EventDispatcher.php 1 month ago ExceptionHandler.php 4 months ago FileIntegrity.php 1 month ago Filechecks.php 1 year ago Filesystem.php 1 month ago FrontController.php 4 months ago Http.php 1 month ago IP.php 1 year ago Log.php 3 months ago LogDeleter.php 1 year ago Mail.php 1 year ago Metrics.php 1 month ago NoAccessException.php 2 years ago Nonce.php 6 months ago Notification.php 1 month ago NumberFormatter.php 5 months ago Option.php 5 months ago Period.php 1 month ago Piwik.php 1 month ago Plugin.php 1 month ago Process.php 1 month ago Profiler.php 6 months ago ProxyHeaders.php 4 months ago ProxyHttp.php 5 months ago QuickForm2.php 3 months ago RankingQuery.php 1 month ago ReportRenderer.php 1 month ago Request.php 1 month ago Segment.php 1 month ago Sequence.php 6 months ago Session.php 2 weeks ago SettingsPiwik.php 1 month ago SettingsServer.php 1 year ago Singleton.php 2 years ago Site.php 1 month ago SiteContentDetector.php 1 month ago SupportedBrowser.php 2 years ago TCPDF.php 1 year ago Theme.php 1 year ago Timer.php 1 month ago Tracker.php 1 month ago Twig.php 1 month ago Unzip.php 1 year ago UpdateCheck.php 1 month ago Updater.php 1 month ago UpdaterErrorException.php 2 years ago Updates.php 3 months ago Url.php 3 months ago UrlHelper.php 1 month ago Version.php 2 days ago View.php 1 month ago bootstrap.php 1 year ago dispatch.php 2 years ago testMinimumPhpVersion.php 6 months ago
View.php
459 lines
1 <?php
2
3 /**
4 * Matomo - free/libre analytics platform
5 *
6 * @link https://matomo.org
7 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
8 */
9 namespace Piwik;
10
11 use Exception;
12 use Piwik\AssetManager\UIAssetCacheBuster;
13 use Piwik\Request\AuthenticationToken;
14 use Piwik\Container\StaticContainer;
15 use Piwik\Plugins\CoreAdminHome\Controller;
16 use Piwik\Plugins\CorePluginsAdmin\CorePluginsAdmin;
17 use Piwik\View\ViewInterface;
18 use Piwik\View\SecurityPolicy;
19 use Matomo\Dependencies\Twig\Environment;
20 /**
21 * Transition for pre-Piwik 0.4.4
22 */
23 if (!defined('PIWIK_USER_PATH')) {
24 define('PIWIK_USER_PATH', PIWIK_INCLUDE_PATH);
25 }
26 /**
27 * Encapsulates and manages a [Twig](https://twig.sensiolabs.org/) template.
28 *
29 * View lets you set properties that will be passed on to a Twig template.
30 * View will also set several properties that will be available in all Twig
31 * templates, including:
32 *
33 * - **currentModule**: The value of the **module** query parameter.
34 * - **currentAction**: The value of the **action** query parameter.
35 * - **userLogin**: The current user login name.
36 * - **sites**: List of site data for every site the current user has at least
37 * view access for.
38 * - **url**: The current URL (sanitized).
39 * - **token_auth**: The current user's token auth.
40 * - **userHasSomeAdminAccess**: True if the user has admin access to at least
41 * one site, false if otherwise.
42 * - **userIsSuperUser**: True if the user is the superuser, false if otherwise.
43 * - **latest_version_available**: The latest version of Piwik available.
44 * - **isWidget**: The value of the 'widget' query parameter.
45 * - **show_autocompleter**: Whether the site selector should be shown or not.
46 * - **loginModule**: The name of the currently used authentication module.
47 * - **isInternetEnabled**: Whether the matomo server is allowed to connect to
48 * external networks.
49 *
50 * ### Template Naming Convention
51 *
52 * Template files should be named after the controller method they are used in.
53 * If they are used in more than one controller method or are included by another
54 * template, they should describe the output they generate and be prefixed with
55 * an underscore, eg, **_dataTable.twig**.
56 *
57 * ### Twig
58 *
59 * Twig templates must exist in the **templates** folder in a plugin's root
60 * folder.
61 *
62 * The following filters are available to twig templates:
63 *
64 * - **translate**: Outputs internationalized text using a translation token, eg,
65 * `{{ 'General_Date'|translate }}`. sprintf parameters can be passed
66 * to the filter.
67 * - **urlRewriteWithParameters**: Modifies the current query string with the given
68 * set of parameters, eg,
69 *
70 * {{ {'module':'MyPlugin', 'action':'index'} | urlRewriteWithParameters }}
71 *
72 * - **sumTime**: Pretty formats an number of seconds.
73 * - **money**: Formats a numerical value as a monetary value using the currency
74 * of the supplied site (second arg is site ID).
75 * eg, `{{ 23|money(site.idsite)|raw }}
76 * - **truncate**: Truncates the text to certain length (determined by first arg.)
77 * eg, `{{ myReallyLongText|truncate(80) }}`
78 * - **implode**: Calls `implode`.
79 * - **ucwords**: Calls `ucwords`.
80 *
81 * The following functions are available to twig templates:
82 *
83 * - **linkTo**: Modifies the current query string with the given set of parameters,
84 * eg `{{ linkTo({'module':'MyPlugin', 'action':'index'}) }}`.
85 * - **sparkline**: Outputs a sparkline image HTML element using the sparkline image
86 * src link. eg, `{{ sparkline(sparklineUrl) }}`.
87 * - **postEvent**: Posts an event that allows event observers to add text to a string
88 * which is outputted in the template, eg, `{{ postEvent('MyPlugin.event') }}`
89 * - **isPluginLoaded**: Returns true if the supplied plugin is loaded, false if otherwise.
90 * `{% if isPluginLoaded('Goals') %}...{% endif %}`
91 * - **areAdsForProfessionalServicesEnabled**: Returns true if it is ok to show some advertising in the UI for providers of Professional Support for Piwik (from Piwik 2.16.0)
92 * - **isMultiServerEnvironment**: Returns true if Piwik is used on more than one server (since Piwik 2.16.1)
93 *
94 * ### Examples
95 *
96 * **Basic usage**
97 *
98 * // a controller method
99 * public function myView()
100 * {
101 * $view = new View("@MyPlugin/myView");
102 * $view->property1 = "a view property";
103 * $view->property2 = "another view property";
104 * return $view->render();
105 * }
106 *
107 *
108 * @api
109 */
110 class View implements ViewInterface
111 {
112 private $template = '';
113 /**
114 * Instance
115 * @var Environment
116 */
117 private $twig;
118 protected $templateVars = array();
119 private $contentType = 'text/html; charset=utf-8';
120 private $xFrameOptions = null;
121 private $enableCacheBuster = \true;
122 private $useStrictReferrerPolicy = \true;
123 /**
124 * Can be disabled to not send headers when rendering a view. This can be useful if heaps of views are being
125 * rendered during one request to possibly prevent a segmentation fault see eg #15307 . It should not be disabled
126 * for a main view, but could be disabled for views that are being rendered eg during a twig event as a "subview" which
127 * is part of the "main view".
128 * @var bool
129 */
130 public $sendHeadersWhenRendering = \true;
131 /**
132 * @param string $templateFile The template file to load. Must be in the following format:
133 * `"@MyPlugin/templateFileName"`. Note the absence of .twig
134 * from the end of the name.
135 */
136 public function __construct($templateFile)
137 {
138 $templateExt = '.twig';
139 if (substr($templateFile, -strlen($templateExt)) !== $templateExt) {
140 $templateFile .= $templateExt;
141 }
142 $this->template = $templateFile;
143 $this->initializeTwig();
144 $this->piwik_version = \Piwik\Version::VERSION;
145 $this->userLogin = \Piwik\Piwik::getCurrentUserLogin();
146 $this->isSuperUser = \Piwik\Access::getInstance()->hasSuperUserAccess();
147 // following is used in ajaxMacros called macro (showMoreHelp as passed in other templates) - requestErrorDiv
148 $isGeneralSettingsAdminEnabled = Controller::isGeneralSettingsAdminEnabled();
149 $isPluginsAdminEnabled = CorePluginsAdmin::isPluginsAdminEnabled();
150 // simplify template usage
151 $this->showMoreFaqInfo = $this->isSuperUser && ($isGeneralSettingsAdminEnabled || $isPluginsAdminEnabled);
152 try {
153 $this->piwikUrl = \Piwik\SettingsPiwik::getPiwikUrl();
154 } catch (Exception $ex) {
155 // pass (occurs when DB cannot be connected to, perhaps piwik URL cache should be stored in config file...)
156 }
157 $this->userRequiresPasswordConfirmation = \Piwik\Piwik::doesUserRequirePasswordConfirmation(\Piwik\Piwik::getCurrentUserLogin());
158 }
159 /**
160 * Disables the cache buster (adding of ?cb=...) to JavaScript and stylesheet files
161 */
162 public function disableCacheBuster()
163 {
164 $this->enableCacheBuster = \false;
165 }
166 /**
167 * Returns the template filename.
168 *
169 * @return string
170 */
171 public function getTemplateFile()
172 {
173 return $this->template;
174 }
175 /**
176 * Returns the variables to bind to the template when rendering.
177 *
178 * @param array $override Template variable override values. Mainly useful
179 * when including View templates in other templates.
180 * @return array
181 */
182 public function getTemplateVars($override = array())
183 {
184 return $override + $this->templateVars;
185 }
186 /**
187 * Directly assigns a variable to the view script.
188 * Variable names may not be prefixed with '_'.
189 *
190 * @param string $key The variable name.
191 * @param mixed $val The variable value.
192 */
193 public function __set($key, $val)
194 {
195 $this->templateVars[$key] = $val;
196 }
197 /**
198 * Retrieves an assigned variable.
199 * Variable names may not be prefixed with '_'.
200 *
201 * @param string $key The variable name.
202 * @return mixed The variable value.
203 */
204 public function &__get($key)
205 {
206 return $this->templateVars[$key];
207 }
208 /**
209 * Returns true if a template variable has been set or not.
210 *
211 * @param string $name The name of the template variable.
212 * @return bool
213 */
214 public function __isset($name)
215 {
216 return isset($this->templateVars[$name]);
217 }
218 /**
219 * Unsets a template variable.
220 *
221 * @param string $name The name of the template variable.
222 */
223 public function __unset($name)
224 {
225 unset($this->templateVars[$name]);
226 }
227 private function initializeTwig()
228 {
229 $this->twig = StaticContainer::get(\Piwik\Twig::class)->getTwigEnvironment();
230 }
231 /**
232 * Renders the current view. Also sends the stored 'Content-Type' HTML header.
233 * See {@link setContentType()}.
234 *
235 * @return string Generated template.
236 */
237 public function render()
238 {
239 try {
240 $this->currentModule = \Piwik\Piwik::getModule();
241 $this->currentAction = \Piwik\Piwik::getAction();
242 $this->url = \Piwik\Common::sanitizeInputValue(\Piwik\Url::getCurrentUrl());
243 $this->token_auth = \Piwik\Piwik::getCurrentUserTokenAuth();
244 $this->userHasSomeAdminAccess = \Piwik\Piwik::isUserHasSomeAdminAccess();
245 $this->userIsAnonymous = \Piwik\Piwik::isUserIsAnonymous();
246 $this->userIsSuperUser = \Piwik\Piwik::hasUserSuperUserAccess();
247 $this->latest_version_available = \Piwik\UpdateCheck::isNewestVersionAvailable();
248 $this->showUpdateNotificationToUser = !\Piwik\SettingsPiwik::isShowUpdateNotificationToSuperUsersOnlyEnabled() || \Piwik\Piwik::hasUserSuperUserAccess();
249 $this->disableLink = \Piwik\Common::getRequestVar('disableLink', 0, 'int');
250 $this->isWidget = \Piwik\Common::getRequestVar('widget', 0, 'int');
251 $this->isMultiServerEnvironment = \Piwik\SettingsPiwik::isMultiServerEnvironment();
252 $this->isInternetEnabled = \Piwik\SettingsPiwik::isInternetEnabled();
253 $this->shouldPropagateTokenAuth = $this->shouldPropagateTokenAuthInAjaxRequests();
254 $this->isAutoUpdateEnabled = \Piwik\SettingsPiwik::isAutoUpdateEnabled();
255 $piwikAds = StaticContainer::get('Piwik\\ProfessionalServices\\Advertising');
256 $this->areAdsForProfessionalServicesEnabled = $piwikAds->areAdsForProfessionalServicesEnabled();
257 if (\Piwik\Development::isEnabled()) {
258 $cacheBuster = rand(0, 10000);
259 } else {
260 $cacheBuster = UIAssetCacheBuster::getInstance()->piwikVersionBasedCacheBuster();
261 }
262 $this->cacheBuster = $cacheBuster;
263 $this->loginModule = \Piwik\Piwik::getLoginPluginName();
264 } catch (Exception $e) {
265 \Piwik\Log::debug($e);
266 // can fail, for example at installation (no plugin loaded yet)
267 }
268 if ($this->sendHeadersWhenRendering) {
269 \Piwik\ProxyHttp::overrideCacheControlHeaders('no-store');
270 \Piwik\Common::sendHeader('Content-Type: ' . $this->contentType);
271 // always sending this header, sometimes empty, to ensure that Dashboard embed loads
272 // - when calling sendHeader() multiple times, the last one prevails
273 if (!empty($this->xFrameOptions)) {
274 \Piwik\Common::sendHeader('X-Frame-Options: ' . (string) $this->xFrameOptions);
275 }
276 // don't send Referer-Header for outgoing links
277 if (!empty($this->useStrictReferrerPolicy)) {
278 \Piwik\Common::sendHeader('Referrer-Policy: same-origin');
279 } else {
280 // always send explicit default header
281 \Piwik\Common::sendHeader('Referrer-Policy: no-referrer-when-downgrade');
282 }
283 // this will be an empty string if CSP is disabled
284 $cspHeader = StaticContainer::get(SecurityPolicy::class)->createHeaderString();
285 if ('' !== $cspHeader) {
286 \Piwik\Common::sendHeader($cspHeader);
287 }
288 }
289 return $this->renderTwigTemplate();
290 }
291 /**
292 * @internal
293 * @ignore
294 * @return Environment
295 */
296 public function getTwig()
297 {
298 return $this->twig;
299 }
300 protected function renderTwigTemplate()
301 {
302 $output = $this->twig->render($this->getTemplateFile(), $this->getTemplateVars());
303 if ($this->enableCacheBuster) {
304 $output = $this->applyFilterCacheBuster($output);
305 }
306 $helper = new \Piwik\Theme();
307 $output = $helper->rewriteAssetsPathToTheme($output);
308 return $output;
309 }
310 protected function applyFilterCacheBuster($output)
311 {
312 $cacheBuster = UIAssetCacheBuster::getInstance();
313 $cache = \Piwik\Cache::getTransientCache();
314 $cssCacheBusterId = $cache->fetch('cssCacheBusterId');
315 if (empty($cssCacheBusterId)) {
316 $assetManager = \Piwik\AssetManager::getInstance();
317 $stylesheet = $assetManager->getMergedStylesheetAsset();
318 if ($stylesheet->exists()) {
319 $content = $stylesheet->getContent();
320 } else {
321 $content = $assetManager->getMergedStylesheet()->getContent();
322 }
323 $cssCacheBusterId = $cacheBuster->md5BasedCacheBuster($content);
324 $cache->save('cssCacheBusterId', $cssCacheBusterId);
325 }
326 $tagJs = 'cb=' . ($this->cacheBuster ?? $cacheBuster->piwikVersionBasedCacheBuster());
327 $tagCss = 'cb=' . $cssCacheBusterId;
328 $pattern = array(
329 '~<script type=[\'"]text/javascript[\'"] src=[\'"]([^\'"]+)[\'"]>~',
330 '~<script src=[\'"]([^\'"]+)[\'"] type=[\'"]text/javascript[\'"]>~',
331 '~<script type=[\'"]text/javascript[\'"] src=[\'"]([^\'"?]*\\?[^\'"]+)[\'"] defer>~',
332 '~<script type=[\'"]text/javascript[\'"] src=[\'"]([^\'"?]+)[\'"] defer>~',
333 '~<link rel=[\'"]stylesheet[\'"] type=[\'"]text/css[\'"] href=[\'"]([^\'"]+)[\'"] ?/?>~',
334 // removes the double ?cb= tag
335 '~(src|href)=\\"index.php\\?module=([A-Za-z0-9_]+)&action=([A-Za-z0-9_]+)\\?cb=~',
336 );
337 $replace = array('<script type="text/javascript" src="$1?' . $tagJs . '">', '<script type="text/javascript" src="$1?' . $tagJs . '">', '<script type="text/javascript" src="$1&' . $tagJs . '" defer>', '<script type="text/javascript" src="$1?' . $tagJs . '" defer>', '<link rel="stylesheet" type="text/css" href="$1?' . $tagCss . '" />', '$1="index.php?module=$2&amp;action=$3&amp;cb=');
338 return preg_replace($pattern, $replace, $output);
339 }
340 /**
341 * Set stored value used in the Content-Type HTTP header field. The header is
342 * set just before rendering.
343 *
344 * @param string $contentType
345 */
346 public function setContentType($contentType)
347 {
348 $this->contentType = $contentType;
349 }
350 /**
351 * Set X-Frame-Options field in the HTTP response. The header is set just
352 * before rendering.
353 *
354 * _Note: setting this allows you to make sure the View **cannot** be
355 * embedded in iframes. Learn more [here](https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options)._
356 *
357 * @param string $option ('deny' or 'sameorigin')
358 */
359 public function setXFrameOptions($option = 'deny')
360 {
361 if ($option === 'deny' || $option === 'sameorigin') {
362 $this->xFrameOptions = $option;
363 }
364 if ($option == 'allow') {
365 $this->xFrameOptions = null;
366 }
367 }
368 /**
369 * Add form to view
370 *
371 * @ignore
372 */
373 public function addForm(\Piwik\QuickForm2 $form)
374 {
375 // assign array with form data
376 $this->assign('form_data', $form->getFormData());
377 $this->assign('element_list', $form->getElementList());
378 }
379 /**
380 * Assign value to a variable for use in a template
381 * @param string|array $var
382 * @param mixed $value
383 * @ignore
384 */
385 public function assign($var, $value = null)
386 {
387 if (is_string($var)) {
388 $this->{$var} = $value;
389 } elseif (is_array($var)) {
390 foreach ($var as $key => $value) {
391 $this->{$key} = $value;
392 }
393 }
394 }
395 /**
396 * Clear compiled Twig templates
397 * @ignore
398 */
399 public static function clearCompiledTemplates()
400 {
401 $enable = StaticContainer::get('view.clearcompiledtemplates.enable');
402 if ($enable) {
403 // some high performance systems that run many Matomo instances may never want to clear this template cache
404 // if they use eg a blue/green deployment
405 $templatesCompiledPath = StaticContainer::get('path.tmp.templates');
406 \Piwik\Filesystem::unlinkRecursive($templatesCompiledPath, \false);
407 }
408 }
409 /**
410 * Creates a View for and then renders the single report template.
411 *
412 * Can be used for pages that display only one report to avoid having to create
413 * a new template.
414 *
415 * @param string $title The report title.
416 * @param string $reportHtml The report body HTML.
417 * @return string|void The report contents if `$fetch` is true.
418 */
419 public static function singleReport($title, $reportHtml)
420 {
421 $view = new \Piwik\View('@CoreHome/_singleReport');
422 $view->title = $title;
423 $view->report = $reportHtml;
424 return $view->render();
425 }
426 private function shouldPropagateTokenAuthInAjaxRequests()
427 {
428 $generalConfig = \Piwik\Config::getInstance()->General;
429 return \Piwik\Common::getRequestVar('module', \false) == 'Widgetize' || $generalConfig['enable_framed_pages'] == '1' || $this->validTokenAuthInUrl();
430 }
431 /**
432 * @return bool
433 * @throws Exception
434 */
435 private function validTokenAuthInUrl()
436 {
437 $token = StaticContainer::get(AuthenticationToken::class);
438 return !$token->wasTokenAuthProvidedSecurely() && $token->getAuthToken() === \Piwik\Piwik::getCurrentUserTokenAuth();
439 }
440 /**
441 * Returns whether a strict Referrer-Policy header will be sent. Generally this should be set to 'true'.
442 *
443 * @return bool
444 */
445 public function getUseStrictReferrerPolicy()
446 {
447 return $this->useStrictReferrerPolicy;
448 }
449 /**
450 * Sets whether a strict Referrer-Policy header will be sent (if not, nothing is sent).
451 *
452 * @param bool $useStrictReferrerPolicy
453 */
454 public function setUseStrictReferrerPolicy($useStrictReferrerPolicy)
455 {
456 $this->useStrictReferrerPolicy = $useStrictReferrerPolicy;
457 }
458 }
459