protected function sendNotifications() { $latestVersion = $this->getLatestVersion(); $host = SettingsPiwik::getPiwikUrl(); $subject = Piwik::translate('CoreUpdater_NotificationSubjectAvailableCoreUpdate', $latestVersion); $message = Piwik::translate('ScheduledReports_EmailHello'); $message .= "\n\n"; $message .= Piwik::translate('CoreUpdater_ThereIsNewVersionAvailableForUpdate'); $message .= "\n\n"; $message .= Piwik::translate('CoreUpdater_YouCanUpgradeAutomaticallyOrDownloadPackage', $latestVersion); $message .= "\n"; $message .= $host . 'index.php?module=CoreUpdater&action=newVersionAvailable'; $message .= "\n\n"; $version = new Version(); if ($version->isStableVersion($latestVersion)) { $message .= Piwik::translate('CoreUpdater_ViewVersionChangelog'); $message .= "\n"; $message .= $this->getLinkToChangeLog($latestVersion); $message .= "\n\n"; } $message .= Piwik::translate('CoreUpdater_FeedbackRequest'); $message .= "\n"; $message .= 'http://piwik.org/contact/'; $this->sendEmailNotification($subject, $message); }
/** * Computes the output for the given data table * * @param DataTable $table * @return string * @throws Exception */ protected function renderTable($table) { if (!$table instanceof DataTable\Map || $table->getKeyName() != 'date') { throw new Exception("RSS feeds can be generated for one specific website &idSite=X." . "\nPlease specify only one idSite or consider using &format=XML instead."); } $idSite = Common::getRequestVar('idSite', 1, 'int'); $period = Common::getRequestVar('period'); $piwikUrl = SettingsPiwik::getPiwikUrl() . "?module=CoreHome&action=index&idSite=" . $idSite . "&period=" . $period; $out = ""; $moreRecentFirst = array_reverse($table->getDataTables(), true); foreach ($moreRecentFirst as $date => $subtable) { /** @var DataTable $subtable */ $timestamp = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart()->getTimestamp(); $site = $subtable->getMetadata(Archive\DataTableFactory::TABLE_METADATA_SITE_INDEX); $pudDate = date('r', $timestamp); $dateInSiteTimezone = Date::factory($timestamp); if ($site) { $dateInSiteTimezone = $dateInSiteTimezone->setTimezone($site->getTimezone()); } $dateInSiteTimezone = $dateInSiteTimezone->toString('Y-m-d'); $thisPiwikUrl = Common::sanitizeInputValue($piwikUrl . "&date={$dateInSiteTimezone}"); $siteName = $site ? $site->getName() : ''; $title = $siteName . " on " . $date; $out .= "\t<item>\n\t\t<pubDate>{$pudDate}</pubDate>\n\t\t<guid>{$thisPiwikUrl}</guid>\n\t\t<link>{$thisPiwikUrl}</link>\n\t\t<title>{$title}</title>\n\t\t<author>http://piwik.org</author>\n\t\t<description>"; $out .= Common::sanitizeInputValue($this->renderDataTable($subtable)); $out .= "</description>\n\t</item>\n"; } $header = $this->getRssHeader(); $footer = $this->getRssFooter(); return $header . $out . $footer; }
/** * Returns the javascript tag for the given idSite. * This tag must be included on every page to be tracked by Piwik * * @param int $idSite * @param string $piwikUrl * @param bool $mergeSubdomains * @param bool $groupPageTitlesByDomain * @param bool $mergeAliasUrls * @param bool $visitorCustomVariables * @param bool $pageCustomVariables * @param bool $customCampaignNameQueryParam * @param bool $customCampaignKeywordParam * @param bool $doNotTrack * @param bool $disableCookies * @return string The Javascript tag ready to be included on the HTML pages */ public function getJavascriptTag($idSite, $piwikUrl = '', $mergeSubdomains = false, $groupPageTitlesByDomain = false, $mergeAliasUrls = false, $visitorCustomVariables = false, $pageCustomVariables = false, $customCampaignNameQueryParam = false, $customCampaignKeywordParam = false, $doNotTrack = false, $disableCookies = false) { Piwik::checkUserHasViewAccess($idSite); if (empty($piwikUrl)) { $piwikUrl = SettingsPiwik::getPiwikUrl(); } $piwikUrl = Common::sanitizeInputValues($piwikUrl); $htmlEncoded = Piwik::getJavascriptCode($idSite, $piwikUrl, $mergeSubdomains, $groupPageTitlesByDomain, $mergeAliasUrls, $visitorCustomVariables, $pageCustomVariables, $customCampaignNameQueryParam, $customCampaignKeywordParam, $doNotTrack, $disableCookies); $htmlEncoded = str_replace(array('<br>', '<br />', '<br/>'), '', $htmlEncoded); return $htmlEncoded; }
/** * Sets the sender. * * @param string $email Email address of the sender. * @param null|string $name Name of the sender. * @return Zend_Mail */ public function setFrom($email, $name = null) { $hostname = Config::getInstance()->mail['defaultHostnameIfEmpty']; $piwikHost = Url::getCurrentHost($hostname); // If known Piwik URL, use it instead of "localhost" $piwikUrl = SettingsPiwik::getPiwikUrl(); $url = parse_url($piwikUrl); if (isset($url['host']) && $url['host'] != 'localhost' && $url['host'] != '127.0.0.1') { $piwikHost = $url['host']; } $email = str_replace('{DOMAIN}', $piwikHost, $email); return parent::setFrom($email, $name); }
protected function getPathToLogo($pathOnly, $defaultLogo, $themeLogo, $customLogo) { $pathToPiwikRoot = Filesystem::getPathToPiwikRoot(); $logo = $defaultLogo; $themeName = \Piwik\Plugin\Manager::getInstance()->getThemeEnabled()->getPluginName(); $themeLogo = sprintf($themeLogo, $themeName); if (file_exists($pathToPiwikRoot . '/' . $themeLogo)) { $logo = $themeLogo; } if (Config::getInstance()->branding['use_custom_logo'] == 1 && file_exists($pathToPiwikRoot . '/' . $customLogo)) { $logo = $customLogo; } if (!$pathOnly) { return SettingsPiwik::getPiwikUrl() . $logo; } return $pathToPiwikRoot . '/' . $logo; }
/** * @internal For Debugging only * Call metadata reports and draw the default graph for each report. */ public function index() { Piwik::checkUserHasSomeAdminAccess(); $idSite = Common::getRequestVar('idSite', 1, 'int'); $period = Common::getRequestVar('period', 'day', 'string'); $date = Common::getRequestVar('date', 'today', 'string'); $_GET['token_auth'] = Piwik::getCurrentUserTokenAuth(); $reports = APIPlugins::getInstance()->getReportMetadata($idSite, $period, $date); $plot = array(); foreach ($reports as $report) { if (!empty($report['imageGraphUrl'])) { $plot[] = array($report['category'] . ' › ' . $report['name'], SettingsPiwik::getPiwikUrl() . $report['imageGraphUrl']); } } $view = new View('@ImageGraph/index'); $view->titleAndUrls = $plot; return $view->render(); }
/** * Returns the javascript tag for the given idSite. * This tag must be included on every page to be tracked by Piwik * * @param int $idSite * @param string $piwikUrl * @param bool $mergeSubdomains * @param bool $groupPageTitlesByDomain * @param bool $mergeAliasUrls * @param bool $visitorCustomVariables * @param bool $pageCustomVariables * @param bool $customCampaignNameQueryParam * @param bool $customCampaignKeywordParam * @param bool $doNotTrack * @param bool $disableCookies * @return string The Javascript tag ready to be included on the HTML pages */ public function getJavascriptTag($idSite, $piwikUrl = '', $mergeSubdomains = false, $groupPageTitlesByDomain = false, $mergeAliasUrls = false, $visitorCustomVariables = false, $pageCustomVariables = false, $customCampaignNameQueryParam = false, $customCampaignKeywordParam = false, $doNotTrack = false, $disableCookies = false) { Piwik::checkUserHasViewAccess($idSite); if (empty($piwikUrl)) { $piwikUrl = SettingsPiwik::getPiwikUrl(); } // Revert the automatic encoding // TODO remove that when https://github.com/piwik/piwik/issues/4231 is fixed $piwikUrl = Common::unsanitizeInputValue($piwikUrl); $visitorCustomVariables = Common::unsanitizeInputValues($visitorCustomVariables); $pageCustomVariables = Common::unsanitizeInputValues($pageCustomVariables); $customCampaignNameQueryParam = Common::unsanitizeInputValue($customCampaignNameQueryParam); $customCampaignKeywordParam = Common::unsanitizeInputValue($customCampaignKeywordParam); $generator = new TrackerCodeGenerator(); $code = $generator->generate($idSite, $piwikUrl, $mergeSubdomains, $groupPageTitlesByDomain, $mergeAliasUrls, $visitorCustomVariables, $pageCustomVariables, $customCampaignNameQueryParam, $customCampaignKeywordParam, $doNotTrack, $disableCookies); $code = str_replace(array('<br>', '<br />', '<br/>'), '', $code); return $code; }
function prepareServerVariables(Config $config) { $testConfig = $config->tests; if ('@REQUEST_URI@' === $testConfig['request_uri']) { // config not done yet, if Piwik is installed we can automatically configure request_uri and http_host $url = \Piwik\SettingsPiwik::getPiwikUrl(); if (!empty($url)) { $parsedUrl = parse_url($url); $testConfig['request_uri'] = $parsedUrl['path']; $testConfig['http_host'] = $parsedUrl['host']; $config->tests = $testConfig; $config->forceSave(); } } $_SERVER['HTTP_HOST'] = $testConfig['http_host']; $_SERVER['REQUEST_URI'] = $testConfig['request_uri']; $_SERVER['REMOTE_ADDR'] = $testConfig['remote_addr']; }
public function getTargets() { $targets = array(); if ($this->settings->trackToPiwik->getValue()) { $targets[] = array('url' => 'http://demo-anonymous.piwik.org/piwik.php', 'idSite' => 1, 'useAnonymization' => true); } $ownSiteId = $this->settings->ownPiwikSiteId->getValue(); if ($ownSiteId) { $piwikUrl = SettingsPiwik::getPiwikUrl(); if (!Common::stringEndsWith($piwikUrl, '/')) { $piwikUrl .= '/'; } $targets[] = array('url' => $piwikUrl . 'piwik.php', 'idSite' => (int) $ownSiteId, 'useAnonymization' => $this->settings->anonymizeSelfPiwik->getValue()); } $customUrl = $this->settings->customPiwikSiteUrl->getValue(); $customSiteId = $this->settings->customPiwikSiteId->getValue(); if ($customUrl && $customSiteId) { $targets[] = array('url' => $customUrl, 'idSite' => (int) $customSiteId, 'useAnonymization' => $this->settings->anonymizeCustomPiwik->getValue()); } return $targets; }
/** * Tracker requests will automatically trigger the Scheduled tasks. * This is useful for users who don't setup the cron, * but still want daily/weekly/monthly PDF reports emailed automatically. * * This is similar to calling the API CoreAdminHome.runScheduledTasks */ public function runScheduledTasks() { $now = time(); // Currently, there are no hourly tasks. When there are some, // this could be too aggressive minimum interval (some hours would be skipped in case of low traffic) $minimumInterval = TrackerConfig::getConfigValue('scheduled_tasks_min_interval'); // If the user disabled browser archiving, he has already setup a cron // To avoid parallel requests triggering the Scheduled Tasks, // Get last time tasks started executing $cache = Cache::getCacheGeneral(); if ($minimumInterval <= 0 || empty($cache['isBrowserTriggerEnabled'])) { Common::printDebug("-> Scheduled tasks not running in Tracker: Browser archiving is disabled."); return; } $nextRunTime = $cache['lastTrackerCronRun'] + $minimumInterval; if (defined('DEBUG_FORCE_SCHEDULED_TASKS') && DEBUG_FORCE_SCHEDULED_TASKS || $cache['lastTrackerCronRun'] === false || $nextRunTime < $now) { $cache['lastTrackerCronRun'] = $now; Cache::setCacheGeneral($cache); Tracker::initCorePiwikInTrackerMode(); Option::set('lastTrackerCronRun', $cache['lastTrackerCronRun']); Common::printDebug('-> Scheduled Tasks: Starting...'); // save current user privilege and temporarily assume Super User privilege $isSuperUser = Piwik::hasUserSuperUserAccess(); // Scheduled tasks assume Super User is running Piwik::setUserHasSuperUserAccess(); $tokens = CronArchive::getSuperUserTokenAuths(); $tokenAuth = reset($tokens); $invokeScheduledTasksUrl = SettingsPiwik::getPiwikUrl() . "?module=API&format=csv&convertToUnicode=0&method=CoreAdminHome.runScheduledTasks&trigger=archivephp&token_auth={$tokenAuth}"; $cliMulti = new CliMulti(); $responses = $cliMulti->request(array($invokeScheduledTasksUrl)); $resultTasks = reset($responses); // restore original user privilege Piwik::setUserHasSuperUserAccess($isSuperUser); Common::printDebug($resultTasks); Common::printDebug('Finished Scheduled Tasks.'); } else { Common::printDebug("-> Scheduled tasks not triggered."); } Common::printDebug("Next run will be from: " . date('Y-m-d H:i:s', $nextRunTime) . ' UTC'); }
/** * Must be called before dispatch() * - checks that directories are writable, * - loads the configuration file, * - loads the plugin, * - inits the DB connection, * - etc. * * @throws Exception * @return void */ public function init() { static $initialized = false; if ($initialized) { return; } $initialized = true; $tmpPath = StaticContainer::get('path.tmp'); $directoriesToCheck = array($tmpPath, $tmpPath . '/assets/', $tmpPath . '/cache/', $tmpPath . '/logs/', $tmpPath . '/tcpdf/', $tmpPath . '/templates_c/'); Filechecks::dieIfDirectoriesNotWritable($directoriesToCheck); $this->handleMaintenanceMode(); $this->handleProfiler(); $this->handleSSLRedirection(); Plugin\Manager::getInstance()->loadPluginTranslations(); Plugin\Manager::getInstance()->loadActivatedPlugins(); // try to connect to the database try { Db::createDatabaseObject(); Db::fetchAll("SELECT DATABASE()"); } catch (Exception $exception) { if (self::shouldRethrowException()) { throw $exception; } Log::debug($exception); /** * Triggered when Piwik cannot connect to the database. * * This event can be used to start the installation process or to display a custom error * message. * * @param Exception $exception The exception thrown from creating and testing the database * connection. */ Piwik::postEvent('Db.cannotConnectToDb', array($exception), $pending = true); throw $exception; } // try to get an option (to check if data can be queried) try { Option::get('TestingIfDatabaseConnectionWorked'); } catch (Exception $exception) { if (self::shouldRethrowException()) { throw $exception; } Log::debug($exception); /** * Triggered when Piwik cannot access database data. * * This event can be used to start the installation process or to display a custom error * message. * * @param Exception $exception The exception thrown from trying to get an option value. */ Piwik::postEvent('Config.badConfigurationFile', array($exception), $pending = true); throw $exception; } // Init the Access object, so that eg. core/Updates/* can enforce Super User and use some APIs Access::getInstance(); /** * Triggered just after the platform is initialized and plugins are loaded. * * This event can be used to do early initialization. * * _Note: At this point the user is not authenticated yet._ */ Piwik::postEvent('Request.dispatchCoreAndPluginUpdatesScreen'); $this->throwIfPiwikVersionIsOlderThanDBSchema(); \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins(); // ensure the current Piwik URL is known for later use if (method_exists('Piwik\\SettingsPiwik', 'getPiwikUrl')) { SettingsPiwik::getPiwikUrl(); } /** * Triggered before the user is authenticated, when the global authentication object * should be created. * * Plugins that provide their own authentication implementation should use this event * to set the global authentication object (which must derive from {@link Piwik\Auth}). * * **Example** * * Piwik::addAction('Request.initAuthenticationObject', function() { * StaticContainer::getContainer()->set('Piwik\Auth', new MyAuthImplementation()); * }); */ Piwik::postEvent('Request.initAuthenticationObject'); try { $authAdapter = StaticContainer::get('Piwik\\Auth'); } catch (Exception $e) { $message = "Authentication object cannot be found in the container. Maybe the Login plugin is not activated?\n <br />You can activate the plugin by adding:<br />\n <code>Plugins[] = Login</code><br />\n under the <code>[Plugins]</code> section in your config/config.ini.php"; $ex = new AuthenticationFailedException($message); $ex->setIsHtmlMessage(); throw $ex; } Access::getInstance()->reloadAccess($authAdapter); // Force the auth to use the token_auth if specified, so that embed dashboard // and all other non widgetized controller methods works fine if (Common::getRequestVar('token_auth', false, 'string') !== false) { Request::reloadAuthUsingTokenAuth(); } SettingsServer::raiseMemoryLimitIfNecessary(); \Piwik\Plugin\Manager::getInstance()->postLoadPlugins(); /** * Triggered after the platform is initialized and after the user has been authenticated, but * before the platform has handled the request. * * Piwik uses this event to check for updates to Piwik. */ Piwik::postEvent('Platform.initialized'); }
/** * Constructor. * * @param string $templateFile The template file to load. Must be in the following format: * `"@MyPlugin/templateFileName"`. Note the absence of .twig * from the end of the name. */ public function __construct($templateFile) { $templateExt = '.twig'; if (substr($templateFile, -strlen($templateExt)) !== $templateExt) { $templateFile .= $templateExt; } $this->template = $templateFile; $this->initializeTwig(); $this->piwik_version = Version::VERSION; $this->userLogin = Piwik::getCurrentUserLogin(); $this->isSuperUser = Access::getInstance()->hasSuperUserAccess(); try { $this->piwikUrl = SettingsPiwik::getPiwikUrl(); } catch (Exception $ex) { // pass (occurs when DB cannot be connected to, perhaps piwik URL cache should be stored in config file...) } }
/** * Displays the admin UI page showing all tracking tags * @return string */ function displayJavascriptCode() { $idSite = Common::getRequestVar('idSite'); Piwik::checkUserHasViewAccess($idSite); $javascriptGenerator = new TrackerCodeGenerator(); $jsTag = $javascriptGenerator->generate($idSite, SettingsPiwik::getPiwikUrl()); $site = new Site($idSite); return $this->renderTemplate('displayJavascriptCode', array('idSite' => $idSite, 'displaySiteName' => $site->getName(), 'jsTag' => $jsTag)); }
protected function sendNotifications($pluginsToBeNotified) { $hasThemeUpdate = false; $hasPluginUpdate = false; foreach ($pluginsToBeNotified as $plugin) { $hasThemeUpdate = $hasThemeUpdate || $plugin['isTheme']; $hasPluginUpdate = $hasPluginUpdate || !$plugin['isTheme']; } $subject = Piwik::translate('CoreUpdater_NotificationSubjectAvailablePluginUpdate'); $message = Piwik::translate('ScheduledReports_EmailHello'); $message .= "\n\n"; $message .= Piwik::translate('CoreUpdater_ThereIsNewPluginVersionAvailableForUpdate'); $message .= "\n\n"; foreach ($pluginsToBeNotified as $plugin) { $message .= sprintf(' * %s %s', $plugin['name'], $plugin['latestVersion']); $message .= "\n"; } $message .= "\n"; $host = SettingsPiwik::getPiwikUrl(); if ($hasThemeUpdate) { $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdateThemes') . "\n"; $message .= $host . 'index.php?module=CorePluginsAdmin&action=themes'; } if ($hasPluginUpdate) { if ($hasThemeUpdate) { $message .= "\n\n"; } $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdatePlugins') . "\n"; $message .= $host . 'index.php?module=CorePluginsAdmin&action=plugins'; } $message .= "\n\n"; $message .= Piwik::translate('Installation_HappyAnalysing'); $this->sendEmailNotification($subject, $message); }
public function sendReport($reportType, $report, $contents, $filename, $prettyDate, $reportSubject, $reportTitle, $additionalFiles, Period $period = null, $force) { if (!self::manageEvent($reportType)) { return; } // Safeguard against sending the same report twice to the same email (unless $force is true) if (!$force && $this->reportAlreadySent($report, $period)) { Log::warning('Preventing the same scheduled report from being sent again (report #%s for period "%s")', $report['idreport'], $prettyDate); return; } $periods = self::getPeriodToFrequencyAsAdjective(); $message = Piwik::translate('ScheduledReports_EmailHello'); $subject = Piwik::translate('General_Report') . ' ' . $reportTitle . " - " . $prettyDate; $mail = new Mail(); $mail->setDefaultFromPiwik(); $mail->setSubject($subject); $attachmentName = $subject; $this->setReplyToAsSender($mail, $report); $displaySegmentInfo = false; $segmentInfo = null; $segment = API::getSegment($report['idsegment']); if ($segment != null) { $displaySegmentInfo = true; $segmentInfo = Piwik::translate('ScheduledReports_SegmentAppliedToReports', $segment['name']); } $messageFindAttached = Piwik::translate('ScheduledReports_PleaseFindAttachedFile', array($periods[$report['period']], $reportTitle)); $messageFindBelow = Piwik::translate('ScheduledReports_PleaseFindBelow', array($periods[$report['period']], $reportTitle)); $messageSentFrom = ''; $piwikUrl = SettingsPiwik::getPiwikUrl(); if (!empty($piwikUrl)) { $messageSentFrom = Piwik::translate('ScheduledReports_SentFromX', $piwikUrl); } switch ($report['format']) { case 'html': // Needed when using images as attachment with cid $mail->setType(Zend_Mime::MULTIPART_RELATED); $message .= "<br/>{$messageFindBelow}<br/>{$messageSentFrom}"; if ($displaySegmentInfo) { $message .= " " . $segmentInfo; } $mail->setBodyHtml($message . "<br/><br/>" . $contents); break; case 'csv': $message .= "\n{$messageFindAttached}\n{$messageSentFrom}"; if ($displaySegmentInfo) { $message .= " " . $segmentInfo; } $mail->setBodyText($message); $mail->createAttachment($contents, 'application/csv', Zend_Mime::DISPOSITION_INLINE, Zend_Mime::ENCODING_BASE64, $attachmentName . '.csv'); break; default: case 'pdf': $message .= "\n{$messageFindAttached}\n{$messageSentFrom}"; if ($displaySegmentInfo) { $message .= " " . $segmentInfo; } $mail->setBodyText($message); $mail->createAttachment($contents, 'application/pdf', Zend_Mime::DISPOSITION_INLINE, Zend_Mime::ENCODING_BASE64, $attachmentName . '.pdf'); break; } foreach ($additionalFiles as $additionalFile) { $fileContent = $additionalFile['content']; $at = $mail->createAttachment($fileContent, $additionalFile['mimeType'], Zend_Mime::DISPOSITION_INLINE, $additionalFile['encoding'], $additionalFile['filename']); $at->id = $additionalFile['cid']; unset($fileContent); } // Get user emails and languages $reportParameters = $report['parameters']; $emails = array(); if (isset($reportParameters[self::ADDITIONAL_EMAILS_PARAMETER])) { $emails = $reportParameters[self::ADDITIONAL_EMAILS_PARAMETER]; } if ($reportParameters[self::EMAIL_ME_PARAMETER] == 1) { if (Piwik::getCurrentUserLogin() == $report['login']) { $emails[] = Piwik::getCurrentUserEmail(); } else { try { $user = APIUsersManager::getInstance()->getUser($report['login']); } catch (Exception $e) { return; } $emails[] = $user['email']; } } if (!$force) { $this->markReportAsSent($report, $period); } foreach ($emails as $email) { if (empty($email)) { continue; } $mail->addTo($email); try { $mail->send(); } catch (Exception $e) { // If running from piwik.php with debug, we ignore the 'email not sent' error $tracker = new Tracker(); if (!$tracker->isDebugModeEnabled()) { throw new Exception("An error occured while sending '{$filename}' " . " to " . implode(', ', $mail->getRecipients()) . ". Error was '" . $e->getMessage() . "'"); } } $mail->clearRecipients(); } }
public function test_formatAlerts_asHtml() { $alerts = $this->getTriggeredAlerts(); $host = SettingsPiwik::getPiwikUrl(); $rendered = $this->controller->formatAlerts($alerts, 'html'); $expected = <<<FORMATTED <table style="border-collapse: collapse;width:100%" class="tableForm dataTable entityTable"> <thead style="background-color:rgb(228,226,215);color:rgb(37,87,146);"> <tr> <th style="padding:6px 6px;text-align: left;">Alert Name</th> <th style="padding:6px 6px;text-align: left;">Report</th> <th style="padding:6px 6px;text-align: left;">Alert Condition</th> <th style="padding:6px 6px;text-align: left;">Alert</th> </tr> </thead> <tbody> <tr> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;"><a href="{$host}index.php?module=CustomAlerts&action=editAlert&idAlert=1&idSite=1&period=week&date=yesterday">MyName1</a></td> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;">Single Website dashboard</td> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;">Website is 'Piwik'</td> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;">Visits decreased more than 5000 from 228.128 to 4493</td> </tr> <tr> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;"><a href="{$host}index.php?module=CustomAlerts&action=editAlert&idAlert=2&idSite=1&period=week&date=yesterday">MyName2</a></td> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;">Single Website dashboard</td> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;">Website is 'Piwik'</td> <td style="max-width:300px;border-bottom:1px solid rgb(231,231,231);padding:5px 0 5px 6px;">Visits decreased more than 5000 from 228.128 to 4493</td> </tr> </tbody> </table> FORMATTED; $this->assertEquals($expected, $rendered); }
/** * Displays the admin UI page showing all tracking tags * @return string */ function displayJavascriptCode() { $idSite = Common::getRequestVar('idSite'); Piwik::checkUserHasViewAccess($idSite); $jsTag = Piwik::getJavascriptCode($idSite, SettingsPiwik::getPiwikUrl()); $view = new View('@SitesManager/displayJavascriptCode'); $this->setBasicVariablesView($view); $view->idSite = $idSite; $site = new Site($idSite); $view->displaySiteName = $site->getName(); $view->jsTag = $jsTag; return $view->render(); }
private function assignCommonParameters(View $view) { $view->assign("reportFontFamily", ReportRenderer::DEFAULT_REPORT_FONT_FAMILY); $view->assign("reportTitleTextColor", ReportRenderer::REPORT_TITLE_TEXT_COLOR); $view->assign("reportTitleTextSize", self::REPORT_TITLE_TEXT_SIZE); $view->assign("reportTextColor", ReportRenderer::REPORT_TEXT_COLOR); $view->assign("tableHeaderBgColor", ReportRenderer::TABLE_HEADER_BG_COLOR); $view->assign("tableHeaderTextColor", ReportRenderer::TABLE_HEADER_TEXT_COLOR); $view->assign("tableCellBorderColor", ReportRenderer::TABLE_CELL_BORDER_COLOR); $view->assign("tableBgColor", ReportRenderer::TABLE_BG_COLOR); $view->assign("reportTableHeaderTextWeight", self::TABLE_HEADER_TEXT_WEIGHT); $view->assign("reportTableHeaderTextSize", self::REPORT_TABLE_HEADER_TEXT_SIZE); $view->assign("reportTableHeaderTextTransform", ReportRenderer::TABLE_HEADER_TEXT_TRANSFORM); $view->assign("reportTableRowTextSize", self::REPORT_TABLE_ROW_TEXT_SIZE); $view->assign("reportBackToTopTextSize", self::REPORT_BACK_TO_TOP_TEXT_SIZE); $view->assign("currentPath", SettingsPiwik::getPiwikUrl()); $view->assign("logoHeader", API::getInstance()->getHeaderLogoUrl()); }
private function initPiwikHost($piwikUrl = false) { // If core:archive command run as a web cron, we use the current hostname+path if (empty($piwikUrl)) { if (!empty(self::$url)) { $piwikUrl = self::$url; } else { // example.org/piwik/ $piwikUrl = SettingsPiwik::getPiwikUrl(); } } if (!$piwikUrl) { $this->logFatalErrorUrlExpected(); } if (!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) { // try adding http:// in case it's missing $piwikUrl = "http://" . $piwikUrl; } if (!\Piwik\UrlHelper::isLookLikeUrl($piwikUrl)) { $this->logFatalErrorUrlExpected(); } // ensure there is a trailing slash if ($piwikUrl[strlen($piwikUrl) - 1] != '/' && !Common::stringEndsWith($piwikUrl, 'index.php')) { $piwikUrl .= '/'; } $this->initConfigObject($piwikUrl); if (Config::getInstance()->General['force_ssl'] == 1) { $piwikUrl = str_replace('http://', 'https://', $piwikUrl); } if (!Common::stringEndsWith($piwikUrl, 'index.php')) { $piwikUrl .= 'index.php'; } $this->piwikUrl = $piwikUrl; }
/** * Must be called before dispatch() * - checks that directories are writable, * - loads the configuration file, * - loads the plugin, * - inits the DB connection, * - etc. * * @throws Exception * @return void */ public function init() { static $initialized = false; if ($initialized) { return; } $initialized = true; try { Registry::set('timer', new Timer()); $directoriesToCheck = array('/tmp/', '/tmp/assets/', '/tmp/cache/', '/tmp/logs/', '/tmp/tcpdf/', '/tmp/templates_c/'); Filechecks::dieIfDirectoriesNotWritable($directoriesToCheck); self::assignCliParametersToRequest(); Translate::loadEnglishTranslation(); $exceptionToThrow = self::createConfigObject(); if (Session::isFileBasedSessions()) { Session::start(); } $this->handleMaintenanceMode(); $this->handleSSLRedirection(); $this->handleProfiler(); $pluginsManager = \Piwik\Plugin\Manager::getInstance(); $pluginsToLoad = Config::getInstance()->Plugins['Plugins']; $pluginsManager->loadPlugins($pluginsToLoad); if ($exceptionToThrow) { throw $exceptionToThrow; } try { Db::createDatabaseObject(); Option::get('TestingIfDatabaseConnectionWorked'); } catch (Exception $exception) { if (self::shouldRethrowException()) { throw $exception; } /** * Triggered if the INI config file has the incorrect format or if certain required configuration * options are absent. * * This event can be used to start the installation process or to display a custom error message. * * @param Exception $exception The exception thrown from creating and testing the database * connection. */ Piwik::postEvent('Config.badConfigurationFile', array($exception), $pending = true); throw $exception; } // Init the Access object, so that eg. core/Updates/* can enforce Super User and use some APIs Access::getInstance(); /** * Triggered just after the platform is initialized and plugins are loaded. * * This event can be used to do early initialization. * * _Note: At this point the user is not authenticated yet._ */ Piwik::postEvent('Request.dispatchCoreAndPluginUpdatesScreen'); \Piwik\Plugin\Manager::getInstance()->installLoadedPlugins(); // ensure the current Piwik URL is known for later use if (method_exists('Piwik\\SettingsPiwik', 'getPiwikUrl')) { $host = SettingsPiwik::getPiwikUrl(); } /** * Triggered before the user is authenticated, when the global authentication object * should be created. * * Plugins that provide their own authentication implementation should use this event * to set the global authentication object (which must derive from {@link Piwik\Auth}). * * **Example** * * Piwik::addAction('Request.initAuthenticationObject', function() { * Piwik\Registry::set('auth', new MyAuthImplementation()); * }); */ Piwik::postEvent('Request.initAuthenticationObject'); try { $authAdapter = Registry::get('auth'); } catch (Exception $e) { throw new Exception("Authentication object cannot be found in the Registry. Maybe the Login plugin is not activated?\n <br />You can activate the plugin by adding:<br />\n <code>Plugins[] = Login</code><br />\n under the <code>[Plugins]</code> section in your config/config.ini.php"); } Access::getInstance()->reloadAccess($authAdapter); // Force the auth to use the token_auth if specified, so that embed dashboard // and all other non widgetized controller methods works fine if (($token_auth = Common::getRequestVar('token_auth', false, 'string')) !== false) { Request::reloadAuthUsingTokenAuth(); } SettingsServer::raiseMemoryLimitIfNecessary(); Translate::reloadLanguage(); $pluginsManager->postLoadPlugins(); /** * Triggered after the platform is initialized and after the user has been authenticated, but * before the platform has handled the request. * * Piwik uses this event to check for updates to Piwik. */ Piwik::postEvent('Updater.checkForUpdates'); } catch (Exception $e) { if (self::shouldRethrowException()) { throw $e; } $debugTrace = $e->getTraceAsString(); Piwik_ExitWithMessage($e->getMessage(), $debugTrace, true); } }
/** * @param string $email * @return string */ protected function parseDomainPlaceholderAsPiwikHostName($email) { $hostname = Config::getInstance()->mail['defaultHostnameIfEmpty']; $piwikHost = Url::getCurrentHost($hostname); // If known Piwik URL, use it instead of "localhost" $piwikUrl = SettingsPiwik::getPiwikUrl(); $url = parse_url($piwikUrl); if ($this->isHostDefinedAndNotLocal($url)) { $piwikHost = $url['host']; } return str_replace('{DOMAIN}', $piwikHost, $email); }
/** * Initializes Profiling via XHProf. * See: https://github.com/piwik/piwik/blob/master/tests/README.xhprof.md */ public static function setupProfilerXHProf($mainRun = false, $setupDuringTracking = false) { if (!$setupDuringTracking && SettingsServer::isTrackerApiRequest()) { // do not profile Tracker return; } if (self::$isXhprofSetup) { return; } $xhProfPath = PIWIK_INCLUDE_PATH . '/vendor/facebook/xhprof/extension/modules/xhprof.so'; if (!file_exists($xhProfPath)) { throw new Exception("Cannot find xhprof, run 'composer install --dev' and build the extension."); } if (!function_exists('xhprof_enable')) { throw new Exception("Cannot find xhprof_enable, make sure to add 'extension={$xhProfPath}' to your php.ini."); } $outputDir = ini_get("xhprof.output_dir"); if (empty($outputDir)) { throw new Exception("The profiler output dir is not set. Add 'xhprof.output_dir=...' to your php.ini."); } if (!is_writable($outputDir)) { throw new Exception("The profiler output dir '" . ini_get("xhprof.output_dir") . "' should exist and be writable."); } if (!function_exists('xhprof_error')) { function xhprof_error($out) { echo substr($out, 0, 300) . '...'; } } $currentGitBranch = SettingsPiwik::getCurrentGitBranch(); $profilerNamespace = "piwik"; if ($currentGitBranch != 'master') { $profilerNamespace .= "-" . $currentGitBranch; } if ($mainRun) { self::setProfilingRunIds(array()); } xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY); register_shutdown_function(function () use($profilerNamespace, $mainRun) { $xhprofData = xhprof_disable(); $xhprofRuns = new XHProfRuns_Default(); $runId = $xhprofRuns->save_run($xhprofData, $profilerNamespace); if (empty($runId)) { die('could not write profiler run'); } $runs = Profiler::getProfilingRunIds(); array_unshift($runs, $runId); if ($mainRun) { Profiler::aggregateXhprofRuns($runs, $profilerNamespace, $saveTo = $runId); $baseUrlStored = SettingsPiwik::getPiwikUrl(); $out = "\n\n"; $baseUrl = "http://" . @$_SERVER['HTTP_HOST'] . "/" . @$_SERVER['REQUEST_URI']; if (strlen($baseUrlStored) > strlen($baseUrl)) { $baseUrl = $baseUrlStored; } $baseUrl = $baseUrlStored . "vendor/facebook/xhprof/xhprof_html/?source={$profilerNamespace}&run={$runId}"; $out .= "Profiler report is available at:\n"; $out .= "<a href='{$baseUrl}'>{$baseUrl}</a>"; $out .= "\n\n"; if (Development::isEnabled()) { $out .= "WARNING: Development mode is enabled. Many runtime optimizations are not applied in development mode. "; $out .= "Unless you intend to profile Piwik in development mode, your profile may not be accurate."; $out .= "\n\n"; } echo $out; } else { Profiler::setProfilingRunIds($runs); } }); self::$isXhprofSetup = true; }
/** * Tracker requests will automatically trigger the Scheduled tasks. * This is useful for users who don't setup the cron, * but still want daily/weekly/monthly PDF reports emailed automatically. * * This is similar to calling the API CoreAdminHome.runScheduledTasks */ protected static function runScheduledTasks() { $now = time(); // Currently, there are no hourly tasks. When there are some, // this could be too aggressive minimum interval (some hours would be skipped in case of low traffic) $minimumInterval = Config::getInstance()->Tracker['scheduled_tasks_min_interval']; // If the user disabled browser archiving, he has already setup a cron // To avoid parallel requests triggering the Scheduled Tasks, // Get last time tasks started executing $cache = Cache::getCacheGeneral(); if ($minimumInterval <= 0 || empty($cache['isBrowserTriggerEnabled'])) { Common::printDebug("-> Scheduled tasks not running in Tracker: Browser archiving is disabled."); return; } $nextRunTime = $cache['lastTrackerCronRun'] + $minimumInterval; if (isset($GLOBALS['PIWIK_TRACKER_DEBUG_FORCE_SCHEDULED_TASKS']) && $GLOBALS['PIWIK_TRACKER_DEBUG_FORCE_SCHEDULED_TASKS'] || $cache['lastTrackerCronRun'] === false || $nextRunTime < $now) { $cache['lastTrackerCronRun'] = $now; Cache::setCacheGeneral($cache); self::initCorePiwikInTrackerMode(); Option::set('lastTrackerCronRun', $cache['lastTrackerCronRun']); Common::printDebug('-> Scheduled Tasks: Starting...'); // save current user privilege and temporarily assume Super User privilege $isSuperUser = Piwik::hasUserSuperUserAccess(); // Scheduled tasks assume Super User is running Piwik::setUserHasSuperUserAccess(); // While each plugins should ensure that necessary languages are loaded, // we ensure English translations at least are loaded Translate::loadEnglishTranslation(); ob_start(); CronArchive::$url = SettingsPiwik::getPiwikUrl(); $cronArchive = new CronArchive(); $cronArchive->runScheduledTasksInTrackerMode(); $resultTasks = ob_get_contents(); ob_clean(); // restore original user privilege Piwik::setUserHasSuperUserAccess($isSuperUser); foreach (explode('</pre>', $resultTasks) as $resultTask) { Common::printDebug(str_replace('<pre>', '', $resultTask)); } Common::printDebug('Finished Scheduled Tasks.'); } else { Common::printDebug("-> Scheduled tasks not triggered."); } Common::printDebug("Next run will be from: " . date('Y-m-d H:i:s', $nextRunTime) . ' UTC'); }
private function executeNotAsyncHttp($url, Output $output) { $piwikUrl = $this->urlToPiwik ?: SettingsPiwik::getPiwikUrl(); if (empty($piwikUrl)) { $piwikUrl = 'http://' . Url::getHost() . '/'; } $url = $piwikUrl . $url; if (Config::getInstance()->General['force_ssl'] == 1) { $url = str_replace("http://", "https://", $url); } if ($this->runAsSuperUser) { $tokenAuths = self::getSuperUserTokenAuths(); $tokenAuth = reset($tokenAuths); if (strpos($url, '?') === false) { $url .= '?'; } else { $url .= '&'; } $url .= 'token_auth=' . $tokenAuth; } try { Log::debug("Execute HTTP API request: " . $url); $response = Http::sendHttpRequestBy('curl', $url, $timeout = 0, $userAgent = null, $destinationPath = null, $file = null, $followDepth = 0, $acceptLanguage = false, $this->acceptInvalidSSLCertificate); $output->write($response); } catch (\Exception $e) { $message = "Got invalid response from API request: {$url}. "; if (isset($response) && empty($response)) { $message .= "The response was empty. This usually means a server error. This solution to this error is generally to increase the value of 'memory_limit' in your php.ini file. Please check your Web server Error Log file for more details."; } else { $message .= "Response was '" . $e->getMessage() . "'"; } $output->write($message); Log::debug($e); } }
protected function buildNotificationMessage($pluginsToBeNotified, $hasThemeUpdate, $hasPluginUpdate) { $message = Piwik::translate('ScheduledReports_EmailHello'); $message .= "\n\n"; $message .= Piwik::translate('CoreUpdater_ThereIsNewPluginVersionAvailableForUpdate'); $message .= "\n\n"; foreach ($pluginsToBeNotified as $plugin) { $message .= sprintf(' * %s %s', $plugin['name'], $plugin['latestVersion']); $message .= "\n"; } $message .= "\n"; $host = SettingsPiwik::getPiwikUrl(); if ($hasThemeUpdate) { $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdateThemes') . "\n"; $message .= $host . 'index.php?module=CorePluginsAdmin&action=themes'; } if ($hasPluginUpdate) { if ($hasThemeUpdate) { $message .= "\n\n"; } $message .= Piwik::translate('CoreUpdater_NotificationClickToUpdatePlugins') . "\n"; $message .= $host . 'index.php?module=CorePluginsAdmin&action=plugins'; } $message .= "\n\n"; $message .= Piwik::translate('Installation_HappyAnalysing'); return $message; }
protected function getPathToLogo($pathOnly, $defaultLogo, $themeLogo, $customLogo) { $pathToPiwikRoot = Filesystem::getPathToPiwikRoot(); $logo = $defaultLogo; $theme = \Piwik\Plugin\Manager::getInstance()->getThemeEnabled(); if (!$theme) { $themeName = Manager::DEFAULT_THEME; } else { $themeName = $theme->getPluginName(); } $themeLogo = sprintf($themeLogo, $themeName); if (file_exists($pathToPiwikRoot . '/' . $themeLogo)) { $logo = $themeLogo; } if ($this->isEnabled() && file_exists($pathToPiwikRoot . '/' . $customLogo)) { $logo = $customLogo; } if (!$pathOnly) { return SettingsPiwik::getPiwikUrl() . $logo; } return $pathToPiwikRoot . '/' . $logo; }
function getKeywordsForPage() { Piwik::checkUserHasViewAccess($this->idSite); $requestUrl = '&date=previous1' . '&period=week' . '&idSite=' . $this->idSite; $topPageUrlRequest = $requestUrl . '&method=Actions.getPageUrls' . '&filter_limit=50' . '&format=original'; $request = new Request($topPageUrlRequest); $request = $request->process(); /** @var $request Map */ $tables = $request->getDataTables(); $topPageUrl = false; $first = key($tables); if (!empty($first)) { $topPageUrls = $tables[$first]; $topPageUrls = $topPageUrls->getRowsMetadata('url'); $tmpTopPageUrls = array_values($topPageUrls); $topPageUrl = current($tmpTopPageUrls); } if (empty($topPageUrl)) { $topPageUrl = $this->site->getMainUrl(); } $url = $topPageUrl; // HTML $api = SettingsPiwik::getPiwikUrl() . '?module=API&method=Referrers.getKeywordsForPageUrl' . '&format=php' . '&filter_limit=10' . '&token_auth=' . Piwik::getCurrentUserTokenAuth(); $api .= $requestUrl; $code = ' // This function will call the API to get best keyword for current URL. // Then it writes the list of best keywords in a HTML list function DisplayTopKeywords($url = "") { // Do not spend more than 1 second fetching the data @ini_set("default_socket_timeout", $timeout = 1); // Get the Keywords data $url = empty($url) ? "http://". $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] : $url; $api = "' . $api . '&url=" . urlencode($url); $keywords = @unserialize(file_get_contents($api)); if($keywords === false || isset($keywords["result"])) { // DEBUG ONLY: uncomment for troubleshooting an empty output (the URL output reveals the token_auth) // echo "Error while fetching the <a href=\'$api\'>Top Keywords from Piwik</a>"; return; } // Display the list in HTML $url = htmlspecialchars($url, ENT_QUOTES); $output = "<h2>Top Keywords for <a href=\'$url\'>$url</a></h2><ul>"; foreach($keywords as $keyword) { $output .= "<li>". $keyword . "</li>"; } if(empty($keywords)) { $output .= "Nothing yet..."; } $output .= "</ul>"; echo $output; } '; $jsonRequest = str_replace('format=php', 'format=json', $api); echo "<p>This widget is designed to work in your website directly.\n\t\tThis widget makes it easy to use Piwik to <i>automatically display the list of Top Keywords</i>, for each of your website Page URLs.</p>\n\t\t<p>\n\t\t<b>Example API URL</b> - For example if you would like to get the top 10 keywords, used last week, to land on the page <a target='_blank' href='{$topPageUrl}'>{$topPageUrl}</a>,\n\t\tin format JSON: you would dynamically fetch the data using <a target='_blank' href='{$jsonRequest}&url=" . urlencode($topPageUrl) . "'>this API request URL</a>. Make sure you encode the 'url' parameter in the URL.</p>\n\n\t\t<p><b>PHP Function ready to use!</b> - If you use PHP on your website, we have prepared a small code snippet that you can copy paste in your Website PHP files. You can then simply call the function <code>DisplayTopKeywords();</code> anywhere in your template, at the bottom of the content or in your blog sidebar.\n\t\tIf you run this code in your page {$topPageUrl}, it would output the following:"; echo "<div style='width:400px;margin-left:20px;padding:10px;border:1px solid black;'>"; function DisplayTopKeywords($url = "", $api) { // Do not spend more than 1 second fetching the data @ini_set("default_socket_timeout", $timeout = 1); // Get the Keywords data $url = empty($url) ? "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] : $url; $api = $api . "&url=" . urlencode($url); $keywords = @unserialize(file_get_contents($api)); if ($keywords === false || isset($keywords["result"])) { // DEBUG ONLY: uncomment for troubleshooting an empty output (the URL output reveals the token_auth) //echo "Error while fetching the <a href=\'".$api."\'>Top Keywords from Piwik</a>"; return; } // Display the list in HTML $url = htmlspecialchars($url, ENT_QUOTES); $output = "<h2>Top Keywords for <a href=\\'{$url}\\'>{$url}</a></h2><ul>"; foreach ($keywords as $keyword) { $output .= "<li>" . $keyword . "</li>"; } if (empty($keywords)) { $output .= "Nothing yet..."; } $output .= "</ul>"; echo $output; } DisplayTopKeywords($topPageUrl, $api); echo "</div><br/>\n\t\t<p>Here is the PHP function that you can paste in your pages:</P>\n\t\t<textarea cols=60 rows=8><?php\n" . htmlspecialchars($code) . "\n DisplayTopKeywords();</textarea>\n\t\t"; echo "\n\t\t<p><strong>Notes</strong>: You can for example edit the code to to make the Top search keywords link to your Website search result pages.\n\t\t<br/>On medium to large traffic websites, we recommend to cache this data, as to minimize the performance impact of calling the Piwik API on each page view.\n\t\t</p>\n\t\t"; }
/** * Returns true if the supplied instance ID refers to this Piwik instance, false if otherwise. * Assumes the instance ID is the base URL to the Piwik instance. * * @param string $instanceIdUrl * @return bool */ protected function isUrlThisInstanceUrl($instanceIdUrl) { $thisPiwikUrl = SettingsPiwik::getPiwikUrl(); $thisPiwikUrl = $this->getNormalizedUrl($thisPiwikUrl, $isThisPiwikUrl = true); $instanceIdUrl = $this->getNormalizedUrl($instanceIdUrl); return $thisPiwikUrl == $instanceIdUrl; }