diff options
author | mattpiwik <matthieu.aubry@gmail.com> | 2007-08-29 21:28:07 +0400 |
---|---|---|
committer | mattpiwik <matthieu.aubry@gmail.com> | 2007-08-29 21:28:07 +0400 |
commit | 62ff9b52a06d97bd7edecd9d81bb95d060763800 (patch) | |
tree | 8d55bb8503f17707fb0dcf33fd694068da08c90d /modules | |
parent | 5819eda4fff1051164234750a694f9885935b1ca (diff) |
- Comments
- Controller code / frontController
- Login module + deported the auth setup in plugin
- Url helper
git-svn-id: http://dev.piwik.org/svn/trunk@51 59fd770c-687e-43c8-a1e3-f5a4ff64c105
Diffstat (limited to 'modules')
37 files changed, 642 insertions, 183 deletions
diff --git a/modules/API/Proxy.php b/modules/API/Proxy.php index 35d2b6e0e8..5107c82e25 100755 --- a/modules/API/Proxy.php +++ b/modules/API/Proxy.php @@ -258,6 +258,8 @@ class Piwik_API_Proxy try { assert(!is_null(self::$classCalled)); + $this->registerClass(self::$classCalled); + $className = $this->getClassNameFromModule(self::$classCalled); // instanciate the object @@ -286,12 +288,8 @@ class Piwik_API_Proxy $returnedValue ); } - catch( Exception $e) - { - //TODO replace with nice error message - Piwik::log("<br>\n Error during API call {$className}.{$methodName}... - <br>\n => ". $e->getMessage()); - + catch( Piwik_Access_NoAccessException $e) { + throw $e; } self::$classCalled = null; diff --git a/modules/API/Request.php b/modules/API/Request.php index 58204ac631..164a793905 100644 --- a/modules/API/Request.php +++ b/modules/API/Request.php @@ -131,7 +131,7 @@ class Piwik_API_Request } } catch(Exception $e ) { - $toReturn = 'XML ERROR TEMPLATE TODO'; + $toReturn = 'XML ERROR TEMPLATE TODO', $e; } return $toReturn; } diff --git a/modules/Access.php b/modules/Access.php index 28c44103a9..ffa3284824 100755 --- a/modules/Access.php +++ b/modules/Access.php @@ -1,4 +1,25 @@ <?php +/** + * Class to handle User Access. + * In Piwik there are mainly 4 access levels + * - no access + * - VIEW access + * - ADMIN access + * - Super admin access + * + * An access level is on a per website basis. + * A given user has a given access level for a given website. + * For example: + * User Noemie has + * - VIEW access on the website 1, + * - ADMIN on the website 2 and 4, and + * - NO access on the website 3 and 5 + * + * There is only one Super User ; he has ADMIN access to all the websites + * and he only can change the main configuration settings. + * + * @package Piwik + */ require_once 'SitesManager.php'; class Piwik_Access { @@ -11,16 +32,32 @@ class Piwik_Access static private $availableAccess = array('noaccess', 'view', 'admin', 'superuser'); + /** + * Returns the list of the existing Access level. + * Useful when a given API method requests a given acccess Level. + * We first check that the required access level exists. + */ static public function getListAccess() { return self::$availableAccess; } + /** + * @param Piwik_Auth The authentification object + */ public function __construct( $auth ) { $this->auth = $auth; } + /** + * Load the access levels for the current user. + * + * First call the authentication method to try to log the user in the system. + * If the user credentials are not correct we don't load anything. + * If the login/password is correct the user is either the SuperUser or a normal user. + * We load the access levels for this user for all the websites. + */ public function loadAccess() { $accessByIdsite = array(); @@ -64,11 +101,22 @@ class Piwik_Access $this->idsitesByAccess = $idsitesByAccess; } + /** + * Returns the user login + * @return string + */ public function getIdentity() { return $this->identity; } + /** + * Returns an array of ID sites for which the user has at least a VIEW access. + * Which means VIEW or ADMIN or SUPERUSER. + * + * @return array Example if the user is ADMIN for 4 + * and has VIEW access for 1 and 7, it returns array(1, 4, 7); + */ public function getSitesIdWithAtLeastViewAccess() { return array_unique(array_merge( @@ -77,6 +125,13 @@ class Piwik_Access $this->idsitesByAccess['superuser'])); } + + /** + * Returns an array of ID sites for which the user has an ADMIN access. + * + * @return array Example if the user is ADMIN for 4 and 8 + * and has VIEW access for 1 and 7, it returns array(4, 8); + */ public function getSitesIdWithAdminAccess() { return array_unique(array_merge( @@ -84,27 +139,50 @@ class Piwik_Access $this->idsitesByAccess['superuser'])); } + + /** + * Returns an array of ID sites for which the user has a VIEW access only. + * + * @return array Example if the user is ADMIN for 4 + * and has VIEW access for 1 and 7, it returns array(1, 7); + * @see getSitesIdWithAtLeastViewAccess() + */ public function getSitesIdWithViewAccess() { return $this->idsitesByAccess['view']; } - + + /** + * Throws an exception if the user is not the SuperUser + * @throws Exception + */ public function checkUserIsSuperUser() { if($this->isSuperUser === false) { - throw new Exception("You can't access this resource as it requires a 'superuser' access."); + throw new Piwik_Access_NoAccessException("You can't access this resource as it requires a 'superuser' access."); } } + /** + * If the user doesn't have an ADMIN access for at least one website, throws an exception + * @throws Exception + */ public function checkUserHasSomeAdminAccess() { $idSitesAccessible = $this->getSitesIdWithAdminAccess(); if(count($idSitesAccessible) == 0) { - throw new Exception("You can't access this resource as it requires an 'admin' access for at least one website."); + throw new Piwik_Access_NoAccessException("You can't access this resource as it requires an 'admin' access for at least one website."); } } + + /** + * This method checks that the user has ADMIN access for the given list of websites. + * If the user doesn't have ADMIN access for at least one website of the list, we throw an exception. + * @param int|arrayOfIntegers List of ID sites to check + * @throws Exception If for any of the websites the user doesn't have an ADMIN access + */ public function checkUserHasAdminAccess( $idSites ) { if(!is_array($idSites)) @@ -116,11 +194,18 @@ class Piwik_Access { if(!in_array($idsite, $idSitesAccessible)) { - throw new Exception("You can't access this resource as it requires an 'admin' access for the website id = $idsite."); + throw new Piwik_Access_NoAccessException("You can't access this resource as it requires an 'admin' access for the website id = $idsite."); } } } + + /** + * This method checks that the user has VIEW or ADMIN access for the given list of websites. + * If the user doesn't have VIEW or ADMIN access for at least one website of the list, we throw an exception. + * @param int|arrayOfIntegers List of ID sites to check + * @throws Exception If for any of the websites the user doesn't have an VIEW or ADMIN access + */ public function checkUserHasViewAccess( $idSites ) { if(!is_array($idSites)) @@ -132,9 +217,11 @@ class Piwik_Access { if(!in_array($idsite, $idSitesAccessible)) { - throw new Exception("You can't access this resource as it requires a 'view' access for the website id = $idsite."); + throw new Piwik_Access_NoAccessException("You can't access this resource as it requires a 'view' access for the website id = $idsite."); } } } } +class Piwik_Access_NoAccessException extends Exception +{}
\ No newline at end of file diff --git a/modules/Archive.php b/modules/Archive.php index b4dfcd737c..b527e3ea41 100644 --- a/modules/Archive.php +++ b/modules/Archive.php @@ -1,23 +1,11 @@ <?php /** * Archiving process - * - * + * * Requirements * - * + needs powerful and easy date handling => Zend_Date - * + Needs many date helper functions - * from a day, gives the week + list of the days in the week - * from a day, gives the month + list of the days in the month - * from a day, gives the year + list of the days in the year + list of the months in the year - * - Contact with DB abstracted from the archive process - * - Handle multi periods: day, week, month, year - * - Each period logic is separated into different classes - * so that we can in the future easily add new weird periods - * - support for partial archive (today's archive for example, but not limited to today) * - * Features: - * - delete logs once used for days + * TODO delete logs once used for days * it means that we have to keep the useful information for months/week etc. * check also that the logging process doesn't use the logs we are deleting * @@ -36,6 +24,7 @@ * receives data directly from the sql query via a known API * - The *ArchiveProcessing* saves in the DB *numbers* or *Table* objects * + * @package Piwik */ require_once 'Period.php'; diff --git a/modules/ArchiveProcessing.php b/modules/ArchiveProcessing.php index beac05210d..79a0b21232 100644 --- a/modules/ArchiveProcessing.php +++ b/modules/ArchiveProcessing.php @@ -1,5 +1,4 @@ <?php - /** * The ArchiveProcessing module is a module that reads the Piwik logs from the DB and * compute all the reports, which are then stored in the database. @@ -13,6 +12,8 @@ * - ts_archived = timestamp when the archive was processed * - name = the name of the report (ex: uniq_visitors or search_keywords_by_search_engines) * - value = the actual data + * + * @package Piwik_ArchiveProcessing */ require_once 'TablePartitioning.php'; require_once 'ArchiveProcessing/Record.php'; @@ -32,7 +33,7 @@ abstract class Piwik_ArchiveProcessing protected $tableArchiveBlob; protected $maxTimestampArchive; - // Attributes that can be used by plugins + // Attributes that can be accessed by plugins (that is why they are public) public $idsite = null; public $period = null; public $site = null; @@ -44,7 +45,9 @@ abstract class Piwik_ArchiveProcessing public $logVisitActionTable; public $logActionTable; - + /** + * + */ protected function loadArchiveProperties() { $this->idsite = $this->site->getId(); @@ -76,6 +79,7 @@ abstract class Piwik_ArchiveProcessing { return $this->tableArchiveNumeric; } + public function getTableArchiveBlobName() { return $this->tableArchiveBlob; diff --git a/modules/Auth.php b/modules/Auth.php index 49cecc573d..94769e0824 100644 --- a/modules/Auth.php +++ b/modules/Auth.php @@ -1,15 +1,8 @@ <?php - -class Piwik_Auth_Result extends Zend_Auth_Result -{ - public function __construct($code, $identity, array $messages = array()) - { - $this->_code = (int)$code; - $this->_identity = $identity; - $this->_messages = $messages; - } -} - +/** + * + * @package Piwik + */ class Piwik_Auth extends Zend_Auth_Adapter_DbTable { const SUCCESS_SUPERUSER_AUTH_CODE = 42; @@ -25,17 +18,18 @@ class Piwik_Auth extends Zend_Auth_Adapter_DbTable // we first try if the user is the super user $login = $this->_identity; - $password = $this->_credential; + $token = $this->_credential; $rootLogin = Zend_Registry::get('config')->superuser->login; $rootPassword = Zend_Registry::get('config')->superuser->password; + $rootToken = Piwik_UsersManager_API::getTokenAuth($rootLogin,$rootPassword); if($login == $rootLogin - && $password == $rootPassword) + && $token == $rootToken) { return new Piwik_Auth_Result(Piwik_Auth::SUCCESS_SUPERUSER_AUTH_CODE, $login, array() // message empty - ); + ); } // if not then we return the result of the database authentification provided by zend @@ -45,3 +39,17 @@ class Piwik_Auth extends Zend_Auth_Adapter_DbTable } + +/** + * + * @package Piwik + */ +class Piwik_Auth_Result extends Zend_Auth_Result +{ + public function __construct($code, $identity, array $messages = array()) + { + $this->_code = (int)$code; + $this->_identity = $identity; + $this->_messages = $messages; + } +} diff --git a/modules/Common.php b/modules/Common.php index d4101569fb..278a1dc878 100644 --- a/modules/Common.php +++ b/modules/Common.php @@ -6,6 +6,8 @@ * This is the only external class loaded by the Piwik.php file. * This class should contain only the functions that are used in * both the CORE and the piwik.php statistics logging engine. + * + * @package Piwik */ class Piwik_Common { diff --git a/modules/Config.php b/modules/Config.php index ff31e16e56..a228312c78 100755 --- a/modules/Config.php +++ b/modules/Config.php @@ -1,4 +1,8 @@ <?php +/** + * + * @package Piwik + */ require_once "Zend/Config/Ini.php"; require_once "Zend/Registry.php"; class Piwik_Config extends Zend_Config_Ini diff --git a/modules/Controller.php b/modules/Controller.php new file mode 100644 index 0000000000..8bf0087eff --- /dev/null +++ b/modules/Controller.php @@ -0,0 +1,9 @@ +<?php +abstract class Piwik_Controller +{ + function getDefaultAction() + { + return 'index'; + } +} +?> diff --git a/modules/DataTable.php b/modules/DataTable.php index c14a6040ed..da835fd200 100644 --- a/modules/DataTable.php +++ b/modules/DataTable.php @@ -1,6 +1,7 @@ <?php /** * + * * Initial Specification * --------------------------------------------------------- * CAREFUL: It may be outdated as I have not reviewed it yet @@ -106,6 +107,8 @@ * $XMLstring = $xmlOutput->getOutput(); * * + * @package Piwik + * @subpackage Piwik_DataTable * */ require_once "DataTable/Renderer.php"; @@ -250,7 +253,7 @@ class Piwik_DataTable { if(isset($this->rowsIndexByLabel[$label])) { - throw new Exception("The row with the label $label already exist in this DataTable"); + throw new Exception("The row with the label $label already exists in this DataTable"); } $this->rowsIndexByLabel[$label] = count($this->rows) - 1; } diff --git a/modules/Date.php b/modules/Date.php index 0eec3c9206..9857c395aa 100644 --- a/modules/Date.php +++ b/modules/Date.php @@ -1,4 +1,8 @@ <?php +/** + * + * @package Piwik + */ Zend_Loader::loadClass('Zend_Date'); class Piwik_Date extends Zend_Date { diff --git a/modules/ErrorHandler.php b/modules/ErrorHandler.php index 76a562da8a..5887e071ff 100755 --- a/modules/ErrorHandler.php +++ b/modules/ErrorHandler.php @@ -1,10 +1,14 @@ <?php +/** + * + * @package Piwik + */ function Piwik_ErrorHandler($errno, $errstr, $errfile, $errline) { -// ob_start(); -// debug_print_backtrace(); -// $backtrace = ob_get_contents(); -// ob_end_clean(); + ob_start(); + debug_print_backtrace(); + $backtrace = ob_get_contents(); + ob_end_clean(); Zend_Registry::get('logger_error')->log($errno, $errstr, $errfile, $errline, $backtrace); switch($errno) diff --git a/modules/ExceptionHandler.php b/modules/ExceptionHandler.php index 9446ef02a0..5d17925841 100644 --- a/modules/ExceptionHandler.php +++ b/modules/ExceptionHandler.php @@ -1,5 +1,8 @@ <?php - +/** + * + * @package Piwik + */ function Piwik_ExceptionHandler(Exception $exception) { try { diff --git a/modules/Log.php b/modules/Log.php index b1b56363ac..7e66a45112 100755 --- a/modules/Log.php +++ b/modules/Log.php @@ -1,4 +1,9 @@ <?php +/** + * + * + * @package Piwik_Log + */ Zend_Loader::loadClass('Zend_Log'); Zend_Loader::loadClass('Zend_Log_Formatter_Interface'); Zend_Loader::loadClass('Zend_Log_Writer_Stream'); diff --git a/modules/Log/APICall.php b/modules/Log/APICall.php index 72574620d3..519e328d02 100644 --- a/modules/Log/APICall.php +++ b/modules/Log/APICall.php @@ -1,5 +1,10 @@ <?php - +/** + * Class used to log all the API Calls information (class / method / parameters / returned value / time spent) + * + * @package Piwik_Log + * @subpackage Piwik_Log_APICall + */ class Piwik_Log_APICall extends Piwik_Log { const ID = 'logger_api_call'; @@ -35,6 +40,12 @@ class Piwik_Log_APICall extends Piwik_Log } } +/** + * Class used to format the API Call log on the screen. + * + * @package Piwik_Log + * @subpackage Piwik_Log_APICall + */ class Piwik_Log_Formatter_APICall_ScreenFormatter implements Zend_Log_Formatter_Interface { /** diff --git a/modules/Log/Error.php b/modules/Log/Error.php index dfd3558937..015695c3b2 100644 --- a/modules/Log/Error.php +++ b/modules/Log/Error.php @@ -1,5 +1,11 @@ <?php +/** + * Class used to log an error event. + * + * @package Piwik_Log + * @subpackage Piwik_Log_Error + */ class Piwik_Log_Error extends Piwik_Log { const ID = 'logger_error'; @@ -33,6 +39,12 @@ class Piwik_Log_Error extends Piwik_Log +/** + * Format an error event to be displayed on the screen. + * + * @package Piwik_Log + * @subpackage Piwik_Log_Error + */ class Piwik_Log_Formatter_Error_ScreenFormatter implements Zend_Log_Formatter_Interface { /** diff --git a/modules/Log/Exception.php b/modules/Log/Exception.php index 189fe55407..59a4ec7811 100644 --- a/modules/Log/Exception.php +++ b/modules/Log/Exception.php @@ -1,5 +1,11 @@ <?php +/** + * Class used to log an exception event. + * + * @package Piwik_Log + * @subpackage Piwik_Log_Exception + */ class Piwik_Log_Exception extends Piwik_Log { const ID = 'logger_exception'; @@ -33,6 +39,12 @@ class Piwik_Log_Exception extends Piwik_Log } +/** + * Format an exception event to be displayed on the screen. + * + * @package Piwik_Log + * @subpackage Piwik_Log_Exception + */ class Piwik_Log_Formatter_Exception_ScreenFormatter implements Zend_Log_Formatter_Interface { /** diff --git a/modules/Log/Message.php b/modules/Log/Message.php index e9890ada59..78b84196fb 100644 --- a/modules/Log/Message.php +++ b/modules/Log/Message.php @@ -1,5 +1,11 @@ <?php +/** + * Class used to log a standard message event. + * + * @package Piwik_Log + * @subpackage Piwik_Log_Message + */ class Piwik_Log_Message extends Piwik_Log { const ID = 'logger_message'; @@ -28,6 +34,13 @@ class Piwik_Log_Message extends Piwik_Log } +/** + * Format a standard message event to be displayed on the screen. + * The message can be a PHP array or a string. + * + * @package Piwik_Log + * @subpackage Piwik_Log_Message + */ class Piwik_Log_Formatter_Message_ScreenFormatter implements Zend_Log_Formatter_Interface { /** diff --git a/modules/Log/Null.php b/modules/Log/Null.php deleted file mode 100644 index 0f9e628f32..0000000000 --- a/modules/Log/Null.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - - -class Piwik_Log_Null extends Zend_Log -{ - public function __construct() - { - } - - public function log($message, $priority = Zend_Log::INFO ) - { - parent::log($message, $priority); - } -} - - diff --git a/modules/LogStats.php b/modules/LogStats.php index d603366f08..7b0e80c837 100644 --- a/modules/LogStats.php +++ b/modules/LogStats.php @@ -28,6 +28,8 @@ * We could also imagine a batch system that would read a log file every 5min, * and which prepares the file containg the rows to insert, then we load DATA INFILE * + * + * @package Piwik_LogStats */ /** diff --git a/modules/LogStats/Action.php b/modules/LogStats/Action.php index 7c10d8abc5..79ac0fedb6 100644 --- a/modules/LogStats/Action.php +++ b/modules/LogStats/Action.php @@ -1,68 +1,83 @@ <?php +/** + * Handles an action by the visitor. + * A request to the piwik.php script is associated with one Action. + * This class is used to build the Action Name (which can be built from the URL, + * or can be directly specified in the JS code, etc.). + * It also saves the Action when necessary in the DB. + * + * + * About the Action concept + * ------------------------------------ + * - An action is defined by a name. + * - The name can be specified in the JS Code in the variable 'action_name' + * - Handling UTF8 in the action name + * PLUGIN_IDEA - An action is associated to URLs and link to the URL from the interface + * PLUGIN_IDEA - An action hit by a visitor is associated to the HTML title of the page that triggered the action + * + * + If the name is not specified, we use the URL(path+query) to build a default name. + * For example for "http://piwik.org/test/my_page/test.html" + * the name would be "test/my_page/test.html" + * + * We make sure it is clean and displayable. + * If the name is empty we set it to a default name. + * + * TODO UTF8 handling to test + * + * Specifications + * + * - Download tracking + * + * * MANUAL Download tracking + * download = http://piwik.org/hellokity.zip + * (name = dir1/file alias name) + * + * * AUTOMATIC Download tracking for a known list of file extensions. + * Make a hit to the piwik.php with the parameter: + * download = http://piwik.org/hellokity.zip + * + * When 'name' is not specified, + * if AUTOMATIC and if anchor not empty => name = link title anchor + * else name = path+query of the URL + * Ex: myfiles/beta.zip + * + * - External link tracking + * + * * MANUAL External link tracking + * outlink = http://amazon.org/test + * (name = the big partners / amazon) + * + * * AUTOMATIC External link tracking + * When a link is not detected as being part of the same website + * AND when the url extension is not detected as being a file download + * outlink = http://amazon.org/test + * + * When 'name' is not specified, + * if AUTOMATIC and if anchor not empty => name = link title anchor + * else name = URL + * Ex: http://amazon.org/test + * + * + * @package Piwik_LogStats + */ class Piwik_LogStats_Action { - - /* - * About the Action concept: - * - * - An action is defined by a name. - * - The name can be specified in the JS Code in the variable 'action_name' - * - Handling UTF8 in the action name - * PLUGIN_IDEA - An action is associated to URLs and link to the URL from the interface - * PLUGIN_IDEA - An action hit by a visitor is associated to the HTML title of the page that triggered the action - * - * + If the name is not specified, we use the URL(path+query) to build a default name. - * For example for "http://piwik.org/test/my_page/test.html" - * the name would be "test/my_page/test.html" - * - * We make sure it is clean and displayable. - * If the name is empty we set it to a default name. - * - * TODO UTF8 handling to test - * - * Specifications - * - * - Download tracking - * - * * MANUAL Download tracking - * download = http://piwik.org/hellokity.zip - * (name = dir1/file alias name) - * - * * AUTOMATIC Download tracking for a known list of file extensions. - * Make a hit to the piwik.php with the parameter: - * download = http://piwik.org/hellokity.zip - * - * When 'name' is not specified, - * if AUTOMATIC and if anchor not empty => name = link title anchor - * else name = path+query of the URL - * Ex: myfiles/beta.zip - * - * - External link tracking - * - * * MANUAL External link tracking - * outlink = http://amazon.org/test - * (name = the big partners / amazon) - * - * * AUTOMATIC External link tracking - * When a link is not detected as being part of the same website - * AND when the url extension is not detected as being a file download - * outlink = http://amazon.org/test - * - * When 'name' is not specified, - * if AUTOMATIC and if anchor not empty => name = link title anchor - * else name = URL - * Ex: http://amazon.org/test - */ private $actionName; private $url; private $defaultActionName; private $nameDownloadOutlink; + /** + * 3 types of action, Standard action / Download / Outlink click + */ const TYPE_ACTION = 1; const TYPE_DOWNLOAD = 3; const TYPE_OUTLINK = 2; + /** + * @param Piwik_LogStats_Db object + */ function __construct( $db ) { $this->actionName = Piwik_Common::getRequestVar( 'action_name', '', 'string'); @@ -81,6 +96,10 @@ class Piwik_LogStats_Action $this->defaultActionName = Piwik_LogStats_Config::getInstance()->LogStats['default_action_name']; } + /** + * Generate the name of the action from the URL or the specified name. + * See the class description for more information. + */ private function generateInfo() { if(!empty($this->downloadUrl)) @@ -170,7 +189,7 @@ class Piwik_LogStats_Action * The methods takes care of creating a new record in the action table if the existing * action name doesn't exist yet. * - * @return int Id action + * @return int Id action that is associated to this action name in the Actions table lookup */ function getActionId() { @@ -209,6 +228,11 @@ class Piwik_LogStats_Action /** * Records in the DB the association between the visit and this action. + * + * @param int idVisit is the ID of the current visit in the DB table log_visit + * @param int idRefererAction is the ID of the last action done by the current visit. + * @param int timeSpentRefererAction is the number of seconds since the last action was done. + * It is directly related to idRefererAction. */ public function record( $idVisit, $idRefererAction, $timeSpentRefererAction) { diff --git a/modules/LogStats/Config.php b/modules/LogStats/Config.php index 1a25ef22d3..a09d17ab42 100644 --- a/modules/LogStats/Config.php +++ b/modules/LogStats/Config.php @@ -2,6 +2,12 @@ /** * Simple class to access the configuration file + * + * This is essentially a very simple version of Zend_Config that we wrote + * because of performance concerns. + * The LogStats module can't afford a dependency with the Zend_Framework. + * + * @package Piwik_LogStats */ class Piwik_LogStats_Config { diff --git a/modules/LogStats/Cookie.php b/modules/LogStats/Cookie.php index 0b095a4c4e..ff479442f2 100644 --- a/modules/LogStats/Cookie.php +++ b/modules/LogStats/Cookie.php @@ -9,6 +9,8 @@ * - create a new cookie, set values, expiration date, etc. and save it * * The cookie content is saved in an optimized way. + * + * @package Piwik_LogStats */ class Piwik_LogStats_Cookie { @@ -27,8 +29,18 @@ class Piwik_LogStats_Cookie */ protected $value = array(); + /** + * The character used to separate the tuple name=value in the cookie + */ const VALUE_SEPARATOR = ':'; + /** + * Instanciate a new Cookie object and tries to load the cookie content if the cookie + * exists already. + * + * @param string cookie Name + * @param int The timestamp after which the cookie will expire, eg time() + 86400 + */ public function __construct( $cookieName, $expire = null) { $this->name = $cookieName; @@ -46,18 +58,28 @@ class Piwik_LogStats_Cookie } } + /** + * Returns true if the visitor already has the cookie. + * @return bool + */ public function isCookieFound() { return isset($_COOKIE[$this->name]); } + /** + * Returns the default expiry time, 10 years + * @return int Timestamp in 10 years + */ protected function getDefaultExpire() { return time() + 86400*365*10; } /** - * taken from http://usphp.com/manual/en/function.setcookie.php + * We don't use the setcookie function because it is buggy for some PHP versions. + * + * Taken from http://usphp.com/manual/en/function.setcookie.php * TODO setCookie: use the other parameters of the function */ protected function setCookie($Name, $Value, $Expires, $Path = '', $Domain = '', $Secure = false, $HTTPOnly = false) @@ -84,17 +106,28 @@ class Piwik_LogStats_Cookie header($header, false); } + /** + * We set the privacy policy header + */ protected function setP3PHeader() { header("P3P: CP='OTI DSP COR NID STP UNI OTPa OUR'"); } + /** + * Delete the cookie + */ public function deleteCookie() { $this->setP3PHeader(); setcookie($this->name, false, time() - 86400); } + /** + * Saves the cookie (set the Cookie header). + * You have to call this method before sending any text to the browser or you would get the + * "Header already sent" error. + */ public function save() { $this->setP3PHeader(); @@ -102,7 +135,10 @@ class Piwik_LogStats_Cookie } /** - * Load the cookie content into a php array + * Load the cookie content into a php array. + * Parses the cookie string to extract the different variables. + * Unserialize the array when necessary. + * Decode the non numeric values that were base64 encoded. */ protected function loadContentFromCookie() { @@ -135,10 +171,11 @@ class Piwik_LogStats_Cookie } /** - * Returns the string to save in the cookie frpm the $this->value array of values - * + * Returns the string to save in the cookie from the $this->value array of values. + * It goes through the array and generate the cookie content string. + * @return string Cookie string */ - public function generateContentString() + protected function generateContentString() { $cookieStr = ''; foreach($this->value as $name=>$value) @@ -163,6 +200,7 @@ class Piwik_LogStats_Cookie * If the value is an array, it will be saved as a serialized and base64 encoded * string which is not very good in terms of bytes usage. * You should save arrays only when you are sure about their maximum data size. + * A cookie has to stay small and its size shouldn't increase over time! * * @param string Name of the value to save; the name will be used to retrieve this value * @param string|array|numeric Value to save @@ -186,6 +224,11 @@ class Piwik_LogStats_Cookie return isset($this->value[$name]) ? self::escapeValue($this->value[$name]) : false; } + /** + * Returns an easy to read cookie dump + * + * @return string The cookie dump + */ public function __toString() { $str = "<-- Content of the cookie '{$this->name}' <br>\n"; @@ -197,13 +240,19 @@ class Piwik_LogStats_Cookie return $str; } + /** + * Escape values from the cookie before sending them back to the client + * (when using the get() method). + * + * @return mixed The value once cleaned. + */ static protected function escapeValue( $value ) { return Piwik_Common::sanitizeInputValues($value); } } -// -// + + //$c = new Piwik_LogStats_Cookie( 'piwik_logstats', 86400); //echo $c; //$c->set(1,1); diff --git a/modules/LogStats/Db.php b/modules/LogStats/Db.php index 6cd9e70287..ed4309f098 100644 --- a/modules/LogStats/Db.php +++ b/modules/LogStats/Db.php @@ -1,18 +1,27 @@ <?php /** - * Simple database PDO wrapper + * Simple database PDO wrapper. + * We can't afford to have a dependency with the Zend_Db module in the LogStats module. * + * TODO write the mysqli wrapper + * + * @package Piwik_LogStats */ + class Piwik_LogStats_Db { private $connection; private $username; private $password; + //TODO test that in production is false static private $profiling = false; protected $queriesProfiling; + /** + * Builds the DB object + */ public function __construct( $host, $username, $password, $dbname) { $this->dsn = "mysql:dbname=$dbname;host=$host"; @@ -20,16 +29,28 @@ class Piwik_LogStats_Db $this->password = $password; } + /** + * Enables the profiling. + * For each query, saves in the DB the time spent on this query. + * Very useful to see the slow query under heavy load. + * You can then use Piwik::printLogStatsSQLProfiling(); + * to display the SQLProfiling report and see which queries take time, etc. + */ static public function enableProfiling() { self::$profiling = true; } + /** + * Disables the profiling logging. + */ static public function disableProfiling() { self::$profiling = false; } - + /** + * Connects to the DB + */ public function connect() { try { @@ -41,6 +62,12 @@ class Piwik_LogStats_Db } } + /** + * Returns the table name prefixed by the table prefix. + * + * @param string The table name to prefix, ie "log_visit" + * @return string The table name prefixed, ie "piwik-production_log_visit" + */ public function prefixTable( $suffix ) { static $prefix; @@ -50,6 +77,10 @@ class Piwik_LogStats_Db return $prefix . $suffix; } + /** + * Returns an array containing all the rows of a query result. + * @see also query() + */ public function fetchAll( $query, $parameters ) { try { @@ -60,6 +91,10 @@ class Piwik_LogStats_Db } } + /** + * Returns the first row of a query result. + * @see query() + */ public function fetch( $query, $parameters ) { try { @@ -70,6 +105,12 @@ class Piwik_LogStats_Db } } + /** + * Executes a query with bind parameters + * + * @param string Query + * @param array Parameters to bind + */ public function query($query, $parameters = array()) { try { @@ -98,11 +139,19 @@ class Piwik_LogStats_Db } } + /** + * Returns the last inserted ID in the DB + * Wrapper of PDO::lastInsertId() + * @return int + */ public function lastInsertId() { return $this->connection->lastInsertId(); } + /** + * When destroyed, log the SQL profiling information + */ public function __destruct() { if(self::$profiling) diff --git a/modules/LogStats/Generator.php b/modules/LogStats/Generator.php index 4871c899a9..36090821d0 100644 --- a/modules/LogStats/Generator.php +++ b/modules/LogStats/Generator.php @@ -1,10 +1,10 @@ <?php /** - * Requirements of the visits generator script - * - * Things possible to change + * Class used to generate fake visits. + * Useful to test performances, general functional testing, etc. * + * Requirements of the visits generator script. It is to edit * * - url => campaigns * - newsletter * - partner @@ -20,8 +20,9 @@ * - HTML title * * Objective: - * Generate thousands of visits / actions per visitor with random data to test the performance + * Generate thousands of visits / actions per visitor * + * @package Piwik_LogStats */ class Piwik_LogStats_Generator @@ -99,33 +100,7 @@ class Piwik_LogStats_Generator { if($this->profiling) { - function maxSumMsFirst($a,$b) - { - return $a['sum_time_ms'] < $b['sum_time_ms']; - } - - $db = Zend_Registry::get('db'); - $all = $db->fetchAll('SELECT *, sum_time_ms / count as avg_time_ms FROM '.Piwik::prefixTable('log_profiling').'' ); - usort($all, 'maxSumMsFirst'); - - - $str='<br><br>Query Profiling<br>----------------------<br>'; - foreach($all as $infoQuery) - { - $query = $infoQuery['query']; - $count = $infoQuery['count']; - $sum_time_ms = $infoQuery['sum_time_ms']; - $avg_time_ms = round($infoQuery['avg_time_ms'],1); - $query = str_replace("\t", "", $query); - - $str .= "$query <br> - $count times, <b>$sum_time_ms ms total</b><br> - $avg_time_ms ms average<br> - <br>"; - } - - - print($str); + Piwik::printLogStatsSQLProfiling(); } } diff --git a/modules/LogStats/Visit.php b/modules/LogStats/Visit.php index 5e3537135b..e98d156fa9 100644 --- a/modules/LogStats/Visit.php +++ b/modules/LogStats/Visit.php @@ -1,5 +1,17 @@ <?php - +/** + * Class used to handle a Visit. + * A visit is either NEW or KNOWN. + * - If a visit is NEW then we process the visitor information (settings, referers, etc.) and save + * a new line in the log_visit table. + * - If a visit is KNOWN then we update the visit row in the log_visit table, updating the number of pages + * views, time spent, etc. + * + * Whether a visit is NEW or KNOWN we also save the action in the DB. One request to the piwik.php script + * is associated to one action. + * + * @package Piwik_LogStats + */ class Piwik_LogStats_Visit { protected $cookieLog = null; @@ -19,25 +31,42 @@ class Piwik_LogStats_Visit $this->idsite = $idsite; } + /** + * Returns the current date in the "Y-m-d" PHP format + * @return string + */ protected function getCurrentDate( $format = "Y-m-d") { return date($format, $this->getCurrentTimestamp() ); } + /** + * Returns the current Timestamp + * @return int + */ protected function getCurrentTimestamp() { return time(); } + /** + * Returns the date in the "Y-m-d H:i:s" PHP format + * @return string + */ protected function getDatetimeFromTimestamp($timestamp) { return date("Y-m-d H:i:s",$timestamp); } - // test if the visitor is excluded because of - // - IP - // - cookie - // - configuration option? + /** + * Test if the current visitor is excluded from the statistics. + * + * Plugins can for example exclude visitors based on the + * - IP + * - If a given cookie is found + * + * @return bool True if the visit must not be saved, false otherwise + */ private function isExcluded() { $excluded = 0; @@ -51,6 +80,10 @@ class Piwik_LogStats_Visit return false; } + /** + * Returns the cookie name used for the Piwik LogStats cookie + * @return string + */ private function getCookieName() { return Piwik_LogStats_Config::getInstance()->LogStats['cookie_name'] . $this->idsite; @@ -159,6 +192,11 @@ class Piwik_LogStats_Visit } } + /** + * Gets the UserSettings information and returns them in an array of name => value + * + * @return array + */ private function getUserSettingsInformation() { // we already called this method before, simply returns the result @@ -238,6 +276,7 @@ class Piwik_LogStats_Visit /** * Returns true if the last action was done during the last 30 minutes + * @return bool */ private function isLastActionInTheSameVisit() { @@ -245,13 +284,18 @@ class Piwik_LogStats_Visit >= ($this->getCurrentTimestamp() - Piwik_LogStats::VISIT_STANDARD_LENGTH); } + /** + * Returns true if the recognizeTheVisitor() method did recognize the visitor + */ private function isVisitorKnown() { return $this->visitorKnown === true; } /** - * Once we have the visitor information, we have to define if the visit is a new or a known visit. + * Main algorith to handle the visit. + * + * Once we have the visitor information, we have to define if the visit is a new or a known visit. * * 1) When the last action was done more than 30min ago, * or if the visitor is new, then this is a new visit. @@ -261,14 +305,11 @@ class Piwik_LogStats_Visit * * NB: * - In the case of a new visit, then the time spent - * during the last action of the previous visit is unknown. + * during the last action of the previous visit is unknown. * * - In the case of a new visit but with a known visitor, * we can set the 'returning visitor' flag. * - */ - - /** * In all the cases we set a cookie to the visitor with the new information. */ public function handle() @@ -294,6 +335,9 @@ class Piwik_LogStats_Visit $this->updateCookie(); } + /** + * Update the cookie information. + */ private function updateCookie() { printDebug("We manage the cookie..."); @@ -526,6 +570,7 @@ class Piwik_LogStats_Visit * - referer_url : the same for all the referer types * */ + //TODO split this big method getRefererInformation into small methods private function getRefererInformation() { // bool that says if the referer detection is done @@ -720,11 +765,20 @@ class Piwik_LogStats_Visit return $refererInformation; } + /** + * Returns a MD5 of all the configuration settings + * @return string + */ private function getConfigHash( $os, $browserName, $browserVersion, $resolution, $colorDepth, $plugin_Flash, $plugin_Director, $plugin_RealPlayer, $plugin_Pdf, $plugin_WindowsMedia, $plugin_Java, $plugin_Cookie, $ip, $browserLang) { return md5( $os . $browserName . $browserVersion . $resolution . $colorDepth . $plugin_Flash . $plugin_Director . $plugin_RealPlayer . $plugin_Pdf . $plugin_WindowsMedia . $plugin_Java . $plugin_Cookie . $ip . $browserLang ); } + /** + * Returns either + * - "-1" for a known visitor + * - a unique 32 char identifier + */ private function getVisitorUniqueId() { if($this->isVisitorKnown()) diff --git a/modules/Period.php b/modules/Period.php index f3082d2014..a5b7908f17 100644 --- a/modules/Period.php +++ b/modules/Period.php @@ -3,14 +3,14 @@ * Creating a new Piwik_Period * * Every overloaded method must start with the code - if(!$this->subperiodsProcessed) - { - $this->generate(); - } - that checks whether the subperiods have already been computed. - This is for performance improvements, computing the subperiods is done a per demand basis. - - + * if(!$this->subperiodsProcessed) + * { + * $this->generate(); + * } + * that checks whether the subperiods have already been computed. + * This is for performance improvements, computing the subperiods is done a per demand basis. + * + * @package Piwik */ abstract class Piwik_Period { diff --git a/modules/Piwik.php b/modules/Piwik.php index 4a7984fc3a..0931d2d6ae 100755 --- a/modules/Piwik.php +++ b/modules/Piwik.php @@ -1,5 +1,8 @@ <?php - +/** + * + * @package Piwik + */ require_once "Config.php"; require_once "Zend/Db.php"; require_once "Zend/Db/Table.php"; @@ -23,7 +26,29 @@ class Piwik Zend_Registry::get('logger_message')->log( "<br>" . PHP_EOL); } + static function displayZendProfiler() + { + $profiler = Zend_Registry::get('db')->getProfiler(); + + $totalTime = $profiler->getTotalElapsedSecs(); + $queryCount = $profiler->getTotalNumQueries(); + $longestTime = 0; + $longestQuery = null; + foreach ($profiler->getQueryProfiles() as $query) { + if ($query->getElapsedSecs() > $longestTime) { + $longestTime = $query->getElapsedSecs(); + $longestQuery = $query->getQuery(); + } + } + + echo '<br>Executed ' . $queryCount . ' queries in ' . $totalTime . ' seconds' . "\n"; + echo '<br>Average query length: ' . $totalTime / $queryCount . ' seconds' . "\n"; + echo '<br>Queries per second: ' . $queryCount / $totalTime . "\n"; + echo '<br>Longest query length: ' . $longestTime . "\n"; + echo '<br>Longest query: <br>' . $longestQuery . "\n"; + } + static public function error($message = '') { trigger_error($message, E_USER_ERROR); @@ -46,6 +71,37 @@ class Piwik $queryCount = $profiler->getTotalNumQueries(); Piwik::log("Total queries = $queryCount (total sql time = ".round($totalTime,2)."s)"); } + + static public function printLogStatsSQLProfiling() + { + function maxSumMsFirst($a,$b) + { + return $a['sum_time_ms'] < $b['sum_time_ms']; + } + + $db = Zend_Registry::get('db'); + $all = $db->fetchAll(' SELECT *, sum_time_ms / count as avg_time_ms + FROM '.Piwik::prefixTable('log_profiling') + ); + usort($all, 'maxSumMsFirst'); + + $str='<br><br>Query Profiling<br>----------------------<br>'; + foreach($all as $infoQuery) + { + $query = $infoQuery['query']; + $count = $infoQuery['count']; + $sum_time_ms = $infoQuery['sum_time_ms']; + $avg_time_ms = round($infoQuery['avg_time_ms'],1); + $query = str_replace("\t", "", $query); + + $str .= " $query <br> + $count times, <b>$sum_time_ms ms total</b><br> + $avg_time_ms ms average<br> + <br>"; + } + + print($str); + } static public function printMemoryUsage( $prefixString = null ) { diff --git a/modules/Plugin.php b/modules/Plugin.php index 057bdc26bb..f1535acc18 100644 --- a/modules/Plugin.php +++ b/modules/Plugin.php @@ -3,6 +3,8 @@ /** * Abstract class to define a Piwik_Plugin. * Any plugin has to at least implement the abstract methods of this class. + * + * @package Piwik */ abstract class Piwik_Plugin { diff --git a/modules/PluginsManager.php b/modules/PluginsManager.php index 090f4cc7f2..c1fbcebe87 100644 --- a/modules/PluginsManager.php +++ b/modules/PluginsManager.php @@ -22,7 +22,8 @@ * - generally a plugin method can modify data (filter) and add/remove data * * - */ + * @package Piwik + */ require_once "Plugin.php"; require_once "Event/Dispatcher.php"; diff --git a/modules/Site.php b/modules/Site.php index aa892465bf..41c75dcd0b 100644 --- a/modules/Site.php +++ b/modules/Site.php @@ -1,5 +1,8 @@ <?php - +/** + * + * @package Piwik + */ class Piwik_Site { protected $id = null; diff --git a/modules/SitesManager.php b/modules/SitesManager.php index d6bac0a111..a481729c47 100755 --- a/modules/SitesManager.php +++ b/modules/SitesManager.php @@ -1,5 +1,8 @@ <?php - +/** + * + * @package Piwik + */ require_once "API/APIable.php"; class Piwik_SitesManager_API extends Piwik_Apiable diff --git a/modules/TablePartitioning.php b/modules/TablePartitioning.php index 59a1d91771..edd6f7b8a7 100644 --- a/modules/TablePartitioning.php +++ b/modules/TablePartitioning.php @@ -1,5 +1,8 @@ <?php - +/** + * + * @package Piwik + */ abstract class Piwik_TablePartitioning { protected $tableName = null; diff --git a/modules/Timer.php b/modules/Timer.php index d26a8cef07..27b9d4c80a 100644 --- a/modules/Timer.php +++ b/modules/Timer.php @@ -1,4 +1,8 @@ <?php +/** + * + * @package Piwik + */ class Piwik_Timer { private $m_Start; diff --git a/modules/Translate.php b/modules/Translate.php index 47a09fc1cf..679a3e48be 100644 --- a/modules/Translate.php +++ b/modules/Translate.php @@ -1,4 +1,8 @@ <?php +/** + * + * @package Piwik + */ class Piwik_Translate { static private $instance = null; diff --git a/modules/Url.php b/modules/Url.php new file mode 100644 index 0000000000..aa7806e0d5 --- /dev/null +++ b/modules/Url.php @@ -0,0 +1,68 @@ +<?php +class Piwik_Url +{ + + static public function getCurrentUrl() + { + return self::getCurrentHost() + . self::getCurrentScriptName() + . self::getCurrentQueryString(); + } + + static public function getCurrentScriptName() + { + $url = ''; + if( !empty($_SERVER['PATH_INFO']) ) + { + $url = $_SERVER['PATH_INFO']; + } + else if( !empty($_SERVER['REQUEST_URI']) ) + { + if( ($pos = strpos($_SERVER['REQUEST_URI'], "?")) !== false ) + { + $url = substr($_SERVER['REQUEST_URI'], 0, $pos); + } + else + { + $url = $_SERVER['REQUEST_URI']; + } + } + + if(empty($url)) + { + $url = $_SERVER['SCRIPT_NAME']; + } + return $url; + } + + static public function getCurrentHost() + { + if(isset($_SERVER['HTTPS']) + && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == true) + ) + { + $url = 'https'; + } + else + { + $url = 'http'; + } + + $url .= '://' . $_SERVER['HTTP_HOST']; + return $url; + } + + + static public function getCurrentQueryString() + { + $url = ''; + if(isset($_SERVER['QUERY_STRING']) + && !empty($_SERVER['QUERY_STRING'])) + { + $url .= "?".$_SERVER['QUERY_STRING']; + } + return $url; + } +} + +//echo Piwik_Url::getCurrentCompleteUrl();
\ No newline at end of file diff --git a/modules/UsersManager.php b/modules/UsersManager.php index 769f8ac00e..78317bc3db 100755 --- a/modules/UsersManager.php +++ b/modules/UsersManager.php @@ -1,4 +1,8 @@ <?php +/** + * + * @package Piwik + */ Zend_Loader::loadClass("Piwik_Access"); class Piwik_UsersManager_API extends Piwik_Apiable @@ -459,7 +463,7 @@ class Piwik_UsersManager_API extends Piwik_Apiable * @param string login * @param string password */ - static private function getTokenAuth($userLogin, $password) + static public function getTokenAuth($userLogin, $password) { return md5($userLogin . $password ); |