Пример #1
0
 /**
  * Constructor
  */
 function __construct($dbtype = '', $host = '', $dbname = '', $username = '', $passwd = '')
 {
     $this->log = LoggerManager::getLogger('DB');
     $this->loadDBConfig($dbtype, $host, $dbname, $username, $passwd);
     // Initialize performance parameters
     $this->isdb_default_utf8_charset = PerformancePrefs::getBoolean('DB_DEFAULT_CHARSET_UTF8');
     if (!isset($this->dbType) || !isset($this->dbHostName) || !isset($this->dbName)) {
         $this->log('No configuration for the database connection', 'fatal');
         return false;
     }
     $this->setDieOnError(SysDebug::get('SQL_DIE_ON_ERROR'));
     $this->connect();
 }
Пример #2
0
 /**
  * Constructor
  */
 function __construct($dbtype = '', $host = '', $dbname = '', $username = '', $passwd = '')
 {
     $this->log = LoggerManager::getLogger('DB');
     $this->resetSettings($dbtype, $host, $dbname, $username, $passwd);
     // Initialize performance parameters
     $this->isdb_default_utf8_charset = PerformancePrefs::getBoolean('DB_DEFAULT_CHARSET_UTF8');
     if (!isset($this->dbType)) {
         $this->log('Database connect : DBType not specified', 'error');
         return;
     }
     $this->setDieOnError(SysDebug::get('SQL_DIE_ON_ERROR'));
     $this->connect();
 }
Пример #3
0
 /**
  * Constructor - Sets the templateDir and compileDir for the Smarty files
  * @param <String> - $media Layout/Media name
  */
 function __construct($media = '')
 {
     parent::__construct();
     $THISDIR = dirname(__FILE__);
     $templatesDir = '';
     $compileDir = '';
     $templateDir = [];
     if (!empty($media)) {
         self::$currentLayout = $media;
         $customTemplatesDir = $THISDIR . '/../../custom/layouts/' . $media;
         $templateDir[] = $THISDIR . '/../../layouts/' . $media;
         $compileDir = $THISDIR . '/../../cache/templates_c/' . $media;
     }
     $defaultLayout = vglobal('defaultLayout');
     if ($defaultLayout && is_file(vglobal('root_directory') . '/layouts/' . $defaultLayout)) {
         $templateDir[] = $THISDIR . '/../../layouts/' . $defaultLayout;
     }
     if (empty($templatesDir) || !file_exists($templatesDir)) {
         self::$currentLayout = self::getDefaultLayoutName();
         $templateDir[] = $THISDIR . '/../../custom/layouts/' . self::getDefaultLayoutName();
         $templateDir[] = $THISDIR . '/../../layouts/' . self::getDefaultLayoutName();
         $compileDir = $THISDIR . '/../../cache/templates_c/' . self::getDefaultLayoutName();
     }
     if (!file_exists($compileDir)) {
         mkdir($compileDir, 0777, true);
     }
     $this->setTemplateDir($templateDir);
     $this->setCompileDir($compileDir);
     self::$debugViewer = SysDebug::get('DEBUG_VIEWER');
     // FOR SECURITY
     // Escape all {$variable} to overcome XSS
     // We need to use {$variable nofilter} to overcome double escaping
     // TODO: Until we review the use disabled.
     //$this->registerFilter('variable', array($this, 'safeHtmlFilter'));
     // FOR DEBUGGING: We need to have this only once.
     static $debugViewerURI = false;
     if (self::$debugViewer && $debugViewerURI === false) {
         $debugViewerURI = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
         if (!empty($_POST)) {
             $debugViewerURI .= '?' . http_build_query($_POST);
         } else {
             $debugViewerURI = $_SERVER['REQUEST_URI'];
         }
         $this->log("URI: {$debugViewerURI}, TYPE: " . $_SERVER['REQUEST_METHOD']);
     }
 }
