添加 Piwik 到代码库中。

+YUCHENG HU+

git-svn-id: https://svn.code.sf.net/p/hawebs/svn@483 a2543c7e-f6e9-4f8a-8bff-1ffc34733512
This commit is contained in:
YuCheng Hu
2010-07-10 04:52:06 +00:00
parent 9684452d40
commit b282d1a279
4 changed files with 958 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
* @version $Id: API.php 2202 2010-05-20 08:49:42Z matt $
*
* @category Piwik_Plugins
* @package Piwik_Actions
*/
/**
* Actions API
*
* @package Piwik_Actions
*/
class Piwik_Actions_API
{
static private $instance = null;
static public function getInstance()
{
if (self::$instance == null)
{
$c = __CLASS__;
self::$instance = new $c();
}
return self::$instance;
}
protected function getDataTable($name, $idSite, $period, $date, $expanded, $idSubtable )
{
Piwik::checkUserHasViewAccess( $idSite );
$archive = Piwik_Archive::build($idSite, $period, $date );
if($idSubtable === false)
{
$idSubtable = null;
}
if($expanded)
{
$dataTable = $archive->getDataTableExpanded($name, $idSubtable);
}
else
{
$dataTable = $archive->getDataTable($name, $idSubtable);
}
$dataTable->filter('Sort', array('nb_visits', 'desc', $naturalSort = false, $expanded));
$dataTable->queueFilter('ReplaceSummaryRowLabel');
return $dataTable;
}
/**
* Backward compatibility. Fallsback to getPageTitles() instead.
* @deprecated Deprecated since Piwik 0.5
*/
public function getActions( $idSite, $period, $date, $expanded = false, $idSubtable = false )
{
return $this->getPageTitles( $idSite, $period, $date, $expanded, $idSubtable );
}
public function getPageUrls( $idSite, $period, $date, $expanded = false, $idSubtable = false )
{
$dataTable = $this->getDataTable('Actions_actions_url', $idSite, $period, $date, $expanded, $idSubtable );
// Average time on page = total time on page / number visits on that page
$dataTable->filter('ColumnCallbackAddColumnQuotient', array('avg_time_on_page', 'sum_time_spent', 'nb_visits', 0));
// Bounce rate = single page visits on this page / visits started on this page
$dataTable->filter('ColumnCallbackAddColumnPercentage', array('bounce_rate', 'entry_bounce_count', 'entry_nb_visits', 0));
// % Exit = Number of visits that finished on this page / visits on this page
$dataTable->filter('ColumnCallbackAddColumnPercentage', array('exit_rate', 'exit_nb_visits', 'nb_visits', 0));
return $dataTable;
}
public function getPageTitles( $idSite, $period, $date, $expanded = false, $idSubtable = false)
{
$dataTable = $this->getDataTable('Actions_actions', $idSite, $period, $date, $expanded, $idSubtable);
return $dataTable;
}
public function getDownloads( $idSite, $period, $date, $expanded = false, $idSubtable = false )
{
$dataTable = $this->getDataTable('Actions_downloads', $idSite, $period, $date, $expanded, $idSubtable );
return $dataTable;
}
public function getOutlinks( $idSite, $period, $date, $expanded = false, $idSubtable = false )
{
$dataTable = $this->getDataTable('Actions_outlink', $idSite, $period, $date, $expanded, $idSubtable );
return $dataTable;
}
}
+486
View File
@@ -0,0 +1,486 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
* @version $Id: Actions.php 2264 2010-06-03 16:53:43Z vipsoft $
*
* @category Piwik_Plugins
* @package Piwik_Actions
*/
/**
* Actions plugin
*
* Reports about the page views, the outlinks and downloads.
*
* @package Piwik_Actions
*/
class Piwik_Actions extends Piwik_Plugin
{
static protected $actionUrlCategoryDelimiter = null;
static protected $actionTitleCategoryDelimiter = null;
static protected $defaultActionName = null;
static protected $defaultActionNameWhenNotDefined = null;
static protected $defaultActionUrlWhenNotDefined = null;
static protected $limitLevelSubCategory = 10; // must be less than Piwik_DataTable::MAXIMUM_DEPTH_LEVEL_ALLOWED
protected $maximumRowsInDataTableLevelZero;
protected $maximumRowsInSubDataTable;
protected $columnToSortByBeforeTruncation;
public function getInformation()
{
$info = array(
'description' => Piwik_Translate('Actions_PluginDescription'),
'author' => 'Piwik',
'author_homepage' => 'http://piwik.org/',
'version' => Piwik_Version::VERSION,
);
return $info;
}
function getListHooksRegistered()
{
$hooks = array(
'ArchiveProcessing_Day.compute' => 'archiveDay',
'ArchiveProcessing_Period.compute' => 'archivePeriod',
'WidgetsList.add' => 'addWidgets',
'Menu.add' => 'addMenus',
);
return $hooks;
}
public function __construct()
{
// for BC, we read the old style delimiter first (see #1067)
$actionDelimiter = Zend_Registry::get('config')->General->action_category_delimiter;
if(empty($actionDelimiter))
{
self::$actionUrlCategoryDelimiter = Zend_Registry::get('config')->General->action_url_category_delimiter;
self::$actionTitleCategoryDelimiter = Zend_Registry::get('config')->General->action_title_category_delimiter;
}
else
{
self::$actionUrlCategoryDelimiter = self::$actionTitleCategoryDelimiter = $actionDelimiter;
}
self::$defaultActionName = Zend_Registry::get('config')->General->action_default_name;
self::$defaultActionNameWhenNotDefined = Zend_Registry::get('config')->General->action_default_name_when_not_defined;
self::$defaultActionUrlWhenNotDefined = Zend_Registry::get('config')->General->action_default_url_when_not_defined;
$this->columnToSortByBeforeTruncation = 'nb_visits';
$this->maximumRowsInDataTableLevelZero = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_actions;
$this->maximumRowsInSubDataTable = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_subtable_actions;
}
function addWidgets()
{
Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuPagesEntry', 'Actions', 'getEntryPageUrls');
Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuPagesExit', 'Actions', 'getExitPageUrls');
Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuPages', 'Actions', 'getPageUrls');
Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuPageTitles', 'Actions', 'getPageTitles');
Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuOutlinks', 'Actions', 'getOutlinks');
Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuDownloads', 'Actions', 'getDownloads');
}
function addMenus()
{
Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getPageUrls'));
Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPagesEntry', array('module' => 'Actions', 'action' => 'getEntryPageUrls'));
Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPagesExit', array('module' => 'Actions', 'action' => 'getExitPageUrls'));
Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPageTitles', array('module' => 'Actions', 'action' => 'getPageTitles'));
Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks'));
Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads'));
}
static protected $invalidSummedColumnNameToRenamedNameForPeriodArchive = array(
'nb_uniq_visitors' => 'sum_daily_nb_uniq_visitors',
'entry_nb_uniq_visitors' => 'sum_daily_entry_nb_uniq_visitors',
'exit_nb_uniq_visitors' => 'sum_daily_exit_nb_uniq_visitors',
);
protected static $invalidSummedColumnNameToDeleteFromDayArchive = array(
'nb_uniq_visitors',
'entry_nb_uniq_visitors',
'exit_nb_uniq_visitors',
);
function archivePeriod( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
$dataTableToSum = array(
'Actions_actions',
'Actions_downloads',
'Actions_outlink',
'Actions_actions_url',
);
$archiveProcessing->archiveDataTable($dataTableToSum, self::$invalidSummedColumnNameToRenamedNameForPeriodArchive, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation);
}
/**
* Compute all the actions along with their hierarchies.
*
* For each action we process the "interest statistics" :
* visits, unique visitors, bouce count, sum visit length.
*
*
*/
public function archiveDay( $notification )
{
//TODO Actions should use integer based keys like other archive in piwik
/* @var $archiveProcessing Piwik_ArchiveProcessing */
$archiveProcessing = $notification->getNotificationObject();
$this->actionsTablesByType = array(
Piwik_Tracker_Action::TYPE_ACTION_URL => array(),
Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
Piwik_Tracker_Action::TYPE_OUTLINK => array(),
Piwik_Tracker_Action::TYPE_ACTION_NAME => array(),
);
// This row is used in the case where an action is know as an exit_action
// but this action was not properly recorded when it was hit in the first place
// so we add this fake row information to make sure there is a nb_hits, etc. column for every action
$this->defaultRow = new Piwik_DataTable_Row(array(
Piwik_DataTable_Row::COLUMNS => array(
'nb_visits' => 1,
'nb_uniq_visitors' => 1,
'nb_hits' => 1,
)));
/*
* Actions urls global information
*/
$query = "SELECT name,
type,
count(distinct t1.idvisit) as nb_visits,
count(distinct visitor_idcookie) as nb_uniq_visitors,
count(*) as nb_hits
FROM (".$archiveProcessing->logTable." as t1
LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit))
LEFT JOIN ".$archiveProcessing->logActionTable." as t3 ON (t2.idaction_url = t3.idaction)
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
AND idsite = ?
GROUP BY t3.idaction
ORDER BY nb_hits DESC";
$query = $archiveProcessing->db->query($query, array( $archiveProcessing->getStartDatetimeUTC(), $archiveProcessing->getEndDatetimeUTC(), $archiveProcessing->idsite ));
$modified = $this->updateActionsTableWithRowQuery($query);
/*
* Actions names global information
*/
$query = "SELECT name,
type,
count(distinct t1.idvisit) as nb_visits,
count(distinct visitor_idcookie) as nb_uniq_visitors,
count(*) as nb_hits
FROM (".$archiveProcessing->logTable." as t1
LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit))
LEFT JOIN ".$archiveProcessing->logActionTable." as t3 ON (t2.idaction_name = t3.idaction)
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
AND idsite = ?
GROUP BY t3.idaction
ORDER BY nb_hits DESC";
$query = $archiveProcessing->db->query($query, array( $archiveProcessing->getStartDatetimeUTC(), $archiveProcessing->getEndDatetimeUTC(), $archiveProcessing->idsite ));
$modified = $this->updateActionsTableWithRowQuery($query);
/*
* Entry actions
*/
$query = "SELECT name,
type,
count(distinct visitor_idcookie) as entry_nb_uniq_visitors,
count(*) as entry_nb_visits,
sum(visit_total_actions) as entry_nb_actions,
sum(visit_total_time) as entry_sum_visit_length,
sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count
FROM ".$archiveProcessing->logTable."
JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction_url = idaction)
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
AND idsite = ?
GROUP BY visit_entry_idaction_url
";
$query = $archiveProcessing->db->query($query, array( $archiveProcessing->getStartDatetimeUTC(), $archiveProcessing->getEndDatetimeUTC(), $archiveProcessing->idsite ));
$modified = $this->updateActionsTableWithRowQuery($query);
/*
* Exit actions
*/
$query = "SELECT name,
type,
count(distinct visitor_idcookie) as exit_nb_uniq_visitors,
count(*) as exit_nb_visits
FROM ".$archiveProcessing->logTable."
JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction_url = idaction)
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
AND idsite = ?
GROUP BY visit_exit_idaction_url
";
$query = $archiveProcessing->db->query($query, array( $archiveProcessing->getStartDatetimeUTC(), $archiveProcessing->getEndDatetimeUTC(), $archiveProcessing->idsite ));
$modified = $this->updateActionsTableWithRowQuery($query);
/*
* Time per action
*/
$query = "SELECT name,
type,
sum(time_spent_ref_action) as sum_time_spent
FROM (".$archiveProcessing->logTable." log_visit
JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit))
JOIN ".$archiveProcessing->logActionTable." log_action ON (log_action.idaction = log_link_visit_action.idaction_url_ref)
WHERE visit_last_action_time >= ?
AND visit_last_action_time <= ?
AND idsite = ?
GROUP BY idaction_url_ref
";
$query = $archiveProcessing->db->query($query, array( $archiveProcessing->getStartDatetimeUTC(), $archiveProcessing->getEndDatetimeUTC(), $archiveProcessing->idsite ));
$modified = $this->updateActionsTableWithRowQuery($query);
$this->archiveDayRecordInDatabase($archiveProcessing);
}
protected function archiveDayRecordInDatabase($archiveProcessing)
{
$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION_URL]);
$this->deleteInvalidSummedColumnsFromDataTable($dataTable);
$s = $dataTable->getSerialized( $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation );
$archiveProcessing->insertBlobRecord('Actions_actions_url', $s);
destroy($dataTable);
$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD]);
$this->deleteInvalidSummedColumnsFromDataTable($dataTable);
$s = $dataTable->getSerialized($this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation );
$archiveProcessing->insertBlobRecord('Actions_downloads', $s);
destroy($dataTable);
$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]);
$this->deleteInvalidSummedColumnsFromDataTable($dataTable);
$s = $dataTable->getSerialized( $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation );
$archiveProcessing->insertBlobRecord('Actions_outlink', $s);
destroy($dataTable);
$dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION_NAME]);
$this->deleteInvalidSummedColumnsFromDataTable($dataTable);
$s = $dataTable->getSerialized( $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation );
$archiveProcessing->insertBlobRecord('Actions_actions', $s);
destroy($dataTable);
unset($this->actionsTablesByType);
}
protected function deleteInvalidSummedColumnsFromDataTable($dataTable)
{
foreach($dataTable->getRows() as $row)
{
if(($idSubtable = $row->getIdSubDataTable()) !== null)
{
foreach(self::$invalidSummedColumnNameToDeleteFromDayArchive as $name)
{
$row->deleteColumn($name);
}
$this->deleteInvalidSummedColumnsFromDataTable(Piwik_DataTable_Manager::getInstance()->getTable($idSubtable));
}
}
}
/**
* Explodes action name into an array of elements.
*
* for downloads:
* we explode link http://piwik.org/some/path/piwik.zip into an array( 'piwik.org', '/some/path/piwik.zip' );
*
* for outlinks:
* we explode link http://dev.piwik.org/some/path into an array( 'dev.piwik.org', '/some/path' );
*
* for action urls:
* 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', 'Category 1', 'Category 2');
*
* @param string action name
* @param int action type
* @return array of exploded elements from $name
*/
static public function getActionExplodedNames($name, $type)
{
$matches = array();
$isUrl = false;
preg_match('@^http[s]?://([^/]+)[/]?([^#]*)[#]?(.*)$@i', $name, $matches);
if( count($matches) )
{
$isUrl = true;
$urlHost = $matches[1];
$urlPath = $matches[2];
$urlAnchor = $matches[3];
}
if($type == Piwik_Tracker_Action::TYPE_DOWNLOAD
|| $type == Piwik_Tracker_Action::TYPE_OUTLINK)
{
if( $isUrl )
{
return array($urlHost, '/' . $urlPath);
}
}
if( $isUrl )
{
$name = $urlPath;
if( empty($name) || substr($name, -1) == '/' )
{
$name .= self::$defaultActionName;
}
}
if($type == Piwik_Tracker_Action::TYPE_ACTION_NAME)
{
$categoryDelimiter = self::$actionTitleCategoryDelimiter;
}
else
{
$categoryDelimiter = self::$actionUrlCategoryDelimiter;
}
if(empty($categoryDelimiter))
{
return array( trim($name) );
}
$split = explode($categoryDelimiter, $name, self::$limitLevelSubCategory);
// trim every category and remove empty categories
$split = array_map('trim', $split);
$split = array_filter($split, 'strlen');
if( empty($split) )
{
if($type == Piwik_Tracker_Action::TYPE_ACTION_NAME) {
$defaultName = self::$defaultActionNameWhenNotDefined;
} else {
$defaultName = self::$defaultActionUrlWhenNotDefined;
}
return array( $defaultName );
}
return array_values( $split );
}
protected function updateActionsTableWithRowQuery($query)
{
$rowsProcessed = 0;
while( $row = $query->fetch() )
{
// in some unknown case, the type field is NULL, as reported in #1082 - we ignore this page view
if(empty($row['type'])) {
continue;
}
$actionExplodedNames = $this->getActionExplodedNames($row['name'], $row['type']);
// we work on the root table of the given TYPE (either ACTION_URL or DOWNLOAD or OUTLINK etc.)
$currentTable =& $this->actionsTablesByType[$row['type']];
// go to the level of the subcategory
$end = count($actionExplodedNames)-1;
for($level = 0 ; $level < $end; $level++)
{
$actionCategory = $actionExplodedNames[$level];
$currentTable =& $currentTable[$actionCategory];
}
$actionName = $actionExplodedNames[$end];
// we are careful to prefix the page URL / name with some value
// so that if a page has the same name as a category
// we don't merge both entries
if($row['type'] == Piwik_Tracker_Action::TYPE_ACTION_URL )
{
$actionName = '/' . $actionName;
}
else
{
$actionName = ' ' . $actionName;
}
// currentTable is now the array element corresponding the the action
// at this point we may be for example at the 4th level of depth in the hierarchy
$currentTable =& $currentTable[$actionName];
// add the row to the matching sub category subtable
if(!($currentTable instanceof Piwik_DataTable_Row))
{
if( $row['type'] == Piwik_Tracker_Action::TYPE_ACTION_NAME )
{
$currentTable = new Piwik_DataTable_Row(array(
Piwik_DataTable_Row::COLUMNS => array('label' => (string)$actionName),
));
}
else
{
$currentTable = new Piwik_DataTable_Row(array(
Piwik_DataTable_Row::COLUMNS => array('label' => (string)$actionName),
Piwik_DataTable_Row::METADATA => array('url' => (string)$row['name']),
));
}
}
// For pages that bounce, we don't know the time on page.
if($row['type'] == Piwik_Tracker_Action::TYPE_ACTION_URL
&& isset($row['nb_visits'])
&& !isset($row['sum_time_spent']))
{
$row['sum_time_spent'] = Zend_Registry::get('config')->Tracker->default_time_one_page_visit * $row['nb_visits'];
}
foreach($row as $name => $value)
{
// we don't add this information as itnot pertinent
// name is already set as the label // and it has been cleaned from the categories and extracted from the initial string
// type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate.
if($name != 'name'
&& $name != 'type')
{
// in some edge cases, we have twice the same action name with 2 different idaction
// this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page,
// and in between the two the other visitor comes.
// here we handle the case where there is already a row for this action name, if this is the case we add the value
if(($alreadyValue = $currentTable->getColumn($name)) !== false)
{
$currentTable->setColumn($name, $alreadyValue+$value);
}
else
{
$currentTable->addColumn($name, $value);
}
}
}
// if the exit_action was not recorded properly in the log_link_visit_action
// there would be an error message when getting the nb_hits column
// we must fake the record and add the columns
if($currentTable->getColumn('nb_hits') === false)
{
// to test this code: delete the entries in log_link_action_visit for
// a given exit_idaction_url
foreach($this->defaultRow->getColumns() as $name => $value)
{
$currentTable->addColumn($name, $value);
}
}
// simple count
$rowsProcessed++;
}
// just to make sure php copies the last $currentTable in the $parentTable array
$currentTable =& $this->actionsTablesByType;
return $rowsProcessed;
}
}
@@ -0,0 +1,296 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
* @version $Id: Controller.php 2339 2010-06-22 18:51:10Z matt $
*
* @category Piwik_Plugins
* @package Piwik_Actions
*/
/**
* Actions controller
*
* @package Piwik_Actions
*/
class Piwik_Actions_Controller extends Piwik_Controller
{
const ACTIONS_REPORT_ROWS_DISPLAY = 100;
protected function getPageUrlsView($currentAction, $controllerActionSubtable)
{
$view = Piwik_ViewDataTable::factory();
$view->init( $this->pluginName,
$currentAction,
'Actions.getPageUrls',
$controllerActionSubtable );
$view->setColumnTranslation('label', Piwik_Translate('Actions_ColumnPageURL'));
return $view;
}
public function getPageUrls($fetch = false)
{
$view = $this->getPageUrlsView(__FUNCTION__, 'getPageUrlsSubDataTable');
$this->configureViewPageUrls($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
public function getPageUrlsSubDataTable($fetch = false)
{
$view = $this->getPageUrlsView(__FUNCTION__, 'getPageUrlsSubDataTable');
$this->configureViewPageUrls($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
protected function configureViewPageUrls($view)
{
$view->setColumnsToDisplay( array('label','nb_hits','nb_visits', 'bounce_rate', 'avg_time_on_page', 'exit_rate') );
}
public function getEntryPageUrls($fetch = false)
{
$view = $this->getPageUrlsView(__FUNCTION__, 'getEntryPageUrlsSubDataTable');
$this->configureViewEntryPageUrls($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
public function getEntryPageUrlsSubDataTable($fetch = false)
{
$view = $this->getPageUrlsView(__FUNCTION__, 'getEntryPageUrlsSubDataTable');
$this->configureViewEntryPageUrls($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
protected function configureViewEntryPageUrls($view)
{
$view->setSortedColumn('entry_nb_visits');
$view->setColumnsToDisplay( array('label','entry_nb_visits', 'entry_bounce_count', 'bounce_rate') );
$view->setColumnTranslation('entry_bounce_count', Piwik_Translate('General_ColumnBounces'), Piwik_Translate('General_BouncesDefinition'));
$view->setColumnTranslation('entry_nb_visits', Piwik_Translate('General_ColumnEntrances'), Piwik_Translate('General_EntrancesDefinition'));
// remove pages that are not entry pages
$view->queueFilter('ColumnCallbackDeleteRow', array('entry_nb_visits', 'strlen'));
}
public function getExitPageUrls($fetch = false)
{
$view = $this->getPageUrlsView(__FUNCTION__, 'getExitPageUrlsSubDataTable');
$this->configureViewExitPageUrls($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
public function getExitPageUrlsSubDataTable($fetch = false)
{
$view = $this->getPageUrlsView(__FUNCTION__, 'getExitPageUrlsSubDataTable');
$this->configureViewExitPageUrls($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
protected function configureViewExitPageUrls($view)
{
$view->setSortedColumn('exit_nb_visits');
$view->setColumnsToDisplay( array('label', 'exit_nb_visits', 'nb_visits', 'exit_rate') );
$view->setColumnTranslation('exit_nb_visits', Piwik_Translate('General_ColumnExits'), Piwik_Translate('General_ExitsDefinition'));
// remove pages that are not exit pages
$view->queueFilter('ColumnCallbackDeleteRow', array('exit_nb_visits', 'strlen'));
}
public function getPageTitles($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
$view->init( $this->pluginName,
__FUNCTION__,
'Actions.getPageTitles',
'getPageTitlesSubDataTable' );
$view->setColumnTranslation('label', Piwik_Translate('Actions_ColumnPageName'));
$this->configureViewPageTitles($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
public function getPageTitlesSubDataTable($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
$view->init( $this->pluginName,
__FUNCTION__,
'Actions.getPageTitles',
'getPageTitlesSubDataTable' );
$this->configureViewPageTitles($view);
$this->configureViewActions($view);
return $this->renderView($view, $fetch);
}
protected function configureViewPageTitles($view)
{
$view->setColumnsToDisplay( array('label','nb_hits','nb_visits') );
}
public function getDownloads($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
$view->init( $this->pluginName,
__FUNCTION__,
'Actions.getDownloads',
'getDownloadsSubDataTable' );
$this->configureViewDownloads($view);
return $this->renderView($view, $fetch);
}
public function getDownloadsSubDataTable($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
$view->init( $this->pluginName,
__FUNCTION__,
'Actions.getDownloads',
'getDownloadsSubDataTable');
$this->configureViewDownloads($view);
return $this->renderView($view, $fetch);
}
public function getOutlinks($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
$view->init( $this->pluginName,
__FUNCTION__,
'Actions.getOutlinks',
'getOutlinksSubDataTable' );
$this->configureViewOutlinks($view);
return $this->renderView($view, $fetch);
}
public function getOutlinksSubDataTable($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
$view->init( $this->pluginName,
__FUNCTION__,
'Actions.getOutlinks',
'getOutlinksSubDataTable');
$this->configureViewOutlinks($view);
return $this->renderView($view, $fetch);
}
/*
* Page titles & Page URLs reports
*/
protected function configureViewActions($view)
{
$view->setColumnTranslation('nb_hits', Piwik_Translate('General_ColumnPageviews'));
$view->setColumnTranslation('nb_visits', Piwik_Translate('General_ColumnUniquePageviews'));
$view->setColumnTranslation('avg_time_on_page', Piwik_Translate('General_ColumnAverageTimeOnPage'), Piwik_Translate('General_AverageTimeOnPageDefinition'));
$view->setColumnTranslation('bounce_rate', Piwik_Translate('General_ColumnBounceRate'), Piwik_Translate('General_PageBounceRateDefinition'));
$view->setColumnTranslation('exit_rate', Piwik_Translate('General_ColumnExitRate'), Piwik_Translate('General_PageExitRateDefinition'));
$view->queueFilter('ColumnCallbackReplace', array('avg_time_on_page', array('Piwik', 'getPrettyTimeFromSeconds')));
if(Piwik_Common::getRequestVar('enable_filter_excludelowpop', '0', 'string' ) != '0')
{
// computing minimum value to exclude
$visitsInfo = Piwik_VisitsSummary_Controller::getVisitsSummary();
$visitsInfo = $visitsInfo->getFirstRow();
$nbActions = $visitsInfo->getColumn('nb_actions');
$nbActionsLowPopulationThreshold = floor(0.02 * $nbActions); // 2 percent of the total number of actions
// we remove 1 to make sure some actions/downloads are displayed in the case we have a very few of them
// and each of them has 1 or 2 hits...
$nbActionsLowPopulationThreshold = min($visitsInfo->getColumn('max_actions')-1, $nbActionsLowPopulationThreshold-1);
$view->setExcludeLowPopulation( 'nb_hits', $nbActionsLowPopulationThreshold );
}
$this->configureGenericViewActions($view);
return $view;
}
/*
* Downloads report
*/
protected function configureViewDownloads($view)
{
$view->setColumnsToDisplay( array('label','nb_visits','nb_hits') );
$view->setColumnTranslation('label', Piwik_Translate('Actions_ColumnDownloadURL'));
$view->setColumnTranslation('nb_hits', Piwik_Translate('Actions_ColumnDownloads'));
$view->setColumnTranslation('nb_visits', Piwik_Translate('Actions_ColumnUniqueDownloads'));
$view->disableExcludeLowPopulation();
$this->configureGenericViewActions($view);
}
/*
* Outlinks report
*/
protected function configureViewOutlinks($view)
{
$view->setColumnsToDisplay( array('label','nb_visits','nb_hits') );
$view->setColumnTranslation('label', Piwik_Translate('Actions_ColumnClickedURL'));
$view->setColumnTranslation('nb_hits', Piwik_Translate('Actions_ColumnClicks'));
$view->setColumnTranslation('nb_visits', Piwik_Translate('Actions_ColumnUniqueClicks'));
$view->disableExcludeLowPopulation();
$this->configureGenericViewActions($view);
}
/*
* Common to all Actions reports, how to use the custom Actions Datatable html
*/
protected function configureGenericViewActions($view)
{
$view->setTemplate('CoreHome/templates/datatable_actions.tpl');
if(Piwik_Common::getRequestVar('idSubtable', -1) != -1)
{
$view->setTemplate('CoreHome/templates/datatable_actions_subdatable.tpl');
}
$currentlySearching = $view->setSearchRecursive();
if($currentlySearching)
{
$view->setTemplate('CoreHome/templates/datatable_actions_recursive.tpl');
}
// disable Footer icons
$view->disableShowAllViewsIcons();
$view->disableShowAllColumns();
$view->setLimit( self::ACTIONS_REPORT_ROWS_DISPLAY );
$view->main();
// we need to rewrite the phpArray so it contains all the recursive arrays
if($currentlySearching)
{
$phpArrayRecursive = $this->getArrayFromRecursiveDataTable($view->getDataTable());
$view->getView()->arrayDataTable = $phpArrayRecursive;
}
}
protected function getArrayFromRecursiveDataTable( $dataTable, $depth = 0 )
{
$table = array();
foreach($dataTable->getRows() as $row)
{
$phpArray = array();
if(($idSubtable = $row->getIdSubDataTable()) !== null)
{
$subTable = Piwik_DataTable_Manager::getInstance()->getTable( $idSubtable );
if($subTable->getRowsCount() > 0)
{
$phpArray = $this->getArrayFromRecursiveDataTable( $subTable, $depth + 1 );
}
}
$label = $row->getColumn('label');
$newRow = array(
'level' => $depth,
'columns' => $row->getColumns(),
'metadata' => $row->getMetadata(),
'idsubdatatable' => $row->getIdSubDataTable()
);
$table[] = $newRow;
if(count($phpArray) > 0)
{
$table = array_merge( $table, $phpArray);
}
}
return $table;
}
}
@@ -0,0 +1,79 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
* @version $Id: AnonymizeIP.php 2264 2010-06-03 16:53:43Z vipsoft $
*
* @category Piwik_Plugins
* @package Piwik_AnonymizeIP
*/
/**
* Anonymize visitor IP addresses to comply with the privacy laws/guidelines in countries, such as Germany.
*
* @package Piwik_AnonymizeIP
*/
class Piwik_AnonymizeIP extends Piwik_Plugin
{
/**
* Get plugin information
*/
public function getInformation()
{
return array(
'description' => Piwik_Translate('AnonymizeIP_PluginDescription'),
'author' => 'Piwik',
'author_homepage' => 'http://piwik.org/',
'version' => Piwik_Version::VERSION,
'TrackerPlugin' => true,
);
}
/**
* Get list of hooks to register
*/
public function getListHooksRegistered()
{
return array(
'Tracker.saveVisitorInformation' => 'anonymizeVisitorIpAddress',
);
}
/**
* Internal function to mask portions of the visitor IP address
*
* @param $ip Unsigned long representation of IP address
* @param $maskLength Number of octets to reset
*/
static public function applyIPMask($ip, $maskLength)
{
$maskedIP = pack('V', (float)$ip);
switch($maskLength) {
case 4:
$maskedIP[3] = "\0";
case 3:
$maskedIP[2] = "\0";
case 2:
$maskedIP[1] = "\0";
case 1:
$maskedIP[0] = "\0";
case 0:
default:
}
$res = unpack('V', $maskedIP);
return sprintf("%u", $res[1]);
}
/**
* Hook on Tracker.saveVisitorInformation to anonymize visitor IP addresses
*/
function anonymizeVisitorIpAddress($notification)
{
$visitorInfo =& $notification->getNotificationObject();
$visitorInfo['location_ip'] = self::applyIPMask($visitorInfo['location_ip'], Piwik_Tracker_Config::getInstance()->Tracker['ip_address_mask_length']);
}
}