protected function LogError($sMsg) { static $bDebug = null; if ($bDebug == null) { $bDebug = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'debug', false); } IssueLog::Error($sMsg); if ($bDebug) { echo 'Error: ' . $sMsg . "\n"; } }
/** * Create a new transaction id, store it in the session and return its id * @param void * @return int The identifier of the new transaction */ public static function GetNewTransactionId() { $bTransactionsEnabled = MetaModel::GetConfig()->Get('transactions_enabled'); if (!$bTransactionsEnabled) { return 'notransactions'; // Any value will do } $sClass = 'privUITransaction' . MetaModel::GetConfig()->Get('transaction_storage'); if (!class_exists($sClass, false)) { IssueLog::Error("Incorrect value '" . MetaModel::GetConfig()->Get('transaction_storage') . "' for 'transaction_storage', the class '{$sClass}' does not exists. Using privUITransactionSession instead for storing sessions."); $sClass = 'privUITransactionSession'; } return (string) $sClass::GetNewTransactionId(); }
$oAttachment->Set('item_class', $sObjClass); $oAttachment->SetDefaultOrgId(); $oAttachment->Set('contents', $oDoc); $iAttId = $oAttachment->DBInsert(); $aResult['msg'] = $oDoc->GetFileName(); $aResult['icon'] = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($oDoc->GetFileName()); $aResult['att_id'] = $iAttId; $aResult['preview'] = $oDoc->IsPreviewAvailable() ? 'true' : 'false'; } catch (FileUploadException $e) { $aResult['error'] = $e->GetMessage(); } } $oPage->add(json_encode($aResult)); break; case 'remove': $iAttachmentId = utils::ReadParam('att_id', ''); $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id = :id"); $oSet = new DBObjectSet($oSearch, array(), array('id' => $iAttachmentId)); while ($oAttachment = $oSet->Fetch()) { $oAttachment->DBDelete(); } break; default: $oPage->p("Missing argument 'operation'"); } $oPage->output(); } catch (Exception $e) { // note: transform to cope with XSS attacks echo htmlentities($e->GetMessage(), ENT_QUOTES, 'utf-8'); IssueLog::Error($e->getMessage()); }
protected function ForgotPwdGo() { $sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data'); try { UserRights::Login($sAuthUser); // Set the user's language (if possible!) $oUser = UserRights::GetUserObject(); if ($oUser == null) { throw new Exception(Dict::Format('UI:ResetPwd-Error-WrongLogin', $sAuthUser)); } if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token')) { throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible')); } if (!$oUser->CanChangePassword()) { throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd')); } $sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed if ($sTo == '') { throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail')); } // This token allows the user to change the password without knowing the previous one $sToken = substr(md5(APPROOT . uniqid()), 0, 16); $oUser->Set('reset_pwd_token', $sToken); CMDBObject::SetTrackInfo('Reset password'); $oUser->DBUpdate(); $oEmail = new Email(); $oEmail->SetRecipientTO($sTo); $sFrom = MetaModel::GetConfig()->Get('forgot_password_from'); if ($sFrom == '') { $sFrom = $sTo; } $oEmail->SetRecipientFrom($sFrom); $oEmail->SetSubject(Dict::S('UI:ResetPwd-EmailSubject')); $sResetUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=reset_pwd&auth_user='******'login')) . '&token=' . urlencode($sToken); $oEmail->SetBody(Dict::Format('UI:ResetPwd-EmailBody', $sResetUrl)); $iRes = $oEmail->Send($aIssues, true); switch ($iRes) { //case EMAIL_SEND_PENDING: case EMAIL_SEND_OK: break; case EMAIL_SEND_ERROR: default: IssueLog::Error('Failed to send the email with the NEW password for ' . $oUser->Get('friendlyname') . ': ' . implode(', ', $aIssues)); throw new Exception(Dict::S('UI:ResetPwd-Error-Send')); } $this->DisplayLoginHeader(); $this->add("<div id=\"login\">\n"); $this->add("<h1>" . Dict::S('UI:Login:ForgotPwdForm') . "</h1>\n"); $this->add("<p>" . Dict::S('UI:ResetPwd-EmailSent') . "</p>"); $this->add("<form method=\"post\">\n"); $this->add("<table>\n"); $this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><input type=\"button\" onClick=\"window.close();\" value=\"" . Dict::S('UI:Button:Done') . "\" /></td></tr>\n"); $this->add("</table>\n"); $this->add("</form>\n"); $this->add("</div\n"); } catch (Exception $e) { $this->DisplayForgotPwdForm(true, $e->getMessage()); } }
$sFormat = utils::ReadParam('format', null, true); $sFileName = utils::ReadParam('filename', '', true, 'string'); $bInteractive = utils::ReadParam('interactive', false); $sMode = utils::ReadParam('mode', ''); if ($bInteractive) { InteractiveShell($sExpression, $sQueryId, $sFormat, $sFileName, $sMode); } else { $oExporter = CheckParameters($sExpression, $sQueryId, $sFormat); $sMimeType = $oExporter->GetMimeType(); if ($sMimeType == 'text/html') { $oP = new NiceWebPage('iTop export'); $oP->add_style("body { overflow: auto; }"); $oP->add_ready_script("\$('table.listResults').tablesorter({widgets: ['MyZebra']});"); } else { $oP = new ajax_page('iTop export'); $oP->SetContentType($oExporter->GetMimeType()); } DoExport($oP, $oExporter, false); $oP->output(); } } catch (BulkExportMissingParameterException $e) { $oP = new ajax_page('iTop Export'); $oP->add($e->getMessage()); Usage($oP); $oP->output(); } catch (Exception $e) { $oP = new WebPage('iTop Export'); $oP->add('Error: ' . $e->getMessage()); IssueLog::Error($e->getMessage() . "\n" . $e->getTraceAsString()); $oP->output(); }
/** * @return boolean True if the task record can be deleted */ public function Process() { // By default: consider that the task is not completed $bRet = false; // Attempt to take the ownership $iStatus = $this->MarkAsRunning(); if ($iStatus == self::OK) { try { $sStatus = $this->DoProcess(); if ($this->Get('event_id') != 0) { $oEventLog = MetaModel::GetObject('Event', $this->Get('event_id')); $oEventLog->Set('message', $sStatus); $oEventLog->DBUpdate(); } $bRet = true; } catch (Exception $e) { $iRemaining = $this->Get('remaining_retries'); if ($iRemaining > 0) { $iRetryDelay = $this->GetRetryDelay(); IssueLog::Info('Failed to process async task #' . $this->GetKey() . ' - reason: ' . $e->getMessage() . ' - remaining retries: ' . $iRemaining . ' - next retry in ' . $iRetryDelay . 's'); $this->Set('remaining_retries', $iRemaining - 1); $this->Set('status', 'planned'); $this->Set('started', null); $this->Set('planned', time() + $iRetryDelay); $this->DBUpdate(); } else { IssueLog::Error('Failed to process async task #' . $this->GetKey() . ' - reason: ' . $e->getMessage()); } } } else { // Already done or being handled by another process... skip... $bRet = false; } return $bRet; }
/** * Add a 'context' OQL query, specifying extra objects to be marked as 'is_reached' * even though they are not part of the sources. * @param string $sOQL The OQL query defining the context objects */ public function AddContextQuery($key, $sOQL) { if ($sOQL === '') { return; } $oSearch = DBObjectSearch::FromOQL($sOQL); $aAliases = $oSearch->GetSelectedClasses(); if (count($aAliases) < 2) { IssueLog::Error("Invalid context query '{$sOQL}'. A context query must contain at least two columns."); throw new Exception("Invalid context query '{$sOQL}'. A context query must contain at least two columns. Columns: " . implode(', ', $aAliases) . '. '); } $aAliasNames = array_keys($aAliases); $sClassAlias = $oSearch->GetClassAlias(); $oCondition = new BinaryExpression(new FieldExpression('id', $aAliasNames[0]), '=', new VariableExpression('id')); $oSearch->AddConditionExpression($oCondition); $sClass = $oSearch->GetClass(); if (!array_key_exists($sClass, $this->aContextSearches)) { $this->aContextSearches[$sClass] = array(); } $this->aContextSearches[$sClass][] = array('key' => $key, 'search' => $oSearch); }
/** * Attempt to acquire the mutex * @returns bool True if the mutex is acquired, false if already locked elsewhere */ public function TryLock() { if ($this->bLocked) { return true; // Already acquired } if (self::$aAcquiredLocks[$this->sName] > 0) { self::$aAcquiredLocks[$this->sName]++; $this->bLocked = true; return true; } $res = $this->QueryToScalar("SELECT GET_LOCK('" . $this->sName . "', 0)"); if (is_null($res)) { throw new Exception("Failed to acquire the lock '" . $this->sName . "'"); } // $res === '1' means I hold the lock // $res === '0' means it timed out if ($res === '1') { $this->bLocked = true; self::$aAcquiredLocks[$this->sName]++; } if ($res !== '1' && $res !== '0') { $sMsg = 'GET_LOCK(' . $this->sName . ', 0) returned: ' . var_export($res, true) . '. Expected values are: 0, 1 or null'; IssueLog::Error($sMsg); throw new Exception($sMsg); } return $res !== '0'; }
protected function LogMessage($sMessage, $aData = array()) { if (MetaModel::IsLogEnabledIssue()) { if (MetaModel::IsValidClass('EventIssue')) { $oLog = new EventIssue(); $oLog->Set('message', $sMessage); $oLog->Set('userinfo', ''); $oLog->Set('issue', 'LDAP Authentication'); $oLog->Set('impact', 'User login rejected'); $oLog->Set('data', $aData); $oLog->DBInsertNoReload(); } IssueLog::Error($sMessage); } }
protected static function IncludeModule($sModuleType, $sToInclude) { $sFirstChar = substr($sToInclude, 0, 1); $sSecondChar = substr($sToInclude, 1, 1); if ($sFirstChar != '/' && $sFirstChar != '\\' && $sSecondChar != ':') { // It is a relative path, prepend APPROOT if (substr($sToInclude, 0, 3) == '../') { // Preserve compatibility with config files written before 1.0.1 // Replace '../' by '<root>/' $sFile = APPROOT . '/' . substr($sToInclude, 3); } else { $sFile = APPROOT . '/' . $sToInclude; } } else { // Leave as is - should be an absolute path $sFile = $sToInclude; } if (!file_exists($sFile)) { $sConfigFile = self::$m_oConfig->GetLoadedFile(); if (strlen($sConfigFile) > 0) { throw new CoreException('Include: wrong file name in configuration file', array('config file' => $sConfigFile, 'section' => $sModuleType, 'filename' => $sFile)); } else { // The configuration is in memory only throw new CoreException('Include: wrong file name in configuration file (in memory)', array('section' => $sModuleType, 'filename' => $sFile)); } } // Note: We do not expect the modules to output characters while loading them. // Therefore, and because unexpected characters can corrupt the output, // they must be trashed here. // Additionnaly, pages aiming at delivering data in their output can call WebPage::TrashUnexpectedOutput() // to get rid of chars that could be generated during the execution of the code ob_start(); require_once $sFile; $sPreviousContent = ob_get_clean(); if (self::$m_oConfig->Get('debug_report_spurious_chars')) { if ($sPreviousContent != '') { IssueLog::Error("Spurious characters injected by {$sModuleType}/{$sToInclude}"); } } }
protected function LogError($sMsg) { IssueLog::Error($sMsg); }
/** * Read the output buffer and deal with its contents: * - trash unexpected output if the flag has been set * - report unexpected behaviors such as the output buffering being stopped * * Possible improvement: I've noticed that several output buffers are stacked, * if they are not empty, the output will be corrupted. The solution would * consist in unstacking all of them (and concatenate the contents). */ protected function ob_get_clean_safe() { $sOutput = ob_get_contents(); if ($sOutput === false) { $sMsg = "Design/integration issue: No output buffer. Some piece of code has called ob_get_clean() or ob_end_clean() without calling ob_start()"; if ($this->bTrashUnexpectedOutput) { IssueLog::Error($sMsg); $sOutput = ''; } else { $sOutput = $sMsg; } } else { ob_end_clean(); // on some versions of PHP doing so when the output buffering is stopped can cause a notice if ($this->bTrashUnexpectedOutput) { if (trim($sOutput) != '') { if (Utils::GetConfig() && Utils::GetConfig()->Get('debug_report_spurious_chars')) { IssueLog::Error("Trashing unexpected output:'{$s_captured_output}'\n"); } } $sOutput = ''; } } return $sOutput; }
/** * Get the description of the graph as text string in the XDot format * including the positions of the nodes and egdes (requires graphviz * to be installed on the machine and the path to dot/dot.exe to be * configured in the iTop configuration file) * Note: the function creates temporary files in APPROOT/data/tmp * @return string */ public function DumpAsXDot() { $sDotExecutable = MetaModel::GetConfig()->Get('graphviz_path'); if (file_exists($sDotExecutable)) { // create the file with Graphviz if (!is_dir(APPROOT . "data")) { @mkdir(APPROOT . "data"); } if (!is_dir(APPROOT . "data/tmp")) { @mkdir(APPROOT . "data/tmp"); } $sXdotFilePath = tempnam(APPROOT . "data/tmp", 'xdot-'); $sDotDescription = $this->GetDotDescription(true); // true => don't put (localized) labels in the file, since it makes it harder to parse $sDotFilePath = tempnam(APPROOT . "data/tmp", 'dot-'); $rFile = @fopen($sDotFilePath, "w"); @fwrite($rFile, $sDotDescription); @fclose($rFile); $aOutput = array(); $CommandLine = "\"{$sDotExecutable}\" -v -Tdot < {$sDotFilePath} -o{$sXdotFilePath} 2>&1"; exec($CommandLine, $aOutput, $iRetCode); if ($iRetCode != 0) { $sHtml = ''; $sHtml .= "<p><b>Error:</b></p>"; $sHtml .= "<p>The command: <pre>{$CommandLine}</pre> returned {$iRetCode}</p>"; $sHtml .= "<p>The output of the command is:<pre>\n" . implode("\n", $aOutput) . "</pre></p>"; IssueLog::Error($sHtml); } else { $sHtml = '<pre>' . file_get_contents($sXdotFilePath) . '</pre>'; @unlink($sXdotFilePath); } @unlink($sDotFilePath); } else { throw new Exception('graphviz not found (executable path: ' . $sDotExecutable . ')'); } return $sHtml; }
public static function SetProperty($sName, $sValue, $sComment = '', $sDescription = null) { try { $oSearch = DBObjectSearch::FromOQL('SELECT DBProperty WHERE name = :name'); $oSet = new DBObjectSet($oSearch, array(), array('name' => $sName)); if ($oSet->Count() == 0) { $oProp = new DBProperty(); $oProp->Set('name', $sName); $oProp->Set('description', $sDescription); $oProp->Set('value', $sValue); $oProp->Set('change_date', time()); $oProp->Set('change_comment', $sComment); $oProp->DBInsert(); } elseif ($oSet->Count() == 1) { $oProp = $oSet->fetch(); if (!is_null($sDescription)) { $oProp->Set('description', $sDescription); } $oProp->Set('value', $sValue); $oProp->Set('change_date', time()); $oProp->Set('change_comment', $sComment); $oProp->DBUpdate(); } else { // Houston... throw new CoreException('duplicate db property'); } } catch (MySQLException $e) { // This might be because the table could not be found, // let's check it and discard silently if this is really the case if (self::IsInstalled()) { throw $e; } IssueLog::Error('Attempting to write a DBProperty while the module has not been installed'); } }
/** * Discard unexpected output data * This is a MUST when the Page output is DATA (download of a document, download CSV export, download ...) */ public function TrashUnexpectedOutput() { // This protection is redundant with a protection implemented in MetaModel::IncludeModule // which detects such issues while loading module files // Here, the purpose is to detect and discard characters produced by the code execution (echo) $sPreviousContent = ob_get_clean(); if (trim($sPreviousContent) != '') { if (Utils::GetConfig() && Utils::GetConfig()->Get('debug_report_spurious_chars')) { IssueLog::Error("Output already started before downloading file:\nContent was:'{$sPreviousContent}'\n"); } } }
/** * Overridable to extend the behavior in case of error (logging) */ protected function HandleError($sErrorMessage, $iErrorCode) { if ($this->Get('last_attempt') == '') { // First attempt $this->Set('remaining_retries', $this->GetMaxRetries($iErrorCode)); } $this->Set('last_error', $sErrorMessage); $this->Set('last_error_code', $iErrorCode); // Note: can be ZERO !!! $this->Set('last_attempt', time()); $iRemaining = $this->Get('remaining_retries'); if ($iRemaining > 0) { $iRetryDelay = $this->GetRetryDelay($iErrorCode); IssueLog::Info('Failed to process async task #' . $this->GetKey() . ' - reason: ' . $sErrorMessage . ' - remaining retries: ' . $iRemaining . ' - next retry in ' . $iRetryDelay . 's'); $this->Set('remaining_retries', $iRemaining - 1); $this->Set('status', 'planned'); $this->Set('started', null); $this->Set('planned', time() + $iRetryDelay); } else { IssueLog::Error('Failed to process async task #' . $this->GetKey() . ' - reason: ' . $sErrorMessage); $this->Set('status', 'error'); $this->Set('started', null); $this->Set('planned', null); $this->OnDefinitiveFailure(); } $this->DBUpdate(); }