Пример #4
0
 function checkError($message, $dieOnError = false, $query = false, $params = false)
 {
     if ($this->hasActiveTransaction) {
         $this->rollbackTransaction();
     }
     if ($this->dieOnError || $dieOnError) {
         if (SysDebug::get('DISPLAY_DEBUG_BACKTRACE')) {
             $queryInfo = '';
             if ($query !== false) {
                 $queryInfo .= 'Query: ' . $query . PHP_EOL;
             }
             if ($params !== false && $params != NULL) {
                 $queryInfo .= 'Params: ' . implode(',', $params) . PHP_EOL;
             }
             $backtrace = Vtiger_Functions::getBacktrace();
             $trace = '<pre>' . $queryInfo . $backtrace . '</pre>';
         }
         Vtiger_Functions::throwNewException('Database ERROR: ' . PHP_EOL . $message . PHP_EOL . $trace);
     }
 }
Пример #5
0
 function process(Vtiger_Request $request)
 {
     vglobal('log', LoggerManager::getLogger('System'));
     Vtiger_Session::init();
     $forceSSL = vglobal('forceSSL');
     if ($forceSSL && !Vtiger_Functions::getBrowserInfo()->https) {
         header("Location: https://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}");
     }
     // Better place this here as session get initiated
     //skipping the csrf checking for the forgot(reset) password
     $csrfProtection = vglobal('csrfProtection');
     if ($csrfProtection) {
         if ($request->get('mode') != 'reset' && $request->get('action') != 'Login') {
             require_once 'libraries/csrf-magic/csrf-magic.php';
         }
     }
     // TODO - Get rid of global variable $current_user
     // common utils api called, depend on this variable right now
     $currentUser = $this->getLogin();
     vglobal('current_user', $currentUser);
     $currentLanguage = Vtiger_Language_Handler::getLanguage();
     vglobal('current_language', $currentLanguage);
     $module = $request->getModule();
     $qualifiedModuleName = $request->getModule(false);
     if ($currentUser && $qualifiedModuleName) {
         $moduleLanguageStrings = Vtiger_Language_Handler::getModuleStringsFromFile($currentLanguage, $qualifiedModuleName);
         vglobal('mod_strings', $moduleLanguageStrings['languageStrings']);
     }
     if ($currentUser) {
         $moduleLanguageStrings = Vtiger_Language_Handler::getModuleStringsFromFile($currentLanguage);
         vglobal('app_strings', $moduleLanguageStrings['languageStrings']);
     }
     $view = $request->get('view');
     $action = $request->get('action');
     $response = false;
     try {
         if ($this->isInstalled() === false && $module != 'Install') {
             header('Location:install/Install.php');
             exit;
         }
         if (empty($module)) {
             if ($this->hasLogin()) {
                 $defaultModule = vglobal('default_module');
                 if (!empty($defaultModule) && $defaultModule != 'Home') {
                     $module = $defaultModule;
                     $qualifiedModuleName = $defaultModule;
                     $view = 'List';
                     if ($module == 'Calendar') {
                         // To load MyCalendar instead of list view for calendar
                         //TODO: see if it has to enhanced and get the default view from module model
                         $view = 'Calendar';
                     }
                 } else {
                     $module = 'Home';
                     $qualifiedModuleName = 'Home';
                     $view = 'DashBoard';
                 }
             } else {
                 $module = 'Users';
                 $qualifiedModuleName = 'Settings:Users';
                 $view = 'Login';
             }
             $request->set('module', $module);
             $request->set('view', $view);
         }
         if (!empty($action)) {
             $componentType = 'Action';
             $componentName = $action;
         } else {
             $componentType = 'View';
             if (empty($view)) {
                 $view = 'Index';
             }
             $componentName = $view;
         }
         $handlerClass = Vtiger_Loader::getComponentClassName($componentType, $componentName, $qualifiedModuleName);
         $handler = new $handlerClass();
         if ($handler) {
             vglobal('currentModule', $module);
             $csrfProtection = vglobal('csrfProtection');
             if ($csrfProtection) {
                 // Ensure handler validates the request
                 $handler->validateRequest($request);
             }
             if ($handler->loginRequired()) {
                 $this->checkLogin($request);
             }
             //TODO : Need to review the design as there can potential security threat
             $skipList = array('Users', 'Home', 'CustomView', 'Import', 'Export', 'Inventory', 'Vtiger', 'Migration', 'Install');
             if (!in_array($module, $skipList) && stripos($qualifiedModuleName, 'Settings') === false) {
                 $this->triggerCheckPermission($handler, $request);
             }
             // Every settings page handler should implement this method
             if (stripos($qualifiedModuleName, 'Settings') === 0 || $module == 'Users') {
                 $handler->checkPermission($request);
             }
             $notPermittedModules = array('ModComments', 'Integration', 'DashBoard');
             if (in_array($module, $notPermittedModules) && $view == 'List') {
                 header('Location:index.php?module=Home&view=DashBoard');
             }
             $this->triggerPreProcess($handler, $request);
             $response = $handler->process($request);
             $this->triggerPostProcess($handler, $request);
         } else {
             throw new AppException(vtranslate('LBL_HANDLER_NOT_FOUND'));
         }
     } catch (AppException $e) {
         $log = vglobal('log');
         if (!$request->isAjax()) {
             // Log for developement.
             $log->error($e->getMessage() . ' => ' . $e->getFile() . ':' . $e->getLine());
             Vtiger_Functions::throwNewException($e->getMessage());
         } else {
             $response = new Vtiger_Response();
             $response->setEmitType(Vtiger_Response::$EMIT_JSON);
             $response->setError($e->getMessage());
             $log->error($e->getMessage() . ' => ' . $e->getFile() . ':' . $e->getLine());
         }
         if (SysDebug::get('DISPLAY_DEBUG_BACKTRACE')) {
             die($e->getTraceAsString());
         }
     }
     if ($response) {
         $response->emit();
     }
 }
