Spade

Mini Shell

Directory:~$ /home/lmsyaran/public_html/joomla4/
Upload File

[Home] [System Details] [Kill Me]
Current File:~$ /home/lmsyaran/public_html/joomla4/Log.tar

DelegatingPsrLogger.php000064400000005335151156443440011162
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log;

defined('JPATH_PLATFORM') or die;

use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException;
use Psr\Log\LogLevel;

/**
 * Delegating logger which delegates log messages received from the PSR-3
interface to the Joomla! Log object.
 *
 * @since  3.8.0
 */
class DelegatingPsrLogger extends AbstractLogger
{
	/**
	 * The Log instance to delegate messages to.
	 *
	 * @var    Log
	 * @since  3.8.0
	 */
	protected $logger;

	/**
	 * Mapping array to map a PSR-3 level to a Joomla priority.
	 *
	 * @var    array
	 * @since  3.8.0
	 */
	protected $priorityMap = array(
		LogLevel::EMERGENCY => Log::EMERGENCY,
		LogLevel::ALERT     => Log::ALERT,
		LogLevel::CRITICAL  => Log::CRITICAL,
		LogLevel::ERROR     => Log::ERROR,
		LogLevel::WARNING   => Log::WARNING,
		LogLevel::NOTICE    => Log::NOTICE,
		LogLevel::INFO      => Log::INFO,
		LogLevel::DEBUG     => Log::DEBUG
	);

	/**
	 * Constructor.
	 *
	 * @param   Log  $logger  The Log instance to delegate messages to.
	 *
	 * @since   3.8.0
	 */
	public function __construct(Log $logger)
	{
		$this->logger = $logger;
	}

	/**
	 * Logs with an arbitrary level.
	 *
	 * @param   mixed   $level    The log level.
	 * @param   string  $message  The log message.
	 * @param   array   $context  Additional message context.
	 *
	 * @return  void
	 *
	 * @since   3.8.0
	 * @throws  InvalidArgumentException
	 */
	public function log($level, $message, array $context = array())
	{
		// Make sure the log level is valid
		if (!array_key_exists($level, $this->priorityMap))
		{
			throw new \InvalidArgumentException('An invalid log level has been
given.');
		}

		// Map the level to Joomla's priority
		$priority = $this->priorityMap[$level];

		$category = null;
		$date     = null;

		// If a message category is given, map it
		if (!empty($context['category']))
		{
			$category = $context['category'];
		}

		// If a message timestamp is given, map it
		if (!empty($context['date']))
		{
			$date = $context['date'];
		}

		// Joomla's logging API will only process a string or a LogEntry
object, if $message is an object without __toString() we can't use it
		if (!is_string($message) && !($message instanceof LogEntry))
		{
			if (!is_object($message) || !method_exists($message,
'__toString'))
			{
				throw new \InvalidArgumentException(
					'The message must be a string, a LogEntry object, or an object
implementing the __toString() method.'
				);
			}

			$message = (string) $message;
		}

		$this->logger->add($message, $priority, $category, $date,
$context);
	}
}
Log.php000064400000022246151156443440006013 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log;

defined('JPATH_PLATFORM') or die;

/**
 * Joomla! Log Class
 *
 * This class hooks into the global log configuration settings to allow for
user configured
 * logging events to be sent to where the user wishes them to be sent. On
high load sites
 * Syslog is probably the best (pure PHP function), then the text file
based loggers (CSV, W3c
 * or plain Formattedtext) and finally MySQL offers the most features (e.g.
rapid searching)
 * but will incur a performance hit due to INSERT being issued.
 *
 * @since  1.7.0
 */
class Log
{
	/**
	 * All log priorities.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const ALL = 30719;

	/**
	 * The system is unusable.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const EMERGENCY = 1;

	/**
	 * Action must be taken immediately.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const ALERT = 2;

	/**
	 * Critical conditions.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const CRITICAL = 4;

	/**
	 * Error conditions.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const ERROR = 8;

	/**
	 * Warning conditions.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const WARNING = 16;

	/**
	 * Normal, but significant condition.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const NOTICE = 32;

	/**
	 * Informational message.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const INFO = 64;

	/**
	 * Debugging message.
	 *
	 * @var    integer
	 * @since  1.7.0
	 */
	const DEBUG = 128;

	/**
	 * The global Log instance.
	 *
	 * @var    Log
	 * @since  1.7.0
	 */
	protected static $instance;

	/**
	 * Container for Logger configurations.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $configurations = array();

	/**
	 * Container for Logger objects.
	 *
	 * @var    Logger[]
	 * @since  1.7.0
	 */
	protected $loggers = array();

	/**
	 * Lookup array for loggers.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $lookup = array();

	/**
	 * Constructor.
	 *
	 * @since   1.7.0
	 */
	protected function __construct()
	{
	}

