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