diff --git a/core/Filechecks.php b/core/Filechecks.php index acf09fb8403..0ab5e79334e 100644 --- a/core/Filechecks.php +++ b/core/Filechecks.php @@ -186,11 +186,11 @@ public static function getErrorMessageMissingPermissions($path) $message = "Please check that the web server has enough permission to write to these files/directories:
"; if (SettingsServer::isWindows()) { - $message .= "On Windows, check that the folder is not read only and is writable. + $message .= "On Windows, check that the folder is not read only and is writable.\n You can try to execute:
"; } else { $message .= "For example, on a Linux server if your Apache httpd user - is www-data, you can try to execute:
" + is www-data, you can try to execute:
\n" . "chown -R www-data:www-data " . $path . "
"; } @@ -208,7 +208,7 @@ public static function getErrorMessageMissingPermissions($path) private static function getMakeWritableCommand($realpath) { if (SettingsServer::isWindows()) { - return "cacls $realpath /t /g " . get_current_user() . ":f
"; + return "cacls $realpath /t /g " . get_current_user() . ":f
\n"; } return "chmod -R 0755 $realpath
"; } diff --git a/core/Log.php b/core/Log.php index 3c3d06eb890..0f883ab631c 100644 --- a/core/Log.php +++ b/core/Log.php @@ -351,7 +351,10 @@ private function logToFile($level, $tag, $datetime, $message) return; } - file_put_contents($this->logToFilePath, $message . "\n", FILE_APPEND); + if(!file_put_contents($this->logToFilePath, $message . "\n", FILE_APPEND)) { + $message = Filechecks::getErrorMessageMissingPermissions($this->logToFilePath); + throw new \Exception( $message ); + } } private function logToScreen($level, $tag, $datetime, $message) diff --git a/core/Tracker.php b/core/Tracker.php index f4618ee3b37..c6ba93ebb65 100644 --- a/core/Tracker.php +++ b/core/Tracker.php @@ -191,7 +191,7 @@ private function authenticateBulkTrackingRequests($rawData) if (isset($jsonData['requests'])) { $this->requests = $jsonData['requests']; } - $tokenAuth = Common::getRequestVar('token_auth', false, null, $jsonData); + $tokenAuth = Common::getRequestVar('token_auth', false, 'string', $jsonData); if (empty($tokenAuth)) { throw new Exception("token_auth must be specified when using Bulk Tracking Import. See Tracking Doc"); } @@ -244,6 +244,9 @@ public function main($args = null) $this->initOutputBuffer(); if (!empty($this->requests)) { + // Request needs the Db to authenticate (if cache files not available) + self::connectDatabaseIfNotConnected(); + foreach ($this->requests as $params) { $request = new Request($params, $tokenAuth); $isAuthenticated = $request->isAuthenticated(); @@ -252,7 +255,6 @@ public function main($args = null) try { if ($this->isVisitValid()) { - self::connectDatabaseIfNotConnected(); $visit = $this->getNewVisitObject(); $request->setForcedVisitorId(self::$forcedVisitorId); diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php index d875ced45f3..c5bfa782dc9 100644 --- a/core/Tracker/Action.php +++ b/core/Tracker/Action.php @@ -17,8 +17,7 @@ use Piwik\Tracker; /** - * Handles an action (page view, download or outlink) by the visitor. - * Parses the action name and URL from the request array, then records the action in the log table. + * * * @package Piwik * @subpackage Tracker @@ -27,7 +26,12 @@ class Action implements ActionInterface { const DB_COLUMN_CUSTOM_FLOAT = 'custom_float'; - static public function make(Request $request) + /** + * + * @param Request $request + * @return ActionClickUrl|ActionPageview|ActionSiteSearch + */ + static public function factory(Request $request) { $downloadUrl = $request->getParam('download'); if (!empty($downloadUrl)) { @@ -54,8 +58,8 @@ static public function make(Request $request) protected $request; private $idLinkVisitAction; - private $idActionName = false; - private $idActionUrl = false; + + protected $actionIdsCached = array(); private $actionName; private $actionType; @@ -67,7 +71,6 @@ public function __construct($type, Request $request) $this->request = $request; } - /** * Returns URL of the page currently being tracked, or the file being downloaded, or the outlink being clicked * @@ -88,25 +91,23 @@ public function getActionType() return $this->actionType; } - protected function getActionNameType() - { - return ActionInterface::TYPE_PAGE_TITLE; - } - public function getIdActionUrl() { - $idUrl = $this->idActionUrl; + $idUrl = $this->actionIdsCached['idaction_url']; // note; idaction_url = 0 is displayed as "Page URL Not Defined" return (int)$idUrl; } public function getIdActionName() { - return $this->idActionName; + if(!isset($this->actionIdsCached['idaction_name'])) { + return false; + } + return $this->actionIdsCached['idaction_name']; } // custom_float column - public function getActionCustomValue() + public function getCustomFloatValue() { return false; } @@ -154,6 +155,36 @@ protected function setActionUrl($url) $this->actionUrl = $url; } + public function getCustomVariables() + { + $customVariables = $this->request->getCustomVariables($scope = 'page'); + return $customVariables; + } + + protected function getActionsToLookup() + { + return array( + 'idaction_name' => $this->getNameAndType(), + 'idaction_url' => $this->getUrlAndType() + ); + } + + protected function getNameAndType() + { + return array($this->getActionName(), ActionInterface::TYPE_PAGE_TITLE, $prefix = false); + } + + protected function getUrlAndType() + { + $url = $this->getActionUrl(); + if (!empty($url)) { + // normalize urls by stripping protocol and www + $url = PageUrl::normalizeUrl($url); + return array($url['url'], Tracker\Action::TYPE_PAGE_URL, $url['prefixId']); + } + return false; + } + public static function getTypeAsString($type) { $class = new \ReflectionClass("\\Piwik\\Tracker\\ActionInterface"); @@ -175,37 +206,20 @@ public static function getTypeAsString($type) * The methods takes care of creating a new record(s) in the action table if the existing * action name and action url doesn't exist yet. */ - function loadIdActionNameAndUrl() + public function loadIdsFromLogActionTable() { - if ($this->idActionUrl !== false - && $this->idActionName !== false - ) { - return; - } - $actions = array(); + $actions = $this->getActionsToLookup(); + $actions = array_filter($actions, 'count'); - $actionNameAndType = $this->getNameAndType(); - if($actionNameAndType) { - $actions[] = $actionNameAndType; + if(empty($actions) + || !empty($this->actionIdsCached)) { + return false; } - $actionUrlAndType = $this->getUrlAndType(); - if($actionUrlAndType) { - $actions[] = $actionUrlAndType; + $loadedActionIds = TableLogAction::loadIdsAction($actions); - } - - $loadedActionIds = TableActionIds::loadActionId($actions); - - foreach ($loadedActionIds as $loadedActionId) { - var_dump($loadedActionId); - list($name, $type, $prefixId, $actionId) = $loadedActionId; - if ($type == $this->getActionNameType()) { - $this->idActionName = $actionId; - } else { - $this->idActionUrl = $actionId; - } - } + $this->actionIdsCached = $loadedActionIds; + return $this->actionIdsCached; } /** @@ -220,7 +234,7 @@ function loadIdActionNameAndUrl() */ public function record($idVisit, $visitorIdCookie, $idReferrerActionUrl, $idReferrerActionName, $timeSpentReferrerAction) { - $this->loadIdActionNameAndUrl(); + $this->loadIdsFromLogActionTable(); $idActionName = in_array($this->getActionType(), array(Tracker\Action::TYPE_PAGE_TITLE, Tracker\Action::TYPE_PAGE_URL, @@ -241,7 +255,7 @@ public function record($idVisit, $visitorIdCookie, $idReferrerActionUrl, $idRefe 'time_spent_ref_action' => $timeSpentReferrerAction ); - $customValue = $this->getActionCustomValue(); + $customValue = $this->getCustomFloatValue(); if (!empty($customValue)) { $insert[self::DB_COLUMN_CUSTOM_FLOAT] = $customValue; } @@ -280,6 +294,7 @@ public function record($idVisit, $visitorIdCookie, $idReferrerActionUrl, $idRefe 'idReferrerActionName' => $idReferrerActionName, 'timeSpentReferrerAction' => $timeSpentReferrerAction, ); + Common::printDebug("Inserted new action:"); Common::printDebug($insertWithoutNulls); /** @@ -289,31 +304,6 @@ public function record($idVisit, $visitorIdCookie, $idReferrerActionUrl, $idRefe Piwik::postEvent('Tracker.recordAction', array($trackerAction = $this, $info)); } - public function getCustomVariables() - { - $customVariables = $this->request->getCustomVariables($scope = 'page'); - return $customVariables; - } - - protected function getNameAndType() - { - $nameType = $this->getActionNameType(); - if (!is_null($nameType)) { - return array($this->getActionName(), $nameType, $prefix = false); - } - return false; - } - - protected function getUrlAndType() - { - $url = $this->getActionUrl(); - if (!empty($url)) { - // normalize urls by stripping protocol and www - $url = PageUrl::normalizeUrl($url); - return array($url['url'], Tracker\Action::TYPE_PAGE_URL, $url['prefixId']); - } - return false; - } } diff --git a/core/Tracker/ActionClickUrl.php b/core/Tracker/ActionClickUrl.php index 3a7e68a1bcf..82d6c312ccc 100644 --- a/core/Tracker/ActionClickUrl.php +++ b/core/Tracker/ActionClickUrl.php @@ -27,9 +27,15 @@ function __construct($type, $url, Request $request) $this->setActionUrl($url); } - function getActionNameType() + protected function getActionsToLookup() { - return null; + $actions = parent::getActionsToLookup(); + // set the right type + $actions['idaction_url'][1] = $this->getActionType(); + + return array( + 'idaction_url' => $actions['idaction_url'] + ); } function writeDebugInfo() diff --git a/core/Tracker/ActionPageview.php b/core/Tracker/ActionPageview.php index ec1e865bb7a..a05db93556e 100644 --- a/core/Tracker/ActionPageview.php +++ b/core/Tracker/ActionPageview.php @@ -15,6 +15,11 @@ use Piwik\Config; +/** + * This class represents a page view, tracking URL, page title and generation time. + * + * @package Piwik\Tracker + */ class ActionPageview extends Action { protected $timeGeneration = false; @@ -32,7 +37,7 @@ function __construct($url, Request $request) $this->timeGeneration = $this->request->getPageGenerationTime(); } - function getActionCustomValue() + function getCustomFloatValue() { return $this->request->getPageGenerationTime(); } diff --git a/core/Tracker/ActionSiteSearch.php b/core/Tracker/ActionSiteSearch.php index ee380be9791..fc9e6e374cb 100644 --- a/core/Tracker/ActionSiteSearch.php +++ b/core/Tracker/ActionSiteSearch.php @@ -16,14 +16,24 @@ use Piwik\Tracker; use Piwik\UrlHelper; +/** + * This class represents a search on the site. + * - Its name is the search keyword + * - by default the URL is not recorded (since it's not used) + * - tracks site search result count and site search category as custom variables + * + * @package Piwik\Tracker + */ class ActionSiteSearch extends Action { + private $searchCategory = false; + private $searchCount = false; + const CVAR_KEY_SEARCH_CATEGORY = '_pk_scat'; const CVAR_KEY_SEARCH_COUNT = '_pk_scount'; const CVAR_INDEX_SEARCH_CATEGORY = '4'; const CVAR_INDEX_SEARCH_COUNT = '5'; - private $searchCategory = false; - private $searchCount = false; + function __construct($url, Request $request) { @@ -31,7 +41,25 @@ function __construct($url, Request $request) $this->originalUrl = $url; } - function getActionCustomValue() + protected function getActionsToLookup() + { + return array( + 'idaction_name' => array($this->getActionName(), ActionInterface::TYPE_SITE_SEARCH, $prefix = false), + 'idaction_url' => $this->getUrlAndType() + ); + } + + public function getIdActionUrl() + { + // Site Search, by default, will not track URL. We do not want URL to appear as "Page URL not defined" + // so we specifically set it to NULL in the table (the archiving query does IS NOT NULL) + if (empty(Config::getInstance()->Tracker['action_sitesearch_record_url'])) { + return null; + } + return parent::getIdActionUrl(); + } + + public function getCustomFloatValue() { return $this->request->getPageGenerationTime(); } @@ -58,21 +86,6 @@ function isSearchDetected() return true; } - // FIXMEA replace by getNameAndType - protected function getActionNameType() - { - return ActionInterface::TYPE_SITE_SEARCH; - } - - public function getIdActionUrl() - { - // Site Search, by default, will not track URL. We do not want URL to appear as "Page URL not defined" - // so we specifically set it to NULL in the table (the archiving query does IS NOT NULL) - if (empty(Config::getInstance()->Tracker['action_sitesearch_record_url'])) { - return null; - } - return parent::getIdActionUrl(); - } public function getCustomVariables() { @@ -96,11 +109,6 @@ public function getCustomVariables() return $customVariables; } - public function isSiteSearchDetected($originalUrl) - { - return true; - } - protected function detectSiteSearchFromUrl($website, $parsedUrl) { $doRemoveSearchParametersFromUrl = false; diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php index 793bb8107ac..0c5e1f330d0 100644 --- a/core/Tracker/GoalManager.php +++ b/core/Tracker/GoalManager.php @@ -630,28 +630,25 @@ protected function getCleanedEcommerceItems($items) $actionsToLookupAllItems = array_merge($actionsToLookupAllItems, $actionsToLookup); } - // add prefixId = false expected by loadActionId() + // add prefixId = false expected by loadIdsFromLogActionTable() foreach($actionsToLookupAllItems as &$actionToLookup) { $actionToLookup[] = false; } - $actionsLookedUp = TableActionIds::loadActionId($actionsToLookupAllItems); - - // id action is returned as the last element of the array - $keyIdAction = 3; + $actionsLookedUp = TableLogAction::loadIdsAction($actionsToLookupAllItems); // Replace SKU, name & category by their ID action foreach ($cleanedItems as $index => &$item) { // SKU - $item[0] = $actionsLookedUp[$index * $columnsInEachRow + 0][$keyIdAction]; + $item[0] = $actionsLookedUp[$index * $columnsInEachRow + 0]; // Name - $item[1] = $actionsLookedUp[$index * $columnsInEachRow + 1][$keyIdAction]; + $item[1] = $actionsLookedUp[$index * $columnsInEachRow + 1]; // Categories - $item[2] = $actionsLookedUp[$index * $columnsInEachRow + 2][$keyIdAction]; - $item[3] = $actionsLookedUp[$index * $columnsInEachRow + 3][$keyIdAction]; - $item[4] = $actionsLookedUp[$index * $columnsInEachRow + 4][$keyIdAction]; - $item[5] = $actionsLookedUp[$index * $columnsInEachRow + 5][$keyIdAction]; - $item[6] = $actionsLookedUp[$index * $columnsInEachRow + 6][$keyIdAction]; + $item[2] = $actionsLookedUp[$index * $columnsInEachRow + 2]; + $item[3] = $actionsLookedUp[$index * $columnsInEachRow + 3]; + $item[4] = $actionsLookedUp[$index * $columnsInEachRow + 4]; + $item[5] = $actionsLookedUp[$index * $columnsInEachRow + 5]; + $item[6] = $actionsLookedUp[$index * $columnsInEachRow + 6]; } return $cleanedItems; } diff --git a/core/Tracker/PageUrl.php b/core/Tracker/PageUrl.php index dc3073b3af5..e0defd4cda9 100644 --- a/core/Tracker/PageUrl.php +++ b/core/Tracker/PageUrl.php @@ -35,7 +35,7 @@ class PageUrl /** * Given the Input URL, will exclude all query parameters set for this site - * Note: Site Search parameters are excluded in isSiteSearchDetected() + * * @static * @param $originalUrl * @param $idSite diff --git a/core/Tracker/Request.php b/core/Tracker/Request.php index 013bcb18da8..2eb72bb5d6d 100644 --- a/core/Tracker/Request.php +++ b/core/Tracker/Request.php @@ -75,7 +75,7 @@ protected function authenticateTrackingApi($tokenAuthFromBulkRequest) { $shouldAuthenticate = Config::getInstance()->Tracker['tracking_requests_require_authentication']; if ($shouldAuthenticate) { - $tokenAuth = $tokenAuthFromBulkRequest || Common::getRequestVar('token_auth', false, 'string', $this->params); + $tokenAuth = $tokenAuthFromBulkRequest ? $tokenAuthFromBulkRequest : Common::getRequestVar('token_auth', false, 'string', $this->params); try { $idSite = $this->getIdSite(); $this->isAuthenticated = $this->authenticateSuperUserOrAdmin($tokenAuth, $idSite); @@ -94,12 +94,12 @@ protected function authenticateTrackingApi($tokenAuthFromBulkRequest) public static function authenticateSuperUserOrAdmin($tokenAuth, $idSite) { - if (!$tokenAuth) { + if (empty($tokenAuth)) { return false; } $superUserLogin = Config::getInstance()->superuser['login']; $superUserPassword = Config::getInstance()->superuser['password']; - if (md5($superUserLogin . $superUserPassword) == $tokenAuth) { + if (md5($superUserLogin . $superUserPassword) === $tokenAuth) { return true; } @@ -528,7 +528,6 @@ public function getParamsCount() return count($this->params); } - const GENERATION_TIME_MS_MAXIMUM = 3600000; // 1 hour public function getPageGenerationTime() diff --git a/core/Tracker/TableActionIds.php b/core/Tracker/TableLogAction.php similarity index 56% rename from core/Tracker/TableActionIds.php rename to core/Tracker/TableLogAction.php index ab64fa34fd9..25b838787c9 100644 --- a/core/Tracker/TableActionIds.php +++ b/core/Tracker/TableLogAction.php @@ -14,9 +14,17 @@ use Piwik\Common; use Piwik\Tracker; -class TableActionIds -{ +/** + * This class is used to query Action IDs from the log_action table. + * + * A pageview, outlink, download or site search are made of several "Action IDs" + * For example pageview is idaction_url and idaction_name. + * + * @package Piwik\Tracker + */ +class TableLogAction +{ public static function getSqlSelectActionId() { $sql = "SELECT idaction, type, name @@ -33,16 +41,47 @@ public static function getSqlSelectActionId() * This is used to record Page URLs, Page Titles, Ecommerce items SKUs, item names, item categories * * If the action name does not exist in the lookup table, it will INSERT it - * @param array $actionNamesAndTypes Array of one or many (name,type) - * @return array Returns the input array, with the idaction appended ie. Array of one or many (name,type,idaction) + * @param array $actionsNameAndType Array of one or many (name,type) + * @return array Returns the an array (Field name => idaction) */ - public static function loadActionId($actionNamesAndTypes) + public static function loadIdsAction($actionsNameAndType) { - // First, we try and select the actions that are already recorded - $sql = TableActionIds::getSqlSelectActionId(); + $actionIds = self::queryIdsAction($actionsNameAndType); + + list($queriedIds, $fieldNamesToInsert) = self::processIdsToInsert($actionsNameAndType, $actionIds); + + $insertedIds = self::insertNewIdsAction($actionsNameAndType, $fieldNamesToInsert); + + $queriedIds = $queriedIds + $insertedIds; + + return $queriedIds; + } + + protected static function insertNewIdsAction($actionsNameAndType, $fieldNamesToInsert) + { + $sql = "INSERT INTO " . Common::prefixTable('log_action') . + "( name, hash, type, url_prefix ) VALUES (?,CRC32(?),?,?)"; + // Then, we insert all new actions in the lookup table + $inserted = array(); + foreach ($fieldNamesToInsert as $fieldName) { + list($name, $type, $urlPrefix) = $actionsNameAndType[$fieldName]; + + Tracker::getDatabase()->query($sql, array($name, $name, $type, $urlPrefix)); + $actionId = Tracker::getDatabase()->lastInsertId(); + + $inserted[$fieldName] = $actionId; + + Common::printDebug("Recorded a new action (" . Action::getTypeAsString($type) . ") in the lookup table: " . $name . " (idaction = " . $actionId . ")"); + } + return $inserted; + } + + protected static function queryIdsAction($actionsNameAndType) + { + $sql = TableLogAction::getSqlSelectActionId(); $bind = array(); $i = 0; - foreach ($actionNamesAndTypes as &$actionNameType) { + foreach ($actionsNameAndType as &$actionNameType) { list($name, $type, $urlPrefix) = $actionNameType; if (empty($name)) { continue; @@ -57,16 +96,21 @@ public static function loadActionId($actionNamesAndTypes) } // Case URL & Title are empty if (empty($bind)) { - return $actionNamesAndTypes; + return false; } $actionIds = Tracker::getDatabase()->fetchAll($sql, $bind); + return $actionIds; + } + protected static function processIdsToInsert($actionsNameAndType, $actionIds) + { // For the Actions found in the lookup table, add the idaction in the array, // If not found in lookup table, queue for INSERT - $actionsToInsert = array(); - foreach ($actionNamesAndTypes as $index => &$actionNameType) { - list($name, $type, $urlPrefix) = $actionNameType; + $fieldNamesToInsert = $fieldNameToActionId = array(); + foreach ($actionsNameAndType as $fieldName => &$actionNameType) { + @list($name, $type, $urlPrefix) = $actionNameType; if (empty($name)) { + $fieldNameToActionId[$fieldName] = false; continue; } @@ -76,28 +120,16 @@ public static function loadActionId($actionNamesAndTypes) && $type == $row['type'] ) { $found = true; - $actionNameType[] = $row['idaction']; + + $fieldNameToActionId[$fieldName] = $row['idaction']; continue; } } if (!$found) { - $actionsToInsert[] = $index; + $fieldNamesToInsert[] = $fieldName; } } - - $sql = "INSERT INTO " . Common::prefixTable('log_action') . - "( name, hash, type, url_prefix ) VALUES (?,CRC32(?),?,?)"; - // Then, we insert all new actions in the lookup table - foreach ($actionsToInsert as $actionToInsert) { - list($name, $type, $urlPrefix) = $actionNamesAndTypes[$actionToInsert]; - - Tracker::getDatabase()->query($sql, array($name, $name, $type, $urlPrefix)); - $actionId = Tracker::getDatabase()->lastInsertId(); - Common::printDebug("Recorded a new action (" . Action::getTypeAsString($type) . ") in the lookup table: " . $name . " (idaction = " . $actionId . ")"); - - $keyIdAction = 3; - $actionNamesAndTypes[$actionToInsert][$keyIdAction] = $actionId; - } - return $actionNamesAndTypes; + return array($fieldNameToActionId, $fieldNamesToInsert); } -} \ No newline at end of file +} + diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php index be9ce912d7b..7772d3be99a 100644 --- a/core/Tracker/Visit.php +++ b/core/Tracker/Visit.php @@ -128,14 +128,14 @@ public function handle() } } // normal page view, potentially triggering a URL matching goal else { - $action = Action::make($this->request); + $action = Action::factory($this->request); $action->writeDebugInfo(); $someGoalsConverted = $this->goalManager->detectGoalsMatchingUrl($this->request->getIdSite(), $action); $visitIsConverted = $someGoalsConverted; - $action->loadIdActionNameAndUrl(); + $action->loadIdsFromLogActionTable(); } // the visitor and session diff --git a/core/ViewDataTable/Manager.php b/core/ViewDataTable/Manager.php index 48d77eec148..de3f0ad7950 100644 --- a/core/ViewDataTable/Manager.php +++ b/core/ViewDataTable/Manager.php @@ -27,7 +27,6 @@ */ class Manager { - /** * Returns the viewDataTable IDs of a visualization's class lineage. * diff --git a/piwik.php b/piwik.php index 36201b00616..f805fee9d3f 100644 --- a/piwik.php +++ b/piwik.php @@ -56,7 +56,7 @@ require_once PIWIK_INCLUDE_PATH . '/core/Tracker/Visit.php'; require_once PIWIK_INCLUDE_PATH . '/core/Tracker/GoalManager.php'; require_once PIWIK_INCLUDE_PATH . '/core/Tracker/PageUrl.php'; -require_once PIWIK_INCLUDE_PATH . '/core/Tracker/TableActionIds.php'; +require_once PIWIK_INCLUDE_PATH . '/core/Tracker/TableLogAction.php'; require_once PIWIK_INCLUDE_PATH . '/core/Tracker/Action.php'; require_once PIWIK_INCLUDE_PATH . '/core/Tracker/ActionClickUrl.php'; require_once PIWIK_INCLUDE_PATH . '/core/Tracker/ActionPageview.php'; diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php index 3d4cddd3881..ca4e9daa392 100644 --- a/plugins/Actions/Actions.php +++ b/plugins/Actions/Actions.php @@ -22,7 +22,7 @@ use Piwik\SegmentExpression; use Piwik\Site; use Piwik\Tracker\Action; -use Piwik\Tracker\TableActionIds; +use Piwik\Tracker\TableLogAction; use Piwik\ViewDataTable\Request as ViewDataTableRequest; use Piwik\WidgetsList; @@ -177,7 +177,7 @@ public function getIdActionFromSegment($valueToMatch, $sqlField, $matchType, $se if ($matchType == SegmentExpression::MATCH_EQUAL || $matchType == SegmentExpression::MATCH_NOT_EQUAL ) { - $sql = TableActionIds::getSqlSelectActionId(); + $sql = TableLogAction::getSqlSelectActionId(); $bind = array($valueToMatch, $valueToMatch, $actionType); $idAction = Db::fetchOne($sql, $bind); // if the action is not found, we hack -100 to ensure it tries to match against an integer diff --git a/plugins/Actions/ArchivingHelper.php b/plugins/Actions/ArchivingHelper.php index e4eb4a313ef..0921452fe4c 100644 --- a/plugins/Actions/ArchivingHelper.php +++ b/plugins/Actions/ArchivingHelper.php @@ -65,8 +65,7 @@ static public function updateActionsTableWithRowQuery($query, $fieldQueried, & $ ) { $url = null; } elseif (!empty($row['name']) - && $row['name'] != DataTable::LABEL_SUMMARY_ROW - ) { + && $row['name'] != DataTable::LABEL_SUMMARY_ROW) { $url = PageUrl::reconstructNormalizedUrl((string)$row['name'], $row['url_prefix']); } @@ -389,7 +388,7 @@ protected static function getActionRow($actionName, $actionType, $urlPrefix = nu * we explode link http://piwik.org/some/path into an array( 'some', 'path' ); * * for action names: - * we explode name 'Piwik / Category 1 / Category 2' into an array('\Piwik\Piwik', 'Category 1', 'Category 2'); + * we explode name 'Piwik / Category 1 / Category 2' into an array('Piwik', 'Category 1', 'Category 2'); * * @param string $name action name * @param int $type action type @@ -403,69 +402,10 @@ static public function getActionExplodedNames($name, $type, $urlPrefix = null) return array($name); } - $matches = array(); - $isUrl = false; $name = str_replace("\n", "", $name); - $urlRegexAfterDomain = '([^/]+)[/]?([^#]*)[#]?(.*)'; - if ($urlPrefix === null) { - // match url with protocol (used for outlinks / downloads) - $urlRegex = '@^http[s]?://' . $urlRegexAfterDomain . '$@i'; - } else { - // the name is a url that does not contain protocol and www anymore - // we know that normalization has been done on db level because $urlPrefix is set - $urlRegex = '@^' . $urlRegexAfterDomain . '$@i'; - } - - preg_match($urlRegex, $name, $matches); - if (count($matches)) { - $isUrl = true; - $urlHost = $matches[1]; - $urlPath = $matches[2]; - $urlFragment = $matches[3]; - } - - if ($type == Action::TYPE_DOWNLOAD - || $type == Action::TYPE_OUTLINK - ) { - if ($isUrl) { - return array(trim($urlHost), '/' . trim($urlPath)); - } - } - - if ($isUrl) { - $name = $urlPath; - - if ($name === '' || substr($name, -1) == '/') { - $name .= self::$defaultActionName; - } - } - - if ($type == Action::TYPE_PAGE_TITLE) { - $categoryDelimiter = self::$actionTitleCategoryDelimiter; - } else { - $categoryDelimiter = self::$actionUrlCategoryDelimiter; - } - - if ($isUrl) { - $urlFragment = PageUrl::processUrlFragment($urlFragment); - if (!empty($urlFragment)) { - $name .= '#' . $urlFragment; - } - } - - if (empty($categoryDelimiter)) { - return array(trim($name)); - } - - $split = explode($categoryDelimiter, $name, self::getSubCategoryLevelLimit()); - - // trim every category and remove empty categories - $split = array_map('trim', $split); - $split = array_filter($split, 'strlen'); - - // forces array key to start at 0 - $split = array_values($split); + $name = self::parseNameFromPageUrl($name, $type, $urlPrefix); + $split = self::splitNameByDelimiter($name, $type); if (empty($split)) { $defaultName = self::getUnknownActionName($type); @@ -597,4 +537,72 @@ private static function createSummaryRow() array('label' => DataTable::LABEL_SUMMARY_ROW) + self::getDefaultRowColumns() )); } + + protected static function splitNameByDelimiter($name, $type) + { + if(is_array($name)) { + return $name; + } + if ($type == Action::TYPE_PAGE_TITLE) { + $categoryDelimiter = self::$actionTitleCategoryDelimiter; + } else { + $categoryDelimiter = self::$actionUrlCategoryDelimiter; + } + + if (empty($categoryDelimiter)) { + return array(trim($name)); + } + + $split = explode($categoryDelimiter, $name, self::getSubCategoryLevelLimit()); + + // trim every category and remove empty categories + $split = array_map('trim', $split); + $split = array_filter($split, 'strlen'); + + // forces array key to start at 0 + $split = array_values($split); + + return $split; + } + + protected static function parseNameFromPageUrl($name, $type, $urlPrefix) + { + if($type == Action::TYPE_PAGE_TITLE) { + return $name; + } + $urlRegexAfterDomain = '([^/]+)[/]?([^#]*)[#]?(.*)'; + if ($urlPrefix === null) { + // match url with protocol (used for outlinks / downloads) + $urlRegex = '@^http[s]?://' . $urlRegexAfterDomain . '$@i'; + } else { + // the name is a url that does not contain protocol and www anymore + // we know that normalization has been done on db level because $urlPrefix is set + $urlRegex = '@^' . $urlRegexAfterDomain . '$@i'; + } + + $matches = array(); + preg_match($urlRegex, $name, $matches); + if (!count($matches)) { + return $name; + } + $urlHost = $matches[1]; + $urlPath = $matches[2]; + $urlFragment = $matches[3]; + + if (in_array($type, array(Action::TYPE_DOWNLOAD, Action::TYPE_OUTLINK))) { + return array(trim($urlHost), trim($urlPath)); + } + + $name = $urlPath; + if ($name === '' || substr($name, -1) == '/') { + $name .= self::$defaultActionName; + } + + $urlFragment = PageUrl::processUrlFragment($urlFragment); + if (!empty($urlFragment)) { + $name .= '#' . $urlFragment; + } + + return $name; + } } diff --git a/plugins/CoreVisualizations/Visualizations/Cloud.php b/plugins/CoreVisualizations/Visualizations/Cloud.php index f75e30ba346..a5d157e6601 100644 --- a/plugins/CoreVisualizations/Visualizations/Cloud.php +++ b/plugins/CoreVisualizations/Visualizations/Cloud.php @@ -101,7 +101,7 @@ public function addWord($word, $value = 1) } } - public function getCloudValues() + private function getCloudValues() { $this->shuffleCloud(); diff --git a/plugins/Transitions/API.php b/plugins/Transitions/API.php index 793d46a1509..618e50505c9 100644 --- a/plugins/Transitions/API.php +++ b/plugins/Transitions/API.php @@ -58,12 +58,11 @@ public function getTransitionsForPageUrl($pageUrl, $idSite, $period, $date, $seg * @param bool $segment * @param bool $limitBeforeGrouping * @param string $parts - * @param bool $returnNormalizedUrls * @return array * @throws Exception */ public function getTransitionsForAction($actionName, $actionType, $idSite, $period, $date, - $segment = false, $limitBeforeGrouping = false, $parts = 'all', $returnNormalizedUrls = false) + $segment = false, $limitBeforeGrouping = false, $parts = 'all') { Piwik::checkUserHasViewAccess($idSite); @@ -84,9 +83,6 @@ public function getTransitionsForAction($actionName, $actionType, $idSite, $peri 'date' => Day::advancedFactory($period->getLabel(), $date)->getLocalizedShortString() ); - // add data to the report - $this->returnNormalizedUrls(); - $partsArray = explode(',', $parts); if ($parts == 'all' || in_array('internalReferrers', $partsArray)) { @@ -226,13 +222,12 @@ private function addFollowingActions($logAggregator, &$report, $idaction, $actio * @param $includeLoops * @return array(followingPages:DataTable, outlinks:DataTable, downloads:DataTable) */ - public function queryFollowingActions($idaction, $actionType, LogAggregator $logAggregator, + protected function queryFollowingActions($idaction, $actionType, LogAggregator $logAggregator, $limitBeforeGrouping = false, $includeLoops = false) { $types = array(); - $isTitle = ($actionType == 'title'); - if (!$isTitle) { + if ($actionType != 'title') { // specific setup for page urls $types[Action::TYPE_PAGE_URL] = 'followingPages'; $dimension = 'IF( idaction_url IS NULL, idaction_name, idaction_url )'; @@ -296,37 +291,11 @@ public function queryFollowingActions($idaction, $actionType, LogAggregator $log $metrics = array(Metrics::INDEX_NB_ACTIONS); $data = $logAggregator->queryActionsByDimension(array($dimension), $where, $selects, $metrics, $rankingQuery, $joinLogActionColumn); - $this->totalTransitionsToFollowingActions = 0; - $dataTables = array(); - foreach ($types as $type => $recordName) { - $dataTable = new DataTable; - if (isset($data[$type])) { - foreach ($data[$type] as &$record) { - $actions = intval($record[Metrics::INDEX_NB_ACTIONS]); - $dataTable->addRow(new Row(array( - Row::COLUMNS => array( - 'label' => $this->getPageLabel($record, $isTitle), - Metrics::INDEX_NB_ACTIONS => $actions - ) - ))); - $this->totalTransitionsToFollowingActions += $actions; - } - } - $dataTables[$recordName] = $dataTable; - } + $dataTables = $this->makeDataTablesFollowingActions($types, $data); return $dataTables; } - /** - * After calling this method, the query*()-Methods will return urls in their - * normalized form (without the prefix reconstructed) - */ - public function returnNormalizedUrls() - { - $this->returnNormalizedUrls = true; - } - /** * Get information about external referrers (i.e. search engines, websites & campaigns) * @@ -336,7 +305,7 @@ public function returnNormalizedUrls() * @param $limitBeforeGrouping * @return DataTable */ - public function queryExternalReferrers($idaction, $actionType, $logAggregator, $limitBeforeGrouping = false) + protected function queryExternalReferrers($idaction, $actionType, $logAggregator, $limitBeforeGrouping = false) { $rankingQuery = new RankingQuery($limitBeforeGrouping ? $limitBeforeGrouping : $this->limitBeforeGrouping); @@ -410,17 +379,20 @@ public function queryExternalReferrers($idaction, $actionType, $logAggregator, $ */ protected function queryInternalReferrers($idaction, $actionType, $logAggregator, $limitBeforeGrouping = false) { + $keyIsOther = 0; + $keyIsPageUrlAction = 1; + $keyIsSiteSearchAction = 2; + $rankingQuery = new RankingQuery($limitBeforeGrouping ? $limitBeforeGrouping : $this->limitBeforeGrouping); $rankingQuery->addLabelColumn(array('name', 'url_prefix')); $rankingQuery->setColumnToMarkExcludedRows('is_self'); - $rankingQuery->partitionResultIntoMultipleGroups('action_partition', array(0, 1, 2)); + $rankingQuery->partitionResultIntoMultipleGroups('action_partition', array($keyIsOther, $keyIsPageUrlAction, $keyIsSiteSearchAction)); $type = $this->getColumnTypeSuffix($actionType); $mainActionType = Action::TYPE_PAGE_URL; $dimension = 'idaction_url_ref'; - $isTitle = $actionType == 'title'; - if ($isTitle) { + if ($actionType == 'title') { $mainActionType = Action::TYPE_PAGE_TITLE; $dimension = 'idaction_name_ref'; } @@ -430,9 +402,9 @@ protected function queryInternalReferrers($idaction, $actionType, $logAggregator 'log_action.url_prefix', 'CASE WHEN log_link_visit_action.idaction_' . $type . '_ref = ' . intval($idaction) . ' THEN 1 ELSE 0 END AS `is_self`', 'CASE - WHEN log_action.type = ' . $mainActionType . ' THEN 1 - WHEN log_action.type = ' . Action::TYPE_SITE_SEARCH . ' THEN 2 - ELSE 0 + WHEN log_action.type = ' . $mainActionType . ' THEN ' . $keyIsPageUrlAction . ' + WHEN log_action.type = ' . Action::TYPE_SITE_SEARCH . ' THEN ' . $keyIsSiteSearchAction .' + ELSE ' . $keyIsOther . ' END AS `action_partition`' ); @@ -453,12 +425,12 @@ protected function queryInternalReferrers($idaction, $actionType, $logAggregator $loops = 0; $nbPageviews = 0; $previousPagesDataTable = new DataTable; - if (isset($data['result'][1])) { - foreach ($data['result'][1] as &$page) { + if (isset($data['result'][$keyIsPageUrlAction])) { + foreach ($data['result'][$keyIsPageUrlAction] as &$page) { $nbActions = intval($page[Metrics::INDEX_NB_ACTIONS]); $previousPagesDataTable->addRow(new Row(array( Row::COLUMNS => array( - 'label' => $this->getPageLabel($page, $isTitle), + 'label' => $this->getPageLabel($page, Action::TYPE_PAGE_URL), Metrics::INDEX_NB_ACTIONS => $nbActions ) ))); @@ -467,8 +439,8 @@ protected function queryInternalReferrers($idaction, $actionType, $logAggregator } $previousSearchesDataTable = new DataTable; - if (isset($data['result'][2])) { - foreach ($data['result'][2] as &$search) { + if (isset($data['result'][$keyIsSiteSearchAction])) { + foreach ($data['result'][$keyIsSiteSearchAction] as &$search) { $nbActions = intval($search[Metrics::INDEX_NB_ACTIONS]); $previousSearchesDataTable->addRow(new Row(array( Row::COLUMNS => array( @@ -499,21 +471,21 @@ protected function queryInternalReferrers($idaction, $actionType, $logAggregator ); } - private function getPageLabel(&$pageRecord, $isTitle) + private function getPageLabel(&$pageRecord, $type) { - if ($isTitle) { + if ($type == Action::TYPE_PAGE_TITLE) { $label = $pageRecord['name']; if (empty($label)) { - $label = ArchivingHelper::getUnknownActionName( - Action::TYPE_PAGE_TITLE); + $label = ArchivingHelper::getUnknownActionName(Action::TYPE_PAGE_TITLE); } return $label; - } else if ($this->returnNormalizedUrls) { - return $pageRecord['name']; - } else { - return PageUrl::reconstructNormalizedUrl( - $pageRecord['name'], $pageRecord['url_prefix']); } + + if ($type == Action::TYPE_OUTLINK || $type == Action::TYPE_DOWNLOAD) { + return PageUrl::reconstructNormalizedUrl($pageRecord['name'], $pageRecord['url_prefix']); + } + + return $pageRecord['name']; } private function getColumnTypeSuffix($actionType) @@ -527,8 +499,6 @@ private function getColumnTypeSuffix($actionType) private $limitBeforeGrouping = 5; private $totalTransitionsToFollowingActions = 0; - private $returnNormalizedUrls = false; - /** * Get the sum of all transitions to following actions (pages, outlinks, downloads). * Only works if queryFollowingActions() has been used directly before. @@ -614,4 +584,27 @@ public function getTranslations() $controller = new Controller(); return $controller->getTranslations(); } + + protected function makeDataTablesFollowingActions($types, $data) + { + $this->totalTransitionsToFollowingActions = 0; + $dataTables = array(); + foreach ($types as $type => $recordName) { + $dataTable = new DataTable; + if (isset($data[$type])) { + foreach ($data[$type] as &$record) { + $actions = intval($record[Metrics::INDEX_NB_ACTIONS]); + $dataTable->addRow(new Row(array( + Row::COLUMNS => array( + 'label' => $this->getPageLabel($record, $type), + Metrics::INDEX_NB_ACTIONS => $actions + ) + ))); + $this->totalTransitionsToFollowingActions += $actions; + } + } + $dataTables[$recordName] = $dataTable; + } + return $dataTables; + } } \ No newline at end of file diff --git a/tests/PHPUnit/BaseFixture.php b/tests/PHPUnit/BaseFixture.php index e05c6ad6c07..a386123bd2b 100644 --- a/tests/PHPUnit/BaseFixture.php +++ b/tests/PHPUnit/BaseFixture.php @@ -180,8 +180,11 @@ public static function checkResponse($response) */ public static function checkBulkTrackingResponse($response) { $data = json_decode($response, true); - if (!is_array($data)) { - echo "Bulk tracking response is not an array: " . var_export($data, true) . "\n"; + if (!is_array($data) || empty($response)) { + throw new Exception("Bulk tracking response (".$response.") is not an array: " . var_export($data, true) . "\n"); + } + if(!isset($data['status'])) { + throw new Exception("Returned data didn't have a status: " . var_export($data,true)); } self::assertArrayHasKey('status', $data); self::assertEquals('success', $data['status']); diff --git a/tests/PHPUnit/Core/Tracker/ActionTest.php b/tests/PHPUnit/Core/Tracker/ActionTest.php index b7f65897982..d3d0e59da84 100644 --- a/tests/PHPUnit/Core/Tracker/ActionTest.php +++ b/tests/PHPUnit/Core/Tracker/ActionTest.php @@ -4,6 +4,7 @@ use Piwik\Plugins\SitesManager\API; use Piwik\Tracker\Action; use Piwik\Tracker\PageUrl; +use Piwik\Tracker\TableLogAction; use Piwik\Tracker\Request; use Piwik\Translate; @@ -26,6 +27,8 @@ public function setUp() \Piwik\Plugin\Manager::getInstance()->loadPlugins(array('SitesManager')); Translate::loadEnglishTranslation(); + + \Piwik\Tracker::connectDatabaseIfNotConnected(); } protected function setUpRootAccess() @@ -190,10 +193,10 @@ public function getExtractUrlData() 'url' => 'http://example.org', 'type' => Action::TYPE_OUTLINK), ), - // outlinks with custom name + // outlinks with custom name -> no custom name array( 'request' => array('link' => 'http://example.org', 'action_name' => 'Example.org'), - 'expected' => array('name' => 'Example.org', + 'expected' => array('name' => null, 'url' => 'http://example.org', 'type' => Action::TYPE_OUTLINK), ), @@ -205,10 +208,10 @@ public function getExtractUrlData() 'type' => Action::TYPE_OUTLINK), ), - // trim the custom name + // no custom name array( 'request' => array('link' => ' http://example.org/Category/Test/ ', 'action_name' => ' Example dot org '), - 'expected' => array('name' => 'Example dot org', + 'expected' => array('name' => null, 'url' => 'http://example.org/Category/Test/', 'type' => Action::TYPE_OUTLINK), ), @@ -221,10 +224,10 @@ public function getExtractUrlData() 'type' => Action::TYPE_DOWNLOAD), ), - // downloads with custom name + // downloads with custom name -> no custom name array( 'request' => array('download' => 'http://example.org/*$test.zip', 'action_name' => 'Download test.zip'), - 'expected' => array('name' => 'Download test.zip', + 'expected' => array('name' => null, 'url' => 'http://example.org/*$test.zip', 'type' => Action::TYPE_DOWNLOAD), ), @@ -361,16 +364,15 @@ public function testExtractUrlAndActionNameFromRequest($request, $expected) $idSite = API::getInstance()->addSite("site1", array('http://example.org')); $request['idsite'] = $idSite; $request = new Request($request); - $action = new Test_Piwik_TrackerAction_extractUrlAndActionNameFromRequest($request); - $this->assertEquals($action->public_extractUrlAndActionNameFromRequest(), $expected); - } -} + $action = Action::factory($request); -class Test_Piwik_TrackerAction_extractUrlAndActionNameFromRequest extends Action -{ - public function public_extractUrlAndActionNameFromRequest() - { - return $this->extractUrlAndActionNameFromRequest(); + $processed = array( + 'name' => $action->getActionName(), + 'url' => $action->getActionUrl(), + 'type' => $action->getActionType(), + ); + + $this->assertEquals($processed, $expected); } } diff --git a/tests/PHPUnit/Fixtures/ThreeSitesWithManyVisitsWithSiteSearch.php b/tests/PHPUnit/Fixtures/ThreeSitesWithManyVisitsWithSiteSearch.php index cecddf208aa..0280e3661f3 100644 --- a/tests/PHPUnit/Fixtures/ThreeSitesWithManyVisitsWithSiteSearch.php +++ b/tests/PHPUnit/Fixtures/ThreeSitesWithManyVisitsWithSiteSearch.php @@ -141,27 +141,6 @@ protected function recordVisitorsSite1() self::checkResponse($visitorB->doTrackPageView('Site Search results')); } - protected function recordVisitorSite3() - { // - - // Third new visitor on Idsite 3 - $visitor = self::getTracker($this->idSite3, $this->dateTime, $defaultInit = true); - $visitor->setResolution(1801, 1301); - - $visitor->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.2)->getDatetime()); - $visitor->setUrl('http://example.org/index.htm?q=Search 1&IsPageView=1'); - $visitor->setCustomVariable(1, 'test cvar name', 'test cvar value'); - self::checkResponse($visitor->doTrackPageView('IsPageView')); - - $visitor->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.35)->getDatetime()); - $visitor->setUrl('http://example.org/index.htm?gkwd=test not a keyword&gcat=Cat not but not keyword, so this is not search'); - self::checkResponse($visitor->doTrackPageView('This is a pageview, not a Search')); - - // Testing UTF8 Title & URL - $crazyTitle = '%2C%20%C3%8Dslenska%2C%20Italiano%2C%20%E6%97%A5%E6%9C%AC%E8%AA%9E%2C%20%E1%83%A5%E1%83%90%E1%83%A0%E1%83%97%E1%83%A3%E1%83%9A%E1%83%98%2C%20%ED%95%9C%EA%B5%AD%EC%96%B4%2C%20Lietuvi%C5%B3%2C%20Latvie%C5%A1u%2C%20Norsk%20(bokm%C3%A5l)%2C%20Nederlands%2C%20Norsk%20(nynorsk)%2C%20Polski%2C%20Portugu%C3%AAs%20brasileiro%2C%20Portugu%C3%AAs%2C%20Rom%C3%A2n%C4%83%2C%20%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%2C%20Slovensky%2C%20Sloven%C5%A1%C4%8Dina%2C%20Shqip%2C%20Srpski%2C%20Svenska%2C%20%E0%B0%A4%E0%B1%86%E0%B0%B2%E0%B1%81%E0%B0%97%E0%B1%81%2C%20%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%E0%B9%84%E0%B8%97%E0%B8%A2%2C%20T%C3%BCrk%C3%A7e%2C%20%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D1%81%D1%8C%D0%BA%D0%B0%2C%20%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%2C%20%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87.'; - $visitor->setUrl('http://example.org/index.htm?' . $crazyTitle); - self::checkResponse($visitor->doTrackPageView('Pageview: ' . $crazyTitle)); - } - protected function recordVisitorSite2() { $visitor = self::getTracker($this->idSite2, $this->dateTime, $defaultInit = true); @@ -189,5 +168,28 @@ protected function recordVisitorSite2() self::checkResponse($visitor->doTrackSiteSearch("No Result Keyword!", "Bad No Result Category bis :(", $count = 0)); return array($defaultInit, $visitor); } + + + protected function recordVisitorSite3() + { + // Third new visitor on Idsite 3 + $visitor = self::getTracker($this->idSite3, $this->dateTime, $defaultInit = true); + $visitor->setResolution(1801, 1301); + + $visitor->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.2)->getDatetime()); + $visitor->setUrl('http://example.org/index.htm?q=Search 1&IsPageView=1'); + $visitor->setCustomVariable(1, 'test cvar name', 'test cvar value'); + self::checkResponse($visitor->doTrackPageView('IsPageView')); + + $visitor->setForceVisitDateTime(Date::factory($this->dateTime)->addHour(0.35)->getDatetime()); + $visitor->setUrl('http://example.org/index.htm?gkwd=test not a keyword&gcat=Cat not but not keyword, so this is not search'); + self::checkResponse($visitor->doTrackPageView('This is a pageview, not a Search')); + + // Testing UTF8 Title & URL + $crazyTitle = '%2C%20%C3%8Dslenska%2C%20Italiano%2C%20%E6%97%A5%E6%9C%AC%E8%AA%9E%2C%20%E1%83%A5%E1%83%90%E1%83%A0%E1%83%97%E1%83%A3%E1%83%9A%E1%83%98%2C%20%ED%95%9C%EA%B5%AD%EC%96%B4%2C%20Lietuvi%C5%B3%2C%20Latvie%C5%A1u%2C%20Norsk%20(bokm%C3%A5l)%2C%20Nederlands%2C%20Norsk%20(nynorsk)%2C%20Polski%2C%20Portugu%C3%AAs%20brasileiro%2C%20Portugu%C3%AAs%2C%20Rom%C3%A2n%C4%83%2C%20%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9%2C%20Slovensky%2C%20Sloven%C5%A1%C4%8Dina%2C%20Shqip%2C%20Srpski%2C%20Svenska%2C%20%E0%B0%A4%E0%B1%86%E0%B0%B2%E0%B1%81%E0%B0%97%E0%B1%81%2C%20%E0%B8%A0%E0%B8%B2%E0%B8%A9%E0%B8%B2%E0%B9%84%E0%B8%97%E0%B8%A2%2C%20T%C3%BCrk%C3%A7e%2C%20%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D1%81%D1%8C%D0%BA%D0%B0%2C%20%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%2C%20%E7%B9%81%E9%AB%94%E4%B8%AD%E6%96%87.'; + $visitor->setUrl('http://example.org/index.htm?' . $crazyTitle); + self::checkResponse($visitor->doTrackPageView('Pageview: ' . $crazyTitle)); + } + } diff --git a/tests/PHPUnit/UI b/tests/PHPUnit/UI index 64f408608a9..b42f538c500 160000 --- a/tests/PHPUnit/UI +++ b/tests/PHPUnit/UI @@ -1 +1 @@ -Subproject commit 64f408608a90fb6d199698b34f053de2a7aa0ba0 +Subproject commit b42f538c5002b787cf99b759fe9ad6f059233f32 diff --git a/tests/PHPUnit/bootstrap.php b/tests/PHPUnit/bootstrap.php index f1a7c5f8aff..004c41a706b 100644 --- a/tests/PHPUnit/bootstrap.php +++ b/tests/PHPUnit/bootstrap.php @@ -1,8 +1,8 @@