From 906e61aafe9ff1ff73b16c3738dd00d6d8bfbdd2 Mon Sep 17 00:00:00 2001 From: matthieu_ Date: Mon, 30 Jul 2007 17:37:46 +0000 Subject: - logging system DONE - fixed bug Access - input filtering functions --- .htaccess | 2 - .htaccess_to_use_later | 2 + TODO | 22 +++- config/config.ini.php | 40 +++---- index.php | 77 ++++++++---- libs/Zend/Log/Writer/Stream.php | 2 +- modules/Access.php | 9 -- modules/Auth.php | 2 +- modules/Common.php | 127 ++++++++++++++++++++ modules/ErrorHandler.php | 34 +----- modules/ExceptionHandler.php | 14 ++- modules/Log.php | 259 +++++++++++++++++++++++++++++++++++----- modules/Piwik.php | 80 ++++++++++++- modules/PublicAPI.php | 36 ++++-- modules/Timer.php | 32 +++++ modules/UsersManager.php | 2 +- piwik.php | 14 +++ tests/config_test.php | 3 +- tests/modules/Common.test.php | 33 +++++ 19 files changed, 660 insertions(+), 130 deletions(-) delete mode 100755 .htaccess create mode 100755 .htaccess_to_use_later create mode 100644 modules/Common.php create mode 100644 modules/Timer.php create mode 100644 tests/modules/Common.test.php diff --git a/.htaccess b/.htaccess deleted file mode 100755 index 1037c5b0bb..0000000000 --- a/.htaccess +++ /dev/null @@ -1,2 +0,0 @@ -php_flag magic_quotes_gpc off -php_flag register_globals off diff --git a/.htaccess_to_use_later b/.htaccess_to_use_later new file mode 100755 index 0000000000..1037c5b0bb --- /dev/null +++ b/.htaccess_to_use_later @@ -0,0 +1,2 @@ +php_flag magic_quotes_gpc off +php_flag register_globals off diff --git a/TODO b/TODO index f43ad4eede..d3d16b7e6f 100644 --- a/TODO +++ b/TODO @@ -6,4 +6,24 @@ FEATURES BUGS ==== - the token md5 generation doesn't check that the md5 generated is unique, - but it should (the field is unique in the database) \ No newline at end of file + but it should (the field is unique in the database) +- if elements from the config file are deleted, bug without any notice or warning + system for config file default values? +- if the path necessary sometimes in the configuration do not have a / when they should + it could break the system... + /* + * Make sure the compare directory has a trailing slash so that /tmp doesn't + * accidentally match /tmpfoo + */ + if ($element{strlen($element)-1} != $slash) { + $element .= $slash; + } + +TODO MISC +========= +- tell zend that the attributes in Zend_Log have to be PROTECTED +- tell zend_log the test on fwrite===false + +NOTES +===== +- edited zend_log and changed attr to protected \ No newline at end of file diff --git a/config/config.ini.php b/config/config.ini.php index 12cb06bb23..e2e0477ee1 100755 --- a/config/config.ini.php +++ b/config/config.ini.php @@ -18,30 +18,30 @@ tables_prefix = piwiktests_ [log] -; query profiling information (SQL, avg execution time, etc.) -query_profiles[] = screen -query_profiles[] = database -query_profiles[] = file - -; all call to the API (method name, parameters, execution time, caller IP, etc.) -api_calls[] = screen -api_calls[] = database -api_calls[] = file +; normal messages +;logger_message[] = screen +;logger_message[] = database +;logger_message[] = file -; exception raised -exceptions[] = screen -exceptions[] = database -exceptions[] = file +; all calls to the API (method name, parameters, execution time, caller IP, etc.) +;logger_api_call[] = screen +;logger_api_call[] = database +;logger_api_call[] = file ; error intercepted -errors[] = screen -errors[] = database -errors[] = file +;logger_error[] = screen +;logger_error[] = database +;logger_error[] = file -; normal messages -messages[] = screen -messages[] = database -messages[] = file +; exception raised +;logger_exception[] = screen +;logger_exception[] = database +;logger_exception[] = file + +; query profiling information (SQL, avg execution time, etc.) +;logger_query_profile[] = screen +;logger_query_profile[] = database +;logger_query_profile[] = file [path] diff --git a/index.php b/index.php index 20beb8df84..fe5c63ed86 100755 --- a/index.php +++ b/index.php @@ -44,6 +44,7 @@ Zend_Loader::loadClass('Piwik_Log'); Zend_Loader::loadClass('Piwik_Auth'); Zend_Loader::loadClass('Piwik_Config'); Zend_Loader::loadClass('Piwik_PublicAPI'); +Zend_Loader::loadClass('Piwik_Timer'); Zend_Loader::loadClass('Piwik'); //move into a init() method @@ -53,40 +54,72 @@ Piwik::createLogObject(); //TODO move all DB related methods in a DB static class Piwik::createDatabase(); - +Piwik::createDatabaseObject(); +Piwik::dropTables(); Piwik::createTables(); - - - -//$logger = new Piwik_Log_APICalls; -$logger = new Piwik_Log_Messages; - -$configAPI = Zend_Registry::get('config')->log->api_calls; - -foreach($configAPI as $recordTo) +$configAPI = Zend_Registry::get('config')->log; +foreach($configAPI as $loggerType => $aRecordTo) { - switch($recordTo) + $logger = null; + + switch($loggerType) { - case 'screen': - $logger->addWriteToScreen(); + case 'logger_query_profile': + //$logger = new Piwik_Log_QueryProfile; + break; + + case 'logger_api_call': + $logger = new Piwik_Log_APICall; + break; + + case 'logger_exception': + $logger = new Piwik_Log_Exception; break; - case 'database': - $logger->addWriteToDatabase(); + case 'logger_error': + $logger = new Piwik_Log_Error; break; - case 'file': - $logger->addWriteToFile(); + case 'logger_message': + $logger = new Piwik_Log_Message; break; default: throw new Exception("TODO"); break; } + + if(is_null($logger)) + { + continue; + } + + foreach($aRecordTo as $recordTo) + { + switch($recordTo) + { + case 'screen': + $logger->addWriteToScreen(); + break; + + case 'database': + $logger->addWriteToDatabase(); + break; + + case 'file': + $logger->addWriteToFile(); + break; + + default: + throw new Exception("TODO"); + break; + } + } + + Zend_Registry::set($loggerType, $logger); } -Zend_Registry::set('logger', $logger); // Create auth object @@ -105,13 +138,13 @@ $authAdapter->setIdentity('root') $access = new Piwik_Access($authAdapter); Zend_Registry::set('access', $access); -$access->loadAccess(); +Zend_Registry::get('access')->loadAccess(); main(); //Piwik::uninstall(); -Piwik_Log::dump( Zend_Registry::get('db')->getProfiler()->getQueryProfiles() ); +//Piwik_Log::dump( Zend_Registry::get('db')->getProfiler()->getQueryProfiles() ); function main() { @@ -124,6 +157,10 @@ function main() $api->SitesManager->getSiteUrlsFromId(1); $api->SitesManager->addSite("test name site", array("http://localhost", "http://test.com")); + + + Zend_Registry::get('access')->loadAccess(); + $api->UsersManager->deleteUser("login"); $api->UsersManager->addUser("login", "password", "email@geage.com"); } diff --git a/libs/Zend/Log/Writer/Stream.php b/libs/Zend/Log/Writer/Stream.php index f4f0f2f7f0..206a1251ab 100755 --- a/libs/Zend/Log/Writer/Stream.php +++ b/libs/Zend/Log/Writer/Stream.php @@ -92,7 +92,7 @@ class Zend_Log_Writer_Stream extends Zend_Log_Writer_Abstract { $line = $this->_formatter->format($event); - if ( fwrite($this->_stream, $line) === false) { + if (! @fwrite($this->_stream, $line)) { throw new Zend_Log_Exception("Unable to write to stream"); } } diff --git a/modules/Access.php b/modules/Access.php index 422360b983..830877f454 100755 --- a/modules/Access.php +++ b/modules/Access.php @@ -99,14 +99,11 @@ class Piwik_Access public function checkUserHasSomeAdminAccess() { - if(!$this->isSuperUser) - { $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."); } - } } public function checkUserHasAdminAccess( $idSites ) { @@ -114,8 +111,6 @@ class Piwik_Access { $idSites = array($idSites); } - if(!$this->isSuperUser) - { $idSitesAccessible = $this->getSitesIdWithAdminAccess(); foreach($idSites as $idsite) { @@ -124,7 +119,6 @@ class Piwik_Access throw new Exception("You can't access this resource as it requires an 'admin' access for the website id = $idsite."); } } - } } public function checkUserHasViewAccess( $idSites ) @@ -133,8 +127,6 @@ class Piwik_Access { $idSites = array($idSites); } - if(!$this->isSuperUser) - { $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess(); foreach($idSites as $idsite) { @@ -143,7 +135,6 @@ class Piwik_Access throw new Exception("You can't access this resource as it requires a 'view' access for the website id = $idsite."); } } - } } } diff --git a/modules/Auth.php b/modules/Auth.php index e64738b637..982ec466bb 100644 --- a/modules/Auth.php +++ b/modules/Auth.php @@ -39,7 +39,7 @@ class Piwik_Auth extends Zend_Auth_Adapter_DbTable } // if not then we return the result of the database authentification provided by zend - $this->authenticate(); + return parent::authenticate(); } } diff --git a/modules/Common.php b/modules/Common.php new file mode 100644 index 0000000000..947e0bfa09 --- /dev/null +++ b/modules/Common.php @@ -0,0 +1,127 @@ +' (greater than) becomes '>' + * - It handles the magic_quotes setting. + * + * @param mixed The variable to be cleaned + * @return mixed The variable after cleaning + */ + static public function sanitizeInputValues($value) + { + if (is_array($value)) + { + foreach ($value as &$currentValue) + { + $currentValue = Piwik_Common::sanitizeInputValues($currentValue); + } + } + else + { + $value = htmlspecialchars($value, ENT_COMPAT, 'UTF-8'); + + /* Undo the damage caused by magic_quotes */ + if (get_magic_quotes_gpc()) + { + $value = stripslashes($value); + } + } + return $value; + } + + /** + * Returns a variable from the $_REQUEST superglobal. + * If the variable doesn't have a value, returns the defaultValue if specified. + * If the variable doesn't have neither a value nor a default value provided, then we trigger \ + * an error. + * + * @param string $varName name of the variable + * @param string $varDefault default value. If '', and if the type doesn't match, exit() ! + * @param string $varType Expected type, the value must be one of the following: array, numeric, int, integer, float, string + * + * @exception if the variable type is not known + * @exception if the variable we want to read doesn't have neither a value nor a default value specified + * + * @return mixed The variable after cleaning + */ + static public function getRequestVar($varName, $varDefault = null, $varType = 'string') + { + $varDefault = self::sanitizeInputValue( $varDefault ); + + // there is no value $varName in the REQUEST so we try to use the default value + if(!isset($_REQUEST[$varName]) + || empty($_REQUEST[$varName])) + { + if($varDefault === null) + { + throw new Exception("\$varName '$varName' doesn't have value in \$_REQUEST and doesn't have a" . + " \$varDefault value"); + } + else + { + settype($varDefault, $varType); + return $varDefault; + } + } + + // Normal case, there is a value available in REQUEST for the requested varName + $value = self::sanitizeInputValues( $_REQUEST[$varName] ); + + $ok = false; + + if($varType == 'string') + { + if(is_string($value)) $ok = true; + } + elseif($varType == 'numeric' + || $varType == 'int' + || $varType == 'integer' + || $varType == 'float') + { + if(is_numeric($value)) $ok = true; + } + elseif($varType == 'array') + { + if(is_array($value)) $ok = true; + } + else + { + throw new Exception("\$varType specified is not known. It should be one of the following: array, numeric, int, integer, float, string"); + } + + // The type is not correct + if($ok === false) + { + if($varDefault === null) + { + throw new Exception("\$varName '$varName' doesn't have a correct type in \$_REQUEST and doesn't " . + "have a \$varDefault value"); + } + // we return the default value with the good type set + else + { + settype($varDefault, $varType); + return $varDefault; + } + } + + return $value; + } +} +?> diff --git a/modules/ErrorHandler.php b/modules/ErrorHandler.php index d7f9b52a0c..cb746380e6 100755 --- a/modules/ErrorHandler.php +++ b/modules/ErrorHandler.php @@ -1,36 +1,10 @@ "; - switch($errno) - { - case E_ERROR: print "Error"; break; - case E_WARNING: print "Warning"; break; - case E_PARSE: print "Parse Error"; break; - case E_NOTICE: print "Notice"; break; - case E_CORE_ERROR: print "Core Error"; break; - case E_CORE_WARNING: print "Core Warning"; break; - case E_COMPILE_ERROR: print "Compile Error"; break; - case E_COMPILE_WARNING: print "Compile Warning"; break; - case E_USER_ERROR: print "User Error"; break; - case E_USER_WARNING: print "User Warning"; break; - case E_USER_NOTICE: print "User Notice"; break; - case E_STRICT: print "Strict Notice"; break; - case E_RECOVERABLE_ERROR: print "Recoverable Error"; break; - default: print "Unknown error ($errno)"; break; - } - print ": $errstr in $errfile on line $errline\n"; - print("

