*/ /** The logger class permit to log the information from the soft It allow to debug too */ class logger { /* The logger class can be used with : $d=new logger; $d->timezone = "Europe/Paris"; $d->logtype="display|file"; $d->logfile="/tmp/toto.log"; $d->logwrite ("Super log default"); $d->logwrite ("Super log DEBUG", $d::DEBUG); $d->logwrite ("Super log NOTICE", $d::NOTICE); */ // TODO : Add SQL support /** The method to log. Can be display, file, syslog, stderr, session Can be merged with a pipe : "display|syslog|file" or put in array */ public $logtype = "stderr"; /** For logtype=file, the filename to use */ public $logfile = FALSE; /** Timezone use to save the logs */ public $timezone = "UTC"; /** Minimum log level in the logs */ public $loglevelmin = LOG_NOTICE; /** In Syslog mode, the facility to use See http://fr2.php.net/manual/en/function.openlog.php for $syslogFacility */ public $syslogFacility = LOG_USER; /** In Syslog, prefix the log by the text */ public $syslogPrefix = FALSE; /** Remove X entries of backtrace to see the right file generating the error */ public $backTraceSkip = 1; /** Display the backtrace in all the messages */ public $backtraceDisplay = false; /** The priorities which can be used in the priorities LOG_EMERG system is unusable LOG_ALERT action must be taken immediately LOG_CRIT critical conditions LOG_ERR error conditions LOG_WARNING warning conditions LOG_NOTICE normal, but significant, condition LOG_INFO informational message LOG_DEBUG debug-level message */ private $priorities = array (LOG_EMERG => "EMERG", LOG_ALERT => "ALERT", LOG_CRIT => "CRITICAL", LOG_ERR => "ERROR", LOG_WARNING => "WARNING", LOG_NOTICE => "NOTICE", LOG_INFO => "INFO", LOG_DEBUG => "DEBUG"); /** Catch all the messages raised by the PHP, in trigger_error Use the properties of the logger to save the logs */ public function catchAll () { set_error_handler (array (&$this, "errorHandler")); } /** The error handler to log * @param integer $errno The error number to use * @param string $errstr The error message to save * @param string $errfile The file which generate the error * @param integer $errline The line where the error is generated */ public function errorHandler ($errno, $errstr, $errfile, $errline) { if (!(error_reporting() & $errno)) { // This error code is not included in error_reporting return; } switch($errno) { case E_ERROR: $priority = LOG_ERR; break; case E_WARNING: $priority = LOG_WARNING; break; case E_PARSE: $priority = LOG_PARSE; break; case E_NOTICE: $priority = LOG_NOTICE; break; case E_CORE_ERROR: $priority = LOG_ERR; break; case E_CORE_WARNING: $priority = LOG_WARNING; break; case E_COMPILE_ERROR: $priority = LOG_ERR; break; case E_COMPILE_WARNING: $priority = LOG_WARNING; break; case E_USER_ERROR: $priority = LOG_ERR; break; case E_USER_WARNING: $priority = LOG_WARNING; break; case E_USER_NOTICE: $priority = LOG_NOTICE; break; case E_STRICT: $priority = LOG_WARNING; break; case E_RECOVERABLE_ERROR: $priority = LOG_ERR; break; case E_DEPRECATED: $priority = LOG_WARNING; break; case E_USER_DEPRECATED: $priority = LOG_WARNING; break; } $this->log ($priority, $errstr); } /** Store a new message log in the log manager defined by $logtype The message can be multiple types. An array will be stored in textual form but it will accept only one depth. The $message is not fixed, you can pass the number of parameters you want @param integer|null $priority Priority to use @param mixed ...$message Message to log */ public function log ($priority=LOG_NOTICE, $message) { if (! is_int ($priority)) { switch ($priority) { case "LOG_EMERG": $priority = LOG_EMERG; break; case "LOG_ALERT": $priority = LOG_ALERT; break; case "LOG_CRIT": $priority = LOG_CRIT; break; case "LOG_ERR": $priority = LOG_ERR; break; case "LOG_WARNING": $priority = LOG_WARNING; break; case "LOG_NOTICE": $priority = LOG_NOTICE; break; case "LOG_INFO": $priority = LOG_INFO; break; case "LOG_DEBUG": $priority = LOG_DEBUG; break; } } if (! is_int ($this->loglevelmin)) { switch ($this->loglevelmin) { case "LOG_EMERG": $this->loglevelmin = LOG_EMERG; break; case "LOG_ALERT": $this->loglevelmin = LOG_ALERT; break; case "LOG_CRIT": $this->loglevelmin = LOG_CRIT; break; case "LOG_ERR": $this->loglevelmin = LOG_ERR; break; case "LOG_WARNING": $this->loglevelmin = LOG_WARNING; break; case "LOG_NOTICE": $this->loglevelmin = LOG_NOTICE; break; case "LOG_INFO": $this->loglevelmin = LOG_INFO; break; case "LOG_DEBUG": $this->loglevelmin = LOG_DEBUG; break; } } if ($this->loglevelmin < $priority) return; $backtrace = debug_backtrace(); for ($i = 0 ; $i <= $this->backTraceSkip ; $i++) $back = array_shift ($backtrace); while (! array_key_exists ("file", $back) && count ($backtrace) > 0) $back = array_shift ($backtrace); $msg = ""; if (isset ($_SERVER["HTTP_X_FORWARDED_FOR"])) $msg .= "[".$_SERVER["HTTP_X_FORWARDED_FOR"]."] "; elseif (isset ($_SERVER["REMOTE_ADDR"])) $msg .= "[".$_SERVER["REMOTE_ADDR"]."] "; // The messages are all the parameters of the function except the first, // which is the priority $messages = func_get_args (); array_shift ($messages); // Convert each part of message to text foreach ($messages as $m) { if (is_array ($m)) { $msg .= "["; foreach ($m as $key=>$val) { if (is_array ($val)) { foreach ($val as $key2=>$val2) { $msg .= "$key2=>$val2,"; } } else { $msg .= "$key=>$val,"; } } $msg .= "]"; } else { $msg .= $m; } } // Add the filename which generate the error $msg .= " [".basename ($back["file"]).":".$back["line"]."]"; // Display the backtrace if it is needed if ($this->backtraceDisplay) { $e = new Exception(); $msg .= "\n".($e->getTraceAsString()); } if (is_string ($this->logtype)) $logsType = explode ("|", $this->logtype); elseif (is_array ($this->logtype)) $logsType = $this->logtype; if (in_array ("display", $logsType)) $this->logdisplay ($msg, $priority); if (in_array ("stderr", $logsType)) $this->logstderr ($msg, $priority); if (in_array ("file", $logsType)) $this->logfile ($msg, $priority); if (in_array ("syslog", $logsType)) $this->logsyslog ($msg, $priority); if (in_array ("session", $logsType)) $this->logsession ($msg, $priority); } /** Log $message on file @param string $message Message to log @param integer|null $priority Priority to use */ private function logfile ($message, $priority) { if ($this->logfile === FALSE) throw new Exception ("Undefined file where logging"); if (!file_exists ($this->logfile)) { if (! is_dir (dirname ($this->logfile))) throw new Exception ("You must create the ".dirname ($this->logfile). "directory"); if (! is_writable (dirname ($this->logfile))) throw new Exception ("The directory ".dirname ($this->logfile)." must" ." be writable to create log file"); } elseif (!is_writable ($this->logfile)) { if (function_exists ("posix_geteuid")) $user = posix_geteuid (); elseif (getenv('USERNAME') !== FALSE) $user = getenv('USERNAME'); else $user = ""; throw new Exception ("Logfile $this->logfile is not writable for user ". $user); } ini_set ("date.timezone", $this->timezone); $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". $message."\n"; file_put_contents ($this->logfile, $message, FILE_APPEND|LOCK_EX); } /** Log $message on screen with adding date. Add the HTML flags if not in CLI. @param string $message Message to log @param integer|null $priority Priority to use */ private function logdisplay ($message, $priority) { if (php_sapi_name () !== "cli") echo ""; ini_set ("date.timezone", $this->timezone); $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". $message; if (php_sapi_name () !== "cli") $message = nl2br ($message); echo "$message"; if (php_sapi_name () !== "cli") echo "
"; echo "\n"; } /** Log $message on stderr with adding date. Add the HTML flags if not in CLI. @param string $message Message to log @param integer|null $priority Priority to use */ private function logstderr ($message, $priority) { ini_set ("date.timezone", $this->timezone); $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". $message; file_put_contents("php://stderr", "$message"); file_put_contents("php://stderr", "\n"); } /** Log $message on syslog @param string $message Message to log @param integer|null $priority Priority to use */ private function logsyslog ($message, $priority) { if (is_string ($this->syslogFacility)) { switch ($this->syslogFacility) { case "LOG_AUTH": $this->syslogFacility=LOG_AUTH; break; case "LOG_AUTHPRIV": $this->syslogFacility=LOG_AUTHPRIV; break; case "LOG_DAEMON": $this->syslogFacility=LOG_DAEMON; break; case "LOG_KERN": $this->syslogFacility=LOG_KERN; break; case "LOG_LOCAL0": $this->syslogFacility=LOG_LOCAL0; break; case "LOG_LOCAL1": $this->syslogFacility=LOG_LOCAL1; break; case "LOG_LOCAL2": $this->syslogFacility=LOG_LOCAL2; break; case "LOG_LOCAL3": $this->syslogFacility=LOG_LOCAL3; break; case "LOG_LOCAL4": $this->syslogFacility=LOG_LOCAL4; break; case "LOG_LOCAL5": $this->syslogFacility=LOG_LOCAL5; break; case "LOG_LOCAL6": $this->syslogFacility=LOG_LOCAL6; break; case "LOG_LOCAL7": $this->syslogFacility=LOG_LOCAL7; break; case "LOG_LPR": $this->syslogFacility=LOG_LPR; break; case "LOG_MAIL": $this->syslogFacility=LOG_MAIL; break; case "LOG_NEWS": $this->syslogFacility=LOG_NEWS; break; case "LOG_SYSLOG": $this->syslogFacility=LOG_SYSLOG; break; case "LOG_USER": $this->syslogFacility=LOG_USER; break; case "LOG_UUCP": $this->syslogFacility=LOG_UUCP; break; } } openlog ($this->syslogPrefix, NULL, $this->syslogFacility); syslog ($priority, $message); } /** Log $message on session (for debug) @param string $message Message to log @param integer|null $priority Priority to use */ private function logsession ($message, $priority) { if (! isset ($_SESSION)) throw new Exception ("No session available to store the log", 500); ini_set ("date.timezone", $this->timezone); $message = date ("Y/m/d H:i:s")." [".$this->priorities[$priority]."] ". $message; $_SESSION["domframework"]["logger"][] = $message; } }