Beispiel #1
0
/**
 * Append a message onto the end of a given log file.
 *
 * @param string      $filebase The log type base to write to, (used to create ${filebase}.log).
 * @param string      $message  The message to append.
 * @param null|string $code     Code or error type to prefix the log with.
 *
 * @throws \Exception
 */
function append_to($filebase, $message, $code = null){
	if(class_exists('Core\\Utilities\\Logger\\LogFile')){
		$log = new LogFile($filebase);
		$log->write($message, $code);
	}
	else{
		error_log($message);
	}

}
Beispiel #2
0
	/**
	 * Remove the test log file left on the filesystem.
	 *
	 * @depends testArchive
	 */
	public function testDelete(\Core\Utilities\Logger\LogFile $log){
		// Delete will throw exceptions if there were any problems.
		$log->delete();
	}
Beispiel #3
0
	private static function _Rotate(){
		$dir = new DirectoryLocal('logs/');
		$entries = $dir->ls('log');
		foreach($entries as $file){
			/** @var \Core\Filestore\Backends\FileLocal $file */

			$log = new LogFile($file->getBasename(true));
			try{
				$log->archive();
				echo 'Archived ' . $file->getBasename(true) . ' log.' . NL;
			}
			catch(\Exception $e){
				echo $e->getMessage();
				return false;
			}
		}

		if(\ConfigHandler::Get('/core/logs/rotate/keep')){
			$entries = $dir->ls();
			$types = [];
			foreach($entries as $file){
				/** @var \Core\Filestore\Backends\FileLocal $file */

				$base = $file->getBasename();
				// I want only the filename before the first '.'.
				$base = substr($base, 0, strpos($base, '.'));

				if(!isset($types[$base])){
					$types[$base] = [];
				}

				$types[$base][ $file->getMTime() ] = $file;
			}

			foreach($types as $base => $files){
				// This will sort the files newest-to-oldest.
				krsort($files);

				$limit = \ConfigHandler::Get('/core/logs/rotate/keep');
				$x = 0;
				$deleted = 0;
				foreach($files as $file){
					/** @var \Core\Filestore\Backends\FileLocal $file */
					++$x;
					if($x > $limit){
						if($file->exists()){
							$file->delete();
							++$deleted;
						}
					}
				}

				if($deleted > 0){
					echo 'Purged ' . $deleted . ' old ' . $base  . ' log file(s).' . NL;
				}
			}
		}

		return true;
	}
Beispiel #4
0
/**
 * Handle an error and report it to the Core system log.
 *
 * @param      $errno
 * @param      $errstr
 * @param      $errfile
 * @param      $errline
 * @param null $errcontext
 */
function error_handler($errno, $errstr, $errfile, $errline, $errcontext = null){
	$type       = null;
	$fatal      = false;
	$code       = null;
	$class      = '';
	// The exception to this is when error_reporting is explictly set to 0.
	// This happens when a function is called with the "@" error suppressor.
	// In this event, I still want to log the error, but simply do not display it on the screen.
	// Damn f*****g "@" operator.....
	$suppressed = (error_reporting() === 0);

	switch($errno){
		case E_ERROR:
		case E_USER_ERROR:
			$fatal = true;
			$type  = 'error';
			$class = 'error';
			$code  = 'PHP Error';
			break;
		case E_WARNING:
		case E_USER_WARNING:
			$type = 'error';
			$class = 'warning';
			$code = 'PHP Warning';
			break;
		case E_NOTICE:
		case E_USER_NOTICE:
			$type = 'info';
			$class = 'info';
			$code = 'PHP Notice';
			break;
		case E_DEPRECATED:
		case E_USER_DEPRECATED:
			$type = 'info';
			$class = 'deprecated';
			$code = 'PHP Deprecated Notice';
			break;
		case E_STRICT:
			$type = 'info';
			$class = 'warning';
			$code = 'PHP Strict Warning';
			$suppressed = true;
			break;
		default:
			$type = 'info';
			$class = 'unknown';
			$code = 'Unknown PHP Error [' . $errno . ']';
			break;
	}

	if($suppressed){
		// Ignore suppressed errors when on production.
		// This is required because PHP < 7.0 has some functions that can only be called with the '@' operator.
		// Such as LDAP binding or many things in Smarty.
		if(!DEVELOPMENT_MODE){
			return;	
		}
		$code .= ' @SUPPRESSED';
	}

	// All errors/warnings/notices get logged!
	if($errfile && strpos($errfile, ROOT_PDIR) === 0){
		$details = '[src: ' . '/' . substr($errfile, strlen(ROOT_PDIR)) . ':' . $errline . '] ';
	}
	elseif($errfile){
		$details = '[src: ' . $errfile . ':' . $errline . '] ';
	}
	else{
		$details = '';
	}

	try{
		if(!\Core::GetComponent()){
			// SQUAK!  Core isn't even loaded yet!
			return;
		}

		// Allow external systems to hook into this event.
		\HookHandler::DispatchHook('/core/error_handler', $code, $errstr);

		$log = \SystemLogModel::Factory();
		$log->setFromArray([
			'type'    => $type,
			'code'    => $code,
			'message' => $details . $errstr
		]);
		$log->save();
	}
	catch(\Exception $e){
		// meh, try a traditional log.
		try{
			if(class_exists('Core\\Utilities\\Logger\\LogFile')){
				$log = new LogFile($type);
				$log->write($details . $errstr, $code);
			}
			else{
				error_log($details . $errstr);
			}
		}
		catch(\Exception $e){
			// Really meh now!
		}
	}

	// Display all errors when in development mode.
	if(DEVELOPMENT_MODE && !$suppressed){
		// The correct way to handle output is via EXEC_MODE.
		// HOWEVER, since the unit tests emulate a WEB mode so that the scripts behave as they would in the web browser,
		// this is not a reliable test here.
		if(isset($_SERVER['TERM']) || isset($_SERVER['SHELL'])){
			print_error_as_text($class, $code, $errstr);
		}
		elseif(EXEC_MODE == 'WEB'){
			print_error_as_html($class, $code, $errstr);
		}
		else{
			print_error_as_text($class, $code, $errstr);
		}
	}

	// If it's a fatal error and it's not in development mode, simply display a friendly error page instead.
	if($fatal){
		if(EXEC_MODE == 'WEB'){
			require(ROOT_PDIR . 'core/templates/halt_pages/fatal_error.inc.html');
		}
		exit();
	}
}