Пример #6
0
 * License. You may obtain a copy of the License at http://www.sugarcrm.com/SPL
 * Software distributed under the License is distributed on an  "AS IS"  basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 * The Original Code is:  SugarCRM Open Source
 * The Initial Developer of the Original Code is SugarCRM, Inc.
 * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.;
 * All Rights Reserved.
 * Contributor(s): YetiForce.com
 * ****************************************************************************** */
/* * *******************************************************************************
 * $Header: /advent/projects/wesat/vtiger_crm/sugarcrm/include/logging.php,v 1.1 2004/08/17 13:23:37 gjayakrishnan Exp $
 * Description:  Kicks off log4php.
 * ****************************************************************************** */
include_once 'config/debug.php';
require_once 'config/config.php';
require_once 'include/ConfigUtils.php';
// Performance Optimization: Configure the log folder
if (SysDebug::getBoolean('LOG4PHP_DEBUG', false)) {
    define('LOG4PHP_DIR', 'libraries/log4php.debug');
} else {
    define('LOG4PHP_DIR', 'libraries/log4php');
}
// END
define('LOG4PHP_DEFAULT_INIT_OVERRIDE', true);
require_once LOG4PHP_DIR . '/LoggerManager.php';
require_once LOG4PHP_DIR . '/LoggerPropertyConfigurator.php';
$config = new LoggerPropertyConfigurator();
$config->configure('config/log4php.properties');
global $log;
$log = LoggerManager::getLogger('System');
Пример #7
0
    $directory->getRootChild();
    $nodes[] = $directory;
}
// The object tree needs in turn to be passed to the server class
$server = new Yeti\DAV_Server($nodes);
$server->setBaseUri($baseUri);
$server->debugExceptions = SysDebug::get('DAV_DEBUG_EXCEPTIONS');
// Plugins
$server->addPlugin(new Sabre\DAV\Auth\Plugin($authBackend, 'YetiDAV'));
$server->addPlugin(new Sabre\DAVACL\Plugin());
$server->addPlugin(new Sabre\DAV\Sync\Plugin());
if ($enableBrowser) {
    $server->addPlugin(new Sabre\DAV\Browser\Plugin());
    // Automatically guess (some) contenttypes, based on extesion
    $server->addPlugin(new Sabre\DAV\Browser\GuessContentType());
}
if ($enableCardDAV) {
    //CardDav integration
    $server->addPlugin(new Sabre\CardDAV\Plugin());
}
if ($enableCalDAV) {
    //CalDAV integration
    $server->addPlugin(new Sabre\CalDAV\Plugin());
    $server->addPlugin(new Sabre\CalDAV\Subscriptions\Plugin());
    $server->addPlugin(new Sabre\CalDAV\Schedule\Plugin());
}
if (SysDebug::get('DAV_DEBUG_PLUGIN')) {
    $server->addPlugin(new Yeti\Debug());
}
// And off we go!
$server->exec();
Пример #8
0
 function checkError($message, $dieOnError = false)
 {
     if ($this->hasActiveTransaction) {
         $this->rollbackTransaction();
     }
     if ($this->dieOnError || $dieOnError) {
         if (SysDebug::get('DISPLAY_DEBUG_BACKTRACE')) {
             ob_start();
             debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
             $trace = '<pre>' . ob_get_contents() . '</pre>';
             ob_end_clean();
         }
         die('Database ERROR: ' . $message . $trace);
     }
 }
