Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

382 lines (336 sloc) 12.133 kB
<?php
/**
* @package Habari
*
*/
/**
* Habari EventLog class
*
* @todo Apply system error handling
*/
class EventLog extends ArrayObject
{
protected $get_param_cache; // Stores info about the last set of data fetched that was not a single value
/**
* Returns properties of a EventLog object.
* This is the function that returns information about the set of log entries that
* was requested. This function should offer property names that are identical
* to properties of instances of the URL class. A call to EventLog::get()
* without parameters should return mostly the same property values as the
* global $url object for the request. The difference would occur when
* the data returned doesn't necessarily match the request, such as when
* several log entries are requested, but only one is available to return.
*
* @param string The name of the property to return.
*/
public function __get( $name )
{
switch ( $name ) {
case 'onelogentry':
return ( count( $this ) == 1 );
}
return false;
}
/**
* Adds a logging type to the lookup table
*
* @param string $type The type of the error
* @param string $module The module of the error
*/
public static function register_type( $type = 'default', $module = null )
{
try {
DB::query( 'INSERT INTO {log_types} (module, type) VALUES (?,?)', array( self::get_module( $module ), $type ) );
}
catch( Exception $e ) {
// Don't really care if there's a duplicate.
}
}
/**
* Removes a logging type from the lookup table
*
* @param string $type The type of the error
* @param string $module The module of the error
*/
public static function unregister_type( $type = 'default', $module = null )
{
$id = DB::get_value( "SELECT id FROM {log_types} WHERE module = ? and type = ?", array( self::get_module( $module ), $type ) );
if ( $id ) {
if ( !DB::exists( '{log}', array( 'type_id' => $id ) ) ) {
DB::delete( '{log_types}', array( 'id' => $id ) );
}
}
}
/**
* Write an entry to the event log.
*
* @param string $message The message
* @param string $severity The severity
* @param string $type The type
* @param string $module The module
* @param mixed $data The data
* @return object LogEntry The inserted LogEntry object
*/
public static function log( $message, $severity = 'info', $type = 'default', $module = null, $data = null )
{
$module = self::get_module( $module );
$log = new LogEntry( array(
'message' => $message,
'severity' => $severity,
'module' => $module,
'type' => $type,
'data' => $data,
'ip' => Utils::get_ip(),
) );
$user = User::identify();
if ( $user->loggedin ) {
$log->user_id = $user->id;
}
$log->insert();
return $log;
}
/**
* Get the module in which the logged code was executed
*
* @param integer $level How many backtrace calls to go back through the trace
* @return string The classname or .php module in which the log code was called.
*/
public static function get_module( $module = null, $level = 2 )
{
if ( is_null( $module ) ) {
$bt = debug_backtrace();
$last = $bt[$level];
$module = isset( $last['class'] ) ? $last['class'] : basename( $last['file'], '.php' );
}
return $module;
}
/**
* Returns a LogEntry or EventLog array based on supplied parameters.
* By default,fetch as many entries as pagination allows and order them in a descending fashion based on timestamp.
*
* @todo Cache query results.
* @param array $paramarry An associated array of parameters, or a querystring
* @return array An array of LogEntry objects, or a single LogEntry object, depending on request
*/
public static function get( $paramarray = array() )
{
$params = array();
$fns = array( 'get_results', 'get_row', 'get_value' );
$select = '';
// Put incoming parameters into the local scope
$paramarray = Utils::get_params( $paramarray );
$select_fields = LogEntry::default_fields();
if ( !isset( $paramarray['return_data'] ) ) {
unset( $select_fields['data'] );
}
foreach ( $select_fields as $field => $value ) {
$select .= ( '' == $select )
? "{log}.$field"
: ", {log}.$field";
}
// Default parameters.
$orderby = 'ORDER BY timestamp DESC, id DESC';
$limit = Options::get( 'pagination' );
// Get any full-query parameters
$possible = array( 'orderby', 'fetch_fn', 'count', 'month_cts', 'nolimit', 'index', 'limit', 'offset' );
foreach ( $possible as $varname ) {
if ( isset( $paramarray[$varname] ) ) {
$$varname = $paramarray[$varname];
}
}
foreach ( $paramarray as $key => $value ) {
if ( 'orderby' == $key ) {
$orderby = ' ORDER BY ' . $value;
continue;
}
}
// Transact on possible multiple sets of where information that is to be OR'ed
if ( isset( $paramarray['where'] ) && is_array( $paramarray['where'] ) ) {
$wheresets = $paramarray['where'];
}
else {
$wheresets = array( array() );
}
$wheres = array();
$join = '';
if ( isset( $paramarray['where'] ) && is_string( $paramarray['where'] ) ) {
$wheres[] = $paramarray['where'];
}
else {
foreach ( $wheresets as $paramset ) {
// Safety mechanism to prevent empty queries
$where = array( '1=1' );
$paramset = array_merge( ( array ) $paramarray, ( array ) $paramset );
if ( isset( $paramset['id'] ) && is_numeric( $paramset['id'] ) ) {
$where[] = "id= ?";
$params[] = $paramset['id'];
}
if ( isset( $paramset['user_id'] ) ) {
$where[] = "user_id= ?";
$params[] = $paramset['user_id'];
}
if ( isset( $paramset['severity'] ) && ( 'any' != LogEntry::severity_name( $paramset['severity'] ) ) ) {
$where[] = "severity_id= ?";
$params[] = LogEntry::severity( $paramset['severity'] );
}
if ( isset( $paramset['type_id'] ) ) {
if ( is_array( $paramset['type_id'] ) ) {
$types = array_filter( $paramset['type_id'], 'is_numeric' );
if ( count( $types ) ) {
$where[] = 'type_id IN (' . implode( ',', $types ) . ')';
}
}
else {
$where[] = 'type_id = ?';
$params[] = $paramset['type_id'];
}
}
if ( isset( $paramset['module'] ) ) {
if ( !is_array( $paramset['module'] ) ) {
$paramset['module'] = array( $paramset['module'] );
}
$where[] = 'type_id IN ( SELECT DISTINCT id FROM {log_types} WHERE module IN ( ' . implode( ', ', array_fill( 0, count( $paramset['module'] ), '?' ) ) . ' ) )';
$params = array_merge( $params, $paramset['module'] );
}
if ( isset( $paramset['type'] ) ) {
if ( !is_array( $paramset['type'] ) ) {
$paramset['type'] = array( $paramset['type'] );
}
$where[] = 'type_id IN ( SELECT DISTINCT id FROM {log_types} WHERE type IN ( ' . implode( ', ', array_fill( 0, count( $paramset['type'] ), '?' ) ) . ' ) )';
$params = array_merge( $params, $paramset['type'] );
}
if ( isset( $paramset['ip'] ) ) {
$where[] = 'ip = ?';
$params[] = $paramset['ip'];
}
/* do searching */
if ( isset( $paramset['criteria'] ) ) {
preg_match_all( '/(?<=")(\w[^"]*)(?=")|([:\w]+)/u', $paramset['criteria'], $matches );
foreach ( $matches[0] as $word ) {
if ( preg_match( '%^id:(\d+)$%i', $word, $special_crit ) ) {
$where[] .= '(id = ?)';
$params[] = $special_crit[1];
}
else {
$where[] .= "( LOWER( message ) LIKE ? )";
$params[] = '%' . MultiByte::strtolower( $word ) . '%';
}
}
}
/**
* Build the pubdate
* If we've got the day, then get the date.
* If we've got the month, but no date, get the month.
* If we've only got the year, get the whole year.
*
* @todo Ensure that we've actually got all the needed parts when we query on them
*/
if ( isset( $paramset['day'] ) ) {
$where[] = 'timestamp BETWEEN ? AND ?';
$start_date = sprintf( '%d-%02d-%02d', $paramset['year'], $paramset['month'], $paramset['day'] );
$start_date = HabariDateTime::date_create( $start_date );
$params[] = $start_date->sql;
$params[] = $start_date->modify( '+1 day' )->sql;
//$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, 0, $paramset['month'], $paramset['day'], $paramset['year'] ) );
//$params[] = date( 'Y-m-d H:i:s', mktime( 23, 59, 59, $paramset['month'], $paramset['day'], $paramset['year'] ) );
}
elseif ( isset( $paramset['month'] ) ) {
$where[] = 'timestamp BETWEEN ? AND ?';
$start_date = sprintf( '%d-%02d-%02d', $paramset['year'], $paramset['month'], 1 );
$start_date = HabariDateTime::date_create( $start_date );
$params[] = $start_date->sql;
$params[] = $start_date->modify( '+1 month' )->sql;
//$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, 0, $paramset['month'], 1, $paramset['year'] ) );
//$params[] = date( 'Y-m-d H:i:s', mktime( 23, 59, 59, $paramset['month'] + 1, 0, $paramset['year'] ) );
}
elseif ( isset( $paramset['year'] ) ) {
$where[] = 'timestamp BETWEEN ? AND ?';
$start_date = sprintf( '%d-%02d-%02d', $paramset['year'], 1, 1 );
$start_date = HabariDateTime::date_create( $start_date );
$params[] = $start_date->sql;
$params[] = $start_date->modify( '+1 year' )->sql;
//$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, 0, 1, 1, $paramset['year'] ) );
//$params[] = date( 'Y-m-d H:i:s', mktime( 0, 0, -1, 1, 1, $paramset['year'] + 1 ) );
}
$wheres[] = ' (' . implode( ' AND ', $where ) . ') ';
}
}
if ( isset( $index ) && is_numeric( $index ) ) {
$offset = ( intval( $index ) - 1 ) * intval( $limit );
}
if ( isset( $fetch_fn ) ) {
if ( ! in_array( $fetch_fn, $fns ) ) {
$fetch_fn = $fns[0];
}
}
else {
$fetch_fn = $fns[0];
}
if ( isset( $count ) ) {
$select = "COUNT($count)";
$fetch_fn = 'get_value';
$orderby = '';
}
if ( isset( $limit ) ) {
$limit = " LIMIT $limit";
if ( isset( $offset ) ) {
$limit .= " OFFSET $offset";
}
}
// If the month counts are requested, replace the select clause
if ( isset( $paramset['month_cts'] ) ) {
// @todo shouldn't this hand back to habari to convert to DateTime so it reflects the right timezone?
$select = 'MONTH(FROM_UNIXTIME(timestamp)) AS month, YEAR(FROM_UNIXTIME(timestamp)) AS year, COUNT(*) AS ct';
$groupby = 'year, month';
$orderby = ' ORDER BY year, month';
}
if ( isset( $nolimit ) || isset( $month_cts ) ) {
$limit = '';
}
$query = '
SELECT ' . $select . '
FROM {log} ' . $join;
if ( count( $wheres ) > 0 ) {
$query .= ' WHERE ' . implode( " \nOR\n ", $wheres );
}
$query .= ( ! isset( $groupby ) || $groupby == '' ) ? '' : ' GROUP BY ' . $groupby;
$query .= $orderby . $limit;
// Utils::debug( $paramarray, $fetch_fn, $query, $params );
DB::set_fetch_mode( PDO::FETCH_CLASS );
DB::set_fetch_class( 'LogEntry' );
$results = DB::$fetch_fn( $query, $params, 'LogEntry' );
// If the fetch callback function is not get_results,
// return an EventLog ArrayObject filled with the results as LogEntry objects.
if ( 'get_results' != $fetch_fn ) {
return $results;
}
elseif ( is_array( $results ) ) {
$c = __CLASS__;
$return_value = new $c( $results );
$return_value->get_param_cache = $paramarray;
return $return_value;
}
}
/*
* Trim the EventLog down to the defined number of days to prevent it getting massively large.
*/
public static function trim()
{
// allow an option to be set to override the log retention - in days
$retention = Options::get( 'log_retention', 14 ); // default to 14 days
// make it into the string we'll use
$retention = '-' . intval( $retention ) . ' days';
// Trim the log table down
$date = HabariDateTime::date_create()->modify( $retention );
return DB::query( 'DELETE FROM {log} WHERE timestamp < ?', array( $date->sql ) );
}
public static function purge ()
{
$result = DB::query( 'DELETE FROM {log}' );
if ( $result ) {
EventLog::log( _t( 'Logs purged.' ), 'info' );
}
return $result;
}
}
?>
Jump to Line
Something went wrong with that request. Please try again.