/** * Purges old data from the following tables: * - log_visit * - log_link_visit_action * - log_conversion * - log_conversion_item * - log_action */ public function purgeData() { $maxIdVisit = $this->getDeleteIdVisitOffset(); // break if no ID was found (nothing to delete for given period) if (empty($maxIdVisit)) { return; } $logTables = self::getDeleteTableLogTables(); // delete data from log tables $where = "WHERE idvisit <= ?"; foreach ($logTables as $logTable) { // deleting from log_action must be handled differently, so we do it later if ($logTable != Common::prefixTable('log_action')) { Db::deleteAllRows($logTable, $where, "idvisit ASC", $this->maxRowsToDeletePerQuery, array($maxIdVisit)); } } // delete unused actions from the log_action table (but only if we can lock tables) if (Db::isLockPrivilegeGranted()) { $this->purgeUnusedLogActions(); } else { $logMessage = get_class($this) . ": LOCK TABLES privilege not granted; skipping unused actions purge"; Log::warning($logMessage); } // optimize table overhead after deletion Db::optimizeTables($logTables); }
private function addCommandIfExists($command) { if (!class_exists($command)) { Log::warning(sprintf('Cannot add command %s, class does not exist', $command)); } elseif (!is_subclass_of($command, 'Piwik\\Plugin\\ConsoleCommand')) { Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\\Plugin\\ConsoleCommand', $command)); } else { $this->add(new $command()); } }
/** * Purges old data from the following tables: * - log_visit * - log_link_visit_action * - log_conversion * - log_conversion_item * - log_action * * @param int $deleteLogsOlderThan The number of days after which log entires are considered old. * Visits and related data whose age is greater than this number * will be purged. */ public function purgeData($deleteLogsOlderThan) { $dateUpperLimit = Date::factory("today")->subDay($deleteLogsOlderThan); $this->logDeleter->deleteVisitsFor($start = null, $dateUpperLimit->getDatetime()); $logTables = self::getDeleteTableLogTables(); // delete unused actions from the log_action table (but only if we can lock tables) if (Db::isLockPrivilegeGranted()) { $this->rawLogDao->deleteUnusedLogActions(); } else { $logMessage = get_class($this) . ": LOCK TABLES privilege not granted; skipping unused actions purge"; Log::warning($logMessage); } // optimize table overhead after deletion Db::optimizeTables($logTables); }
private function addCommandIfExists($command) { if (!class_exists($command)) { Log::warning(sprintf('Cannot add command %s, class does not exist', $command)); } elseif (!is_subclass_of($command, 'Piwik\\Plugin\\ConsoleCommand')) { Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\\Plugin\\ConsoleCommand', $command)); } else { /** @var Command $commandInstance */ $commandInstance = new $command(); // do not add the command if it already exists; this way we can add the command ourselves in tests if (!$this->has($commandInstance->getName())) { $this->add($commandInstance); } } }
public function run() { $console = new Application(); $commands = $this->getAvailableCommands(); foreach ($commands as $command) { if (!class_exists($command)) { Log::warning(sprintf('Cannot add command %s, class does not exist', $command)); } elseif (!is_subclass_of($command, 'Piwik\\Plugin\\ConsoleCommand')) { Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\\Plugin\\ConsoleCommand', $command)); } else { $console->add(new $command()); } } $console->run(); }
public function doRun(InputInterface $input, OutputInterface $output) { $this->initPiwikHost($input); $this->initConfig($output); try { self::initPlugins(); } catch (\Exception $e) { // Piwik not installed yet, no config file? } Translate::reloadLanguage('en'); $commands = $this->getAvailableCommands(); foreach ($commands as $command) { if (!class_exists($command)) { Log::warning(sprintf('Cannot add command %s, class does not exist', $command)); } elseif (!is_subclass_of($command, 'Piwik\\Plugin\\ConsoleCommand')) { Log::warning(sprintf('Cannot add command %s, class does not extend Piwik\\Plugin\\ConsoleCommand', $command)); } else { $this->add(new $command()); } } return parent::doRun($input, $output); }
/** * Tries to find a component such as a Menu or Tasks within this plugin. * * @param string $componentName The name of the component you want to look for. In case you request a * component named 'Menu' it'll look for a file named 'Menu.php' within the * root of the plugin folder that implements a class named * Piwik\Plugin\$PluginName\Menu . If such a file exists but does not implement * this class it'll silently ignored. * @param string $expectedSubclass If not empty, a check will be performed whether a found file extends the * given subclass. If the requested file exists but does not extend this class * a warning will be shown to advice a developer to extend this certain class. * * @return \stdClass|null Null if the requested component does not exist or an instance of the found * component. */ public function findComponent($componentName, $expectedSubclass) { $this->createCacheIfNeeded(); $cacheId = 'Plugin' . $this->pluginName . $componentName . $expectedSubclass; $componentFile = sprintf('%s/plugins/%s/%s.php', PIWIK_INCLUDE_PATH, $this->pluginName, $componentName); if ($this->cache->contains($cacheId)) { $classname = $this->cache->fetch($cacheId); if (empty($classname)) { return null; // might by "false" in case has no menu, widget, ... } if (file_exists($componentFile)) { include_once $componentFile; } } else { $this->cache->save($cacheId, false); // prevent from trying to load over and over again for instance if there is no Menu for a plugin if (!file_exists($componentFile)) { return null; } require_once $componentFile; $classname = sprintf('Piwik\\Plugins\\%s\\%s', $this->pluginName, $componentName); if (!class_exists($classname)) { return null; } if (!empty($expectedSubclass) && !is_subclass_of($classname, $expectedSubclass)) { Log::warning(sprintf('Cannot use component %s for plugin %s, class %s does not extend %s', $componentName, $this->pluginName, $classname, $expectedSubclass)); return null; } $this->cache->save($cacheId, $classname); } return StaticContainer::get($classname); }
private function warnIfSubtableAlreadyExists() { if (!is_null($this->c[self::DATATABLE_ASSOCIATED])) { Log::warning("Row with label '%s' (columns = %s) has already a subtable id=%s but it was not loaded - overwriting the existing sub-table.", $this->getColumn('label'), implode(", ", $this->getColumns()), $this->getIdSubDataTable()); } }
/** * @dataProvider getBackendsToTest */ public function testLoggingNonString($backend) { $this->recreateLogSingleton($backend); Log::warning(123); $this->checkBackend($backend, '123', $formatMessage = true, $tag = 'Monolog'); }
private function logMessageIfRequestPropertiesHaveChanged(array $requestPropertiesBefore) { $requestProperties = $this->requestConfig->getProperties(); $diff = array_diff_assoc($this->makeSureArrayContainsOnlyStrings($requestProperties), $this->makeSureArrayContainsOnlyStrings($requestPropertiesBefore)); if (!empty($diff['filter_sort_column'])) { // this here might be ok as it can be changed after data loaded but before filters applied unset($diff['filter_sort_column']); } if (!empty($diff['filter_sort_order'])) { // this here might be ok as it can be changed after data loaded but before filters applied unset($diff['filter_sort_order']); } if (empty($diff)) { return; } $details = array('changedProperties' => $diff, 'apiMethod' => $this->requestConfig->apiMethodToRequestDataTable, 'controller' => $this->config->controllerName . '.' . $this->config->controllerAction, 'viewDataTable' => static::getViewDataTableId()); $message = 'Some ViewDataTable::requestConfig properties have changed after requesting the data table. ' . 'That means the changed values had probably no effect. For instance in beforeRender() hook. ' . 'Probably a bug? Details:' . print_r($details, 1); Log::warning($message); }
private function getPreviousScheduledTime($rescheduledTime) { $updaterPeriod = Option::get(self::SCHEDULE_PERIOD_OPTION_NAME); if ($updaterPeriod == 'week') { return Date::factory($rescheduledTime)->subWeek(1); } else { if ($updaterPeriod == 'month') { return Date::factory($rescheduledTime)->subMonth(1); } else { Log::warning("Unknown GeoIP updater period found in database: %s", $updaterPeriod); return Date::factory(0); } } }
/** * Start the session * * @param array|bool $options An array of configuration options; the auto-start (bool) setting is ignored * @return void */ public static function start($options = false) { if (headers_sent() || self::$sessionStarted || defined('PIWIK_ENABLE_SESSION_START') && !PIWIK_ENABLE_SESSION_START) { return; } self::$sessionStarted = true; // use cookies to store session id on the client side @ini_set('session.use_cookies', '1'); // prevent attacks involving session ids passed in URLs @ini_set('session.use_only_cookies', '1'); // advise browser that session cookie should only be sent over secure connection if (ProxyHttp::isHttps()) { @ini_set('session.cookie_secure', '1'); } // advise browser that session cookie should only be accessible through the HTTP protocol (i.e., not JavaScript) @ini_set('session.cookie_httponly', '1'); // don't use the default: PHPSESSID @ini_set('session.name', self::SESSION_NAME); // proxies may cause the referer check to fail and // incorrectly invalidate the session @ini_set('session.referer_check', ''); $currentSaveHandler = ini_get('session.save_handler'); $config = Config::getInstance(); if (self::isFileBasedSessions()) { // Note: this handler doesn't work well in load-balanced environments and may have a concurrency issue with locked session files // for "files", use our own folder to prevent local session file hijacking $sessionPath = self::getSessionsDirectory(); // We always call mkdir since it also chmods the directory which might help when permissions were reverted for some reasons Filesystem::mkdir($sessionPath); @ini_set('session.save_handler', 'files'); @ini_set('session.save_path', $sessionPath); } else { if ($config->General['session_save_handler'] === 'dbtable' || in_array($currentSaveHandler, array('user', 'mm'))) { // We consider these to be misconfigurations, in that: // - user - we can't verify that user-defined session handler functions have already been set via session_set_save_handler() // - mm - this handler is not recommended, unsupported, not available for Windows, and has a potential concurrency issue $config = array('name' => Common::prefixTable('session'), 'primary' => 'id', 'modifiedColumn' => 'modified', 'dataColumn' => 'data', 'lifetimeColumn' => 'lifetime'); $saveHandler = new DbTable($config); if ($saveHandler) { self::setSaveHandler($saveHandler); } } } // garbage collection may disabled by default (e.g., Debian) if (ini_get('session.gc_probability') == 0) { @ini_set('session.gc_probability', 1); } try { parent::start(); register_shutdown_function(array('Zend_Session', 'writeClose'), true); } catch (Exception $e) { Log::warning('Unable to start session: ' . $e->getMessage()); $enableDbSessions = ''; if (DbHelper::isInstalled()) { $enableDbSessions = "<br/>If you still experience issues after trying these changes,\n\t\t\t \t\t\twe recommend that you <a href='http://piwik.org/faq/how-to-install/#faq_133' target='_blank'>enable database session storage</a>."; } $pathToSessions = Filechecks::getErrorMessageMissingPermissions(Filesystem::getPathToPiwikRoot() . '/tmp/sessions/'); $pathToSessions = SettingsPiwik::rewriteTmpPathWithInstanceId($pathToSessions); $message = sprintf("Error: %s %s %s\n<pre>Debug: the original error was \n%s</pre>", Piwik::translate('General_ExceptionUnableToStartSession'), $pathToSessions, $enableDbSessions, $e->getMessage()); Piwik_ExitWithMessage($message, $e->getTraceAsString()); } }
public function download() { Piwik::checkUserHasSuperUserAccess(); $this->dieIfPluginsAdminIsDisabled(); $pluginName = new PluginName(); $pluginName = $pluginName->getPluginName(); Nonce::checkNonce($pluginName); $filename = $pluginName . '.zip'; try { $pathToPlugin = $this->marketplaceApi->download($pluginName); ProxyHttp::serverStaticFile($pathToPlugin, 'application/zip', $expire = 0, $start = false, $end = false, $filename); } catch (Exception $e) { Common::sendResponseCode(500); Log::warning('Could not download file . ' . $e->getMessage()); } if (!empty($pathToPlugin)) { Filesystem::deleteFileIfExists($pathToPlugin); } }
public function sendReport($idReport, $period = false, $date = false, $force = false) { Piwik::checkUserIsNotAnonymous(); $reports = $this->getReports($idSite = false, false, $idReport); $report = reset($reports); if ($report['period'] == 'never') { $report['period'] = 'day'; } if (!empty($period)) { $report['period'] = $period; } if (empty($date)) { $date = Date::now()->subPeriod(1, $report['period'])->toString(); } $language = \Piwik\Plugins\LanguagesManager\API::getInstance()->getLanguageForUser($report['login']); // generate report list($outputFilename, $prettyDate, $reportSubject, $reportTitle, $additionalFiles) = $this->generateReport($idReport, $date, $language, self::OUTPUT_SAVE_ON_DISK, $report['period']); if (!file_exists($outputFilename)) { throw new Exception("The report file wasn't found in {$outputFilename}"); } $contents = file_get_contents($outputFilename); if (empty($contents)) { Log::warning("Scheduled report file '%s' exists but is empty!", $outputFilename); } /** * Triggered when sending scheduled reports. * * Plugins that provide new scheduled report transport mediums should use this event to * send the scheduled report. * * @param string $reportType A string ID describing how the report is sent, eg, * `'sms'` or `'email'`. * @param array $report An array describing the scheduled report that is being * generated. * @param string $contents The contents of the scheduled report that was generated * and now should be sent. * @param string $filename The path to the file where the scheduled report has * been saved. * @param string $prettyDate A prettified date string for the data within the * scheduled report. * @param string $reportSubject A string describing what's in the scheduled * report. * @param string $reportTitle The scheduled report's given title (given by a Piwik user). * @param array $additionalFiles The list of additional files that should be * sent with this report. * @param \Piwik\Period $period The period for which the report has been generated. * @param boolean $force A report can only be sent once per period. Setting this to true * will force to send the report even if it has already been sent. */ Piwik::postEvent(self::SEND_REPORT_EVENT, array($report['type'], $report, $contents, $filename = basename($outputFilename), $prettyDate, $reportSubject, $reportTitle, $additionalFiles, \Piwik\Period\Factory::build($report['period'], $date), $force)); // Update flag in DB $now = Date::now()->getDatetime(); $this->getModel()->updateReport($report['idreport'], array('ts_last_sent' => $now)); // If running from piwik.php with debug, do not delete the PDF after sending the email if (!isset($GLOBALS['PIWIK_TRACKER_DEBUG']) || !$GLOBALS['PIWIK_TRACKER_DEBUG']) { @chmod($outputFilename, 0600); } }
/** * The password we store for a mapped user isn't used to authenticate, it's just * data used to generate a user's token auth. */ private function getPiwikPasswordForLdapUser($ldapUser, $user) { $ldapPassword = $this->getLdapUserField($ldapUser, $this->ldapUserPasswordField); if ($this->isRandomTokenAuthGenerationEnabled || empty($ldapPassword)) { if (!empty($user['password'])) { // do not generate new passwords for users that are already synchronized return $user['password']; } else { if (!$this->isRandomTokenAuthGenerationEnabled) { Log::warning("UserMapper::%s: Could not find LDAP password for user '%s', generating random one.", __FUNCTION__, @$ldapUser[$this->ldapUserIdField]); } return $this->generateRandomPassword(); } } else { return $this->processPassword($ldapPassword); } }
/** * @dataProvider getBackendsToTest */ public function testLoggingNonString($backend) { Config::getInstance()->log['log_writers'] = array($backend); Log::warning(123); $this->checkBackend($backend, '123', $formatMessage = true, $tag = 'Monolog'); }
/** * Remove a file. * * @param string $file * @param bool $silenceErrors If true, no exception will be thrown in case removing fails. */ public static function remove($file, $silenceErrors = false) { if (!file_exists($file)) { return; } $result = @unlink($file); // Testing if the file still exist avoids race conditions if (!$result && file_exists($file)) { if ($silenceErrors) { Log::warning('Failed to delete file ' . $file); } else { throw new \RuntimeException('Unable to delete file ' . $file); } } }
/** * Utility function that checks if geolocation works with each installed database, * and if one or more doesn't, they are renamed to make sure tracking will work. * This is a safety measure used to make sure tracking isn't affected if strange * update errors occur. * * Databases are renamed to ${original}.broken . * * Note: method is protected for testability. */ protected function performRedundantDbChecks() { $databaseTypes = array_keys(GeoIp::$dbNames); foreach ($databaseTypes as $type) { $customNames = array('loc' => array(), 'isp' => array(), 'org' => array()); $customNames[$type] = GeoIp::$dbNames[$type]; // create provider that only uses the DB type we're testing $provider = new Php($customNames); // test the provider. on error, we rename the broken DB. self::getTestLocationCatchPhpErrors($provider); if (self::$unzipPhpError !== null) { list($errno, $errstr, $errfile, $errline) = self::$unzipPhpError; Log::warning("GeoIPAutoUpdater: Encountered PHP error when performing redundant tests on GeoIP " . "%s database: %s: %s on line %s of %s.", $type, $errno, $errstr, $errline, $errfile); // get the current filename for the DB and an available new one to rename it to list($oldPath, $newPath) = $this->getOldAndNewPathsForBrokenDb($customNames[$type]); // rename the DB so tracking will not fail if ($oldPath !== false && $newPath !== false) { if (file_exists($newPath)) { unlink($newPath); } rename($oldPath, $newPath); } } } }
public static function downloadAndUnzip($url, $outputDir, $filename) { $bufferSize = 1024 * 1024; if (!is_dir($outputDir)) { mkdir($outputDir); } $deflatedOut = $outputDir . '/' . $filename; $outfileName = $deflatedOut . '.gz'; if (file_exists($deflatedOut)) { $filesize = filesize($deflatedOut); if ($filesize == 0) { throw new Exception("The file {$deflatedOut} is empty. Suggestion: delete it and try again."); } // Valid geoip db found return; } Log::warning("Geoip database {$outfileName} is not found. Downloading from {$url}..."); $dump = fopen($url, 'rb'); $outfile = fopen($outfileName, 'wb'); if (!$outfile) { throw new Exception("Failed to create file {$outfileName} - please check permissions"); } while (!feof($dump)) { fwrite($outfile, fread($dump, $bufferSize), $bufferSize); } fclose($dump); fclose($outfile); // unzip the dump exec("gunzip -c \"" . $outfileName . "\" > \"{$deflatedOut}\"", $output, $return); if ($return !== 0) { Log::info("gunzip failed with file that has following contents:"); Log::info(file_get_contents($outfile)); throw new Exception("gunzip failed({$return}): " . implode("\n", $output)); } }
/** * Returns the count of LDAP entries that match a filter. * * All PHP errors triggered by ldap_* calls are wrapped in exceptions and thrown. * * @param string $baseDn The base DN to use. * @param string $ldapFilter The LDAP filter string, ie, `"(&(...)(...))"`. This client allows you to use * `"?"` placeholders in the string. * @param array $filterBind Bind parameters for $ldapFilter. * @return int The count of matched entries. * @throws Exception If an error occurs during the `ldap_search` or `ldap_count_entries` calls, or if * `ldap_search` returns null. */ public function count($baseDn, $ldapFilter, $filterBind = array()) { $ldapFilter = $this->bindFilterParameters($ldapFilter, $filterBind); $searchResultResource = $this->initiateSearch($baseDn, $ldapFilter); if (!empty($searchResultResource)) { $connectionResource = $this->connectionResource; Log::debug("Calling ldap_count_entries(%s, %s)", $connectionResource, $searchResultResource); $result = ldap_count_entries($connectionResource, $searchResultResource); Log::debug("ldap_count_entries returned %s", $result); return $result; } else { Log::warning("Unexpected error: ldap_search returned null, extra info: %s", ldap_error($this->connectionResource)); throw new Exception("Unexpected error: ldap_search returned null."); } }
protected function warnWhenSummingTwoStrings($thisColumnValue, $columnToSumValue) { if (is_string($columnToSumValue)) { Log::warning("Trying to add two strings in DataTable\\Row::sumRowArray: %s + %s for row %s", $thisColumnValue, $columnToSumValue, $this->__toString()); } }
/** * Tries to find a component such as a Menu or Tasks within this plugin. * * @param string $componentName The name of the component you want to look for. In case you request a * component named 'Menu' it'll look for a file named 'Menu.php' within the * root of the plugin folder that implements a class named * Piwik\Plugin\$PluginName\Menu . If such a file exists but does not implement * this class it'll silently ignored. * @param string $expectedSubclass If not empty, a check will be performed whether a found file extends the * given subclass. If the requested file exists but does not extend this class * a warning will be shown to advice a developer to extend this certain class. * * @return \stdClass|null Null if the requested component does not exist or an instance of the found * component. */ public function findComponent($componentName, $expectedSubclass) { $componentFile = sprintf('%s/plugins/%s/%s.php', PIWIK_INCLUDE_PATH, $this->pluginName, $componentName); if (!file_exists($componentFile)) { return; } $klassName = sprintf('Piwik\\Plugins\\%s\\%s', $this->pluginName, $componentName); if (!class_exists($klassName)) { return; } if (!empty($expectedSubclass) && !is_subclass_of($klassName, $expectedSubclass)) { Log::warning(sprintf('Cannot use component %s for plugin %s, class %s does not extend %s', $componentName, $this->pluginName, $klassName, $expectedSubclass)); return; } return new $klassName(); }
/** * Returns true if this provider has been setup correctly, the error message if * otherwise. * * @return bool|string */ public function isWorking() { if (!function_exists('mb_internal_encoding')) { return Piwik::translate('UserCountry_GeoIPCannotFindMbstringExtension', array('mb_internal_encoding', 'mbstring')); } $geoIpError = false; $catchGeoIpError = function ($errno, $errstr, $errfile, $errline) use(&$geoIpError) { $filename = basename($errfile); if ($filename == 'geoip.inc' || $filename == 'geoipcity.inc') { $geoIpError = array($errno, $errstr, $errfile, $errline); } else { throw new \Exception("Error in PHP GeoIP provider: {$errstr} on line {$errline} of {$errfile}"); // unexpected } }; // catch GeoIP errors set_error_handler($catchGeoIpError); $result = parent::isWorking(); restore_error_handler(); if ($geoIpError) { list($errno, $errstr, $errfile, $errline) = $geoIpError; Log::warning("Got GeoIP error when testing PHP GeoIP location provider: %s(%s): %s", $errfile, $errline, $errstr); return Piwik::translate('UserCountry_GeoIPIncorrectDatabaseFormat'); } return $result; }
public static function install() { foreach (self::getScopes() as $scope) { $model = new Model($scope); try { $maxCustomVars = 5; $customVarsToAdd = $maxCustomVars - $model->getCurrentNumCustomVars(); for ($index = 0; $index < $customVarsToAdd; $index++) { $model->addCustomVariable(); } } catch (\Exception $e) { Log::warning('Failed to add custom variable: ' . $e->getMessage()); } } }
/** * Tries to find a component such as a Menu or Tasks within this plugin. * * @param string $componentName The name of the component you want to look for. In case you request a * component named 'Menu' it'll look for a file named 'Menu.php' within the * root of the plugin folder that implements a class named * Piwik\Plugin\$PluginName\Menu . If such a file exists but does not implement * this class it'll silently ignored. * @param string $expectedSubclass If not empty, a check will be performed whether a found file extends the * given subclass. If the requested file exists but does not extend this class * a warning will be shown to advice a developer to extend this certain class. * * @return \stdClass|null Null if the requested component does not exist or an instance of the found * component. */ public function findComponent($componentName, $expectedSubclass) { $this->cache->setCacheKey('Plugin' . $this->pluginName . $componentName . $expectedSubclass); $componentFile = sprintf('%s/plugins/%s/%s.php', PIWIK_INCLUDE_PATH, $this->pluginName, $componentName); if ($this->cache->has()) { $klassName = $this->cache->get(); if (empty($klassName)) { return; // might by "false" in case has no menu, widget, ... } if (file_exists($componentFile)) { include_once $componentFile; } } else { $this->cache->set(false); // prevent from trying to load over and over again for instance if there is no Menu for a plugin if (!file_exists($componentFile)) { return; } require_once $componentFile; $klassName = sprintf('Piwik\\Plugins\\%s\\%s', $this->pluginName, $componentName); if (!class_exists($klassName)) { return; } if (!empty($expectedSubclass) && !is_subclass_of($klassName, $expectedSubclass)) { Log::warning(sprintf('Cannot use component %s for plugin %s, class %s does not extend %s', $componentName, $this->pluginName, $klassName, $expectedSubclass)); return; } $this->cache->set($klassName); } return new $klassName(); }
/** * @group Core * * @dataProvider getBackendsToTest */ public function testLoggingWorksWhenMessageIsSprintfString($backend) { Config::getInstance()->log['log_writers'] = array($backend); ob_start(); Log::warning(self::TESTMESSAGE, " subst "); $this->screenOutput = ob_get_contents(); ob_end_clean(); $this->checkBackend($backend, sprintf(self::TESTMESSAGE, " subst "), $formatMessage = true, $tag = 'Core_LogTest'); }
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(); } }
/** Adds data to Piwik. Creates sites, tracks visits, imports log files, etc. */ public function setUp() { Log::warning('Piwik\\Tests\\Fixture is deprecated, use \\Piwik\\Tests\\Framework\\Fixture instead'); parent::setUp(); }
public static function doLog($message) { Log::warning($message); }
/** * Creates a UserSynchronizer using INI configuration. * * @return UserSynchronizer */ public static function makeConfigured() { $result = new UserSynchronizer(); $result->setUserMapper(UserMapper::makeConfigured()); $result->setUsersManagerApi(UsersManagerAPI::getInstance()); $result->setUserModel(new UserModel()); if (Config::isAccessSynchronizationEnabled()) { $result->setUserAccessMapper(UserAccessMapper::makeConfigured()); Log::debug("UserSynchronizer::%s(): Using UserAccessMapper when synchronizing users.", __FUNCTION__); } else { Log::debug("UserSynchronizer::%s(): LDAP access synchronization not enabled.", __FUNCTION__); } $defaultSitesWithViewAccess = Config::getDefaultSitesToGiveViewAccessTo(); if (!empty($defaultSitesWithViewAccess)) { $siteIds = Access::doAsSuperUser(function () use($defaultSitesWithViewAccess) { return Site::getIdSitesFromIdSitesString($defaultSitesWithViewAccess); }); if (empty($siteIds)) { Log::warning("UserSynchronizer::%s(): new_user_default_sites_view_access INI config option has no " . "entries. Newly synchronized users will not have any access.", __FUNCTION__); } $result->setNewUserDefaultSitesWithViewAccess($siteIds); } Log::debug("UserSynchronizer::%s: configuring with defaultSitesWithViewAccess = %s", __FUNCTION__, $defaultSitesWithViewAccess); return $result; }