	/**
	 * Method to add an entry to the log.
	 *
	 * @param   mixed    $entry     The LogEntry object to add to the log or
the message for a new LogEntry object.
	 * @param   integer  $priority  Message priority.
	 * @param   string   $category  Type of entry
	 * @param   string   $date      Date of entry (defaults to now if not
specified or blank)
	 * @param   array    $context   An optional array with additional message
context.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	public static function add($entry, $priority = self::INFO, $category =
'', $date = null, array $context = array())
	{
		// Automatically instantiate the singleton object if not already done.
		if (empty(static::$instance))
		{
			static::setInstance(new Log);
		}

		// If the entry object isn't a LogEntry object let's make one.
		if (!($entry instanceof LogEntry))
		{
			$entry = new LogEntry((string) $entry, $priority, $category, $date,
$context);
		}

		static::$instance->addLogEntry($entry);
	}

	/**
	 * Add a logger to the Log instance.  Loggers route log entries to the
correct files/systems to be logged.
	 *
	 * @param   array    $options     The object configuration array.
	 * @param   integer  $priorities  Message priority
	 * @param   array    $categories  Types of entry
	 * @param   boolean  $exclude     If true, all categories will be logged
except those in the $categories array
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	public static function addLogger(array $options, $priorities = self::ALL,
$categories = array(), $exclude = false)
	{
		// Automatically instantiate the singleton object if not already done.
		if (empty(static::$instance))
		{
			static::setInstance(new Log);
		}

		static::$instance->addLoggerInternal($options, $priorities,
$categories, $exclude);
	}

	/**
	 * Add a logger to the Log instance.  Loggers route log entries to the
correct files/systems to be logged.
	 * This method allows you to extend Log completely.
	 *
	 * @param   array    $options     The object configuration array.
	 * @param   integer  $priorities  Message priority
	 * @param   array    $categories  Types of entry
	 * @param   boolean  $exclude     If true, all categories will be logged
except those in the $categories array
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	protected function addLoggerInternal(array $options, $priorities =
self::ALL, $categories = array(), $exclude = false)
	{
		// The default logger is the formatted text log file.
		if (empty($options['logger']))
		{
			$options['logger'] = 'formattedtext';
		}

		$options['logger'] = strtolower($options['logger']);

		// Special case - if a Closure object is sent as the callback (in case of
CallbackLogger)
		// Closure objects are not serializable so swap it out for a unique id
first then back again later
		if (isset($options['callback']))
		{
			if (is_a($options['callback'], 'closure'))
			{
				$callback = $options['callback'];
				$options['callback'] =
spl_object_hash($options['callback']);
			}
			elseif (is_array($options['callback']) &&
count($options['callback']) == 2 &&
is_object($options['callback'][0]))
			{
				$callback = $options['callback'];
				$options['callback'] =
spl_object_hash($options['callback'][0]) . '::' .
$options['callback'][1];
			}
		}

		// Generate a unique signature for the Log instance based on its options.
		$signature = md5(serialize($options));

		// Now that the options array has been serialized, swap the callback back
in
		if (isset($callback))
		{
			$options['callback'] = $callback;
		}

		// Register the configuration if it doesn't exist.
		if (empty($this->configurations[$signature]))
		{
			$this->configurations[$signature] = $options;
		}

		$this->lookup[$signature] = (object) array(
			'priorities' => $priorities,
			'categories' => array_map('strtolower', (array)
$categories),
			'exclude' => (bool) $exclude,
		);
	}

	/**
	 * Creates a delegated PSR-3 compatible logger from the current singleton
instance. This method always returns a new delegated logger.
	 *
	 * @return  DelegatingPsrLogger
	 *
	 * @since   3.8.0
	 */
	public static function createDelegatedLogger()
	{
		// Ensure a singleton instance has been created first
		if (empty(static::$instance))
		{
			static::setInstance(new static);
		}

		return new DelegatingPsrLogger(static::$instance);
	}

	/**
	 * Returns a reference to the a Log object, only creating it if it
doesn't already exist.
	 * Note: This is principally made available for testing and internal
purposes.
	 *
	 * @param   Log  $instance  The logging object instance to be used by the
static methods.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	public static function setInstance($instance)
	{
		if (($instance instanceof Log) || $instance === null)
		{
			static::$instance = & $instance;
		}
	}

	/**
	 * Method to add an entry to the appropriate loggers.
	 *
	 * @param   LogEntry  $entry  The LogEntry object to send to the loggers.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 * @throws  \RuntimeException
	 */
	protected function addLogEntry(LogEntry $entry)
	{
		// Find all the appropriate loggers based on priority and category for
the entry.
		$loggers = $this->findLoggers($entry->priority,
$entry->category);

		foreach ((array) $loggers as $signature)
		{
			// Attempt to instantiate the logger object if it doesn't already
exist.
			if (empty($this->loggers[$signature]))
			{
				$class = __NAMESPACE__ . '\\Logger\\' .
ucfirst($this->configurations[$signature]['logger']) .
'Logger';

				if (!class_exists($class))
				{
					throw new \RuntimeException('Unable to create a Logger instance:
' . $class);
				}

				$this->loggers[$signature] = new
$class($this->configurations[$signature]);
			}

			// Add the entry to the logger.
			$this->loggers[$signature]->addEntry(clone $entry);
		}
	}

	/**
	 * Method to find the loggers to use based on priority and category
values.
	 *
	 * @param   integer  $priority  Message priority.
	 * @param   string   $category  Type of entry
	 *
	 * @return  array  The array of loggers to use for the given priority and
category values.
	 *
	 * @since   1.7.0
	 */
	protected function findLoggers($priority, $category)
	{
		$loggers = array();

		// Sanitize inputs.
		$priority = (int) $priority;
		$category = strtolower($category);

		// Let's go iterate over the loggers and get all the ones we need.
		foreach ((array) $this->lookup as $signature => $rules)
		{
			// Check to make sure the priority matches the logger.
			if ($priority & $rules->priorities)
			{
				if ($rules->exclude)
				{
					// If either there are no set categories or the category (including
the empty case) is not in the list of excluded categories, add this logger.
					if (empty($rules->categories) || !in_array($category,
$rules->categories))
					{
						$loggers[] = $signature;
					}
				}
				else
				{
					// If either there are no set categories (meaning all) or the specific
category is set, add this logger.
					if (empty($rules->categories) || in_array($category,
$rules->categories))
					{
						$loggers[] = $signature;
					}
				}
			}
		}

		return $loggers;
	}
}
LogEntry.php000064400000005153151156443440007033 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Date\Date;

/**
 * Joomla! Log Entry class
 *
 * This class is designed to hold log entries for either writing to an
engine, or for
 * supported engines, retrieving lists and building in memory (PHP based)
search operations.
 *
 * @since  1.7.0
 */
class LogEntry
{
	/**
	 * Application responsible for log entry.
	 * @var    string
	 * @since  1.7.0
	 */
	public $category;

	/**
	 * The message context.
	 *
	 * @var    array
	 * @since  3.8.0
	 */
	public $context;

	/**
	 * The date the message was logged.
	 * @var    Date
	 * @since  1.7.0
	 */
	public $date;

	/**
	 * Message to be logged.
	 * @var    string
	 * @since  1.7.0
	 */
	public $message;

	/**
	 * The priority of the message to be logged.
	 * @var    string
	 * @since  1.7.0
	 * @see    LogEntry::$priorities
	 */
	public $priority = Log::INFO;

	/**
	 * List of available log priority levels [Based on the Syslog default
levels].
	 * @var    array
	 * @since  1.7.0
	 */
	protected $priorities = array(
		Log::EMERGENCY,
		Log::ALERT,
		Log::CRITICAL,
		Log::ERROR,
		Log::WARNING,
		Log::NOTICE,
		Log::INFO,
		Log::DEBUG,
	);