Backtrace -->
"); - - ob_start(); + ob_start(); debug_print_backtrace(); - $out1 = ob_get_clean(); - print(str_replace("\n", "
", $out1)); - print("


"); - print "\n
"; + $backtrace = ob_get_contents(); + ob_end_clean(); + Zend_Registry::get('logger_error')->log($errno, $errstr, $errfile, $errline, $backtrace); } ?> diff --git a/modules/ExceptionHandler.php b/modules/ExceptionHandler.php index e4258f3cdf..f6fd67e0f1 100644 --- a/modules/ExceptionHandler.php +++ b/modules/ExceptionHandler.php @@ -1,9 +1,13 @@
Uncaught exception: " , $exception->getMessage(), "\n";
-  print( $exception->__toString() );
-  echo "";
-  exit;
+function Piwik_ExceptionHandler(Exception $exception) 
+{
+	try	{
+		Zend_Registry::get('logger_exception')->log($exception);
+	} catch(Exception $e) {
+		print("
--------------------------
An exception occured while dealing with an uncaught exception...
"); + print("'" . $e->getMessage()."'"); + print("
The initial exception was: 
'". $exception->getMessage()."'"); + } } ?> diff --git a/modules/Log.php b/modules/Log.php index 29d05b9582..338bb3b8b0 100755 --- a/modules/Log.php +++ b/modules/Log.php @@ -22,16 +22,18 @@ class Piwik_Log extends Zend_Log { parent::__construct(); - $this->logToFileFilename = $logToFileFilename; + Piwik::mkdir(Zend_Registry::get('config')->path->log); + + $this->logToFileFilename = Zend_Registry::get('config')->path->log . $logToFileFilename; $this->fileFormatter = $fileFormatter; $this->screenFormatter = $screenFormatter; - $this->logToDatabaseTableName = $logToDatabaseTableName; + $this->logToDatabaseTableName = Piwik::prefixTable($logToDatabaseTableName); $this->logToDatabaseColumnMapping = $logToDatabaseColumnMapping; } static public function dump($var, $label=null) { - Zend_Registry::get('LoggerMessages')->log(Zend_Debug::dump($var, $label, false), Piwik_Log::DEBUG); + Zend_Registry::get('logger_message')->log(Zend_Debug::dump($var, $label, false), Piwik_Log::DEBUG); } function addWriteToFile() @@ -68,12 +70,7 @@ class Piwik_Log extends Zend_Log if (empty($this->_writers)) { throw new Zend_Log_Exception('No writers were added'); } - if(isset($event['priority'])) - { - if (! isset($this->_priorities[$event['priority']])) { - throw new Zend_Log_Exception('Bad log priority'); - } - } + $event['timestamp'] = date('c'); // pack into event required by filters and writers @@ -104,12 +101,30 @@ class Piwik_Log_Formatter_FileFormatter implements Zend_Log_Formatter_Interface */ public function format($event) { - $str = implode(" ", $event); + foreach($event as &$value) + { + $value = str_replace("\n", '\n', $value); + $value = '"'.$value.'"'; + } + $str = implode(" ", $event) . "\n"; return $str; } } -class Piwik_Log_Formatter_ScreenFormatter implements Zend_Log_Formatter_Interface +class Piwik_Log_Formatter_Message_ScreenFormatter implements Zend_Log_Formatter_Interface +{ + /** + * Formats data into a single line to be written by the writer. + * + * @param array $event event data + * @return string formatted line to write to the log + */ + public function format($event) + { + return $event['message']; + } +} +class Piwik_Log_Formatter_APICall_ScreenFormatter implements Zend_Log_Formatter_Interface { /** * Formats data into a single line to be written by the writer. @@ -119,23 +134,64 @@ class Piwik_Log_Formatter_ScreenFormatter implements Zend_Log_Formatter_Interfac */ public function format($event) { - $str = ''; - foreach($event as $name => $value) + $str = "\n
"; + $str .= "Called: {$event['class_name']}.{$event['method_name']} (took {$event['execution_time']}ms) \n
"; + $str .= "Parameters: "; + $parameterNamesAndDefault = unserialize($event['parameter_names_default_values']); + $parameterValues = unserialize($event['parameter_values']); + + $i = 0; + foreach($parameterNamesAndDefault as $pName => $pDefault) { - $str .= "$name : $value \n
"; + if(isset($parameterValues[$i])) + { + $currentValue = $parameterValues[$i]; + } + else + { + $currentValue = $pDefault; + } + + $currentValue = $this->formatValue($currentValue); + $str .= "$pName = $currentValue, "; + + $i++; } + $str .= "\n
"; + + $str .= "Returned: ".$this->formatValue($event['returned_value']); + $str .= "\n
"; return $str; } + + private function formatValue( $value ) + { + if(is_string($value)) + { + $value = "'$value'"; + } + if(is_null($value)) + { + $value= 'null'; + } + if(is_array($value)) + { + $value = "array( ".implode(", ", $value). ")"; + } + return $value; + + } } -class Piwik_Log_APICalls extends Piwik_Log +class Piwik_Log_APICall extends Piwik_Log { + const ID = 'logger_api_call'; function __construct() { - $logToFileFilename = 'api_call'; - $logToDatabaseTableName = 'log_api_calls';//TODO generalize + $logToFileFilename = self::ID; + $logToDatabaseTableName = self::ID; $logToDatabaseColumnMapping = null; - $screenFormatter = new Piwik_Log_Formatter_ScreenFormatter; + $screenFormatter = new Piwik_Log_Formatter_APICall_ScreenFormatter; $fileFormatter = new Piwik_Log_Formatter_FileFormatter; parent::__construct($logToFileFilename, @@ -144,28 +200,32 @@ class Piwik_Log_APICalls extends Piwik_Log $logToDatabaseTableName, $logToDatabaseColumnMapping ); - $this->setEventItem('ip', ip2long( Piwik::getIp() ) ); + $this->setEventItem('caller_ip', ip2long( Piwik::getIp() ) ); } - function log( $methodName, $parameters, $executionTime) + function log( $className, $methodName, $parameterNames, $parameterValues, $executionTime, $returnedValue) { $event = array(); - $event['methodName'] = $methodName; - $event['parameters'] = serialize($parameters); - $event['executionTime'] = $executionTime; + $event['class_name'] = $className; + $event['method_name'] = $methodName; + $event['parameter_names_default_values'] = serialize($parameterNames); + $event['parameter_values'] = serialize($parameterValues); + $event['execution_time'] = $executionTime; + $event['returned_value'] = is_array($returnedValue) ? serialize($returnedValue) : $returnedValue; parent::log($event); } } -class Piwik_Log_Messages extends Piwik_Log +class Piwik_Log_Message extends Piwik_Log { + const ID = 'logger_message'; function __construct() { - $logToFileFilename = 'message'; - $logToDatabaseTableName = 'log_message';//TODO generalize + $logToFileFilename = self::ID; + $logToDatabaseTableName = self::ID; $logToDatabaseColumnMapping = null; - $screenFormatter = new Piwik_Log_Formatter_ScreenFormatter; + $screenFormatter = new Piwik_Log_Formatter_Message_ScreenFormatter; $fileFormatter = new Piwik_Log_Formatter_FileFormatter; parent::__construct($logToFileFilename, @@ -173,8 +233,6 @@ class Piwik_Log_Messages extends Piwik_Log $screenFormatter, $logToDatabaseTableName, $logToDatabaseColumnMapping ); - - $this->setEventItem('ip', ip2long( Piwik::getIp() ) ); } public function log( $message ) @@ -186,4 +244,147 @@ class Piwik_Log_Messages extends Piwik_Log } } +class Piwik_Log_Formatter_Error_ScreenFormatter implements Zend_Log_Formatter_Interface +{ + /** + * Formats data into a single line to be written by the writer. + * + * @param array $event event data + * @return string formatted line to write to the log + */ + public function format($event) + { + $errno = $event['errno'] ; + $errstr = $event['message'] ; + $errfile = $event['errfile'] ; + $errline = $event['errline'] ; + $backtrace = $event['backtrace'] ; + + $strReturned = ''; + $errno = $errno & error_reporting(); + if($errno == 0) return ''; + if(!defined('E_STRICT')) define('E_STRICT', 2048); + if(!defined('E_RECOVERABLE_ERROR')) define('E_RECOVERABLE_ERROR', 4096); + if(!defined('E_EXCEPTION')) define('E_EXCEPTION', 8192); + $strReturned .= "\n
"; + switch($errno) + { + case E_ERROR: $strReturned .= "Error"; break; + case E_WARNING: $strReturned .= "Warning"; break; + case E_PARSE: $strReturned .= "Parse Error"; break; + case E_NOTICE: $strReturned .= "Notice"; break; + case E_CORE_ERROR: $strReturned .= "Core Error"; break; + case E_CORE_WARNING: $strReturned .= "Core Warning"; break; + case E_COMPILE_ERROR: $strReturned .= "Compile Error"; break; + case E_COMPILE_WARNING: $strReturned .= "Compile Warning"; break; + case E_USER_ERROR: $strReturned .= "User Error"; break; + case E_USER_WARNING: $strReturned .= "User Warning"; break; + case E_USER_NOTICE: $strReturned .= "User Notice"; break; + case E_STRICT: $strReturned .= "Strict Notice"; break; + case E_RECOVERABLE_ERROR: $strReturned .= "Recoverable Error"; break; + case E_EXCEPTION: $strReturned .= "Exception"; break; + default: $strReturned .= "Unknown error ($errno)"; break; + } + $strReturned .= ": $errstr in $errfile on line $errline\n"; + $strReturned .= "

Backtrace -->
"; + $strReturned .= str_replace("\n", "
", $backtrace); + $strReturned .= "


"; + $strReturned .= "\n

"; + + return $strReturned; + } +} + +class Piwik_Log_Formatter_Exception_ScreenFormatter implements Zend_Log_Formatter_Interface +{ + /** + * Formats data into a single line to be written by the writer. + * + * @param array $event event data + * @return string formatted line to write to the log + */ + public function format($event) + { + $errno = $event['errno'] ; + $errstr = $event['message'] ; + $errfile = $event['errfile'] ; + $errline = $event['errline'] ; + $backtrace = $event['backtrace'] ; + + $strReturned = ''; + $strReturned .= "\n
"; + $strReturned .= "Exception uncaught $errstr in $errfile on line $errline\n"; + $strReturned .= "

Backtrace -->
"; + $strReturned .= str_replace("\n", "
", $backtrace); + $strReturned .= "


"; + $strReturned .= "\n

"; + + return $strReturned; + } +} + + +class Piwik_Log_Error extends Piwik_Log +{ + const ID = 'logger_error'; + function __construct() + { + $logToFileFilename = self::ID; + $logToDatabaseTableName = self::ID; + $logToDatabaseColumnMapping = null; + $screenFormatter = new Piwik_Log_Formatter_Error_ScreenFormatter; + $fileFormatter = new Piwik_Log_Formatter_FileFormatter; + + parent::__construct($logToFileFilename, + $fileFormatter, + $screenFormatter, + $logToDatabaseTableName, + $logToDatabaseColumnMapping ); + } + + public function log($errno, $errstr, $errfile, $errline, $backtrace) + { + $event = array(); + $event['errno'] = $errno; + $event['message'] = $errstr; + $event['errfile'] = $errfile; + $event['errline'] = $errline; + $event['backtrace'] = $backtrace; + + parent::log($event); + } +} + +class Piwik_Log_Exception extends Piwik_Log +{ + const ID = 'logger_exception'; + function __construct() + { + $logToFileFilename = self::ID; + $logToDatabaseTableName = self::ID; + $logToDatabaseColumnMapping = null; + $screenFormatter = new Piwik_Log_Formatter_Exception_ScreenFormatter; + $fileFormatter = new Piwik_Log_Formatter_FileFormatter; + + parent::__construct($logToFileFilename, + $fileFormatter, + $screenFormatter, + $logToDatabaseTableName, + $logToDatabaseColumnMapping ); + } + + public function log($exception) + { + + $event = array(); + $event['errno'] = $exception->getCode(); + $event['message'] = $exception->getMessage(); + $event['errfile'] = $exception->getFile(); + $event['errline'] = $exception->getLine(); + $event['backtrace'] = $exception->getTraceAsString(); + + parent::log($event); + } +} + ?> diff --git a/modules/Piwik.php b/modules/Piwik.php index 80c5a2fc3b..192d940f9e 100755 --- a/modules/Piwik.php +++ b/modules/Piwik.php @@ -6,7 +6,7 @@ class Piwik static public function log($message, $priority = Zend_Log::NOTICE) { - Zend_Registry::get('logger')->log($message . PHP_EOL); + Zend_Registry::get('logger_message')->log($message . "
" . PHP_EOL); } static public function getTablesCreateSql() @@ -49,6 +49,54 @@ class Piwik ) ", + + 'logger_message' => "CREATE TABLE {$prefixTables}logger_message ( + idlogger_message INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + timestamp TIMESTAMP NULL, + message TINYTEXT NULL, + PRIMARY KEY(idlogger_message) + ) + ", + + 'logger_api_call' => "CREATE TABLE {$prefixTables}logger_api_call ( + idlogger_api_call INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + class_name VARCHAR(255) NULL, + method_name VARCHAR(255) NULL, + parameter_names_default_values TINYTEXT NULL, + parameter_values TINYTEXT NULL, + execution_time FLOAT NULL, + caller_ip BIGINT NULL, + timestamp TIMESTAMP NULL, + returned_value TINYTEXT NULL, + PRIMARY KEY(idlogger_api_call) + ) + ", + + 'logger_error' => "CREATE TABLE {$prefixTables}logger_error ( + idlogger_error INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + timestamp TIMESTAMP NULL, + message TINYTEXT NULL, + errno INTEGER UNSIGNED NULL, + errline INTEGER UNSIGNED NULL, + errfile VARCHAR(255) NULL, + backtrace TEXT NULL, + PRIMARY KEY(idlogger_error) + ) + ", + + 'logger_exception' => "CREATE TABLE {$prefixTables}logger_exception ( + idlogger_exception INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, + timestamp TIMESTAMP NULL, + message TINYTEXT NULL, + errno INTEGER UNSIGNED NULL, + errline INTEGER UNSIGNED NULL, + errfile VARCHAR(255) NULL, + backtrace TEXT NULL, + PRIMARY KEY(idlogger_exception) + ) + ", + + ); return $tables; } @@ -106,6 +154,25 @@ class Piwik return Piwik::CLASSES_PREFIX.$class; } + static public function createHtAccess( $path ) + { + file_put_contents($path . ".htaccess", "Deny from all"); + } + + static public function mkdir( $path, $mode = 0755, $denyAccess = true ) + { + $path = PIWIK_INCLUDE_PATH . '/' . $path; + if(!is_dir($path)) + { + mkdir($path, $mode, true); + + } + if($denyAccess) + { + Piwik::createHtAccess($path); + } + } + static public function prefixTable( $table ) { $config = Zend_Registry::get('config'); @@ -174,6 +241,17 @@ class Piwik assert(count($config) != 0); } + static public function dropTables() + { + $tablesAlreadyInstalled = self::getTablesInstalled(); + $db = Zend_Registry::get('db'); + + foreach($tablesAlreadyInstalled as $tableName) + { + $db->query("DROP TABLE $tableName"); + } + } + static public function createTables() { $db = Zend_Registry::get('db'); diff --git a/modules/PublicAPI.php b/modules/PublicAPI.php index ce0b990484..d281eb0100 100755 --- a/modules/PublicAPI.php +++ b/modules/PublicAPI.php @@ -88,7 +88,15 @@ class Piwik_PublicAPI $sParameters = implode(", ", $asParameters); return "[$sParameters]"; } - + /** + * Returns the parameters names and default values for the method $name + * of the class $class + * + * @return array Format array( + * 'parameter1Name' => 42 // default value = 42, + * 'date' => 'yesterday', + * ); + */ private function getParametersList($class, $name) { return $this->api[$class][$name]['parameters']; @@ -143,7 +151,7 @@ class Piwik_PublicAPI } } - public function __call($methodName, $parameters ) + public function __call($methodName, $parameterValues ) { try { assert(!is_null(self::$classCalled)); @@ -157,19 +165,29 @@ class Piwik_PublicAPI $this->checkMethodExists($className, $methodName); // first check number of parameters do match - $this->checkNumberOfParametersMatch($className, $methodName, $parameters); + $this->checkNumberOfParametersMatch($className, $methodName, $parameterValues); + + // start the timer + $timer = new Piwik_Timer; - $args = @implode(", ", $parameters); - Piwik::log("Calling ".self::$classCalled.".$methodName [$args]"); - // call the method - $returnedValue = call_user_func_array(array($object, $methodName), $parameters); + $returnedValue = call_user_func_array(array($object, $methodName), $parameterValues); - Piwik_Log::dump($returnedValue); + // log the API Call + $parameterNamesDefaultValues = $this->getParametersList($className, $methodName); + Zend_Registry::get('logger_api_call')->log( + self::$classCalled, + $methodName, + $parameterNamesDefaultValues, + $parameterValues, + $timer->getTimeMs(), + $returnedValue + ); } catch( Exception $e) { - Piwik::log("Error during API call...
=> ". $e->getMessage()); + Piwik::log("
\n Error during API call {$className}.{$methodName}... +
\n => ". $e->getMessage()); } diff --git a/modules/Timer.php b/modules/Timer.php new file mode 100644 index 0000000000..5854313516 --- /dev/null +++ b/modules/Timer.php @@ -0,0 +1,32 @@ +m_Start = 0.0; + $this->init(); + } + + private function getMicrotime() + { + list($micro_seconds, $seconds) = explode(" ", microtime()); + return ((float)$micro_seconds + (float)$seconds); + } + + public function init() + { + $this->m_Start = $this->getMicrotime(); + } + + public function getTime($decimals = 2) + { + return number_format($this->getMicrotime() - $this->m_Start, $decimals, '.', ''); + } + public function getTimeMs($decimals = 2) + { + return number_format(1000*($this->getMicrotime() - $this->m_Start), $decimals, '.', ''); + } +} +?> \ No newline at end of file diff --git a/modules/UsersManager.php b/modules/UsersManager.php index ba0c47e92b..2d45f57b30 100755 --- a/modules/UsersManager.php +++ b/modules/UsersManager.php @@ -304,7 +304,7 @@ class Piwik_UsersManager extends Piwik_APIable if(!self::userExists($userLogin)) { - throw new Exception("User $userLogin doesn't exist therefore it can't be deleted."); + throw new Exception("User '$userLogin' doesn't exist therefore it can't be deleted."); } self::deleteUserOnly( $userLogin ); self::deleteUserAccess( $userLogin ); diff --git a/piwik.php b/piwik.php index 9b921a793c..4b6a8d14d8 100644 --- a/piwik.php +++ b/piwik.php @@ -1,4 +1,18 @@ \ No newline at end of file -- cgit v1.2.3