'Installation_Welcome', 'systemCheck' => 'Installation_SystemCheck', 'databaseSetup' => 'Installation_DatabaseSetup', 'databaseCheck' => 'Installation_DatabaseCheck', 'tablesCreation' => 'Installation_Tables', 'generalSetup' => 'Installation_SuperUser', 'firstWebsiteSetup' => 'Installation_SetupWebsite', 'trackingCode' => 'Installation_JsTag', 'finished' => 'Installation_Congratulations', ); protected $session; public function __construct() { $this->session = new Piwik_Session_Namespace('Piwik_Installation'); if (!isset($this->session->currentStepDone)) { $this->session->currentStepDone = ''; $this->session->skipThisStep = array(); } Piwik_PostEvent('InstallationController.construct', array($this)); } /** * Get installation steps * * @return array installation steps */ public function getInstallationSteps() { return $this->steps; } /** * Get default action (first installation step) * * @return string function name */ function getDefaultAction() { $steps = array_keys($this->steps); return $steps[0]; } /** * Installation Step 1: Welcome */ function welcome($message = false) { // Delete merged js/css files to force regenerations based on updated activated plugin list Piwik::deleteAllCacheOnUpdate(); $view = new Piwik_Installation_View( '@Installation/welcome', $this->getInstallationSteps(), __FUNCTION__ ); $view->newInstall = !file_exists(Config::getLocalConfigPath()); $view->errorMessage = $message; $this->skipThisStep(__FUNCTION__); $view->showNextStep = $view->newInstall; $this->session->currentStepDone = __FUNCTION__; echo $view->render(); } /** * Installation Step 2: System Check */ function systemCheck() { $this->checkPreviousStepIsValid(__FUNCTION__); $view = new Piwik_Installation_View( '@Installation/systemCheck', $this->getInstallationSteps(), __FUNCTION__ ); $this->skipThisStep(__FUNCTION__); $view->duringInstall = true; $this->setupSystemCheckView($view); $this->session->general_infos = $view->infos['general_infos']; // make sure DB sessions are used if the filesystem is NFS if ($view->infos['is_nfs']) { $this->session->general_infos['session_save_handler'] = 'dbtable'; } $view->showNextStep = !$view->problemWithSomeDirectories && $view->infos['phpVersion_ok'] && count($view->infos['adapters']) && !count($view->infos['missing_extensions']) && !count($view->infos['missing_functions']); // On the system check page, if all is green, display Next link at the top $view->showNextStepAtTop = $view->showNextStep; $this->session->currentStepDone = __FUNCTION__; echo $view->render(); } /** * Installation Step 3: Database Set-up * @throws Exception|Zend_Db_Adapter_Exception */ function databaseSetup() { $this->checkPreviousStepIsValid(__FUNCTION__); // case the user hits the back button $this->session->skipThisStep = array( 'firstWebsiteSetup' => false, 'trackingCode' => false, ); $view = new Piwik_Installation_View( '@Installation/databaseSetup', $this->getInstallationSteps(), __FUNCTION__ ); $this->skipThisStep(__FUNCTION__); $view->showNextStep = false; $form = new Piwik_Installation_FormDatabaseSetup(); if ($form->validate()) { try { $dbInfos = $form->createDatabaseObject(); $this->session->databaseCreated = true; Piwik::checkDatabaseVersion(); $this->session->databaseVersionOk = true; $this->session->db_infos = $dbInfos; $this->redirectToNextStep(__FUNCTION__); } catch (Exception $e) { $view->errorMessage = Common::sanitizeInputValue($e->getMessage()); } } $view->addForm($form); echo $view->render(); } /** * Installation Step 4: Database Check */ function databaseCheck() { $this->checkPreviousStepIsValid(__FUNCTION__); $view = new Piwik_Installation_View( '@Installation/databaseCheck', $this->getInstallationSteps(), __FUNCTION__ ); $error = false; $this->skipThisStep(__FUNCTION__); if (isset($this->session->databaseVersionOk) && $this->session->databaseVersionOk === true ) { $view->databaseVersionOk = true; } else { $error = true; } if (isset($this->session->databaseCreated) && $this->session->databaseCreated === true ) { $dbInfos = $this->session->db_infos; $view->databaseName = $dbInfos['dbname']; $view->databaseCreated = true; } else { $error = true; } $this->createDbFromSessionInformation(); $db = Zend_Registry::get('db'); try { $db->checkClientVersion(); } catch (Exception $e) { $view->clientVersionWarning = $e->getMessage(); $error = true; } if (!Piwik::isDatabaseConnectionUTF8()) { $dbInfos = $this->session->db_infos; $dbInfos['charset'] = 'utf8'; $this->session->db_infos = $dbInfos; } $view->showNextStep = true; $this->session->currentStepDone = __FUNCTION__; if ($error === false) { $this->redirectToNextStep(__FUNCTION__); } echo $view->render(); } /** * Installation Step 5: Table Creation */ function tablesCreation() { $this->checkPreviousStepIsValid(__FUNCTION__); $view = new Piwik_Installation_View( '@Installation/tablesCreation', $this->getInstallationSteps(), __FUNCTION__ ); $this->skipThisStep(__FUNCTION__); $this->createDbFromSessionInformation(); if (Common::getRequestVar('deleteTables', 0, 'int') == 1) { Piwik::dropTables(); $view->existingTablesDeleted = true; // when the user decides to drop the tables then we dont skip the next steps anymore // workaround ZF-1743 $tmp = $this->session->skipThisStep; $tmp['firstWebsiteSetup'] = false; $tmp['trackingCode'] = false; $this->session->skipThisStep = $tmp; } $tablesInstalled = Piwik::getTablesInstalled(); $view->tablesInstalled = ''; if (count($tablesInstalled) > 0) { // we have existing tables $view->tablesInstalled = implode(', ', $tablesInstalled); $view->someTablesInstalled = true; // remove monthly archive tables $archiveTables = Piwik_DataAccess_ArchiveTableCreator::getTablesArchivesInstalled(); $baseTablesInstalled = count($tablesInstalled) - count($archiveTables); $minimumCountPiwikTables = 17; Access::getInstance(); Piwik::setUserIsSuperUser(); if ($baseTablesInstalled >= $minimumCountPiwikTables && count(Piwik_SitesManager_API::getInstance()->getAllSitesId()) > 0 && count(Piwik_UsersManager_API::getInstance()->getUsers()) > 0 ) { $view->showReuseExistingTables = true; // when the user reuses the same tables we skip the website creation step // workaround ZF-1743 $tmp = $this->session->skipThisStep; $tmp['firstWebsiteSetup'] = true; $tmp['trackingCode'] = true; $this->session->skipThisStep = $tmp; } } else { Piwik::createTables(); Piwik::createAnonymousUser(); $updater = new Piwik_Updater(); $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION); $view->tablesCreated = true; $view->showNextStep = true; } $this->session->currentStepDone = __FUNCTION__; echo $view->render(); } /** * Installation Step 6: General Set-up (superuser login/password/email and subscriptions) */ function generalSetup() { $this->checkPreviousStepIsValid(__FUNCTION__); $view = new Piwik_Installation_View( '@Installation/generalSetup', $this->getInstallationSteps(), __FUNCTION__ ); $this->skipThisStep(__FUNCTION__); $form = new Piwik_Installation_FormGeneralSetup(); if ($form->validate()) { $superUserInfos = array( 'login' => $form->getSubmitValue('login'), 'password' => md5($form->getSubmitValue('password')), 'email' => $form->getSubmitValue('email'), 'salt' => Common::generateUniqId(), ); $this->session->superuser_infos = $superUserInfos; $url = Config::getInstance()->General['api_service_url']; $url .= '/1.0/subscribeNewsletter/'; $params = array( 'email' => $form->getSubmitValue('email'), 'security' => $form->getSubmitValue('subscribe_newsletter_security'), 'community' => $form->getSubmitValue('subscribe_newsletter_community'), 'url' => Piwik_Url::getCurrentUrlWithoutQueryString(), ); if ($params['security'] == '1' || $params['community'] == '1' ) { if (!isset($params['security'])) { $params['security'] = '0'; } if (!isset($params['community'])) { $params['community'] = '0'; } $url .= '?' . http_build_query($params, '', '&'); try { Piwik_Http::sendHttpRequest($url, $timeout = 2); } catch (Exception $e) { // e.g., disable_functions = fsockopen; allow_url_open = Off } } $this->redirectToNextStep(__FUNCTION__); } $view->addForm($form); echo $view->render(); } /** * Installation Step 7: Configure first web-site */ public function firstWebsiteSetup() { $this->checkPreviousStepIsValid(__FUNCTION__); $view = new Piwik_Installation_View( '@Installation/firstWebsiteSetup', $this->getInstallationSteps(), __FUNCTION__ ); $this->skipThisStep(__FUNCTION__); $form = new Piwik_Installation_FormFirstWebsiteSetup(); if (!isset($this->session->generalSetupSuccessMessage)) { $view->displayGeneralSetupSuccess = true; $this->session->generalSetupSuccessMessage = true; } $this->initObjectsToCallAPI(); if ($form->validate()) { $name = urlencode($form->getSubmitValue('siteName')); $url = urlencode($form->getSubmitValue('url')); $ecommerce = (int)$form->getSubmitValue('ecommerce'); $request = new Piwik_API_Request(" method=SitesManager.addSite &siteName=$name &urls=$url &ecommerce=$ecommerce &format=original "); try { $result = $request->process(); $this->session->site_idSite = $result; $this->session->site_name = $name; $this->session->site_url = $url; $this->redirectToNextStep(__FUNCTION__); } catch (Exception $e) { $view->errorMessage = $e->getMessage(); } } $view->addForm($form); echo $view->render(); } /** * Installation Step 8: Display JavaScript tracking code */ public function trackingCode() { $this->checkPreviousStepIsValid(__FUNCTION__); $view = new Piwik_Installation_View( '@Installation/trackingCode', $this->getInstallationSteps(), __FUNCTION__ ); $this->skipThisStep(__FUNCTION__); if (!isset($this->session->firstWebsiteSetupSuccessMessage)) { $view->displayfirstWebsiteSetupSuccess = true; $this->session->firstWebsiteSetupSuccessMessage = true; } $siteName = $this->session->site_name; $siteName = Common::sanitizeInputValue(urldecode($siteName)); $idSite = $this->session->site_idSite; // Load the Tracking code and help text from the SitesManager $viewTrackingHelp = new Piwik_View('@SitesManager/_displayJavascriptCode'); $viewTrackingHelp->displaySiteName = $siteName; $viewTrackingHelp->jsTag = Piwik::getJavascriptCode($idSite, Piwik_Url::getCurrentUrlWithoutFileName()); $viewTrackingHelp->idSite = $idSite; $viewTrackingHelp->piwikUrl = Piwik_Url::getCurrentUrlWithoutFileName(); $view->trackingHelp = $viewTrackingHelp->render(); $view->displaySiteName = $siteName; $view->showNextStep = true; $this->session->currentStepDone = __FUNCTION__; echo $view->render(); } /** * Installation Step 9: Finished! */ public function finished() { $this->checkPreviousStepIsValid(__FUNCTION__); $view = new Piwik_Installation_View( '@Installation/finished', $this->getInstallationSteps(), __FUNCTION__ ); $this->skipThisStep(__FUNCTION__); if (!file_exists(Config::getLocalConfigPath())) { // $this->addTrustedHosts(); $this->writeConfigFileFromSession(); } $view->showNextStep = false; $this->session->currentStepDone = __FUNCTION__; echo $view->render(); $this->session->unsetAll(); } /** * This controller action renders an admin tab that runs the installation * system check, so people can see if there are any issues w/ their running * Piwik installation. * * This admin tab is only viewable by the super user. */ public function systemCheckPage() { Piwik::checkUserIsSuperUser(); $view = new Piwik_View('@Installation/systemCheckPage'); $this->setBasicVariablesView($view); $view->duringInstall = false; $this->setupSystemCheckView($view); $infos = $view->infos; $infos['extra'] = self::performAdminPageOnlySystemCheck(); $view->infos = $infos; echo $view->render(); } /** * Instantiate access and log objects */ protected function initObjectsToCallAPI() { // connect to the database using the DB infos currently in the session $this->createDbFromSessionInformation(); Piwik::setUserIsSuperUser(); Piwik::createLogObject(); } /** * Create database connection from session-store */ protected function createDbFromSessionInformation() { $dbInfos = $this->session->db_infos; Config::getInstance()->database = $dbInfos; Piwik::createDatabaseObject($dbInfos); } /** * Write configuration file from session-store */ protected function writeConfigFileFromSession() { if (!isset($this->session->superuser_infos) || !isset($this->session->db_infos) ) { return; } $config = Config::getInstance(); try { // expect exception since config.ini.php doesn't exist yet $config->init(); } catch (Exception $e) { $config->superuser = $this->session->superuser_infos; $config->database = $this->session->db_infos; if (!empty($this->session->general_infos)) { $config->General = $this->session->general_infos; } $config->forceSave(); } unset($this->session->superuser_infos); unset($this->session->db_infos); unset($this->session->general_infos); } /** * Save language selection in session-store */ public function saveLanguage() { $language = Common::getRequestVar('language'); Piwik_LanguagesManager::setLanguageForSession($language); Piwik_Url::redirectToReferer(); } /** * The previous step is valid if it is either * - any step before (OK to go back) * - the current step (case when validating a form) * If step is invalid, then exit. * * @param string $currentStep Current step */ protected function checkPreviousStepIsValid($currentStep) { $error = false; if (empty($this->session->currentStepDone)) { $error = true; } else if ($currentStep == 'finished' && $this->session->currentStepDone == 'finished') { // ok to refresh this page or use language selector } else { if (file_exists(Config::getLocalConfigPath())) { $error = true; } $steps = array_keys($this->steps); // the currentStep $currentStepId = array_search($currentStep, $steps); // the step before $previousStepId = array_search($this->session->currentStepDone, $steps); // not OK if currentStepId > previous+1 if ($currentStepId > $previousStepId + 1) { $error = true; } } if ($error) { Piwik_Login_Controller::clearSession(); $message = Piwik_Translate('Installation_ErrorInvalidState', array('
', '', '', '') ); Piwik::exitWithErrorMessage($message); } } /** * Redirect to next step * * @param string Current step * @return none */ protected function redirectToNextStep($currentStep) { $steps = array_keys($this->steps); $this->session->currentStepDone = $currentStep; $nextStep = $steps[1 + array_search($currentStep, $steps)]; Piwik::redirectToModule('Installation', $nextStep); } /** * Skip this step (typically to mark the current function as completed) * * @param string function name */ protected function skipThisStep($step) { $skipThisStep = $this->session->skipThisStep; if (isset($skipThisStep[$step]) && $skipThisStep[$step]) { $this->redirectToNextStep($step); } } /** * Extract host from URL * * @param string $url URL * * @return string|false */ protected function extractHost($url) { $urlParts = parse_url($url); if (isset($urlParts['host']) && strlen($host = $urlParts['host'])) { return $host; } return false; } /** * Add trusted hosts */ protected function addTrustedHosts() { $trustedHosts = array(); // extract host from the request header if (($host = $this->extractHost('http://' . Piwik_Url::getHost())) !== false) { $trustedHosts[] = $host; } // extract host from first web site if (($host = $this->extractHost(urldecode($this->session->site_url))) !== false) { $trustedHosts[] = $host; } $trustedHosts = array_unique($trustedHosts); if (count($trustedHosts)) { $this->session->general_infos['trusted_hosts'] = $trustedHosts; } } /** * Get system information */ public static function getSystemInformation() { global $piwik_minimumPHPVersion; $minimumMemoryLimit = Config::getInstance()->General['minimum_memory_limit']; $infos = array(); $infos['general_infos'] = array(); $directoriesToCheck = array(); if(!Piwik::isInstalled()) { // at install, need /config to be writable (so we can create config.ini.php) $directoriesToCheck[] = '/config/'; } $directoriesToCheck = array_merge($directoriesToCheck, array( '/tmp/', '/tmp/templates_c/', '/tmp/cache/', '/tmp/assets/', '/tmp/latest/', '/tmp/tcpdf/', '/tmp/sessions/', )); $infos['directories'] = Piwik::checkDirectoriesWritable($directoriesToCheck); $infos['can_auto_update'] = Piwik::canAutoUpdate(); if (Common::isIIS()) { Piwik::createWebConfigFiles(); } else { Piwik::createHtAccessFiles(); } Piwik::createWebRootFiles(); $infos['phpVersion_minimum'] = $piwik_minimumPHPVersion; $infos['phpVersion'] = PHP_VERSION; $infos['phpVersion_ok'] = version_compare($piwik_minimumPHPVersion, $infos['phpVersion']) === -1; // critical errors $extensions = @get_loaded_extensions(); $needed_extensions = array( 'zlib', 'SPL', 'iconv', 'Reflection', ); $infos['needed_extensions'] = $needed_extensions; $infos['missing_extensions'] = array(); foreach ($needed_extensions as $needed_extension) { if (!in_array($needed_extension, $extensions)) { $infos['missing_extensions'][] = $needed_extension; } } $infos['pdo_ok'] = false; if (in_array('PDO', $extensions)) { $infos['pdo_ok'] = true; } $infos['adapters'] = Piwik_Db_Adapter::getAdapters(); $needed_functions = array( 'debug_backtrace', 'create_function', 'eval', 'gzcompress', 'gzuncompress', 'pack', ); $infos['needed_functions'] = $needed_functions; $infos['missing_functions'] = array(); foreach ($needed_functions as $needed_function) { if (!self::functionExists($needed_function)) { $infos['missing_functions'][] = $needed_function; } } // warnings $desired_extensions = array( 'json', 'libxml', 'dom', 'SimpleXML', ); $infos['desired_extensions'] = $desired_extensions; $infos['missing_desired_extensions'] = array(); foreach ($desired_extensions as $desired_extension) { if (!in_array($desired_extension, $extensions)) { $infos['missing_desired_extensions'][] = $desired_extension; } } $desired_functions = array( 'set_time_limit', 'mail', 'parse_ini_file', 'glob', ); $infos['desired_functions'] = $desired_functions; $infos['missing_desired_functions'] = array(); foreach ($desired_functions as $desired_function) { if (!self::functionExists($desired_function)) { $infos['missing_desired_functions'][] = $desired_function; } } $infos['openurl'] = Piwik_Http::getTransportMethod(); $infos['gd_ok'] = Piwik::isGdExtensionEnabled(); $infos['hasMbstring'] = false; $infos['multibyte_ok'] = true; if (function_exists('mb_internal_encoding')) { $infos['hasMbstring'] = true; if (((int)ini_get('mbstring.func_overload')) != 0) { $infos['multibyte_ok'] = false; } } $serverSoftware = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : ''; $infos['serverVersion'] = addslashes($serverSoftware); $infos['serverOs'] = @php_uname(); $infos['serverTime'] = date('H:i:s'); $infos['registerGlobals_ok'] = ini_get('register_globals') == 0; $infos['memoryMinimum'] = $minimumMemoryLimit; $infos['memory_ok'] = true; $infos['memoryCurrent'] = ''; $raised = Piwik::raiseMemoryLimitIfNecessary(); if (($memoryValue = Piwik::getMemoryLimitValue()) > 0) { $infos['memoryCurrent'] = $memoryValue . 'M'; $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit; } $infos['isWindows'] = Common::isWindows(); $integrityInfo = Piwik::getFileIntegrityInformation(); $infos['integrity'] = $integrityInfo[0]; $infos['integrityErrorMessages'] = array(); if (isset($integrityInfo[1])) { if ($infos['integrity'] == false) { $infos['integrityErrorMessages'][] = '' . Piwik_Translate('General_FileIntegrityWarningExplanation') . ''; } $infos['integrityErrorMessages'] = array_merge($infos['integrityErrorMessages'], array_slice($integrityInfo, 1)); } $infos['timezone'] = Piwik::isTimezoneSupportEnabled(); $infos['tracker_status'] = Common::getRequestVar('trackerStatus', 0, 'int'); $infos['protocol'] = Piwik_ProxyHeaders::getProtocolInformation(); if (!Piwik::isHttps() && $infos['protocol'] !== null) { $infos['general_infos']['assume_secure_protocol'] = '1'; } if (count($headers = Piwik_ProxyHeaders::getProxyClientHeaders()) > 0) { $infos['general_infos']['proxy_client_headers'] = $headers; } if (count($headers = Piwik_ProxyHeaders::getProxyHostHeaders()) > 0) { $infos['general_infos']['proxy_host_headers'] = $headers; } // check if filesystem is NFS, if it is file based sessions won't work properly $infos['is_nfs'] = Piwik::checkIfFileSystemIsNFS(); // determine whether there are any errors/warnings from the checks done above $infos['has_errors'] = false; $infos['has_warnings'] = false; if (in_array(0, $infos['directories']) // if a directory is not writable || !$infos['phpVersion_ok'] || !empty($infos['missing_extensions']) || empty($infos['adapters']) || !empty($infos['missing_functions']) ) { $infos['has_errors'] = true; } if (!$infos['can_auto_update'] || !empty($infos['missing_desired_extensions']) || !$infos['gd_ok'] || !$infos['multibyte_ok'] || !$infos['registerGlobals_ok'] || !$infos['memory_ok'] || !empty($infos['integrityErrorMessages']) || !$infos['timezone'] // if timezone support isn't available || $infos['tracker_status'] != 0 || $infos['is_nfs'] ) { $infos['has_warnings'] = true; } return $infos; } /** * Test if function exists. Also handles case where function is disabled via Suhosin. * * @param string $functionName Function name * @return bool True if function exists (not disabled); False otherwise. */ public static function functionExists($functionName) { // eval() is a language construct if ($functionName == 'eval') { // does not check suhosin.executor.eval.whitelist (or blacklist) if (extension_loaded('suhosin')) { return @ini_get("suhosin.executor.disable_eval") != "1"; } return true; } $exists = function_exists($functionName); if (extension_loaded('suhosin')) { $blacklist = @ini_get("suhosin.executor.func.blacklist"); if (!empty($blacklist)) { $blacklistFunctions = array_map('strtolower', array_map('trim', explode(',', $blacklist))); return $exists && !in_array($functionName, $blacklistFunctions); } } return $exists; } /** * Utility function, sets up a view that will display system check info. * * @param Piwik_View $view */ private function setupSystemCheckView($view) { $view->infos = self::getSystemInformation(); $view->helpMessages = array( 'zlib' => 'Installation_SystemCheckZlibHelp', 'SPL' => 'Installation_SystemCheckSplHelp', 'iconv' => 'Installation_SystemCheckIconvHelp', 'Reflection' => 'Required extension that is built in PHP, see http://www.php.net/manual/en/book.reflection.php', 'json' => 'Installation_SystemCheckWarnJsonHelp', 'libxml' => 'Installation_SystemCheckWarnLibXmlHelp', 'dom' => 'Installation_SystemCheckWarnDomHelp', 'SimpleXML' => 'Installation_SystemCheckWarnSimpleXMLHelp', 'set_time_limit' => 'Installation_SystemCheckTimeLimitHelp', 'mail' => 'Installation_SystemCheckMailHelp', 'parse_ini_file' => 'Installation_SystemCheckParseIniFileHelp', 'glob' => 'Installation_SystemCheckGlobHelp', 'debug_backtrace' => 'Installation_SystemCheckDebugBacktraceHelp', 'create_function' => 'Installation_SystemCheckCreateFunctionHelp', 'eval' => 'Installation_SystemCheckEvalHelp', 'gzcompress' => 'Installation_SystemCheckGzcompressHelp', 'gzuncompress' => 'Installation_SystemCheckGzuncompressHelp', 'pack' => 'Installation_SystemCheckPackHelp', ); $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories'])); } /** * Performs extra system checks for the 'System Check' admin page. These * checks are not performed during Installation. * * The following checks are performed: * - Check for whether LOAD DATA INFILE can be used. The result of the check * is stored in $result['load_data_infile_available']. The error message is * stored in $result['load_data_infile_error']. * * @return array */ public static function performAdminPageOnlySystemCheck() { $result = array(); // check if LOAD DATA INFILE works $optionTable = Common::prefixTable('option'); $testOptionNames = array('test_system_check1', 'test_system_check2'); $result['load_data_infile_available'] = false; try { $result['load_data_infile_available'] = Piwik::tableInsertBatch( $optionTable, array('option_name', 'option_value'), array( array($testOptionNames[0], '1'), array($testOptionNames[1], '2'), ), $throwException = true ); } catch (Exception $ex) { $result['load_data_infile_error'] = str_replace("\n", "
", $ex->getMessage()); } // delete the temporary rows that were created Piwik_Exec("DELETE FROM `$optionTable` WHERE option_name IN ('" . implode("','", $testOptionNames) . "')"); return $result; } }