PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.1.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.1.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 / View.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 6 years ago DataFiles 6 years ago DataTable 6 years ago Db 6 years ago DeviceDetector 6 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 6 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 6 years ago CronArchive.php 6 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 6 years ago Notification.php 6 years ago NumberFormatter.php 6 years ago Option.php 6 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 6 years ago View.php 6 years ago bootstrap.php 6 years ago dispatch.php 6 years ago testMinimumPhpVersion.php 6 years ago
View.php
492 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\AssetManager\UIAssetCacheBuster;
13 use Piwik\Container\StaticContainer;
14 use Piwik\Plugins\UsersManager\API as APIUsersManager;
15 use Piwik\View\ViewInterface;
16 use Twig_Environment;
17
18 /**
19 * Transition for pre-Piwik 0.4.4
20 */
21 if (!defined('PIWIK_USER_PATH')) {
22 define('PIWIK_USER_PATH', PIWIK_INCLUDE_PATH);
23 }
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 * - **userAlias**: The alias of the current user.
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 /**
115 * Instance
116 * @var Twig_Environment
117 */
118 private $twig;
119 protected $templateVars = array();
120 private $contentType = 'text/html; charset=utf-8';
121 private $xFrameOptions = null;
122 private $enableCacheBuster = true;
123
124 private $useStrictReferrerPolicy = true;
125
126 /**
127 * Constructor.
128 *
129 * @param string $templateFile The template file to load. Must be in the following format:
130 * `"@MyPlugin/templateFileName"`. Note the absence of .twig
131 * from the end of the name.
132 */
133 public function __construct($templateFile)
134 {
135 $templateExt = '.twig';
136 if (substr($templateFile, -strlen($templateExt)) !== $templateExt) {
137 $templateFile .= $templateExt;
138 }
139 $this->template = $templateFile;
140
141 $this->initializeTwig();
142
143 $this->piwik_version = Version::VERSION;
144 $this->userLogin = Piwik::getCurrentUserLogin();
145 $this->isSuperUser = Access::getInstance()->hasSuperUserAccess();
146
147 try {
148 $this->piwikUrl = SettingsPiwik::getPiwikUrl();
149 } catch (Exception $ex) {
150 // pass (occurs when DB cannot be connected to, perhaps piwik URL cache should be stored in config file...)
151 }
152 }
153
154 /**
155 * Disables the cache buster (adding of ?cb=...) to JavaScript and stylesheet files
156 */
157 public function disableCacheBuster()
158 {
159 $this->enableCacheBuster = false;
160 }
161
162 /**
163 * Returns the template filename.
164 *
165 * @return string
166 */
167 public function getTemplateFile()
168 {
169 return $this->template;
170 }
171
172 /**
173 * Returns the variables to bind to the template when rendering.
174 *
175 * @param array $override Template variable override values. Mainly useful
176 * when including View templates in other templates.
177 * @return array
178 */
179 public function getTemplateVars($override = array())
180 {
181 return $override + $this->templateVars;
182 }
183
184 /**
185 * Directly assigns a variable to the view script.
186 * Variable names may not be prefixed with '_'.
187 *
188 * @param string $key The variable name.
189 * @param mixed $val The variable value.
190 */
191 public function __set($key, $val)
192 {
193 $this->templateVars[$key] = $val;
194 }
195
196 /**
197 * Retrieves an assigned variable.
198 * Variable names may not be prefixed with '_'.
199 *
200 * @param string $key The variable name.
201 * @return mixed The variable value.
202 */
203 public function &__get($key)
204 {
205 return $this->templateVars[$key];
206 }
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 /**
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
229 private function initializeTwig()
230 {
231 $this->twig = StaticContainer::get(Twig::class)->getTwigEnvironment();
232 }
233
234 /**
235 * Renders the current view. Also sends the stored 'Content-Type' HTML header.
236 * See {@link setContentType()}.
237 *
238 * @return string Generated template.
239 */
240 public function render()
241 {
242 try {
243 $this->currentModule = Piwik::getModule();
244 $this->currentAction = Piwik::getAction();
245
246 $this->url = Common::sanitizeInputValue(Url::getCurrentUrl());
247 $this->token_auth = Piwik::getCurrentUserTokenAuth();
248 $this->userHasSomeAdminAccess = Piwik::isUserHasSomeAdminAccess();
249 $this->userIsAnonymous = Piwik::isUserIsAnonymous();
250 $this->userIsSuperUser = Piwik::hasUserSuperUserAccess();
251 $this->latest_version_available = UpdateCheck::isNewestVersionAvailable();
252 $this->showUpdateNotificationToUser = !SettingsPiwik::isShowUpdateNotificationToSuperUsersOnlyEnabled() || Piwik::hasUserSuperUserAccess();
253 $this->disableLink = Common::getRequestVar('disableLink', 0, 'int');
254 $this->isWidget = Common::getRequestVar('widget', 0, 'int');
255 $this->isMultiServerEnvironment = SettingsPiwik::isMultiServerEnvironment();
256 $this->isInternetEnabled = SettingsPiwik::isInternetEnabled();
257 $this->shouldPropagateTokenAuth = $this->shouldPropagateTokenAuthInAjaxRequests();
258
259 $piwikAds = StaticContainer::get('Piwik\ProfessionalServices\Advertising');
260 $this->areAdsForProfessionalServicesEnabled = $piwikAds->areAdsForProfessionalServicesEnabled();
261
262 if (Development::isEnabled()) {
263 $cacheBuster = rand(0, 10000);
264 } else {
265 $cacheBuster = UIAssetCacheBuster::getInstance()->piwikVersionBasedCacheBuster();
266 }
267 $this->cacheBuster = $cacheBuster;
268
269 $this->loginModule = Piwik::getLoginPluginName();
270
271 $this->userAlias = $this->userLogin; // can be removed in Matomo 4.0
272 } catch (Exception $e) {
273 Log::debug($e);
274
275 // can fail, for example at installation (no plugin loaded yet)
276 }
277
278 ProxyHttp::overrideCacheControlHeaders('no-store');
279
280 Common::sendHeader('Content-Type: ' . $this->contentType);
281 // always sending this header, sometimes empty, to ensure that Dashboard embed loads
282 // - when calling sendHeader() multiple times, the last one prevails
283 if(!empty($this->xFrameOptions)) {
284 Common::sendHeader('X-Frame-Options: ' . (string)$this->xFrameOptions);
285 }
286
287 // don't send Referer-Header for outgoing links
288 if (!empty($this->useStrictReferrerPolicy)) {
289 Common::sendHeader('Referrer-Policy: same-origin');
290 } else {
291 // always send explicit default header
292 Common::sendHeader('Referrer-Policy: no-referrer-when-downgrade');
293 }
294
295 return $this->renderTwigTemplate();
296 }
297
298 /**
299 * @internal
300 * @ignore
301 * @return Twig_Environment
302 */
303 public function getTwig()
304 {
305 return $this->twig;
306 }
307
308 protected function renderTwigTemplate()
309 {
310 try {
311 $output = $this->twig->render($this->getTemplateFile(), $this->getTemplateVars());
312 } catch (Exception $ex) {
313 // twig does not rethrow exceptions, it wraps them so we log the cause if we can find it
314 $cause = $ex->getPrevious();
315 Log::debug($cause === null ? $ex : $cause);
316
317 throw $ex;
318 }
319
320 if ($this->enableCacheBuster) {
321 $output = $this->applyFilter_cacheBuster($output);
322 }
323
324 $helper = new Theme;
325 $output = $helper->rewriteAssetsPathToTheme($output);
326 return $output;
327 }
328
329 protected function applyFilter_cacheBuster($output)
330 {
331 $cacheBuster = UIAssetCacheBuster::getInstance();
332 $cache = Cache::getTransientCache();
333
334 $cssCacheBusterId = $cache->fetch('cssCacheBusterId');
335 if (empty($cssCacheBusterId)) {
336 $assetManager = AssetManager::getInstance();
337 $stylesheet = $assetManager->getMergedStylesheetAsset();
338 if ($stylesheet->exists()) {
339 $content = $stylesheet->getContent();
340 } else {
341 $content = $assetManager->getMergedStylesheet()->getContent();
342 }
343 $cssCacheBusterId = $cacheBuster->md5BasedCacheBuster($content);
344 $cache->save('cssCacheBusterId', $cssCacheBusterId);
345 }
346
347 $tagJs = 'cb=' . $cacheBuster->piwikVersionBasedCacheBuster();
348 $tagCss = 'cb=' . $cssCacheBusterId;
349
350 $pattern = array(
351 '~<script type=[\'"]text/javascript[\'"] src=[\'"]([^\'"]+)[\'"]>~',
352 '~<script src=[\'"]([^\'"]+)[\'"] type=[\'"]text/javascript[\'"]>~',
353 '~<link rel=[\'"]stylesheet[\'"] type=[\'"]text/css[\'"] href=[\'"]([^\'"]+)[\'"] ?/?>~',
354 // removes the double ?cb= tag
355 '~(src|href)=\"index.php\?module=([A-Za-z0-9_]+)&action=([A-Za-z0-9_]+)\?cb=~',
356 );
357
358 $replace = array(
359 '<script type="text/javascript" src="$1?' . $tagJs . '">',
360 '<script type="text/javascript" src="$1?' . $tagJs . '">',
361 '<link rel="stylesheet" type="text/css" href="$1?' . $tagCss . '" />',
362 '$1="index.php?module=$2&amp;action=$3&amp;cb=',
363 );
364
365 return preg_replace($pattern, $replace, $output);
366 }
367
368 /**
369 * Set stored value used in the Content-Type HTTP header field. The header is
370 * set just before rendering.
371 *
372 * @param string $contentType
373 */
374 public function setContentType($contentType)
375 {
376 $this->contentType = $contentType;
377 }
378
379 /**
380 * Set X-Frame-Options field in the HTTP response. The header is set just
381 * before rendering.
382 *
383 * _Note: setting this allows you to make sure the View **cannot** be
384 * embedded in iframes. Learn more [here](https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options)._
385 *
386 * @param string $option ('deny' or 'sameorigin')
387 */
388 public function setXFrameOptions($option = 'deny')
389 {
390
391 if ($option === 'deny' || $option === 'sameorigin') {
392 $this->xFrameOptions = $option;
393 }
394 if ($option == 'allow') {
395 $this->xFrameOptions = null;
396 }
397 }
398
399 /**
400 * Add form to view
401 *
402 * @param QuickForm2 $form
403 * @ignore
404 */
405 public function addForm(QuickForm2 $form)
406 {
407
408 // assign array with form data
409 $this->assign('form_data', $form->getFormData());
410 $this->assign('element_list', $form->getElementList());
411 }
412
413 /**
414 * Assign value to a variable for use in a template
415 * @param string|array $var
416 * @param mixed $value
417 * @ignore
418 */
419 public function assign($var, $value = null)
420 {
421 if (is_string($var)) {
422 $this->$var = $value;
423 } elseif (is_array($var)) {
424 foreach ($var as $key => $value) {
425 $this->$key = $value;
426 }
427 }
428 }
429
430 /**
431 * Clear compiled Twig templates
432 * @ignore
433 */
434 public static function clearCompiledTemplates()
435 {
436 $twig = StaticContainer::get(Twig::class);
437 $environment = $twig->getTwigEnvironment();
438 $environment->clearTemplateCache();
439
440 $cacheDirectory = $environment->getCache();
441 if (!empty($cacheDirectory)
442 && is_dir($cacheDirectory)
443 ) {
444 $environment->clearCacheFiles();
445 }
446 }
447
448 /**
449 * Creates a View for and then renders the single report template.
450 *
451 * Can be used for pages that display only one report to avoid having to create
452 * a new template.
453 *
454 * @param string $title The report title.
455 * @param string $reportHtml The report body HTML.
456 * @return string|void The report contents if `$fetch` is true.
457 */
458 public static function singleReport($title, $reportHtml)
459 {
460 $view = new View('@CoreHome/_singleReport');
461 $view->title = $title;
462 $view->report = $reportHtml;
463 return $view->render();
464 }
465
466 private function shouldPropagateTokenAuthInAjaxRequests()
467 {
468 $generalConfig = Config::getInstance()->General;
469 return Common::getRequestVar('module', false) == 'Widgetize' || $generalConfig['enable_framed_pages'] == '1';
470 }
471
472 /**
473 * Returns whether a strict Referrer-Policy header will be sent. Generally this should be set to 'true'.
474 *
475 * @return bool
476 */
477 public function getUseStrictReferrerPolicy()
478 {
479 return $this->useStrictReferrerPolicy;
480 }
481
482 /**
483 * Sets whether a strict Referrer-Policy header will be sent (if not, nothing is sent).
484 *
485 * @param bool $useStrictReferrerPolicy
486 */
487 public function setUseStrictReferrerPolicy($useStrictReferrerPolicy)
488 {
489 $this->useStrictReferrerPolicy = $useStrictReferrerPolicy;
490 }
491 }
492