Version 4.0.13.1

This commit is contained in:
Neo committed 2025-12-19 04:57:54 -08:00
1 parent f9e857d255
commit c6a86f0d9b
7517 files changed
+597400 -668041

No files matched your search

+274
View File
@@ -0,0 +1,274 @@
<?php
/**
* @brief Disk Log Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 12 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Log;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Disk log class
*/
class _Disk extends \IPS\Log
{
/* @Brief Log directory */
public $logDir = NULL;
/**
* The constructor
*
* @param array|null $config
* @param int $severity
* @return void
*/
public function __construct( $config, $severity )
{
$this->logDir = \IPS\ROOT_PATH . '/uploads/logs';
parent::__construct( $config, $severity );
}
/**
* Get the most recent log titles
*
* @param int $limit
* @return array array( array( 'date' => unixTimeStamp, 'title' => title, 'suffix' => suffix ), ... );
*/
public function getMostRecentLogsTitles( $limit=50 )
{
$logs = array();
if ( is_dir( $this->logDir ) )
{
$dir = new \DirectoryIterator( $this->logDir );
$files = array();
foreach ( $dir as $file )
{
if ( ! $file->isDir() and ! $file->isDot() and mb_substr( $file, -4 ) === '.php' and mb_substr( $file, 0, 6 ) !== 'latest' )
{
$files[ $file->getMTime() ] = $file->getFilename();
}
}
krsort( $files );
$set = array_slice( $files, 0, $limit, true );
foreach( $set as $mtime => $name )
{
$suffix = mb_substr( mb_substr( $name, 0, -4 ), 11 ); #[YYYY-mm-dd_]suffix[.cgi]
$logs[] = array( 'date' => $mtime, 'title' => $name, 'suffix' => $suffix );
}
}
return $logs;
}
/**
* Get latest logs
*
* @param \IPS\DateTime $date Limit only to logs after this date
* @return array
*/
public function getLatestTitles( \IPS\DateTime $date )
{
$logs = array();
if ( is_dir( $this->logDir ) )
{
$dir = new \DirectoryIterator( $this->logDir );
foreach ( $dir as $file )
{
if ( ! $file->isDir() and ! $file->isDot() and mb_substr( $file, -4 ) === '.php' and mb_substr( $file, 0, 6 ) === 'latest' and $file->getMTime() > $date->getTimestamp() )
{
$logs[ $file->getMTime() ] = $file->getFilename();
}
}
krsort( $logs );
}
return $logs;
}
/**
* Get log content
*
* @param string $title Title of log to fetch
* @return string Raw log contents
*/
public function getLog( $title )
{
/* Paranoid clean */
$title = preg_replace( '#^[^a-z0-9-_\.]+?$#i', '', $title );
if ( file_exists( $this->logDir . '/' . $title ) )
{
/* Get the last 300 lines max */
$handle = @fopen( $this->logDir . '/' . $title, 'r' );
$content = '';
$lines = 300;
if ( $handle )
{
$l = $lines;
$pos = -2;
$beg = false;
while ( $l > 0 )
{
$_t = " ";
while( $_t != "\n" )
{
if ( @fseek( $handle, $pos, SEEK_END ) == -1 )
{
$beg = true;
break;
}
$_t = @fgetc( $handle );
$pos--;
}
$l--;
if ( $beg )
{
rewind( $handle );
break;
}
$t[ $lines - $l - 1 ] = @fgets( $handle );
}
@fclose ($handle);
$content = trim( implode( "", array_reverse( $t ) ) );
}
return $content;
}
return NULL;
}
/**
* Prune logs
*
* @param int $days Older than (days) to prune
* @return void
*/
public function prune( $days )
{
try
{
foreach( new \DirectoryIterator( $this->logDir ) as $file )
{
if( $file->isDot() OR !$file->isFile() )
{
continue;
}
if( preg_match( "#.cgi$#", $file->getFilename(), $matches ) or ( preg_match( "#.php$#", $file->getFilename(), $matches ) and $file->getMTime() < ( time() - ( 60 * 60 * 24 * (int) $days ) ) ) )
{
@unlink( $file->getPathname() );
}
}
} catch ( Exception $e ) {}
}
/**
* Log
*
* @param string $message The message
* @param string $suffix Unique key for this log
* @return void
*/
public function write( $message, $suffix=NULL )
{
$date = date( 'r' );
$ip = $this->getIpAddress();
$url = ( mb_strtolower( php_sapi_name() ) == 'cli' ) ? "Command line" : \IPS\Request::i()->url();
$fileSuffix = ( $suffix !== NULL ) ? '_' . $suffix : '';
if ( is_array( $message ) )
{
$message = var_export( $message, TRUE );
}
#$debug = @print_r( debug_backtrace(), true );
$header = "<?php exit; ?>\n\n";
$message = <<<MSG
{$date} (Severity: {$this->severity})
{$ip} - {$url}
{$message}
------------------------------------------------------------------------
MSG;
if ( ! is_dir( $this->logDir ) )
{
if ( ! @mkdir( $this->logDir ) )
{
if( $this->severity === LOG_DEBUG )
{
return;
}
throw new \RuntimeException( 'COULD_NOT_CREATE_LOG_DIR' );
}
@chmod( $this->logDir, \IPS\IPS_FOLDER_PERMISSION );
}
/* Latest */
if ( ! @\file_put_contents( $this->logDir . '/latest' . $fileSuffix . '.php', $header . $message ) )
{
if( $this->severity === LOG_DEBUG )
{
return;
}
throw new \RuntimeException( 'COULD_NOT_WRITE_FILE' );
}
@chmod( $this->logDir . '/latest' . $fileSuffix . '.php', \IPS\IPS_FILE_PERMISSION );
/* Log */
$file = $this->logDir . '/' . date( 'Y' ) . '_' . date( 'm' ) . '_' . date('d') . $fileSuffix . '.php';
if ( file_exists( $file ) )
{
$return = @\file_put_contents( $file, $message, FILE_APPEND );
}
else
{
$return = @\file_put_contents( $file, $header . $message );
}
if ( !$return )
{
if( $this->severity === LOG_DEBUG )
{
return;
}
throw new \RuntimeException( 'COULD_NOT_WRITE_FILE' );
}
@chmod( $file, \IPS\IPS_FILE_PERMISSION );
}
}
+90
View File
@@ -0,0 +1,90 @@
<?php
/**
* @brief Email Log Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 12 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Log;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Email log class
*/
class _Email extends \IPS\Log\Disk
{
/**
* Log
*
* @param string $message The message
* @param string $suffix Unique key for this log
* @return void
*/
public function write( $message, $suffix=NULL )
{
$date = date( 'r' );
$ip = $this->getIpAddress();
$url = \IPS\Request::i()->url();
$fileSuffix = ( $suffix !== NULL ) ? '_' . $suffix : '';
$text = <<<MSG
Hello,
An error has occured at {$url}. Here is the message:
------------------------------------------------------------------------
{$date} (Severity: {$this->severity})
{$ip} - {$url}
{$message}
------------------------------------------------------------------------
You are receiving this email as you have chosen to recieve emails for certain
errors. You can disable this by editing the constant LOG_METHOD in constants.php
MSG;
$html = <<<MSG
Hello,
<p>An error has occured at {$url}. Here is the message:</p>
<hr>
<br />{$date} (Severity: {$this->severity})
<br />{$ip} - {$url}
<br />{$message}
<hr>
<p>You are receiving this email as you have chosen to recieve emails for certain
errors. You can disable this by editing the constant LOG_METHOD in constants.php</p>
MSG;
/* Log to disk first so it's saved if email fails */
parent::write( $message, $suffix );
if ( isset( $this->config['to'] ) )
{
$subSuffix = ( $suffix !== NULL ) ? mb_strtoupper( $suffix ) . ': ' : '';
try
{
$email = \IPS\Email::buildFromContent( $subSuffix . ( ( isset( $this->config['subject'] ) ) ? $this->config['subject'] : "New error log" ), $html, $text );
$email->from = $this->config['to'];
$email->useWrapper = false;
$email->send( $this->config['to'] );
}
catch( Exception $e )
{
/* So bad something failed setting up email class, retreat! */
@mail( $this->config['to'], $subSuffix . ( ( isset( $this->config['subject'] ) ) ? $this->config['subject'] : "New error log" ), $text );
}
}
}
}
+296
View File
@@ -0,0 +1,296 @@
<?php
/**
* @brief Log Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 07 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Log Class
*/
abstract class _Log
{
/**
* @brief Multitons
*/
protected static $instances = array();
/**
* @brief Configuration
*/
protected static $configuration = NULL;
/**
* Log
*
* Severity constants
* @li LOG_EMERG system is unusable
* @li LOG_ALERT action must be taken immediately
* @li LOG_CRIT critical conditions
* @li LOG_ERR error conditions
* @li LOG_WARNING warning conditions
* @li LOG_NOTICE normal, but significant, condition
* @li LOG_INFO informational message
* @li LOG_DEBUG debug-level message
*
* LOG_METHOD example JSON object
* [
* {
* 'levels': [0,1,2,3,4,5],
* 'method': 'disk'
* },
* {
* 'levels': [6,7],
* 'method': 'email',
* 'config': { 'to': 'sales@invisionpower.com', 'subject': 'New error log from My Community' }
* }
* ]
*
* Acceptable methods are "disk", "email" and "syslog".
*
* Caveats:
* @li Email method falls back to PHPs 'mail' command if using the framework fails (critical DB error, etc). If your server cannot use
* PHPs mail, then do not use the email method.
*
* Any missing levels (between 0 and 6) are populated by 'disk' method. 7 is debug and can be left blank
*
* @param int|string $key PHP syslog constant (int) or method name (string)
* @return object \IPS\Log
*
* @see <a href='http://tools.ietf.org/html/rfc5424'>RFC 5424</a>
* @see <a href='http://php.net/syslog'>PHP's syslog</a>
*/
public static function i( $key )
{
if ( is_string( $key ) )
{
$severity = static::getSeverityFromMethod( $key );
}
else
{
$severity = intval( $key );
}
$config = static::getConfiguration();
if ( !isset( static::$instances[ $severity ] ) )
{
$classname = '\IPS\Log\\' . ucfirst( $config[ $severity ]['method'] );
static::$instances[ $severity ] = new $classname( $config[ $severity ]['config'], $severity );
}
/* One method can have multiple severities, so lets set the current severity for this call */
static::$instances[ $severity ]->setSeverity( $severity );
return static::$instances[ $severity ];
}
/**
* Return a severity level based on method name (disk, syslog, etc)
*
* @param string $method Method name (disk, syslog, etc)
* @return int
*/
public static function getSeverityFromMethod( $method )
{
foreach( static::getUsedMethods() as $method => $levels )
{
$severity = array_pop( $levels );
return $severity;
}
return LOG_DEBUG;
}
/**
* Return an array of used methods with the severity levels assigned
*
* @return array
*/
public static function getUsedMethods()
{
$config = static::getConfiguration();
$methods = array();
foreach( $config as $level => $data )
{
$methods[ $data['method'] ][] = $level;
}
return $methods;
}
/**
* Returns the configuration from LOG_METHOD parsed and checked
*
* @return array
*/
protected static function getConfiguration()
{
if ( static::$configuration === NULL )
{
$json = @json_decode( LOG_METHOD, TRUE );
if ( is_array( $json ) )
{
foreach( $json as $row )
{
if ( isset( $row['levels'] ) AND isset( $row['method'] ) AND is_array( $row['levels'] ) )
{
foreach( $row['levels'] as $level )
{
static::$configuration[ $level ]['method'] = $row['method'];
static::$configuration[ $level ]['config'] = ( isset( $row['config'] ) ) ? $row['config'] : NULL;
}
}
}
}
/* Ensure everything except DEBUG has a value */
foreach( range( 0, 6 ) as $level )
{
if ( ! isset( static::$configuration[ $level ] ) )
{
static::$configuration[ $level ]['method'] = 'disk';
static::$configuration[ $level ]['config'] = NULL;
}
}
/* And then make sure DEBUG has a value set to None if not already set */
if ( ! isset( static::$configuration[ 7 ] ) )
{
static::$configuration[ 7 ]['method'] = 'none';
static::$configuration[ 7 ]['config'] = NULL;
}
}
return static::$configuration;
}
/**
* Prune logs where possible
*
* @param int $days Older than (days) to prune
* @return void
*/
public static function pruneLogs( $days )
{
if ( ! $days )
{
return;
}
foreach( static::getUsedMethods() as $method => $levels )
{
\IPS\Log::i( $method )->prune( $days );
}
}
/* @Brief Configuration array */
protected $config = NULL;
/* @Brief Severity level */
protected $severity = NULL;
/**
* The constructor
*
* @param array|null $config
* @param int $severity
* @return void
*/
public function __construct( $config, $severity )
{
$this->config = $config;
$this->setSeverity( $severity );
}
/**
* Store the severity for this call
*
* @param int $severity Severity
* @return \IPS\Log
*/
public function setSeverity( $severity )
{
$this->severity = $severity;
return $this;
}
/**
* @brief IP address to use or NULL to retrieve from Request class
*/
protected $ipAddress = NULL;
/**
* Set the IP address
*
* @param string $ip IP address
* @return \IPS\Log
* @note This method is designed so that we can bypass issues with \IPS\Settings not loaded yet for instance when logging cache-related calls (since settings are stored in cache)
*/
public function setIpAddress( $ip )
{
$this->ipAddress = $ip;
return $this;
}
/**
* Get the IP address
*
* @return string
* @note This call will reset the stored IP address every time so that other log requests use the correct IP
*/
public function getIpAddress()
{
$result = ( $this->ipAddress !== NULL ) ? $this->ipAddress : \IPS\Request::i()->ipAddress();
$this->ipAddress = NULL;
return $result;
}
/**
* Get the most recent log titles
*
* @param int $limit
* @return array array( array( 'date' => unixTimeStamp, 'title' => title, 'suffix' => suffix ), ... );
*/
public function getMostRecentLogsTitles( $limit=50 )
{
return array();
}
/**
* Get latest logs
*
* @param \IPS\DateTime $date Limit only to logs after this date
* @return array array( array( 'date' => unixTimeStamp, 'title' => title, 'suffix' => suffix ), ... );
*/
public function getLatestTitles( \IPS\DateTime $date )
{
return array();
}
/**
* Prune logs
*
* @param int $days Older than (days) to prune
* @return void
*/
public function prune( $days )
{
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* @brief No logging Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 12 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Log;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Disk log class
*/
class _None extends \IPS\Log
{
/**
* Log
*
* @param string $message The message
* @param string $suffix Unique key for this log
* @return void
*/
public function write( $message, $suffix=NULL )
{
return TRUE;
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
/**
* @brief Syslog Log Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @since 14 Nov 2013
* @version SVN_VERSION_NUMBER
*/
namespace IPS\Log;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* Disk log class
*/
class _Syslog extends \IPS\Log
{
/**
* Get log content
*
* @param string $title Title of log to fetch
* @return string Raw log contents
*/
public function getLog( $title )
{
return NULL;
}
/**
* Log
*
* @param string $message The message
* @param string $suffix Unique key for this log
* @return void
*/
public function write( $message, $suffix=NULL )
{
$date = date( 'r' );
$ip = $this->getIpAddress();
$url = \IPS\Request::i()->url();
syslog( $this->severity, $suffix . ': ' . $ip . ': ' . $url . ': ' . $date . ': ' . $message );
}
}
View File
Whitespace-only changes.