	/**
	 * Call stack and back trace of the logged call.
	 * @var    array
	 * @since  3.1.4
	 */
	public $callStack = array();

	/**
	 * Constructor
	 *
	 * @param   string  $message   The message to log.
	 * @param   int     $priority  Message priority based on
{$this->priorities}.
	 * @param   string  $category  Type of entry
	 * @param   string  $date      Date of entry (defaults to now if not
specified or blank)
	 * @param   array   $context   An optional array with additional message
context.
	 *
	 * @since   1.7.0
	 */
	public function __construct($message, $priority = Log::INFO, $category =
'', $date = null, array $context = array())
	{
		$this->message = (string) $message;

		// Sanitize the priority.
		if (!in_array($priority, $this->priorities, true))
		{
			$priority = Log::INFO;
		}

		$this->priority = $priority;
		$this->context  = $context;

		// Sanitize category if it exists.
		if (!empty($category))
		{
			$this->category = (string)
strtolower(preg_replace('/[^A-Z0-9_\.-]/i', '',
$category));
		}

		// Get the current call stack and back trace (without args to save
memory).
		$this->callStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

		// Get the date as a Date object.
		$this->date = new Date($date ? $date : 'now');
	}
}
Logger/CallbackLogger.php000064400000003123151156443440011336
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log\Logger;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;

/**
 * Joomla! Callback Log class
 *
 * This class allows logging to be handled by a callback function.
 * This allows unprecedented flexibility in the way logging can be handled.
 *
 * @since  3.0.1
 */
class CallbackLogger extends Logger
{
	/**
	 * The function to call when an entry is added
	 *
	 * @var    callable
	 * @since  3.0.1
	 */
	protected $callback;

