diff --git a/core/action.class.inc.php b/core/action.class.inc.php
index 259972f0b..603a107f9 100644
--- a/core/action.class.inc.php
+++ b/core/action.class.inc.php
@@ -291,53 +291,55 @@ class ActionEmail extends ActionNotification
$this->m_aMailErrors[] = $e->getMessage();
}
- $oLog = new EventNotificationEmail();
- if (empty($this->m_aMailErrors))
+ if (MetaModel::IsLogEnabledNotification())
{
- if ($this->IsBeingTested())
+ $oLog = new EventNotificationEmail();
+ if (empty($this->m_aMailErrors))
{
- $oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
+ if ($this->IsBeingTested())
+ {
+ $oLog->Set('message', 'TEST - Notification sent ('.$this->Get('test_recipient').')');
+ }
+ else
+ {
+ $oLog->Set('message', 'Notification sent');
+ }
}
else
{
- $oLog->Set('message', 'Notification sent');
+ if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
+ {
+ $sError = implode(', ', $this->m_aMailErrors);
+ }
+ else
+ {
+ $sError = 'Unknown reason';
+ }
+ if ($this->IsBeingTested())
+ {
+ $oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
+ }
+ else
+ {
+ $oLog->Set('message', 'Notification was not sent: '.$sError);
+ }
}
- }
- else
- {
- if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
- {
- $sError = implode(', ', $this->m_aMailErrors);
- }
- else
- {
- $sError = 'Unknown reason';
- }
- if ($this->IsBeingTested())
- {
- $oLog->Set('message', 'TEST - Notification was not sent: '.$sError);
- }
- else
- {
- $oLog->Set('message', 'Notification was not sent: '.$sError);
- }
- }
+ $oLog->Set('userinfo', UserRights::GetUser());
+ $oLog->Set('trigger_id', $oTrigger->GetKey());
+ $oLog->Set('action_id', $this->GetKey());
+ $oLog->Set('object_id', $aContextArgs['this->id']);
- $oLog->Set('userinfo', UserRights::GetUser());
- $oLog->Set('trigger_id', $oTrigger->GetKey());
- $oLog->Set('action_id', $this->GetKey());
- $oLog->Set('object_id', $aContextArgs['this->id']);
-
- // Note: we have to secure this because those values are calculated
- // inside the try statement, and we would like to keep track of as
- // many data as we could while some variables may still be undefined
- if (isset($sTo)) $oLog->Set('to', $sTo);
- if (isset($sCC)) $oLog->Set('cc', $sCC);
- if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
- if (isset($sFrom)) $oLog->Set('from', $sFrom);
- if (isset($sSubject)) $oLog->Set('subject', $sSubject);
- if (isset($sBody)) $oLog->Set('body', $sBody);
- $oLog->DBInsertNoReload();
+ // Note: we have to secure this because those values are calculated
+ // inside the try statement, and we would like to keep track of as
+ // many data as we could while some variables may still be undefined
+ if (isset($sTo)) $oLog->Set('to', $sTo);
+ if (isset($sCC)) $oLog->Set('cc', $sCC);
+ if (isset($sBCC)) $oLog->Set('bcc', $sBCC);
+ if (isset($sFrom)) $oLog->Set('from', $sFrom);
+ if (isset($sSubject)) $oLog->Set('subject', $sSubject);
+ if (isset($sBody)) $oLog->Set('body', $sBody);
+ $oLog->DBInsertNoReload();
+ }
}
}
?>
diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php
index 3b615cf38..118e4ab29 100644
--- a/core/attributedef.class.inc.php
+++ b/core/attributedef.class.inc.php
@@ -1441,10 +1441,20 @@ class AttributeBlob extends AttributeDefinition
// (temporary tables created on disk)
// We will have to remove the blobs from the list of attributes when doing the select
// then the use of Get() should finalize the load
- $aValues = array();
- $aValues[$this->GetCode().'_data'] = $value->GetData();
- $aValues[$this->GetCode().'_mimetype'] = $value->GetMimeType();
- $aValues[$this->GetCode().'_filename'] = $value->GetFileName();
+ if ($value instanceOf ormDocument)
+ {
+ $aValues = array();
+ $aValues[$this->GetCode().'_data'] = $value->GetData();
+ $aValues[$this->GetCode().'_mimetype'] = $value->GetMimeType();
+ $aValues[$this->GetCode().'_filename'] = $value->GetFileName();
+ }
+ else
+ {
+ $aValues = array();
+ $aValues[$this->GetCode().'_data'] = '';
+ $aValues[$this->GetCode().'_mimetype'] = '';
+ $aValues[$this->GetCode().'_filename'] = '';
+ }
return $aValues;
}
@@ -1490,5 +1500,121 @@ class AttributeBlob extends AttributeDefinition
}
}
+// Indexed array having two dimensions
+class AttributeTable extends AttributeText
+{
+ public function GetType() {return "Table";}
+ public function GetTypeDesc() {return "Array with 2 dimensions";}
+ public function GetEditClass() {return "Text";}
+ protected function GetSQLCol() {return "TEXT";}
+
+
+ // Facilitate things: allow the user to Set the value from a string
+ public function MakeRealValue($proposedValue)
+ {
+ if (!is_array($proposedValue))
+ {
+ return array(0 => array(0 => $proposedValue));
+ }
+ return $proposedValue;
+ }
+
+ public function FromSQLToValue($aCols, $sPrefix = '')
+ {
+ try
+ {
+ $value = @unserialize($aCols[$sPrefix.'']);
+ if ($value === false)
+ {
+ $value = $this->MakeRealValue($aCols[$sPrefix.'']);
+ }
+ }
+ catch(Exception $e)
+ {
+ $value = $this->MakeRealValue($aCols[$sPrefix.'']);
+ }
+
+ return $value;
+ }
+
+ public function GetSQLValues($value)
+ {
+ $aValues = array();
+ $aValues[$this->Get("sql")] = serialize($value);
+ return $aValues;
+ }
+
+ public function GetAsHTML($value)
+ {
+ if (!is_array($value))
+ {
+ throw new CoreException('Expecting an array', array('found' => get_class($value)));
+ }
+ if (count($value) == 0)
+ {
+ return "";
+ }
+
+ $sRes = "
";
+ $sRes .= "";
+ foreach($value as $iRow => $aRawData)
+ {
+ $sRes .= "";
+ foreach ($aRawData as $iCol => $cell)
+ {
+ $sCell = str_replace("\n", "
\n", Str::pure2html((string)$cell));
+ $sRes .= "$sCell | ";
+ }
+ $sRes .= "
";
+ }
+ $sRes .= "";
+ $sRes .= "
";
+ return $sRes;
+ }
+}
+
+// The PHP value is a hash array, it is stored as a TEXT column
+class AttributePropertySet extends AttributeTable
+{
+ public function GetType() {return "PropertySet";}
+ public function GetTypeDesc() {return "List of properties (name and value)";}
+ public function GetEditClass() {return "Text";}
+ protected function GetSQLCol() {return "TEXT";}
+
+ // Facilitate things: allow the user to Set the value from a string
+ public function MakeRealValue($proposedValue)
+ {
+ if (!is_array($proposedValue))
+ {
+ return array('?' => (string)$proposedValue);
+ }
+ return $proposedValue;
+ }
+
+ public function GetAsHTML($value)
+ {
+ if (!is_array($value))
+ {
+ throw new CoreException('Expecting an array', array('found' => get_class($value)));
+ }
+ if (count($value) == 0)
+ {
+ return "";
+ }
+
+ $sRes = "";
+ $sRes .= "";
+ foreach($value as $sProperty => $sValue)
+ {
+ $sRes .= "";
+ $sCell = str_replace("\n", "
\n", Str::pure2html((string)$sValue));
+ $sRes .= "$sProperty | $sCell | ";
+ $sRes .= "
";
+ }
+ $sRes .= "";
+ $sRes .= "
";
+ return $sRes;
+ }
+}
?>
diff --git a/core/cmdbobject.class.inc.php b/core/cmdbobject.class.inc.php
index 64485a4e8..c82c536c4 100644
--- a/core/cmdbobject.class.inc.php
+++ b/core/cmdbobject.class.inc.php
@@ -16,6 +16,7 @@
require_once('coreexception.class.inc.php');
require_once('config.class.inc.php');
+require_once('log.class.inc.php');
require_once('dict.class.inc.php');
diff --git a/core/config.class.inc.php b/core/config.class.inc.php
index dd9be7628..be3438777 100644
--- a/core/config.class.inc.php
+++ b/core/config.class.inc.php
@@ -16,6 +16,11 @@ class ConfigException extends CoreException
{
}
+define ('DEFAULT_LOG_GLOBAL', true);
+define ('DEFAULT_LOG_NOTIFICATION', true);
+define ('DEFAULT_LOG_ISSUE', true);
+define ('DEFAULT_LOG_WEB_SERVICE', true);
+
define ('DEFAULT_MIN_DISPLAY_LIMIT', 10);
define ('DEFAULT_MAX_DISPLAY_LIMIT', 15);
define ('DEFAULT_STANDARD_RELOAD_INTERVAL', 5*60);
@@ -38,6 +43,14 @@ class Config
protected $m_sDBName;
protected $m_sDBSubname;
+ /**
+ * @var integer Event log options (see LOG_... definition)
+ */
+ protected $m_bLogGlobal;
+ protected $m_bLogNotification;
+ protected $m_bLogIssue;
+ protected $m_bLogWebService;
+
/**
* @var integer Number of elements to be displayed when there are more than m_iMaxDisplayLimit elements
*/
@@ -79,6 +92,10 @@ class Config
$this->m_sDBPwd = '';
$this->m_sDBName = '';
$this->m_sDBSubname = '';
+ $this->m_bLogGlobal = DEFAULT_LOG_GLOBAL;
+ $this->m_bLogNotification = DEFAULT_LOG_NOTIFICATION;
+ $this->m_bLogIssue = DEFAULT_LOG_ISSUE;
+ $this->m_bLogWebService = DEFAULT_LOG_WEB_SERVICE;
$this->m_iMinDisplayLimit = DEFAULT_MIN_DISPLAY_LIMIT;
$this->m_iMaxDisplayLimit = DEFAULT_MAX_DISPLAY_LIMIT;
$this->m_iStandardReloadInterval = DEFAULT_STANDARD_RELOAD_INTERVAL;
@@ -167,6 +184,10 @@ class Config
$this->m_sDBName = trim($MySettings['db_name']);
$this->m_sDBSubname = trim($MySettings['db_subname']);
+ $this->m_bLogGlobal = isset($MySettings['log_global']) ? trim($MySettings['log_global']) : DEFAULT_LOG_GLOBAL;
+ $this->m_bLogNotification = isset($MySettings['log_notification']) ? trim($MySettings['log_notification']) : DEFAULT_LOG_NOTIFICATION;
+ $this->m_bLogIssue = isset($MySettings['log_issue']) ? trim($MySettings['log_issue']) : DEFAULT_LOG_ISSUE;
+ $this->m_bLogWebService = isset($MySettings['log_web_service']) ? trim($MySettings['log_web_service']) : DEFAULT_LOG_WEB_SERVICE;
$this->m_iMinDisplayLimit = isset($MySettings['min_display_limit']) ? trim($MySettings['min_display_limit']) : DEFAULT_MIN_DISPLAY_LIMIT;
$this->m_iMaxDisplayLimit = isset($MySettings['max_display_limit']) ? trim($MySettings['max_display_limit']) : DEFAULT_MAX_DISPLAY_LIMIT;
$this->m_iStandardReloadInterval = isset($MySettings['standard_reload_interval']) ? trim($MySettings['standard_reload_interval']) : DEFAULT_STANDARD_RELOAD_INTERVAL;
@@ -241,6 +262,26 @@ class Config
return $this->m_sDBPwd;
}
+ public function GetLogGlobal()
+ {
+ return $this->m_bLogGlobal;
+ }
+
+ public function GetLogNotification()
+ {
+ return $this->m_bLogNotification;
+ }
+
+ public function GetLogIssue()
+ {
+ return $this->m_bLogIssue;
+ }
+
+ public function GetLogWebService()
+ {
+ return $this->m_bLogWebService;
+ }
+
public function GetMinDisplayLimit()
{
return $this->m_iMinDisplayLimit;
@@ -296,6 +337,26 @@ class Config
$this->m_sDBPwd = $sPwd;
}
+ public function SetLogGlobal($iLogGlobal)
+ {
+ $this->m_iLogGlobal = $iLogGlobal;
+ }
+
+ public function SetLogNotification($iLogNotification)
+ {
+ $this->m_iLogNotification = $iLogNotification;
+ }
+
+ public function SetLogIssue($iLogIssue)
+ {
+ $this->m_iLogIssue = $iLogIssue;
+ }
+
+ public function SetLogWebService($iLogWebService)
+ {
+ $this->m_iLogWebService = $iLogWebService;
+ }
+
public function SetMinDisplayLimit($iMinDisplayLimit)
{
$this->m_iMinDisplayLimit = $iMinDisplayLimit;
@@ -363,6 +424,10 @@ class Config
fwrite($hFile, "\t'db_name' => '{$this->m_sDBName}',\n");
fwrite($hFile, "\t'db_subname' => '{$this->m_sDBSubname}',\n");
fwrite($hFile, "\n");
+ fwrite($hFile, "\t'log_global' => {$this->m_bLogGlobal},\n");
+ fwrite($hFile, "\t'log_notification' => {$this->m_bLogNotification},\n");
+ fwrite($hFile, "\t'log_issue' => {$this->m_bLogIssue},\n");
+ fwrite($hFile, "\t'log_web_service' => {$this->m_bLogWebService},\n");
fwrite($hFile, "\t'min_display_limit' => {$this->m_iMinDisplayLimit},\n");
fwrite($hFile, "\t'max_display_limit' => {$this->m_iMaxDisplayLimit},\n");
fwrite($hFile, "\t'standard_reload_interval' => {$this->m_iStandardReloadInterval},\n");
diff --git a/core/coreexception.class.inc.php b/core/coreexception.class.inc.php
index e92447c5e..7d1b6a3de 100644
--- a/core/coreexception.class.inc.php
+++ b/core/coreexception.class.inc.php
@@ -64,6 +64,19 @@ class CoreException extends Exception
{
$this->m_aContextData[$sKey] = $value;
}
+
+ public function getIssue()
+ {
+ return $this->m_sIssue;
+ }
+ public function getImpact()
+ {
+ return $this->m_sImpact;
+ }
+ public function getContextData()
+ {
+ return $this->m_aContextData;
+ }
}
class CoreWarning extends CoreException
diff --git a/core/event.class.inc.php b/core/event.class.inc.php
index 8045c798b..10ff395e6 100644
--- a/core/event.class.inc.php
+++ b/core/event.class.inc.php
@@ -145,10 +145,10 @@ class EventIssue extends Event
MetaModel::Init_AddAttribute(new AttributeString("issue", array("allowed_values"=>null, "sql"=>"issue", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("impact", array("allowed_values"=>null, "sql"=>"impact", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("page", array("allowed_values"=>null, "sql"=>"page", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
- MetaModel::Init_AddAttribute(new AttributeText("arguments_post", array("allowed_values"=>null, "sql"=>"arguments_post", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
- MetaModel::Init_AddAttribute(new AttributeText("arguments_get", array("allowed_values"=>null, "sql"=>"arguments_get", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
- MetaModel::Init_AddAttribute(new AttributeText("callstack", array("allowed_values"=>null, "sql"=>"callstack", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
- MetaModel::Init_AddAttribute(new AttributeBlob("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
+ MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_post", array("allowed_values"=>null, "sql"=>"arguments_post", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
+ MetaModel::Init_AddAttribute(new AttributePropertySet("arguments_get", array("allowed_values"=>null, "sql"=>"arguments_get", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
+ MetaModel::Init_AddAttribute(new AttributeTable("callstack", array("allowed_values"=>null, "sql"=>"callstack", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
+ MetaModel::Init_AddAttribute(new AttributePropertySet("data", array("allowed_values"=>null, "sql"=>"data", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
MetaModel::Init_InheritFilters();
MetaModel::Init_AddFilterFromAttribute("issue");
@@ -161,6 +161,43 @@ class EventIssue extends Event
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
+
+ public function OnInsert()
+ {
+ // Init page information: name, arguments
+ //
+ $this->Set('page', @$GLOBALS['_SERVER']['SCRIPT_NAME']);
+
+ if (array_key_exists('_GET', $GLOBALS) && is_array($GLOBALS['_GET']))
+ {
+ $this->Set('arguments_get', $GLOBALS['_GET']);
+ }
+ else
+ {
+ $this->Set('arguments_get', array());
+ }
+
+ if (array_key_exists('_POST', $GLOBALS) && is_array($GLOBALS['_POST']))
+ {
+ $aPost = array();
+ foreach($GLOBALS['_POST'] as $sKey => $sValue)
+ {
+ if (strlen($sValue) < 256)
+ {
+ $aPost[$sKey] = $sValue;
+ }
+ else
+ {
+ $aPost[$sKey] = "!long string: ".strlen($sValue). " chars";
+ }
+ }
+ $this->Set('arguments_post', $aPost);
+ }
+ else
+ {
+ $this->Set('arguments_post', array());
+ }
+ }
}
diff --git a/core/log.class.inc.php b/core/log.class.inc.php
new file mode 100644
index 000000000..0f5838d6a
--- /dev/null
+++ b/core/log.class.inc.php
@@ -0,0 +1,109 @@
+
+ * @author Denis Flaven
+ * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
+ * @link www.itop.com
+ * @since 1.0
+ * @version 1.1.1.1 $
+ */
+
+class FileLog
+{
+ protected $m_sFile = ''; // log is disabled if this is empty
+
+ public function __construct($sFileName = '')
+ {
+ $this->m_sFile = $sFileName;
+ }
+
+ public function Error($sText)
+ {
+ self::Write("Error | ".$sText);
+ }
+
+ public function Warning($sText)
+ {
+ self::Write("Warning | ".$sText);
+ }
+
+ public function Info($sText)
+ {
+ self::Write("Info | ".$sText);
+ }
+
+ public function Ok($sText)
+ {
+ self::Write("Ok | ".$sText);
+ }
+
+ protected function Write($sText)
+ {
+ if (strlen($this->m_sFile) == 0) return;
+
+ $hLogFile = @fopen($this->m_sFile, 'a');
+ if ($hLogFile !== false)
+ {
+ $sDate = date('Y-m-d H:i:s');
+ fwrite($hLogFile, "$sDate | $sText\n");
+ fclose($hLogFile);
+ }
+ }
+}
+
+class SetupLog
+{
+ protected static $m_oFileLog;
+
+ public static function Enable($sTargetFile)
+ {
+ self::$m_oFileLog = new FileLog($sTargetFile);
+ }
+ public static function Error($sText)
+ {
+ self::$m_oFileLog->Error($sText);
+ }
+ public static function Warning($sText)
+ {
+ self::$m_oFileLog->Warning($sText);
+ }
+ public static function Info($sText)
+ {
+ self::$m_oFileLog->Info($sText);
+ }
+ public static function Ok($sText)
+ {
+ self::$m_oFileLog->Ok($sText);
+ }
+}
+
+class IssueLog
+{
+ protected static $m_oFileLog;
+
+ public static function Enable($sTargetFile)
+ {
+ self::$m_oFileLog = new FileLog($sTargetFile);
+ }
+ public static function Error($sText)
+ {
+ self::$m_oFileLog->Error($sText);
+ }
+ public static function Warning($sText)
+ {
+ self::$m_oFileLog->Warning($sText);
+ }
+ public static function Info($sText)
+ {
+ self::$m_oFileLog->Info($sText);
+ }
+ public static function Ok($sText)
+ {
+ self::$m_oFileLog->Ok($sText);
+ }
+}
+?>
diff --git a/core/metamodel.class.php b/core/metamodel.class.php
index 00b3489af..54fd02e8b 100644
--- a/core/metamodel.class.php
+++ b/core/metamodel.class.php
@@ -167,6 +167,22 @@ abstract class MetaModel
private static $m_bTraceQueries = true;
private static $m_aQueriesLog = array();
+ private static $m_bLogIssue = false;
+ private static $m_bLogNotification = false;
+ private static $m_bLogWebService = false;
+
+ public static function IsLogEnabledIssue()
+ {
+ return self::$m_bLogIssue;
+ }
+ public static function IsLogEnabledNotification()
+ {
+ return self::$m_bLogNotification;
+ }
+ public static function IsLogEnabledWebService()
+ {
+ return self::$m_bLogWebService;
+ }
private static $m_sDBName = "";
private static $m_sTablePrefix = ""; // table prefix for the current application instance (allow several applications on the same DB)
@@ -2839,6 +2855,24 @@ abstract class MetaModel
{
$oConfig = new Config($sConfigFile);
+ // Set log ASAP
+ if ($oConfig->GetLogGlobal())
+ {
+ if ($oConfig->GetLogIssue())
+ {
+ self::$m_bLogIssue = true;
+ IssueLog::Enable('../error.log');
+ }
+ self::$m_bLogNotification = $oConfig->GetLogNotification();
+ self::$m_bLogWebService = $oConfig->GetLogWebService();
+ }
+ else
+ {
+ self::$m_bLogIssue = false;
+ self::$m_bLogNotification = false;
+ self::$m_bLogWebService = false;
+ }
+
foreach ($oConfig->GetAppModules() as $sModule => $sToInclude)
{
self::Plugin($sConfigFile, 'application', $sToInclude);
diff --git a/core/test.class.inc.php b/core/test.class.inc.php
index d65364615..1c0f2b0e2 100644
--- a/core/test.class.inc.php
+++ b/core/test.class.inc.php
@@ -10,6 +10,8 @@ require_once('expression.class.inc.php');
require_once('cmdbsource.class.inc.php');
require_once('sqlquery.class.inc.php');
+require_once('log.class.inc.php');
+
require_once('dbobject.class.php');
require_once('dbobjectsearch.class.php');
require_once('dbobjectset.class.php');
diff --git a/pages/UI.php b/pages/UI.php
index 245bca642..2185c8cf8 100644
--- a/pages/UI.php
+++ b/pages/UI.php
@@ -290,7 +290,7 @@ function DeleteObjects(WebPage $oP, $sClass, $aObjects, $bDeleteConfirmed)
{
if (count($aObjects) == 1)
{
- $oObj = $aObjects[0];
+ $oObj = $aObjects[0];
$id = $oObj->GetKey();
$oP->p("Please confirm that you want to delete ".$oObj->GetHyperLink());
$oP->add("