Пример #9
0
 function checkError($message, $dieOnError = false, $query = false, $params = false)
 {
     if ($this->hasActiveTransaction) {
         $this->rollbackTransaction();
     }
     if ($this->dieOnError || $dieOnError) {
         if (SysDebug::get('DISPLAY_DEBUG_BACKTRACE')) {
             ob_start();
             debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
             $queryInfo = '';
             if ($query !== false) {
                 $queryInfo .= 'Query: ' . $query . PHP_EOL;
             }
             if ($params !== false && $params != NULL) {
                 $queryInfo .= 'Params: ' . implode(',', $params) . PHP_EOL;
             }
             $trace = '<pre>' . $queryInfo . ob_get_contents() . '</pre>';
             ob_end_clean();
         }
         die('Database ERROR: ' . $message . $trace);
     }
 }
Пример #10
0
 /**
  * Constructor
  */
 function PearDatabase($dbtype = '', $host = '', $dbname = '', $username = '', $passwd = '')
 {
     global $currentModule;
     $this->log = LoggerManager::getLogger('PearDatabase_' . $currentModule);
     $this->resetSettings($dbtype, $host, $dbname, $username, $passwd);
     // Initialize performance parameters
     $this->isdb_default_utf8_charset = PerformancePrefs::getBoolean('DB_DEFAULT_CHARSET_UTF8');
     // END
     if (!isset($this->dbType)) {
         $this->println("ADODB Connect : DBType not specified");
         return;
     }
     $this->setDieOnError(SysDebug::get('SQL_DIE_ON_ERROR'));
 }
Пример #11
0
 /**
  * Realiza o calculo do tempo de realização de um debug.
  *
  * @param mixed $label Rotina a sofrer debug.
  * @param bool $imprimir Determina se será exibido resultado em tela.
  * @return void
  */
 public static function custoTempoDebug($label, $imprimir = false)
 {
     if (!self::$debug_time_start) {
         self::$debug_time_start = microtime();
     }
     if (!self::$debug_time_last) {
         self::$debug_time_last = microtime();
     }
     $acumulado = microtime() - self::$debug_time_start;
     $parcial = microtime() - self::$debug_time_last;
     self::$debug_time_last = microtime();
     self::$debug_times[] = array('acumulado' => $acumulado, 'parcial' => $parcial, 'label' => $label);
     if ($imprimir) {
         echo "\n{$label}: {$acumulado}/{$parcial}\n";
     }
 }
Пример #12
0
 /**
  * Initialize new Smarty object
  */
 public function __construct()
 {
     // selfpointer needed by some other class methods
     $this->smarty = $this;
     if (is_callable('mb_internal_encoding')) {
         mb_internal_encoding(Smarty::$_CHARSET);
     }
     $this->start_time = microtime(true);
     // set default dirs
     $this->setTemplateDir('.' . DS . 'templates' . DS)->setCompileDir('.' . DS . 'templates_c' . DS)->setPluginsDir(SMARTY_PLUGINS_DIR)->setCacheDir('.' . DS . 'cache' . DS)->setConfigDir('.' . DS . 'configs' . DS);
     $this->debug_tpl = 'file:' . dirname(__FILE__) . '/debug.tpl';
     if (isset($_SERVER['SCRIPT_NAME'])) {
         $this->assignGlobal('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']);
     }
     $this->debugging = SysDebug::get('DISPLAY_DEBUG_VIEWER');
     // YetiForce Sp. z o.o. //
 }
