Remove \Basic class from all other Class extensions

If not created Logger class will be auto created in \DB\IO
Recommended to run a CoreLibs\Debug\Logging([...]); and use this class
for all ACL\Login, Admin\Backend, DB\IO, Output\Form\Generate calls.
Last parameter after DB CONFIG is the log parameter

Session create has been moved to a new Create\Session class from the
\Basic class and MUST be started before using ACL\Login. Currently
ACL\Login will fallback and start it if no session is yet started.

See the Readme.md file for which classes use _SESSION data

In future the _SESSION settings should be moved to some wrapper class
for this so we can unit test sessions

Only Output\Form\Generate class call has the new changed with the second
parameter no longer beeing the table width setting but the class
setting.
But as this is a semi retired class and only used for edit_base this is
not 100% breaking.
All other classes can be used as is and have internal fallback to run as
before.
Deprecation messages will be added later.
This commit is contained in:
Clemens Schwaighofer
2022-01-18 10:51:13 +09:00
parent 1bd45d8a8a
commit ad39a5b21f
45 changed files with 991 additions and 284 deletions

View File

@@ -24,8 +24,16 @@ declare(strict_types=1);
namespace CoreLibs\Debug;
use CoreLibs\Debug\Support;
use CoreLibs\Create\Hash;
use CoreLibs\Get\System;
use CoreLibs\Convert\Html;
class Logging
{
// options
/** @var array<mixed> */
private $options = [];
// page and host name
/** @var string */
private $page_name;
@@ -66,12 +74,16 @@ class Logging
private $log_folder = '';
/** @var string */
private $log_file_name_ext = 'log'; // use this for date rotate
/** @var string */
private $log_file_name = '';
/** @var int */
private $log_max_filesize = 0; // set in kilobytes
/** @var string */
private $log_print_file = 'error_msg##LOGID####LEVEL####CLASS####PAGENAME####DATE##';
/** @var string */
private $log_file_unique_id; // a unique ID set only once for call derived from this class
/** @var string */
private $log_file_date = ''; // Y-m-d file in file name
/** @var bool */
private $log_print_file_date = true; // if set add Y-m-d and do automatic daily rotation
/** @var string */
@@ -88,30 +100,82 @@ class Logging
/** @var float */
private $script_starttime;
public function __construct()
/**
* Init logger
*
* global vars that can be used
* - BASE
* - LOG
* - LOG_FILE_ID
* options array layout
* - log_folder:
* - print_file_date:
* - file_id:
* - unique_id:
* - log_per_level:
* - log_per_class:
* - log_per_page:
* - log_per_run:
* - debug_all:
* - echo_all:
* - print_all:
* - debug (array):
* - echo (array):
* - print (array):
* - debug_not (array):
* - echo_not (array):
* - print_not (array):
*
* @param array<mixed> $options Array with settings options
*/
public function __construct(array $options = [])
{
// check must set constants
if (defined('BASE') && defined('LOG')) {
// copy the options over
$this->options = $options;
// set log folder from options
$this->log_folder = $this->options['log_folder'] ?? '';
// legacy flow, check must set constants
if (empty($this->log_folder) && defined('BASE') && defined('LOG')) {
// make sure this is writeable, else skip
$this->log_folder = BASE . LOG;
} else {
// fallback + warning
trigger_error('constant BASE or LOG are not defined, fallback to getcwd()', E_USER_WARNING);
$this->log_folder = getcwd() . DS;
}
// fallback + notice
if (empty($this->log_folder)) {
/* trigger_error(
'options or constant not set or folder not writable. fallback to: ' . getcwd(),
E_USER_NOTICE
); */
$this->log_folder = getcwd() . DIRECTORY_SEPARATOR;
}
// if folder is not writeable, abort
if (!is_writeable($this->log_folder)) {
trigger_error(
'Folder: ' . $this->log_folder . ' is not writeable for logging',
E_USER_ERROR
);
}
// check if log_folder has a trailing /
if (substr($this->log_folder, -1, 1) != DIRECTORY_SEPARATOR) {
$this->log_folder .= DIRECTORY_SEPARATOR;
}
// running time start for script
$this->script_starttime = microtime(true);
// set per run UID for logging
$this->running_uid = \CoreLibs\Create\Hash::__uniqId();
$this->running_uid = Hash::__uniqId();
// set the page name
$this->page_name = \CoreLibs\Get\System::getPageName();
$this->page_name = System::getPageName();
// set host name
list($this->host_name , $this->host_port) = \CoreLibs\Get\System::getHostName();
list($this->host_name , $this->host_port) = System::getHostName();
// add port to host name if not port 80
if ($this->host_port != 80) {
$this->host_name .= ':' . $this->host_port;
}
// can be overridden with basicSetLogFileId
if (isset($GLOBALS['LOG_FILE_ID'])) {
// can be overridden with basicSetLogFileId later
if (!empty($this->options['file_id'])) {
$this->basicSetLogId($this->options['file_id'] ?? '');
} elseif (!empty($GLOBALS['LOG_FILE_ID'])) {
// legacy flow, should be removed and only set via options
$this->basicSetLogId($GLOBALS['LOG_FILE_ID']);
} elseif (defined('LOG_FILE_ID')) {
$this->basicSetLogId(LOG_FILE_ID);
@@ -132,38 +196,90 @@ class Logging
{
// if given via parameters, only for all
// globals overrule given settings, for one (array), eg $ECHO['db'] = 1;
if (isset($GLOBALS['DEBUG']) && is_array($GLOBALS['DEBUG'])) {
if (isset($this->options['debug']) && is_array($this->options['debug'])) {
$this->debug_output = $this->options['debug'];
} elseif (isset($GLOBALS['DEBUG']) && is_array($GLOBALS['DEBUG'])) {
$this->debug_output = $GLOBALS['DEBUG'];
}
if (isset($GLOBALS['ECHO']) && is_array($GLOBALS['ECHO'])) {
if (isset($this->options['echo']) && is_array($this->options['echo'])) {
$this->debug_output = $this->options['echo'];
} elseif (isset($GLOBALS['ECHO']) && is_array($GLOBALS['ECHO'])) {
$this->echo_output = $GLOBALS['ECHO'];
}
if (isset($GLOBALS['PRINT']) && is_array($GLOBALS['PRINT'])) {
if (isset($this->options['print']) && is_array($this->options['print'])) {
$this->debug_output = $this->options['print'];
} elseif (isset($GLOBALS['PRINT']) && is_array($GLOBALS['PRINT'])) {
$this->print_output = $GLOBALS['PRINT'];
}
// exclude these ones from output
if (isset($GLOBALS['DEBUG_NOT']) && is_array($GLOBALS['DEBUG_NOT'])) {
if (isset($this->options['debug_not']) && is_array($this->options['debug_not'])) {
$this->debug_output = $this->options['debug_not'];
} elseif (isset($GLOBALS['DEBUG_NOT']) && is_array($GLOBALS['DEBUG_NOT'])) {
$this->debug_output_not = $GLOBALS['DEBUG_NOT'];
}
if (isset($GLOBALS['ECHO_NOT']) && is_array($GLOBALS['ECHO_NOT'])) {
if (isset($this->options['echo_not']) && is_array($this->options['echo_not'])) {
$this->debug_output = $this->options['echo_not'];
} elseif (isset($GLOBALS['ECHO_NOT']) && is_array($GLOBALS['ECHO_NOT'])) {
$this->echo_output_not = $GLOBALS['ECHO_NOT'];
}
if (isset($GLOBALS['PRINT_NOT']) && is_array($GLOBALS['PRINT_NOT'])) {
if (isset($this->options['print_not']) && is_array($this->options['print_not'])) {
$this->debug_output = $this->options['print_not'];
} elseif (isset($GLOBALS['PRINT_NOT']) && is_array($GLOBALS['PRINT_NOT'])) {
$this->print_output_not = $GLOBALS['PRINT_NOT'];
}
// all overrule
$this->debug_output_all = $GLOBALS['DEBUG_ALL'] ?? false;
$this->echo_output_all = $GLOBALS['ECHO_ALL'] ?? false;
$this->print_output_all = $GLOBALS['PRINT_ALL'] ?? false;
$this->debug_output_all =
$this->options['debug_all'] ??
$GLOBALS['DEBUG_ALL'] ??
false;
$this->echo_output_all =
$this->options['echo_all'] ??
$GLOBALS['ECHO_ALL'] ??
false;
$this->print_output_all =
$this->options['print_all'] ??
$GLOBALS['PRINT_ALL'] ??
false;
// GLOBAL rules for log writing
$this->log_print_file_date = $GLOBALS['LOG_PRINT_FILE_DATE'] ?? true;
$this->log_per_level = $GLOBALS['LOG_PER_LEVEL'] ?? false;
$this->log_per_class = $GLOBALS['LOG_PER_CLASS'] ?? false;
$this->log_per_page = $GLOBALS['LOG_PER_PAGE'] ?? false;
$this->log_per_run = $GLOBALS['LOG_PER_RUN'] ?? false;
$this->log_print_file_date =
$this->options['print_file_date'] ??
$GLOBALS['LOG_PRINT_FILE_DATE'] ??
true;
$this->log_per_level =
$this->options['per_level'] ??
$GLOBALS['LOG_PER_LEVEL'] ??
false;
$this->log_per_class =
$this->options['per_class'] ??
$GLOBALS['LOG_PER_CLASS'] ??
false;
$this->log_per_page =
$this->options['per_page'] ??
$GLOBALS['LOG_PER_PAGE'] ??
false;
$this->log_per_run =
$this->options['per_run'] ??
$GLOBALS['LOG_PER_RUN'] ??
false;
// set log per date
if ($this->log_print_file_date) {
$this->log_file_date = date('Y-m-d');
}
// set per run ID
if ($this->log_per_run) {
/* if (isset($GLOBALS['LOG_FILE_UNIQUE_ID'])) {
$this->log_file_unique_id = $GLOBALS['LOG_FILE_UNIQUE_ID'];
} */
if (!$this->log_file_unique_id) {
// $GLOBALS['LOG_FILE_UNIQUE_ID'] =
$this->log_file_unique_id =
date('Y-m-d_His') . '_U_'
. substr(hash('sha1', uniqid((string)mt_rand(), true)), 0, 8);
}
}
}
/**
@@ -238,18 +354,13 @@ class Logging
) {
return false;
}
// replace all html tags
// $error_string = preg_replace("/(<\/?)(\w+)([^>]*>)/", "##\\2##", $error_string);
// $error_string = preg_replace("/(<\/?)(\w+)([^>]*>)/", "", $error_string);
// replace special line break tag
// $error_string = str_replace('<!--#BR#-->', "\n", $error_string);
// init output variable
$output = $error_string; // output formated error string to output file
// init base file path
$fn = $this->log_folder . $this->log_print_file . '.' . $this->log_file_name_ext;
// log ID prefix settings, if not valid, replace with empty
if (preg_match("/^[A-Za-z0-9]+$/", $this->log_file_id)) {
if (!empty($this->log_file_id)) {
$rpl_string = '_' . $this->log_file_id;
} else {
$rpl_string = '';
@@ -257,17 +368,9 @@ class Logging
$fn = str_replace('##LOGID##', $rpl_string, $fn); // log id (like a log file prefix)
if ($this->log_per_run) {
if (isset($GLOBALS['LOG_FILE_UNIQUE_ID'])) {
$this->log_file_unique_id = $GLOBALS['LOG_FILE_UNIQUE_ID'];
}
if (!$this->log_file_unique_id) {
$GLOBALS['LOG_FILE_UNIQUE_ID'] = $this->log_file_unique_id =
date('Y-m-d_His') . '_U_'
. substr(hash('sha1', uniqid((string)mt_rand(), true)), 0, 8);
}
$rpl_string = '_' . $this->log_file_unique_id; // add 8 char unique string
} else {
$rpl_string = !$this->log_print_file_date ? '' : '_' . date('Y-m-d'); // add date to file
} elseif ($this->log_print_file_date) {
$rpl_string = '_' . $this->log_file_date; // add date to file
}
$fn = str_replace('##DATE##', $rpl_string, $fn); // create output filename
@@ -276,11 +379,13 @@ class Logging
// set per class, but don't use get_class as we will only get self
$rpl_string = !$this->log_per_class ? '' : '_'
// set sub class settings
. str_replace('\\', '-', \CoreLibs\Debug\Support::getCallerClass());
. str_replace('\\', '-', Support::getCallerClass());
$fn = str_replace('##CLASS##', $rpl_string, $fn); // create output filename
// if request to write to one file
$rpl_string = !$this->log_per_page ? '' : '_' . \CoreLibs\Get\System::getPageName(1);
$rpl_string = !$this->log_per_page ?
'' :
'_' . System::getPageName(System::NO_EXTENSION);
$fn = str_replace('##PAGENAME##', $rpl_string, $fn); // create output filename
// write to file
@@ -289,32 +394,30 @@ class Logging
// for easy purpose, rename file only to attach timestamp, nur sequence numbering
rename($fn, $fn . '.' . date("YmdHis"));
}
$fp = fopen($fn, 'a');
$this->log_file_name = $fn;
$fp = fopen($this->log_file_name, 'a');
if ($fp !== false) {
fwrite($fp, $output);
fclose($fp);
} else {
echo "<!-- could not open file: $fn //-->";
echo "<!-- could not open file: " . $this->log_file_name . " //-->";
}
return true;
}
/**
* Superseeded by \CoreLibs\Debug\Support::getCallerClass() calls
*
* @return string Class name where called
* @deprecated Use \CoreLibs\Debug\Support::getCallerClass() insteader
*/
private function getCallerClass(): string
{
// get the last class entry and wrie that
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// make sure if false it is an array and then check if not class set return empty string
return (end($backtrace) ?: [])['class'] ?? '';
}
// *** PUBLIC ***
/**
* Temporary method to read all class variables for testing purpose
* @param string $name
* @return mixed can be anything, bool, string, int, array
*/
public function getSetting(string $name): mixed
{
// for debug purpose only
return $this->{$name};
}
/**
* sets the internal log file prefix id
* string must be a alphanumeric string
@@ -324,12 +427,51 @@ class Logging
*/
public function basicSetLogId(string $string): string
{
if (preg_match("/^\w+$/", $string)) {
if (preg_match("/^[\w\-]+$/", $string)) {
$this->log_file_id = $string;
}
return $this->log_file_id;
}
/**
* return current set log file id
* @return string
*/
public function getLogId(): string
{
return $this->log_file_id;
}
/**
* old name for setLogLevel
* @param string $type debug, echo, print
* @param string $flag on/off
* array $array of levels to turn on/off debug
* @return bool Return false if type or flag is invalid
*/
public function debugFor(string $type, string $flag): bool
{
/** @phan-suppress-next-line PhanTypeMismatchArgumentReal, PhanParamTooFew @phpstan-ignore-next-line */
return $this->setLogLevel(...[func_get_args()]);
}
/**
* set log level settings for All types
* if invalid type, skip
* @param string $type Type to get: debug, echo, print
* @param bool $set True or False
* @return bool Return false if type invalid
*/
public function setLogLevelAll(string $type, bool $set): bool
{
// skip set if not valid
if (!in_array($type, ['debug', 'echo', 'print'])) {
return false;
}
$this->{$type . '_output_all'} = $set;
return true;
}
/**
* get the current log level setting for All level blocks
* @param string $type Type to get: debug, echo, print
@@ -344,35 +486,6 @@ class Logging
return $this->{$type . '_output_all'};
}
/**
* set log level settings for All types
* if invalid type, skip
* @param string $type Type to get: debug, echo, print
* @param bool $set True or False
* @return void No return
*/
public function setLogLevelAll(string $type, bool $set): void
{
// skip set if not valid
if (!in_array($type, ['debug', 'echo', 'print'])) {
return;
}
$this->{$type . '_output_all'} = $set;
}
/**
* old name for setLogLevel
* @param string $type debug, echo, print
* @param string $flag on/off
* array $array of levels to turn on/off debug
* @return void has no return
*/
public function debugFor(string $type, string $flag): void
{
/** @phan-suppress-next-line PhanTypeMismatchArgumentReal, PhanParamTooFew @phpstan-ignore-next-line */
$this->setLogLevel(...[func_get_args()]);
}
/**
* passes list of level names, to turn on debug
* eg $foo->debugFor('print', 'on', ['LOG', 'DEBUG', 'INFO']);
@@ -380,17 +493,17 @@ class Logging
* @param string $type debug, echo, print
* @param string $flag on/off
* array $array of levels to turn on/off debug
* @return void has no return
* @return bool Return false if type or falg invalid
*/
public function setLogLevel(string $type, string $flag): void
public function setLogLevel(string $type, string $flag): bool
{
// abort if not valid type
if (!in_array($type, ['debug', 'echo', 'print'])) {
return;
return false;
}
// invalid flag type
if (!in_array($flag, ['on', 'off'])) {
return;
return false;
}
$debug_on = func_get_args();
array_shift($debug_on); // kick out type
@@ -401,6 +514,7 @@ class Logging
$this->{$switch}[$level] = true;
}
}
return true;
}
/**
@@ -438,14 +552,15 @@ class Logging
* - run: for each run
* @param string $type Type to get: level, class, page, run
* @param bool $set True or False
* @return void
* @return bool Return false if type invalid
*/
public function setLogPer(string $type, bool $set): void
public function setLogPer(string $type, bool $set): bool
{
if (!in_array($type, ['level', 'class', 'page', 'run'])) {
return;
return false;
}
$this->{'log_per_' . $type} = $set;
return true;
}
/**
@@ -493,16 +608,16 @@ class Logging
return false;
}
// get the last class entry and wrie that
$class = \CoreLibs\Debug\Support::getCallerClass();
$class = Support::getCallerClass();
// get timestamp
$timestamp = \CoreLibs\Debug\Support::printTime();
$timestamp = Support::printTime();
// same string put for print (no html data inside)
// write to file if set
$this->writeErrorMsg(
$level,
'[' . $timestamp . '] '
. '[' . $this->host_name . '] '
. '[' . \CoreLibs\Get\System::getPageName(2) . '] '
. '[' . System::getPageName(System::FULL_PATH) . '] '
. '[' . $this->running_uid . '] '
. '{' . $class . '} '
. '<' . $level . '> - '
@@ -544,7 +659,7 @@ class Logging
. str_replace(
['##HTMLPRE##', '##/HTMLPRE##'],
['<pre>', '</pre>'],
\CoreLibs\Convert\Html::htmlent($string)
Html::htmlent($string)
)
. "</div><!--#BR#-->";
}
@@ -583,7 +698,7 @@ class Logging
if ($this->doDebugTrigger('echo', $level)) {
$string_output .= '<div style="font-size: 12px;">'
. '[<span style="font-style: italic; color: #c56c00;">' . $level . '</span>] '
. ($string ? "<b>**** " . \CoreLibs\Convert\Html::htmlent($string) . " ****</br>\n" : "")
. ($string ? "<b>**** " . Html::htmlent($string) . " ****</br>\n" : "")
. '</div>'
. join('', $temp_debug_output);
} // echo it out
@@ -596,7 +711,7 @@ class Logging
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
. 'background-color: white; color: black;">'
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
. \CoreLibs\Debug\Support::getCallerClass() . '</span>}</div>';
. Support::getCallerClass() . '</span>}</div>';
$string_output = $string_prefix . $string_output
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
. $script_end . '</div>'