	/**
	 * Constructor.
	 *
	 * @param   array  &$options  Log object options.
	 *
	 * @since   3.0.1
	 * @throws  \RuntimeException
	 */
	public function __construct(array &$options)
	{
		// Call the parent constructor.
		parent::__construct($options);

		// Throw an exception if there is not a valid callback
		if (!isset($this->options['callback']) ||
!is_callable($this->options['callback']))
		{
			throw new \RuntimeException(sprintf('%s created without valid
callback function.', get_class($this)));
		}

		$this->callback = $this->options['callback'];
	}

	/**
	 * Method to add an entry to the log.
	 *
	 * @param   LogEntry  $entry  The log entry object to add to the log.
	 *
	 * @return  void
	 *
	 * @since   3.0.1
	 * @throws  \RuntimeException
	 */
	public function addEntry(LogEntry $entry)
	{
		// Pass the log entry to the callback function
		call_user_func($this->callback, $entry);
	}
}
Logger/DatabaseLogger.php000064400000007662151156443440011362
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log\Logger;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;

/**
 * Joomla! MySQL Database Log class
 *
 * This class is designed to output logs to a specific MySQL database
table. Fields in this
 * table are based on the Syslog style of log output. This is designed to
allow quick and
 * easy searching.
 *
 * @since  1.7.0
 */
class DatabaseLogger extends Logger
{
	/**
	 * The name of the database driver to use for connecting to the database.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $driver = 'mysqli';

	/**
	 * The host name (or IP) of the server with which to connect for the
logger.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $host = '127.0.0.1';

	/**
	 * The database server user to connect as for the logger.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $user = 'root';

	/**
	 * The password to use for connecting to the database server.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $password = '';

	/**
	 * The name of the database table to use for the logger.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $database = 'logging';

	/**
	 * The database table to use for logging entries.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $table = 'jos_';

	/**
	 * The database driver object for the logger.
	 *
	 * @var    \JDatabaseDriver
	 * @since  1.7.0
	 */
	protected $db;

	/**
	 * Constructor.
	 *
	 * @param   array  &$options  Log object options.
	 *
	 * @since   1.7.0
	 */
	public function __construct(array &$options)
	{
		// Call the parent constructor.
		parent::__construct($options);

		// If both the database object and driver options are empty we want to
use the system database connection.
		if (empty($this->options['db_driver']))
		{
			$this->db = \JFactory::getDbo();
			$this->driver = null;
			$this->host = null;
			$this->user = null;
			$this->password = null;
			$this->database = null;
			$this->prefix = null;
		}
		else
		{
			$this->db = null;
			$this->driver = (empty($this->options['db_driver'])) ?
'mysqli' : $this->options['db_driver'];
			$this->host = (empty($this->options['db_host'])) ?
'127.0.0.1' : $this->options['db_host'];
			$this->user = (empty($this->options['db_user'])) ?
'root' : $this->options['db_user'];
			$this->password = (empty($this->options['db_pass'])) ?
'' : $this->options['db_pass'];
			$this->database = (empty($this->options['db_database']))
? 'logging' : $this->options['db_database'];
			$this->prefix = (empty($this->options['db_prefix'])) ?
'jos_' : $this->options['db_prefix'];
		}

		// The table name is independent of how we arrived at the connection
object.
		$this->table = (empty($this->options['db_table'])) ?
'#__log_entries' : $this->options['db_table'];
	}

	/**
	 * Method to add an entry to the log.
	 *
	 * @param   LogEntry  $entry  The log entry object to add to the log.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 * @throws  \RuntimeException
	 */
	public function addEntry(LogEntry $entry)
	{
		// Connect to the database if not connected.
		if (empty($this->db))
		{
			$this->connect();
		}

		// Convert the date.
		$entry->date = $entry->date->toSql(false, $this->db);

		$this->db->insertObject($this->table, $entry);
	}

	/**
	 * Method to connect to the database server based on object properties.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 * @throws  \RuntimeException
	 */
	protected function connect()
	{
		// Build the configuration object to use for JDatabaseDriver.
		$options = array(
			'driver' => $this->driver,
			'host' => $this->host,
			'user' => $this->user,
			'password' => $this->password,
			'database' => $this->database,
			'prefix' => $this->prefix,
		);

		$this->db = \JDatabaseDriver::getInstance($options);
	}
}
Logger/EchoLogger.php000064400000002410151156443440010516 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log\Logger;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;

/**
 * Joomla Echo logger class.
 *
 * @since  1.7.0
 */
class EchoLogger extends Logger
{
	/**
	 * Value to use at the end of an echoed log entry to separate lines.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $line_separator = "\n";

	/**
	 * Constructor.
	 *
	 * @param   array  &$options  Log object options.
	 *
	 * @since   3.0.0
	 */
	public function __construct(array &$options)
	{
		parent::__construct($options);

		if (!empty($this->options['line_separator']))
		{
			$this->line_separator =
$this->options['line_separator'];
		}
	}

	/**
	 * Method to add an entry to the log.
	 *
	 * @param   LogEntry  $entry  The log entry object to add to the log.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	public function addEntry(LogEntry $entry)
	{
		echo $this->priorities[$entry->priority] . ': '
			. $entry->message . (empty($entry->category) ? '' :
' [' . $entry->category . ']')
			. $this->line_separator;
	}
}
Logger/FormattedtextLogger.php000064400000016535151156443440012507
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log\Logger;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;
use Joomla\Utilities\IpHelper;

\JLoader::import('joomla.filesystem.file');
\JLoader::import('joomla.filesystem.folder');

/**
 * Joomla! Formatted Text File Log class
 *
 * This class is designed to use as a base for building formatted text
files for output. By
 * default it emulates the Syslog style format output. This is a disk based
output format.
 *
 * @since  1.7.0
 */
class FormattedtextLogger extends Logger
{
	/**
	 * The format which each entry follows in the log file.
	 *
	 * All fields must be named in all caps and be within curly brackets eg.
{FOOBAR}.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $format = '{DATETIME}	{PRIORITY}
{CLIENTIP}	{CATEGORY}	{MESSAGE}';

	/**
	 * The parsed fields from the format string.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $fields = array();

	/**
	 * The full filesystem path for the log file.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $path;

	/**
	 * If true, all writes will be deferred as long as possible.
	 * NOTE: Deferred logs may never be written if the application encounters
a fatal error.
	 *
	 * @var    boolean
	 * @since  3.9.0
	 */
	protected $defer = false;

	/**
	 * If deferring, entries will be stored here prior to writing.
	 *
	 * @var    array
	 * @since  3.9.0
	 */
	protected $deferredEntries = array();

	/**
	 * Constructor.
	 *
	 * @param   array  &$options  Log object options.
	 *
	 * @since   1.7.0
	 */
	public function __construct(array &$options)
	{
		// Call the parent constructor.
		parent::__construct($options);

		// The name of the text file defaults to 'error.php' if not
explicitly given.
		if (empty($this->options['text_file']))
		{
			$this->options['text_file'] = 'error.php';
		}

		// The name of the text file path defaults to that which is set in
configuration if not explicitly given.
		if (empty($this->options['text_file_path']))
		{
			$this->options['text_file_path'] =
\JFactory::getConfig()->get('log_path');
		}

		// False to treat the log file as a php file.
		if (empty($this->options['text_file_no_php']))
		{
			$this->options['text_file_no_php'] = false;
		}

		// Build the full path to the log file.
		$this->path = $this->options['text_file_path'] .
'/' . $this->options['text_file'];

		// Use the default entry format unless explicitly set otherwise.
		if (!empty($this->options['text_entry_format']))
		{
			$this->format = (string)
$this->options['text_entry_format'];
		}

		// Wait as long as possible before writing logs
		if (!empty($this->options['defer']))
		{
			$this->defer = (boolean) $this->options['defer'];
		}

		// Build the fields array based on the format string.
		$this->parseFields();
	}

	/**
	 * If deferred, write all pending logs.
	 *
	 * @since  3.9.0
	 */
	public function __destruct()
	{
		// Nothing to do
		if (!$this->defer || empty($this->deferredEntries))
		{
			return;
		}

		// Initialise the file if not already done.
		$this->initFile();

		// Format all lines and write to file.
		$lines = array_map(array($this, 'formatLine'),
$this->deferredEntries);

		if (!\JFile::append($this->path, implode("\n", $lines) .
"\n"))
		{
			throw new \RuntimeException('Cannot write to log file.');
		}
	}

	/**
	 * Method to add an entry to the log.
	 *
	 * @param   LogEntry  $entry  The log entry object to add to the log.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 * @throws  \RuntimeException
	 */
	public function addEntry(LogEntry $entry)
	{
		// Store the entry to be written later.
		if ($this->defer)
		{
			$this->deferredEntries[] = $entry;
		}
		// Write it immediately.
		else
		{
			// Initialise the file if not already done.
			$this->initFile();

			// Write the new entry to the file.
			$line = $this->formatLine($entry);
			$line .= "\n";

			if (!\JFile::append($this->path, $line))
			{
				throw new \RuntimeException('Cannot write to log file.');
			}
		}
	}

	/**
	 * Format a line for the log file.
	 *
	 * @param   JLogEntry  $entry  The log entry to format as a string.
	 *
	 * @return  String
	 *
	 * @since  3.9.0
	 */
	protected function formatLine(LogEntry $entry)
	{
		// Set some default field values if not already set.
		if (!isset($entry->clientIP))
		{
			$ip = IpHelper::getIp();

			if ($ip !== '')
			{
				$entry->clientIP = $ip;
			}
		}

		// If the time field is missing or the date field isn't only the
date we need to rework it.
		if ((strlen($entry->date) != 10) || !isset($entry->time))
		{
			// Get the date and time strings in GMT.
			$entry->datetime = $entry->date->toISO8601();
			$entry->time = $entry->date->format('H:i:s', false);
			$entry->date = $entry->date->format('Y-m-d', false);
		}

		// Get a list of all the entry keys and make sure they are upper case.
		$tmp = array_change_key_case(get_object_vars($entry), CASE_UPPER);

		// Decode the entry priority into an English string.
		$tmp['PRIORITY'] = $this->priorities[$entry->priority];

		// Fill in field data for the line.
		$line = $this->format;

		foreach ($this->fields as $field)
		{
			$line = str_replace('{' . $field . '}',
(isset($tmp[$field])) ? $tmp[$field] : '-', $line);
		}

		return $line;
	}

	/**
	 * Method to generate the log file header.
	 *
	 * @return  string  The log file header
	 *
	 * @since   1.7.0
	 */
	protected function generateFileHeader()
	{
		$head = array();

		// Build the log file header.

		// If the no php flag is not set add the php die statement.
		if (empty($this->options['text_file_no_php']))
		{
			// Blank line to prevent information disclose:
https://bugs.php.net/bug.php?id=60677
			$head[] = '#';
			$head[] = '#<?php die(\'Forbidden.\'); ?>';
		}

		$head[] = '#Date: ' . gmdate('Y-m-d H:i:s') . '
UTC';
		$head[] = '#Software: ' . \JPlatform::getLongVersion();
		$head[] = '';

		// Prepare the fields string
		$head[] = '#Fields: ' . strtolower(str_replace('}',
'', str_replace('{', '', $this->format)));
		$head[] = '';

		return implode("\n", $head);
	}

	/**
	 * Method to initialise the log file.  This will create the folder path to
the file if it doesn't already
	 * exist and also get a new file header if the file doesn't already
exist.  If the file already exists it
	 * will simply open it for writing.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 * @throws  \RuntimeException
	 */
	protected function initFile()
	{
		// We only need to make sure the file exists
		if (\JFile::exists($this->path))
		{
			return;
		}

		// Make sure the folder exists in which to create the log file.
		\JFolder::create(dirname($this->path));

		// Build the log file header.
		$head = $this->generateFileHeader();

		if (!\JFile::write($this->path, $head))
		{
			throw new \RuntimeException('Cannot write to log file.');
		}
	}

	/**
	 * Method to parse the format string into an array of fields.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	protected function parseFields()
	{
		$this->fields = array();
		$matches = array();

		// Get all of the available fields in the format string.
		preg_match_all('/{(.*?)}/i', $this->format, $matches);

		// Build the parsed fields list based on the found fields.
		foreach ($matches[1] as $match)
		{
			$this->fields[] = strtoupper($match);
		}
	}
}
Logger/MessagequeueLogger.php000064400000002723151156443440012300
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log\Logger;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Log\Log;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;

/**
 * Joomla MessageQueue logger class.
 *
 * This class is designed to output logs to a specific MySQL database
table. Fields in this
 * table are based on the Syslog style of log output. This is designed to
allow quick and
 * easy searching.
 *
 * @since  1.7.0
 */
class MessagequeueLogger extends Logger
{
	/**
	 * Method to add an entry to the log.
	 *
	 * @param   LogEntry  $entry  The log entry object to add to the log.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	public function addEntry(LogEntry $entry)
	{
		switch ($entry->priority)
		{
			case Log::EMERGENCY:
			case Log::ALERT:
			case Log::CRITICAL:
			case Log::ERROR:
				\JFactory::getApplication()->enqueueMessage($entry->message,
'error');
				break;
			case Log::WARNING:
				\JFactory::getApplication()->enqueueMessage($entry->message,
'warning');
				break;
			case Log::NOTICE:
				\JFactory::getApplication()->enqueueMessage($entry->message,
'notice');
				break;
			case Log::INFO:
				\JFactory::getApplication()->enqueueMessage($entry->message,
'message');
				break;
			default:
				// Ignore other priorities.
				break;
		}
	}
}
Logger/SyslogLogger.php000064400000006446151156443440011135
0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log\Logger;

defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Log\Log;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger;

/**
 * Joomla! Syslog Log class
 *
 * This class is designed to call the PHP Syslog function call which is
then sent to the
 * system wide log system. For Linux/Unix based systems this is the syslog
subsystem, for
 * the Windows based implementations this can be found in the Event Log.
For Windows,
 * permissions may prevent PHP from properly outputting messages.
 *
 * @since  1.7.0
 */
class SyslogLogger extends Logger
{
	/**
	 * Translation array for LogEntry priorities to SysLog priority names.
	 *
	 * @var    array
	 * @since  1.7.0
	 */
	protected $priorities = array(
		Log::EMERGENCY => 'EMERG',
		Log::ALERT => 'ALERT',
		Log::CRITICAL => 'CRIT',
		Log::ERROR => 'ERR',
		Log::WARNING => 'WARNING',
		Log::NOTICE => 'NOTICE',
		Log::INFO => 'INFO',
		Log::DEBUG => 'DEBUG',
	);

	/**
	 * Constructor.
	 *
	 * @param   array  &$options  Log object options.
	 *
	 * @since   1.7.0
	 */
	public function __construct(array &$options)
	{
		// Call the parent constructor.
		parent::__construct($options);

		// Ensure that we have an identity string for the Syslog entries.
		if (empty($this->options['sys_ident']))
		{
			$this->options['sys_ident'] = 'Joomla Platform';
		}

		// If the option to add the process id to Syslog entries is set use it,
otherwise default to true.
		if (isset($this->options['sys_add_pid']))
		{
			$this->options['sys_add_pid'] = (bool)
$this->options['sys_add_pid'];
		}
		else
		{
			$this->options['sys_add_pid'] = true;
		}

		// If the option to also send Syslog entries to STDERR is set use it,
otherwise default to false.
		if (isset($this->options['sys_use_stderr']))
		{
			$this->options['sys_use_stderr'] = (bool)
$this->options['sys_use_stderr'];
		}
		else
		{
			$this->options['sys_use_stderr'] = false;
		}

		// Build the Syslog options from our log object options.
		$sysOptions = 0;

		if ($this->options['sys_add_pid'])
		{
			$sysOptions = $sysOptions | LOG_PID;
		}

		if ($this->options['sys_use_stderr'])
		{
			$sysOptions = $sysOptions | LOG_PERROR;
		}

		// Default logging facility is LOG_USER for Windows compatibility.
		$sysFacility = LOG_USER;

		// If we have a facility passed in and we're not on Windows, reset
it.
		if (isset($this->options['sys_facility']) &&
!IS_WIN)
		{
			$sysFacility = $this->options['sys_facility'];
		}

		// Open the Syslog connection.
		openlog((string) $this->options['sys_ident'], $sysOptions,
$sysFacility);
	}

	/**
	 * Destructor.
	 *
	 * @since   1.7.0
	 */
	public function __destruct()
	{
		closelog();
	}

	/**
	 * Method to add an entry to the log.
	 *
	 * @param   LogEntry  $entry  The log entry object to add to the log.
	 *
	 * @return  void
	 *
	 * @since   1.7.0
	 */
	public function addEntry(LogEntry $entry)
	{
		// Generate the value for the priority based on predefined constants.
		$priority = constant(strtoupper('LOG_' .
$this->priorities[$entry->priority]));

		// Send the entry to Syslog.
		syslog($priority, '[' . $entry->category . '] ' .
$entry->message);
	}
}
Logger/W3cLogger.php000064400000002257151156443440010305 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log\Logger;

defined('JPATH_PLATFORM') or die;

/**
 * Joomla! W3C Logging class
 *
 * This class is designed to build log files based on the W3C
specification.
 *
 * @link   https://www.w3.org/TR/WD-logfile.html
 * @since  1.7.0
 */
class W3cLogger extends FormattedtextLogger
{
	/**
	 * The format which each entry follows in the log file.
	 *
	 * All fields must be named in all caps and be within curly brackets eg.
{FOOBAR}.
	 *
	 * @var    string
	 * @since  1.7.0
	 */
	protected $format =
'{DATE}	{TIME}	{PRIORITY}	{CLIENTIP}	{CATEGORY}	{MESSAGE}';

	/**
	 * Constructor.
	 *
	 * @param   array  &$options  Log object options.
	 *
	 * @since   1.7.0
	 */
	public function __construct(array &$options)
	{
		// The name of the text file defaults to 'error.w3c.php' if not
explicitly given.
		if (empty($options['text_file']))
		{
			$options['text_file'] = 'error.w3c.php';
		}

		// Call the parent constructor.
		parent::__construct($options);
	}
}
Logger.php000064400000002723151156443440006507 0ustar00<?php
/**
 * Joomla! Content Management System
 *
 * @copyright  Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
 * @license    GNU General Public License version 2 or later; see
LICENSE.txt
 */

namespace Joomla\CMS\Log;

defined('JPATH_PLATFORM') or die;

/**
 * Joomla! Logger Base Class
 *
 * This class is used to be the basis of logger classes to allow for
defined functions
 * to exist regardless of the child class.
 *
 * @since  3.0.1
 */
abstract class Logger
{
	/**
	 * Options array for the JLog instance.
	 *
	 * @var    array
	 * @since  3.0.1
	 */
	protected $options = array();

	/**
	 * Translation array for LogEntry priorities to text strings.
	 *
	 * @var    array
	 * @since  3.0.1
	 */
	protected $priorities = array(
		Log::EMERGENCY => 'EMERGENCY',
		Log::ALERT     => 'ALERT',
		Log::CRITICAL  => 'CRITICAL',
		Log::ERROR     => 'ERROR',
		Log::WARNING   => 'WARNING',
		Log::NOTICE    => 'NOTICE',
		Log::INFO      => 'INFO',
		Log::DEBUG     => 'DEBUG',
	);

	/**
	 * Constructor.
	 *
	 * @param   array  &$options  Log object options.
	 *
	 * @since   3.0.1
	 */
	public function __construct(array &$options)
	{
		// Set the options for the class.
		$this->options = & $options;
	}

	/**
	 * Method to add an entry to the log.
	 *
	 * @param   LogEntry  $entry  The log entry object to add to the log.
	 *
	 * @return  void
	 *
	 * @since   3.0.1
	 * @throws  \RuntimeException
	 */
	abstract public function addEntry(LogEntry $entry);
}
AbstractLogger.php000064400000006020151157407530010166 0ustar00<?php

namespace Psr\Log;

/**
 * This is a simple Logger implementation that other Loggers can inherit
from.
 *
 * It simply delegates all log-level-specific methods to the `log` method
to
 * reduce boilerplate code that a simple Logger that does the same thing
with
 * messages regardless of the error level has to implement.
 */
abstract class AbstractLogger implements LoggerInterface
{
    /**
     * System is unusable.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function emergency($message, array $context = array())
    {
        $this->log(LogLevel::EMERGENCY, $message, $context);
    }

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function alert($message, array $context = array())
    {
        $this->log(LogLevel::ALERT, $message, $context);
    }

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function critical($message, array $context = array())
    {
        $this->log(LogLevel::CRITICAL, $message, $context);
    }

    /**
     * Runtime errors that do not require immediate action but should
typically
     * be logged and monitored.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function error($message, array $context = array())
    {
        $this->log(LogLevel::ERROR, $message, $context);
    }

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable
things
     * that are not necessarily wrong.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function warning($message, array $context = array())
    {
        $this->log(LogLevel::WARNING, $message, $context);
    }

    /**
     * Normal but significant events.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function notice($message, array $context = array())
    {
        $this->log(LogLevel::NOTICE, $message, $context);
    }

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function info($message, array $context = array())
    {
        $this->log(LogLevel::INFO, $message, $context);
    }

    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function debug($message, array $context = array())
    {
        $this->log(LogLevel::DEBUG, $message, $context);
    }
}
InvalidArgumentException.php000064400000000140151157407530012230
0ustar00<?php

namespace Psr\Log;

class InvalidArgumentException extends \InvalidArgumentException
{
}
LoggerAwareInterface.php000064400000000451151157407530011305
0ustar00<?php

namespace Psr\Log;

/**
 * Describes a logger-aware instance.
 */
interface LoggerAwareInterface
{
    /**
     * Sets a logger instance on the object.
     *
     * @param LoggerInterface $logger
     *
     * @return void
     */
    public function setLogger(LoggerInterface $logger);
}
LoggerAwareTrait.php000064400000000615151157407530010472 0ustar00<?php

namespace Psr\Log;

/**
 * Basic Implementation of LoggerAwareInterface.
 */
trait LoggerAwareTrait
{
    /**
     * The logger instance.
     *
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * Sets a logger.
     *
     * @param LoggerInterface $logger
     */
    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}
LoggerInterface.php000064400000006052151157407530010330 0ustar00<?php

namespace Psr\Log;

/**
 * Describes a logger instance.
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data. The only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named
"exception".
 *
 * See
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
interface LoggerInterface
{
    /**
     * System is unusable.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function emergency($message, array $context = array());

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function alert($message, array $context = array());

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function critical($message, array $context = array());

    /**
     * Runtime errors that do not require immediate action but should
typically
     * be logged and monitored.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function error($message, array $context = array());

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable
things
     * that are not necessarily wrong.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function warning($message, array $context = array());

    /**
     * Normal but significant events.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function notice($message, array $context = array());

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function info($message, array $context = array());

    /**
     * Detailed debug information.
     *
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     */
    public function debug($message, array $context = array());

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed   $level
     * @param string  $message
     * @param mixed[] $context
     *
     * @return void
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log($level, $message, array $context = array());
}
LoggerTrait.php000064400000006527151157407530007522 0ustar00<?php

namespace Psr\Log;

/**
 * This is a simple Logger trait that classes unable to extend
AbstractLogger
 * (because they extend another class, etc) can include.
 *
 * It simply delegates all log-level-specific methods to the `log` method
to
 * reduce boilerplate code that a simple Logger that does the same thing
with
 * messages regardless of the error level has to implement.
 */
trait LoggerTrait
{
    /**
     * System is unusable.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function emergency($message, array $context = array())
    {
        $this->log(LogLevel::EMERGENCY, $message, $context);
    }

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function alert($message, array $context = array())
    {
        $this->log(LogLevel::ALERT, $message, $context);
    }

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function critical($message, array $context = array())
    {
        $this->log(LogLevel::CRITICAL, $message, $context);
    }

    /**
     * Runtime errors that do not require immediate action but should
typically
     * be logged and monitored.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function error($message, array $context = array())
    {
        $this->log(LogLevel::ERROR, $message, $context);
    }

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable
things
     * that are not necessarily wrong.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function warning($message, array $context = array())
    {
        $this->log(LogLevel::WARNING, $message, $context);
    }

    /**
     * Normal but significant events.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function notice($message, array $context = array())
    {
        $this->log(LogLevel::NOTICE, $message, $context);
    }

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function info($message, array $context = array())
    {
        $this->log(LogLevel::INFO, $message, $context);
    }

    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param array  $context
     *
     * @return void
     */
    public function debug($message, array $context = array())
    {
        $this->log(LogLevel::DEBUG, $message, $context);
    }

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed  $level
     * @param string $message
     * @param array  $context
     *
     * @return void
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    abstract public function log($level, $message, array $context =
array());
}
LogLevel.php000064400000000520151157407530006773 0ustar00<?php

namespace Psr\Log;

/**
 * Describes log levels.
 */
class LogLevel
{
    const EMERGENCY = 'emergency';
    const ALERT     = 'alert';
    const CRITICAL  = 'critical';
    const ERROR     = 'error';
    const WARNING   = 'warning';
    const NOTICE    = 'notice';
    const INFO      = 'info';
    const DEBUG     = 'debug';
}
NullLogger.php000064400000001303151157407530007334 0ustar00<?php

namespace Psr\Log;

/**
 * This Logger can be used to avoid conditional log calls.
 *
 * Logging should always be optional, and if no logger is provided to your
 * library creating a NullLogger instance to have something to throw logs
at
 * is a good way to avoid littering your code with `if ($this->logger) {
}`
 * blocks.
 */
class NullLogger extends AbstractLogger
{
    /**
     * Logs with an arbitrary level.
     *
     * @param mixed  $level
     * @param string $message
     * @param array  $context
     *
     * @return void
     *
     * @throws \Psr\Log\InvalidArgumentException
     */
    public function log($level, $message, array $context = array())
    {
        // noop
    }
}
Test/DummyTest.php000064400000000373151161773140010140 0ustar00<?php

namespace Psr\Log\Test;

/**
 * This class is internal and does not follow the BC promise.
 *
 * Do NOT use this class in any way.
 *
 * @internal
 */
class DummyTest
{
    public function __toString()
    {
        return 'DummyTest';
    }
}
Test/LoggerInterfaceTest.php000064400000011051151161773140012100
0ustar00<?php

namespace Psr\Log\Test;

use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use PHPUnit\Framework\TestCase;

/**
 * Provides a base test class for ensuring compliance with the
LoggerInterface.
 *
 * Implementors can extend the class and implement abstract methods to run
this
 * as part of their test suite.
 */
abstract class LoggerInterfaceTest extends TestCase
{
    /**
     * @return LoggerInterface
     */
    abstract public function getLogger();

    /**
     * This must return the log messages in order.
     *
     * The simple formatting of the messages is: "<LOG LEVEL>
<MESSAGE>".
     *
     * Example ->error('Foo') would yield "error
Foo".
     *
     * @return string[]
     */
    abstract public function getLogs();

    public function testImplements()
    {
        $this->assertInstanceOf('Psr\Log\LoggerInterface',
$this->getLogger());
    }

    /**
     * @dataProvider provideLevelsAndMessages
     */
    public function testLogsAtAllLevels($level, $message)
    {
        $logger = $this->getLogger();
        $logger->{$level}($message, array('user' =>
'Bob'));
        $logger->log($level, $message, array('user' =>
'Bob'));

        $expected = array(
            $level.' message of level '.$level.' with
context: Bob',
            $level.' message of level '.$level.' with
context: Bob',
        );
        $this->assertEquals($expected, $this->getLogs());
    }

    public function provideLevelsAndMessages()
    {
        return array(
            LogLevel::EMERGENCY => array(LogLevel::EMERGENCY,
'message of level emergency with context: {user}'),
            LogLevel::ALERT => array(LogLevel::ALERT, 'message of
level alert with context: {user}'),
            LogLevel::CRITICAL => array(LogLevel::CRITICAL,
'message of level critical with context: {user}'),
            LogLevel::ERROR => array(LogLevel::ERROR, 'message of
level error with context: {user}'),
            LogLevel::WARNING => array(LogLevel::WARNING, 'message
of level warning with context: {user}'),
            LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of
level notice with context: {user}'),
            LogLevel::INFO => array(LogLevel::INFO, 'message of
level info with context: {user}'),
            LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of
level debug with context: {user}'),
        );
    }

    /**
     * @expectedException \Psr\Log\InvalidArgumentException
     */
    public function testThrowsOnInvalidLevel()
    {
        $logger = $this->getLogger();
        $logger->log('invalid level', 'Foo');
    }

    public function testContextReplacement()
    {
        $logger = $this->getLogger();
        $logger->info('{Message {nothing} {user} {foo.bar}
a}', array('user' => 'Bob', 'foo.bar'
=> 'Bar'));

        $expected = array('info {Message {nothing} Bob Bar a}');
        $this->assertEquals($expected, $this->getLogs());
    }

    public function testObjectCastToString()
    {
        if (method_exists($this, 'createPartialMock')) {
            $dummy =
$this->createPartialMock('Psr\Log\Test\DummyTest',
array('__toString'));
        } else {
            $dummy = $this->getMock('Psr\Log\Test\DummyTest',
array('__toString'));
        }
        $dummy->expects($this->once())
            ->method('__toString')
            ->will($this->returnValue('DUMMY'));

        $this->getLogger()->warning($dummy);

        $expected = array('warning DUMMY');
        $this->assertEquals($expected, $this->getLogs());
    }

    public function testContextCanContainAnything()
    {
        $closed = fopen('php://memory', 'r');
        fclose($closed);

        $context = array(
            'bool' => true,
            'null' => null,
            'string' => 'Foo',
            'int' => 0,
            'float' => 0.5,
            'nested' => array('with object' =>
new DummyTest),
            'object' => new \DateTime,
            'resource' => fopen('php://memory',
'r'),
            'closed' => $closed,
        );

        $this->getLogger()->warning('Crazy context data',
$context);

        $expected = array('warning Crazy context data');
        $this->assertEquals($expected, $this->getLogs());
    }

    public function testContextExceptionKeyCanBeExceptionOrOtherValues()
    {
        $logger = $this->getLogger();
        $logger->warning('Random message',
array('exception' => 'oops'));
        $logger->critical('Uncaught Exception!',
array('exception' => new \LogicException('Fail')));

        $expected = array(
            'warning Random message',
            'critical Uncaught Exception!'
        );
        $this->assertEquals($expected, $this->getLogs());
    }
}
Test/TestLogger.php000064400000010657151161773140010272 0ustar00<?php

namespace Psr\Log\Test;

use Psr\Log\AbstractLogger;

/**
 * Used for testing purposes.
 *
 * It records all records and gives you access to them for verification.
 *
 * @method bool hasEmergency($record)
 * @method bool hasAlert($record)
 * @method bool hasCritical($record)
 * @method bool hasError($record)
 * @method bool hasWarning($record)
 * @method bool hasNotice($record)
 * @method bool hasInfo($record)
 * @method bool hasDebug($record)
 *
 * @method bool hasEmergencyRecords()
 * @method bool hasAlertRecords()
 * @method bool hasCriticalRecords()
 * @method bool hasErrorRecords()
 * @method bool hasWarningRecords()
 * @method bool hasNoticeRecords()
 * @method bool hasInfoRecords()
 * @method bool hasDebugRecords()
 *
 * @method bool hasEmergencyThatContains($message)
 * @method bool hasAlertThatContains($message)
 * @method bool hasCriticalThatContains($message)
 * @method bool hasErrorThatContains($message)
 * @method bool hasWarningThatContains($message)
 * @method bool hasNoticeThatContains($message)
 * @method bool hasInfoThatContains($message)
 * @method bool hasDebugThatContains($message)
 *
 * @method bool hasEmergencyThatMatches($message)
 * @method bool hasAlertThatMatches($message)
 * @method bool hasCriticalThatMatches($message)
 * @method bool hasErrorThatMatches($message)
 * @method bool hasWarningThatMatches($message)
 * @method bool hasNoticeThatMatches($message)
 * @method bool hasInfoThatMatches($message)
 * @method bool hasDebugThatMatches($message)
 *
 * @method bool hasEmergencyThatPasses($message)
 * @method bool hasAlertThatPasses($message)
 * @method bool hasCriticalThatPasses($message)
 * @method bool hasErrorThatPasses($message)
 * @method bool hasWarningThatPasses($message)
 * @method bool hasNoticeThatPasses($message)
 * @method bool hasInfoThatPasses($message)
 * @method bool hasDebugThatPasses($message)
 */
class TestLogger extends AbstractLogger
{
    /**
     * @var array
     */
    public $records = [];

    public $recordsByLevel = [];

    /**
     * @inheritdoc
     */
    public function log($level, $message, array $context = [])
    {
        $record = [
            'level' => $level,
            'message' => $message,
            'context' => $context,
        ];

        $this->recordsByLevel[$record['level']][] = $record;
        $this->records[] = $record;
    }

    public function hasRecords($level)
    {
        return isset($this->recordsByLevel[$level]);
    }

    public function hasRecord($record, $level)
    {
        if (is_string($record)) {
            $record = ['message' => $record];
        }
        return $this->hasRecordThatPasses(function ($rec) use ($record)
{
            if ($rec['message'] !== $record['message'])
{
                return false;
            }
            if (isset($record['context']) &&
$rec['context'] !== $record['context']) {
                return false;
            }
            return true;
        }, $level);
    }

    public function hasRecordThatContains($message, $level)
    {
        return $this->hasRecordThatPasses(function ($rec) use ($message)
{
            return strpos($rec['message'], $message) !== false;
        }, $level);
    }

    public function hasRecordThatMatches($regex, $level)
    {
        return $this->hasRecordThatPasses(function ($rec) use ($regex) {
            return preg_match($regex, $rec['message']) > 0;
        }, $level);
    }

    public function hasRecordThatPasses(callable $predicate, $level)
    {
        if (!isset($this->recordsByLevel[$level])) {
            return false;
        }
        foreach ($this->recordsByLevel[$level] as $i => $rec) {
            if (call_user_func($predicate, $rec, $i)) {
                return true;
            }
        }
        return false;
    }

    public function __call($method, $args)
    {
        if
(preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/',
$method, $matches) > 0) {
            $genericMethod = $matches[1] . ('Records' !==
$matches[3] ? 'Record' : '') . $matches[3];
            $level = strtolower($matches[2]);
            if (method_exists($this, $genericMethod)) {
                $args[] = $level;
                return call_user_func_array([$this, $genericMethod],
$args);
            }
        }
        throw new \BadMethodCallException('Call to undefined method
' . get_class($this) . '::' . $method . '()');
    }

    public function reset()
    {
        $this->records = [];
        $this->recordsByLevel = [];
    }
}