Пример #13
0
 /**
  * Pode ser chamado diretamente por um throw ou quando o PHP dispara um erro (WARNING, PARSE ou FATAL).
  * No segundo caso um próprio método erro() dessa clase dispara a exceção.
  * 
  * @param String $message Texto descritivo sobre o que pode ter acontecido na rotina que disparou o erro.
  * @param int $gravidade Valor inteiro para indicar a gravidade (0 a 3) da exceção. No caso de ser disparada por um
  *        	erro do PHP esse campo é um valor constante que indica qual tipo de erro.
  * @param array $contexto Array com valores do debug_backtrace() (nativo do PHP), pode não ser enviado ou ignorado
  *        	com valor false. No caso de erros no PHP tráz informações sobre linha, arquivo e contexto (veja doc
  *        	set_error_handler)
  * @param bool $erro_php É usado apenas pelo método erro() da classe para indicar que não é uma exceção do sistema,
  *        	mas sim um erro no PHP. O método erro() está sendo usado como handle dos erros no PHP para que os
  *        	usuários não vejam mensagens de erros.
  * @return void
  */
 public function __construct($message, $gravidade = __CLASS__, $contexto = false, $erro_php = false)
 {
     if (!self::$identificador_execucao) {
         self::$identificador_execucao = str_pad(rand(1, 9999), 4, '0', STR_PAD_LEFT);
     }
     $this->message = $message;
     $this->erro_nome = self::$identificador_execucao . '-' . ++self::$cont_erros . '-' . $gravidade . "-" . date('Y-m-d-H-i-s') . ".json";
     $this->erros['level'] = $gravidade;
     $this->erros['datetime'] = date("H:i:s Y-m-d", time());
     $this->erros['mensagem'] = $message;
     $this->erros['db_error'] = DB::error();
     if ($erro_php) {
         $erro_linha = $contexto['linha'];
         $erro_arquivo = $contexto['arquivo'];
         $message = strip_tags($message);
         /*
          * Não sei porque diabos esta chave as vezes vem com valores recursivos infinitos que causam erro no
          * sistema.
          */
         $contexto['contexto']["GLOBALS"] = " ";
         // muitas vezes o erro do php não traz o debug_backtrace
         $contexto['Backtrace'] = debug_backtrace();
     } else {
         $erro_linha = self::getLine();
         $erro_arquivo = self::getFile();
         if (SYS_MODO_DEVEL) {
             echo "<pre><br /><b>{$gravidade}</b> {$message}\n\nno arquivo {$erro_arquivo} Linha: {$erro_linha}<br /><br /></pre>";
         }
     }
     $this->id_unico = basename($erro_arquivo, '.php') . '.' . $erro_linha;
     $this->erros['PHP']['Arquivo'] = $erro_arquivo;
     $this->erros['PHP']['Linha'] = $erro_linha;
     $this->erros['PHP']['Codigo'] = $this->id_unico;
     /*
      * Caso tenha sido passado um array com o contexto do erro/exceção.
      */
     if ($contexto) {
         $this->erros['Contexto'] = $contexto;
     } else {
         $this->erros['Backtrace'] = debug_backtrace();
     }
     $this->erros["GET"] = $_GET;
     $this->erros["POST"] = $_POST;
     $this->erros["REQUEST"] = $_REQUEST;
     if (isset($_SESSION)) {
         $this->erros["Sessao"] = $_SESSION;
     }
     $this->erros["Cookies"] = $_COOKIE;
     $this->erros["Arquivos"] = $_FILES;
     $this->erros["Servidor"] = $_SERVER;
     $this->erros["APPS"] = (array) System::getInstance();
     foreach (SysDebug::getErros() as $err) {
         $this->erros['user_erros'][] = ['Label' => $err['Label'], 'VAR' => $err['VAR'], 'file' => $err['file'], 'line' => $err['line'], 'stringy' => $err['stringy']];
     }
     $json = utf8_decode(json_encode($this->erros, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
     $tam_file = file_put_contents(PATH_LOG_ERRO . $this->erro_nome, $json);
     if (SYS_MODO_DEVEL) {
         echo "<br/>Erro: " . $this->erro_nome;
         echo "<br/><pre>{$json}</pre>";
     }
     /*
      * Verifica se o sistema está configurado para enviar um e-mail para o administrador com o json.
      */
     if (ERROS_ENVIAR_EMAIL && !self::$erro_pai_enviado) {
         $largura_coluna = 20;
         $msg = '<code><pre>' . SYS_NAME . " Disse:\n" . $message;
         $msg .= "\n\n" . str_pad('Arquivo: ', $largura_coluna) . $erro_arquivo;
         $msg .= "\n" . str_pad('Codigo: ', $largura_coluna) . $this->id_unico;
         $msg .= "\n" . str_pad('Linha: ', $largura_coluna) . $erro_linha;
         $msg .= "\n" . str_pad('Erro banco: ', $largura_coluna) . DB::error();
         $msg .= "\n----------------------------------------------------------------------------------\n";
         $msg .= "\n" . str_pad("Horario:", $largura_coluna) . date('H:i:s d/m/Y');
         if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
             $msg .= "\n" . str_pad("IP:", $largura_coluna) . $_SERVER['HTTP_X_FORWARDED_FOR'];
             $msg .= "\n" . str_pad("Proxy:", $largura_coluna) . '<a href="http://www.geoiptool.com/?IP=' . $_SERVER['REMOTE_ADDR'] . '" target="_blank">' . $_SERVER['REMOTE_ADDR'] . '</a>';
         } else {
             $msg .= "\n" . str_pad("IP:", $largura_coluna) . '<a href="http://www.geoiptool.com/?IP=' . $_SERVER['REMOTE_ADDR'] . '" target="_blank">' . $_SERVER['REMOTE_ADDR'] . '</a>';
         }
         $msg .= "\n" . str_pad("Navegador:", $largura_coluna) . $_SERVER['HTTP_USER_AGENT'];
         $msg .= "\n" . str_pad("URL requisitada:", $largura_coluna) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
         $msg .= "\n" . str_pad("POST:", $largura_coluna) . count($_POST);
         $msg .= "\n" . str_pad("GET:", $largura_coluna) . count($_GET);
         $msg .= "\n" . str_pad("FILES:", $largura_coluna) . count($_FILES);
         $msg .= "\n" . str_pad("URL raiz:", $largura_coluna) . URL_ROOT;
         $msg .= "\n\n\n" . str_pad("JSON", $largura_coluna) . $json;
         if ($tam_file) {
             $msg .= "\n----------------------------------------------------------------------------------\n";
             $msg .= "\n" . str_pad("Arquivo em:", $largura_coluna) . PATH_LOG_ERRO . $this->erro_nome;
         } else {
             $msg .= "\n\nNÃO FOI POSSÍVEL ESCREVER O ARQUIVO EM DISCO!";
         }
         $msg .= "</pre></code>";
         if (ERROS_ANEXAR) {
             $anexo_codificado = chunk_split(base64_encode($json));
             $mailheaders = "\nMIME-version: 1.0\n";
             $mailheaders .= "Content-type: multipart/mixed; ";
             $mailheaders .= "boundary=\"Message-Boundary\"\n";
             $mailheaders .= "Content-transfer-encoding: 7BIT\n";
             $mailheaders .= "X-attachments: {$this->erro_nome}";
             $body_top = "--Message-Boundary\n";
             $body_top .= "Content-type: text/html; charset=utf8\n";
             $body_top .= "Content-transfer-encoding: 7BIT\n";
             $body_top .= "Content-description: Mail message body\n\n";
             $msg = $body_top . $msg;
             $msg .= "\n\n--Message-Boundary\n";
             $msg .= "Content-type: application/json; name=\"{$this->erro_nome}\"\n";
             $msg .= "Content-Transfer-Encoding: BASE64\n";
             $msg .= "Content-disposition: attachment; filename=\"{$this->erro_nome}\"\n\n";
             $msg .= "{$anexo_codificado}\n";
             $msg .= "--Message-Boundary--\n";
         }
         $mailheaders .= "\nReferences: <" . $this->id_unico . "@" . parse_url(URL_ROOT, PHP_URL_HOST) . ">\n";
         $msg .= "\n\nAtt, " . SYS_NAME . " (" . SIS_EMAIL . ")";
         $assunto = "[" . $gravidade . "][" . str_replace("http://", '', URL_ROOT) . '] ' . utf8_decode(substr($this->id_unico, 0, 30));
         if (mail(ERROS_EMAIL, $assunto, $msg, "From: " . SYS_NAME . " <" . SIS_EMAIL . ">" . $mailheaders)) {
             self::$erro_pai_enviado = true;
         } else {
             file_put_contents(PATH_LOG_ERRO . "EMAIL_{$this->erro_nome}", "Erro ao enviar e-mail do erro {$this->erro_nome}");
         }
     }
 }