Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatthieu_ <matthieu_@59fd770c-687e-43c8-a1e3-f5a4ff64c105>2007-07-30 21:37:46 +0400
committermatthieu_ <matthieu_@59fd770c-687e-43c8-a1e3-f5a4ff64c105>2007-07-30 21:37:46 +0400
commit906e61aafe9ff1ff73b16c3738dd00d6d8bfbdd2 (patch)
tree1e1929fa7c09dee753344cb61245c4f964e763e1
parent2157033b8b6a5aeeecad81dd0b094cbfd76a523b (diff)
- logging system DONE
- fixed bug Access - input filtering functions
-rwxr-xr-x.htaccess_to_use_later (renamed from .htaccess)0
-rw-r--r--TODO22
-rwxr-xr-xconfig/config.ini.php40
-rwxr-xr-xindex.php77
-rwxr-xr-xlibs/Zend/Log/Writer/Stream.php2
-rwxr-xr-xmodules/Access.php9
-rw-r--r--modules/Auth.php2
-rw-r--r--modules/Common.php127
-rwxr-xr-xmodules/ErrorHandler.php34
-rw-r--r--modules/ExceptionHandler.php14
-rwxr-xr-xmodules/Log.php259
-rwxr-xr-xmodules/Piwik.php80
-rwxr-xr-xmodules/PublicAPI.php36
-rw-r--r--modules/Timer.php32
-rwxr-xr-xmodules/UsersManager.php2
-rw-r--r--piwik.php14
-rwxr-xr-xtests/config_test.php3
-rw-r--r--tests/modules/Common.test.php33
18 files changed, 658 insertions, 128 deletions
diff --git a/.htaccess b/.htaccess_to_use_later
index 1037c5b0bb..1037c5b0bb 100755
--- a/.htaccess
+++ b/.htaccess_to_use_later
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 @@
+<?php
+/**
+ * Static class providing functions used by both the CORE of Piwik and the
+ * visitor logging engine.
+ * This is the only external class loaded by the Piwik.php file.
+ */
+class Piwik_Common
+{
+ /**
+ * Returns the variable after cleaning operations.
+ * If an array is passed the cleaning is done recursively on all the sub-arrays.
+ *
+ * How this method works:
+ * - The variable returned has been htmlspecialchars to avoid the XSS security problem.
+ * - The single quotes are not protected so "Piwik's amazing" will still be "Piwik's amazing".
+ * - Transformations are:
+ * - '&' (ampersand) becomes '&amp;'
+ * - '"'(double quote) becomes '&quot;'
+ * - '<' (less than) becomes '&lt;'
+ * - '>' (greater than) becomes '&gt;'
+ * - 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 @@
<?php
function Piwik_ErrorHandler($errno, $errstr, $errfile, $errline)
{
- $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);
- print "\n<div style='word-wrap: break-word; border: 3px solid red; padding:4px; width:70%; background-color:#FFFF96;'><b>";
- 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 ":</b> <i>$errstr</i> in <b>$errfile</b> on line <b>$errline</b>\n";
- print("<br><br>Backtrace --><DIV style='font-family:Courier;font-size:10pt'>");
-
- ob_start();
+ ob_start();
debug_print_backtrace();
- $out1 = ob_get_clean();
- print(str_replace("\n", "<br>", $out1));
- print("</div><br><br>");
- print "\n</pre></div><br>";
+ $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 @@
<?php
-function Piwik_ExceptionHandler(Exception $exception) {
- echo "<b><div style='font-size:11pt'><pre>Uncaught exception: " , $exception->getMessage(), "\n";
- print( $exception->__toString() );
- echo "</b>";
- exit;
+function Piwik_ExceptionHandler(Exception $exception)
+{
+ try {
+ Zend_Registry::get('logger_exception')->log($exception);
+ } catch(Exception $e) {
+ print("<br> -------------------------- <br>An exception occured while dealing with an uncaught exception... <br>");
+ print("'" . $e->getMessage()."'");
+ print("<br> The initial exception was: <br>'". $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<br> ";
+ $str .= "Called: {$event['class_name']}.{$event['method_name']} (took {$event['execution_time']}ms) \n<br>";
+ $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<br>";
+ if(isset($parameterValues[$i]))
+ {
+ $currentValue = $parameterValues[$i];
+ }
+ else
+ {
+ $currentValue = $pDefault;
+ }
+
+ $currentValue = $this->formatValue($currentValue);
+ $str .= "$pName = $currentValue, ";
+
+ $i++;
}
+ $str .= "\n<br> ";
+
+ $str .= "Returned: ".$this->formatValue($event['returned_value']);
+ $str .= "\n<br> ";
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<div style='word-wrap: break-word; border: 3px solid red; padding:4px; width:70%; background-color:#FFFF96;'><b>";
+ 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 .= ":</b> <i>$errstr</i> in <b>$errfile</b> on line <b>$errline</b>\n";
+ $strReturned .= "<br><br>Backtrace --><DIV style='font-family:Courier;font-size:10pt'>";
+ $strReturned .= str_replace("\n", "<br>", $backtrace);
+ $strReturned .= "</div><br><br>";
+ $strReturned .= "\n</pre></div><br>";
+
+ 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<div style='word-wrap: break-word; border: 3px solid red; padding:4px; width:70%; background-color:#FFFF96;'><b>";
+ $strReturned .= "Exception uncaught</b> <i>$errstr</i> in <b>$errfile</b> on line <b>$errline</b>\n";
+ $strReturned .= "<br><br>Backtrace --><DIV style='font-family:Courier;font-size:10pt'>";
+ $strReturned .= str_replace("\n", "<br>", $backtrace);
+ $strReturned .= "</div><br><br>";
+ $strReturned .= "\n</pre></div><br>";
+
+ 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 . "<br>" . 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... <br> => ". $e->getMessage());
+ Piwik::log("<br>\n Error during API call {$className}.{$methodName}...
+ <br>\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 @@
+<?php
+class Piwik_Timer
+{
+ private $m_Start;
+
+ public function __construct()
+ {
+ $this->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 @@
<?php
+/**
+ * To maximise the performance of the logging module, we
+ * - minimize the number of external files included.
+ * Ideally only one (the configuration file).
+ * - write all the SQL queries without using any DB abstraction layer.
+ * Of course we carefully filter all input values.
+ * - minimize the number of SQL queries necessary to complete the algorithm.
+ *
+ *
+ *
+ *
+ *
+ */
+
// load config file
// connect Database
diff --git a/tests/config_test.php b/tests/config_test.php
index 922a74cef3..68306bd53a 100755
--- a/tests/config_test.php
+++ b/tests/config_test.php
@@ -30,11 +30,12 @@ set_include_path(PATH_TEST_TO_ROOT
require_once PIWIK_INCLUDE_PATH . "/modules/ErrorHandler.php";
-set_error_handler('Piwik_ErrorHandler');
+//set_error_handler('Piwik_ErrorHandler');
require_once "Zend/Exception.php";
require_once "Zend/Loader.php";
+Zend_Loader::loadClass('Zend_Registry');
Zend_Loader::loadClass('Zend_Config_Ini');
Zend_Loader::loadClass('Zend_Db');
Zend_Loader::loadClass('Zend_Db_Table');
diff --git a/tests/modules/Common.test.php b/tests/modules/Common.test.php
new file mode 100644
index 0000000000..702ef95fb0
--- /dev/null
+++ b/tests/modules/Common.test.php
@@ -0,0 +1,33 @@
+<?php
+if(!defined("PATH_TEST_TO_ROOT")) {
+ define('PATH_TEST_TO_ROOT', '../..');
+}
+require_once PATH_TEST_TO_ROOT ."/tests/config_test.php";
+
+class Test_Piwik_Common extends UnitTestCase
+{
+ function __construct( $title = '')
+ {
+ parent::__construct( $title );
+ }
+
+ public function setUp()
+ {
+ }
+
+ public function tearDown()
+ {
+ }
+
+ // sanitize with magic quotes on
+ // sanitize with magic quotes off
+ // sanitize an array OK
+ // sanitize an array with bad value level1
+ // sanitize an array with bad value level2
+ // sanitize a bad string
+ // sanitize a bad integer
+ public function test_sanitizeInputValues()
+ {
+ }
+}
+?> \ No newline at end of file