/lib/Lampcms/Log.php
PHP | 414 lines | 130 code | 62 blank | 222 comment | 19 complexity | 3be3199ced566bcbbc93add9aa7afebe MD5 | raw file
Possible License(s): LGPL-3.0
- <?php
- /**
- *
- * License, TERMS and CONDITIONS
- *
- * This software is licensed under the GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
- * Please read the license here : http://www.gnu.org/licenses/lgpl-3.0.txt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * ATTRIBUTION REQUIRED
- * 4. All web pages generated by the use of this software, or at least
- * the page that lists the recent questions (usually home page) must include
- * a link to the http://www.lampcms.com and text of the link must indicate that
- * the website's Questions/Answers functionality is powered by lampcms.com
- * An example of acceptable link would be "Powered by <a href="http://www.lampcms.com">LampCMS</a>"
- * The location of the link is not important, it can be in the footer of the page
- * but it must not be hidden by style attributes
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This product includes GeoLite data created by MaxMind,
- * available from http://www.maxmind.com/
- *
- *
- * @author Dmitri Snytkine <cms@lampcms.com>
- * @copyright 2005-2012 (or current year) Dmitri Snytkine
- * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
- * @link http://www.lampcms.com Lampcms.com project
- * @version Release: @package_version@
- *
- *
- */
-
-
- namespace Lampcms;
-
-
- /**
- * Public static logger class
- * This class is responsible for logging
- * messages to a file
- *
- * @author Dmitri Snytkine
- *
- */
- class Log
- {
-
- const PREFIX_ERROR = '[ERROR] ';
-
- const PREFIX_INFO = '[INFO]';
-
- const PREFIX_DEBUG = '[DEBUG]';
-
- /**
- * Location of log file
- * it must point to actual file
- * and that file must be writable to php program
- * (usually this means writable to apache server)
- *
- * @var string
- */
- const LOG_FILE_PATH = '';
-
- /**
- *
- * You may hard-code the email of developer
- * then you don't need to define the same value in !config.ini
- * This way even if email is not defined in !config.ini
- * developers will still receive notifications
- * of all errors logged via the e() function
- *
- * @var string
- */
- const LAMPCMS_DEVELOPER_EMAIL = '';
-
-
- /**
- * Format of timestamp
- *
- * @var string
- */
- const TIME_FORMAT = "F j, Y H:i:s";
-
-
- /**
- * String to be used as a subject line
- * of email notification
- *
- * @var string
- */
- const EMAIL_SUBJECT = 'Error on your website';
-
-
- /**
- * Our main logging function
- *
- * @param string $message message to log
- * @param int $traceLevel this is useful
- * for extracting correct line from debug backtrace
- * you should normally not worry about this
- * This is useful in only some cases where you notice that
- * line number/method name is not logged correctly
- *
- * @param string $logType
- *
- * @return string message that was just logged
- */
- public static function l($message, $traceLevel = 0, $logType = self::DEBUG_LEVEL)
- {
- $logPath = self::getLogPath();
-
- if (empty($logPath)) {
-
- return;
- }
-
- /**
- * automatically stringify array
- * in case we want to just add array to log
- */
- $str = (\is_array($message)) ? \json_encode($message, true) : $message;
-
- $string = '';
- $line = 'unknown';
-
- /**
- * Passing the false as param
- * will reduce the size of backtrace object, sometimes considerably
- * because by default, this value is true and it means
- * that each object of backtrace is dumped!
- *
- */
- $arrBacktrace = \debug_backtrace(false);
-
- /**
- * Special case: if the ->log() called from an object
- * that does not directly extend this class but has the __call() method
- * then the __call() would pass the log() to the upstream object (this object)
- *
- * in such case the level 1 will be the __call method itself
- * and the level 2 will be the actual method that invoked the __call
- *
- * In a case like this we are interested in level2 of backtrace!
- */
- if (\array_key_exists(1, $arrBacktrace)) {
- if ('__call' === $arrBacktrace[1]['function']) {
-
- $traceLevel += 2;
-
- } elseif ('call_user_func_array' === $arrBacktrace[1]['function']) {
-
- $traceLevel += 3;
- }
- }
-
- $level1 = $traceLevel + 1;
- if (!empty($arrBacktrace[$level1])) {
- if (!empty($arrBacktrace[$level1]['class'])) {
- $string .= $arrBacktrace[$level1]['class'];
- $gotClass = true;
- if (!empty($arrBacktrace[$level1]['type'])) {
- $string .= $arrBacktrace[$level1]['type'];
- }
- }
-
- if (!empty($arrBacktrace[$level1]['function'])) {
- $string .= $arrBacktrace[$level1]['function'] . '() ';
- }
- }
-
- if (!empty($arrBacktrace[$traceLevel])) {
- if (!isset($gotClass) && !empty($arrBacktrace[$traceLevel]['file'])) {
- $string .= $arrBacktrace[$traceLevel]['file'] . ' ';
- }
-
- if (!empty($arrBacktrace[$traceLevel]['line'])) {
- $line = $arrBacktrace[$traceLevel]['line'];
- }
-
- $string .= '[' . $line . '] ';
- }
-
- //$string .= PHP_EOL . $str;
- $string .= $str;
-
- $message = PHP_EOL . self::getTimeStamp() . ' ' . $logType . ' ' . $string;
-
- $res = \file_put_contents($logPath, $message, FILE_APPEND | LOCK_EX);
-
- return $message;
- }
-
-
- /**
- * Log debug message. The debug messages
- * are NOT logged in normal production environment
- * Debugging messages are logged
- * ONLY when global constant LAMPCMS_DEBUG is set to true
- *
- *
- * @param string $message message to log
- * @param int $level
- *
- * @return string
- */
- public static function d($message, $level = 0)
- {
-
- /**
- * Increase backtrace level to one
- * to account to delegating from this
- * method to log() method
- */
- return self::l($message, ++$level, self::PREFIX_DEBUG);
- }
-
-
- /**
- * Log debug message. The debug messages
- * are NOT logged in normal production environment
- * Debugging messages are logged
- * ONLY when global constant LAMPCMS_DEBUG is set to true
- *
- *
- * @param string $message message to log
- * @param int $level
- *
- * @return string
- */
- public static function info($message, $level = 0)
- {
-
- /**
- * Increase backtrace level to one
- * to account to delegating from this
- * method to log() method
- */
- return self::l($message, ++$level, self::PREFIX_INFO);
- }
-
-
- /**
- * Log error message. The main difference
- * between using this method and normal log()
- * is that email will also be sent to admin
- *
- * @param string $message message to log
- * @param int $level debug backtrace offset level
- *
- * @return string
- */
- public static function e($message, $level = 0)
- {
- /**
- * Increase backtrace level to one
- * to account to delegating from this
- * method to log() method
- */
- $message = self::l($message, ++$level, self::PREFIX_ERROR);
-
- self::notifyDeveloper($message);
-
- return $message;
- }
-
-
- /**
- * Get path to log file
- * If global constant LOG_FILE_PATH is defined
- * then use it, otherwise use
- * this class's constant
- *
- * @return string a path to log file
- *
- */
- protected static function getLogPath()
- {
- if (defined('SPECIAL_LOG_FILE')) {
- return SPECIAL_LOG_FILE;
- }
-
- return (defined('LOG_FILE_PATH')) ? LOG_FILE_PATH : self::LOG_FILE_PATH;
- }
-
-
- /**
- * Sends email message to developer
- * if message contains error pattern
- *
- * @param string $message message to send to developers
- *
- * @return void
- */
- protected static function notifyDeveloper($message)
- {
- global $Mailer;
-
- $devEmail = self::getDevEmail();
-
- if (empty($devEmail)) {
- return;
- }
-
- $msg = $message;
-
- $ua = self::getServerVar('HTTP_USER_AGENT');
- /**
- * Do NOT send out any errors generated from MSIE 6.0 browsers
- *
- */
- if (isset($_SERVER) && is_array($_SERVER) && (false === \strstr($ua, 'MSIE 6.0'))) {
- $msg .= "\n" . '-----------------------------------------------------';
- $msg .= "\n" . 'HTTP_HOST: ' . self::getServerVar('HTTP_HOST');
- $msg .= "\n" . 'SCRIPT_NAME: ' . self::getServerVar('SCRIPT_NAME');
- $msg .= "\n" . 'REQUEST_METHOD: ' . self::getServerVar('REQUEST_METHOD');
- $msg .= "\n" . 'REQUEST_URI: ' . self::getServerVar('REQUEST_URI');
- $msg .= "\n" . 'SCRIPT_FILENAME: ' . self::getServerVar('SCRIPT_FILENAME');
- $msg .= "\n" . '-----------------------------------------------------';
- $msg .= "\n" . 'HTTP_USER_AGENT: ' . $ua;
- $msg .= "\n" . 'HTTP_REFERER: ' . self::getServerVar('HTTP_REFERER');
- $msg .= "\n" . '-----------------------------------------------------';
- $msg .= "\n" . 'REMOTE_ADDR/IP: ' . self::getServerVar('REMOTE_ADDR');
- $msg .= PHP_EOL . 'REQUEST HEADERS: ' . Request::getAllHeadersAsString();
-
- if (Request::isPost()) {
- $msg .= "\n" . '-----------------------------------------------------';
- $msg .= "\n" . 'POST: ' . \print_r($_POST, true);
- }
-
- /**
- * Add high priority to email headers
- * for error messages of certain types (real errors, no notices)
- */
- $headers = 'X-Mailer: LogObserver' . "\n" . 'X-Priority: 1' . "\n" . 'Importance: High' . "\n" . 'X-MSMail-Priority: High';
- /**
- * Attempt to use Mailer object, then fallback to php's mail()
- */
- $ER = error_reporting(0);
- if (is_object($Mailer)) {
- try {
- $Mailer->mail($devEmail, self::EMAIL_SUBJECT, $msg, null, false);
- } catch ( \Exception $e ) {
- @mail($devEmail, self::EMAIL_SUBJECT, $msg, $headers);
- }
- } else {
- @mail($devEmail, self::EMAIL_SUBJECT, $msg, $headers);
- }
- error_reporting($ER);
- }
-
- return;
- }
-
-
- /**
- * Get value from global $_SERVER array
- * if it exists, otherwise return just an empty string
- *
- * @param string $var
- *
- * @return string value of $var or empty string
- */
- protected static function getServerVar($var)
- {
- return (\array_key_exists($var, $_SERVER)) ? $_SERVER[$var] : '';
- }
-
-
- /**
- * Get string representation of
- * current timestamp
- *
- * @return string a formatted timestamp
- */
- protected static function getTimeStamp()
- {
- return date(self::TIME_FORMAT) . ' ';
- }
-
-
- /**
- * Get email address of developer
- * if global constant LAMPCMS_DEVELOPER_EMAIL exists
- * then return it, otherwise return this class's
- * self::LAMPCMS_DEVELOPER_EMAIL
- *
- *
- * @return string email address of developer
- */
- protected static function getDevEmail()
- {
- return defined('LAMPCMS_DEVELOPER_EMAIL') ? LAMPCMS_DEVELOPER_EMAIL : self::LAMPCMS_DEVELOPER_EMAIL;
- }
-
- }