diff --git a/src/ACL/Login.php b/src/ACL/Login.php index e657ee1..a3681bf 100644 --- a/src/ACL/Login.php +++ b/src/ACL/Login.php @@ -73,65 +73,65 @@ use CoreLibs\Convert\Json; class Login { - /** @var string the user id var*/ - private $euid; + /** @var ?int the user id var*/ + private ?int $euid; /** @var string _GET/_POST loginUserId parameter for non password login */ - private $login_user_id = ''; + private string $login_user_id = ''; /** @var string source, either _GET or _POST or empty */ - private $login_user_id_source = ''; + private string $login_user_id_source = ''; /** @var bool set to true if illegal characters where found in the login user id string */ - private $login_user_id_unclear = false; + private bool $login_user_id_unclear = false; // is set to one if login okay, or EUID is set and user is okay to access this page /** @var bool */ - private $permission_okay = false; + private bool $permission_okay = false; /** @var string pressed login */ - private $login = ''; + private string $login = ''; /** @var string master action command */ - private $action; + private string $action; /** @var string login name */ - private $username; + private string $username; /** @var string login password */ - private $password; + private string $password; /** @var string logout button */ - private $logout; + private string $logout; /** @var bool if this is set to true, the user can change passwords */ - private $password_change = false; + private bool $password_change = false; /** @var bool password change was successful */ - private $password_change_ok = false; + private bool $password_change_ok = false; // can we reset password and mail to user with new password set screen /** @var bool */ - private $password_forgot = false; + private bool $password_forgot = false; /** @var bool password forgot mail send ok */ // private $password_forgot_ok = false; /** @var string */ - private $change_password; + private string $change_password; /** @var string */ - private $pw_username; + private string $pw_username; /** @var string */ - private $pw_old_password; + private string $pw_old_password; /** @var string */ - private $pw_new_password; + private string $pw_new_password; /** @var string */ - private $pw_new_password_confirm; + private string $pw_new_password_confirm; /** @var array array of users for which the password change is forbidden */ - private $pw_change_deny_users = []; + private array $pw_change_deny_users = []; /** @var string */ - private $logout_target = ''; + private string $logout_target = ''; /** @var int */ - private $max_login_error_count = -1; + private int $max_login_error_count = -1; /** @var array */ - private $lock_deny_users = []; + private array $lock_deny_users = []; /** @var string */ - private $page_name = ''; + private string $page_name = ''; /** @var int if we have password change we need to define some rules */ - private $password_min_length = 9; + private int $password_min_length = 9; /** @var int an true maxium min, can never be set below this */ - private $password_min_length_max = 9; + private int $password_min_length_max = 9; // max length is fixed as 255 (for input type max), if set highter // it will be set back to 255 /** @var int */ - private $password_max_length = 255; + private int $password_max_length = 255; /** @var int minum password length */ public const PASSWORD_MIN_LENGTH = 9; @@ -158,7 +158,7 @@ class Login . "$/"; /** @var array can have several regexes, if nothing set, all is ok */ - private $password_valid_chars = [ + private array $password_valid_chars = [ // '^(?=.*\d)(?=.*[A-Za-z])[0-9A-Za-z!@#$%]{8,}$', // '^(?.*(\pL)u)(?=.*(\pN)u)(?=.*([^\pL\pN])u).{8,}', ]; @@ -166,13 +166,13 @@ class Login // login error code, can be matched to the array login_error_msg, // which holds the string /** @var int */ - private $login_error = 0; + private int $login_error = 0; /** @var array all possible login error conditions */ - private $login_error_msg = []; + private array $login_error_msg = []; // this is an array holding all strings & templates passed // rom the outside (translation) /** @var array */ - private $login_template = [ + private array $login_template = [ 'strings' => [], 'password_change' => '', 'template' => '' @@ -180,59 +180,59 @@ class Login // acl vars /** @var array */ - private $acl = []; + private array $acl = []; /** @var array */ - private $default_acl_list = []; + private array $default_acl_list = []; /** @var array Reverse list to lookup level from type */ - private $default_acl_list_type = []; + private array $default_acl_list_type = []; /** @var int default ACL level to be based on if nothing set */ - private $default_acl_level = 0; + private int $default_acl_level = 0; // login html, if we are on an ajax page /** @var string|null */ - private $login_html = ''; + private ?string $login_html = ''; /** @var bool */ - private $login_is_ajax_page = false; + private bool $login_is_ajax_page = false; // settings /** @var array options */ - private $options = []; + private array $options = []; /** @var array locale options: locale, domain, encoding (opt), path */ - private $locale = [ + private array $locale = [ 'locale' => '', 'domain' => '', 'encoding' => '', 'path' => '', ]; - /** @var \CoreLibs\Debug\Logging logger */ - public $log; + /** @var \CoreLibs\Logging\Logging logger */ + public \CoreLibs\Logging\Logging $log; /** @var \CoreLibs\DB\IO database */ - public $db; + public \CoreLibs\DB\IO $db; /** @var \CoreLibs\Language\L10n language */ - public $l; + public \CoreLibs\Language\L10n $l; /** @var \CoreLibs\Create\Session session class */ - public $session; + public \CoreLibs\Create\Session $session; /** * constructor, does ALL, opens db, works through connection checks, * finishes itself * * @param \CoreLibs\DB\IO $db Database connection class - * @param \CoreLibs\Debug\Logging $log Logging class + * @param \CoreLibs\Logging\Logging $log Logging class * @param \CoreLibs\Create\Session $session Session interface class * @param array $options Login ACL settings * $auto_login [default true] DEPRECATED, moved into options */ public function __construct( \CoreLibs\DB\IO $db, - \CoreLibs\Debug\Logging $log, + \CoreLibs\Logging\Logging $log, \CoreLibs\Create\Session $session, array $options = [] ) { // attach db class $this->db = $db; // log login data for this class only - $log->setLogPer('class', true); + $log->setLogFlag(\CoreLibs\Logging\Logger\Flag::per_class); // attach logger $this->log = $log; // attach session class @@ -883,7 +883,7 @@ class Login } // normal user processing // set class var and session var - $_SESSION['EUID'] = $this->euid = $res['edit_user_id']; + $_SESSION['EUID'] = $this->euid = (int)$res['edit_user_id']; // check if user is okay $this->loginCheckPermissions(); if ($this->login_error == 0) { @@ -1048,7 +1048,7 @@ class Login } // build master unit array $unit_access[$res['edit_access_id']] = [ - 'id' => $res['edit_access_id'], + 'id' => (int)$res['edit_access_id'], 'acl_level' => $res['level'], 'acl_type' => $res['type'], 'name' => $res['name'], @@ -1179,6 +1179,12 @@ class Login $this->acl['page'] = $_SESSION['PAGES_ACL_LEVEL'][$this->page_name]; } + $this->acl['unit_id'] = null; + $this->acl['unit_name'] = null; + $this->acl['unit_uid'] = null; + $this->acl['unit'] = []; + $this->acl['unit_detail'] = []; + // PER ACCOUNT (UNIT/edit access)-> foreach ($_SESSION['UNIT'] as $ea_id => $unit) { // if admin flag is set, all units are set to 100 @@ -1849,7 +1855,7 @@ HTML; if ($login_user_id_changed > 0) { $this->login_user_id_unclear = true; // error for invalid user id? - $this->log->debug('LOGIN USER ID', 'Invalid characters: ' + $this->log->error('LOGIN USER ID: Invalid characters: ' . $login_user_id_changed . ' in loginUserId: ' . $this->login_user_id . ' (' . $this->login_user_id_source . ')'); } @@ -1911,21 +1917,6 @@ HTML; // echo $this->login_html; $this->loginPrintLogin(); } - // do not go anywhere, quit processing here - // do something with possible debug data? - if ( - in_array($this->options['target'], ['live', 'remove']) - ) { - // login - $this->log->setLogLevelAll('debug', $this->options['debug']); - $this->log->setLogLevelAll('echo', false); - $this->log->setLogLevelAll('print', $this->options['debug']); - } - $status_msg = $this->log->printErrorMsg(); - // if ($this->echo_output_all) { - if ($this->log->getLogLevelAll('echo')) { - echo $status_msg; - } // exit so we don't process anything further, at all $this->loginTerminate(3000); } else { @@ -2119,7 +2110,7 @@ HTML; // unset session vars set/used in this login $this->session->sessionDestroy(); // unset euid - $this->euid = ''; + $this->euid = null; // then prints the login screen again $this->permission_okay = false; } @@ -2507,7 +2498,7 @@ HTML; */ public function loginGetEuid(): string { - return $this->euid; + return (string)$this->euid; } } diff --git a/src/Admin/Backend.php b/src/Admin/Backend.php index 2ea4804..67f6659 100644 --- a/src/Admin/Backend.php +++ b/src/Admin/Backend.php @@ -35,97 +35,97 @@ class Backend { // page name /** @var array */ - public $menu = []; + public array $menu = []; /** @var int|string */ - public $menu_show_flag = 0; // top menu flag (mostly string) + public int|string $menu_show_flag = 0; // top menu flag (mostly string) // action ids /** @var array */ - public $action_list = [ + public array $action_list = [ 'action', 'action_id', 'action_sub_id', 'action_yes', 'action_flag', 'action_menu', 'action_value', 'action_error', 'action_loaded' ]; /** @var string */ - public $action; + public string $action; /** @var string|int */ - public $action_id; + public string|int $action_id; /** @var string|int */ - public $action_sub_id; + public string|int $action_sub_id; /** @var string|int|bool */ - public $action_yes; + public string|int|bool $action_yes; /** @var string */ - public $action_flag; + public string $action_flag; /** @var string */ - public $action_menu; + public string $action_menu; /** @var string */ - public $action_loaded; + public string $action_loaded; /** @var string */ - public $action_value; + public string $action_value; /** @var string */ - public $action_error; + public string $action_error; // ACL array variable if we want to set acl data from outisde /** @var array */ - public $acl = []; + public array $acl = []; /** @var int */ - public $default_acl; + public int $default_acl; // queue key /** @var string */ - public $queue_key; + public string $queue_key; // the current active edit access id - /** @var int */ - public $edit_access_id; + /** @var int|null */ + public int|null $edit_access_id; /** @var string */ - public $page_name; + public string $page_name; // error/warning/info messages /** @var array */ - public $messages = []; + public array $messages = []; /** @var bool */ - public $error = false; + public bool $error = false; /** @var bool */ - public $warning = false; + public bool $warning = false; /** @var bool */ - public $info = false; + public bool $info = false; // internal lang & encoding vars /** @var string */ - public $lang_dir = ''; + public string $lang_dir = ''; /** @var string */ - public $lang; + public string $lang; /** @var string */ - public $lang_short; + public string $lang_short; /** @var string */ - public $domain; + public string $domain; /** @var string */ - public $encoding; - /** @var \CoreLibs\Debug\Logging logger */ - public $log; + public string $encoding; + /** @var \CoreLibs\Logging\Logging logger */ + public \CoreLibs\Logging\Logging $log; /** @var \CoreLibs\DB\IO database */ - public $db; + public \CoreLibs\DB\IO $db; /** @var \CoreLibs\Language\L10n language */ - public $l; + public \CoreLibs\Language\L10n $l; /** @var \CoreLibs\Create\Session session class */ - public $session; + public \CoreLibs\Create\Session $session; // smarty publics [end processing in smarty class] /** @var array */ - public $DATA; + public array $DATA = []; /** @var array */ - public $HEADER; + public array $HEADER = []; /** @var array */ - public $DEBUG_DATA; + public array $DEBUG_DATA = []; /** @var array */ - public $CONTENT_DATA; + public array $CONTENT_DATA = []; // CONSTRUCTOR / DECONSTRUCTOR |====================================> /** * main class constructor * * @param \CoreLibs\DB\IO $db Database connection class - * @param \CoreLibs\Debug\Logging $log Logging class + * @param \CoreLibs\Logging\Logging $log Logging class * @param \CoreLibs\Create\Session $session Session interface class * @param \CoreLibs\Language\L10n $l10n l10n language class * @param int|null $set_default_acl_level Default ACL level */ public function __construct( \CoreLibs\DB\IO $db, - \CoreLibs\Debug\Logging $log, + \CoreLibs\Logging\Logging $log, \CoreLibs\Create\Session $session, \CoreLibs\Language\L10n $l10n, ?int $set_default_acl_level = null @@ -133,7 +133,7 @@ class Backend // attach db class $this->db = $db; // set to log not per class - $log->setLogPer('class', false); + $log->unsetLogFlag(\CoreLibs\Logging\Logger\Flag::per_class); // attach logger $this->log = $log; // attach session class diff --git a/src/Admin/EditBase.php b/src/Admin/EditBase.php index 3933d53..6a18572 100644 --- a/src/Admin/EditBase.php +++ b/src/Admin/EditBase.php @@ -20,36 +20,36 @@ use SmartyException; class EditBase { /** @var array */ - private $HEADER = []; + private array $HEADER = []; /** @var array */ - private $DATA = []; + private array $DATA = []; /** @var array */ - private $DEBUG_DATA = []; + private array $DEBUG_DATA = []; /** @var string the template name */ - private $EDIT_TEMPLATE = ''; + private string $EDIT_TEMPLATE = ''; /** @var \CoreLibs\Template\SmartyExtend smarty system */ - private $smarty; + private \CoreLibs\Template\SmartyExtend $smarty; /** @var \CoreLibs\Output\Form\Generate form generate system */ - private $form; - /** @var \CoreLibs\Debug\Logging */ - public $log; + private \CoreLibs\Output\Form\Generate $form; + /** @var \CoreLibs\Logging\Logging */ + public \CoreLibs\Logging\Logging $log; /** @var \CoreLibs\ACL\Login */ - public $login; + public \CoreLibs\ACL\Login $login; /** * construct form generator * * @param array $db_config db config array, mandatory - * @param \CoreLibs\Debug\Logging $log Logging class, null auto set + * @param \CoreLibs\Logging\Logging $log Logging class, null auto set * @param \CoreLibs\Language\L10n $l10n l10n language class, null auto set * @param \CoreLibs\ACL\Login $login login class for ACL settings * @param array $options Various settings options */ public function __construct( array $db_config, - \CoreLibs\Debug\Logging $log, + \CoreLibs\Logging\Logging $log, \CoreLibs\Language\L10n $l10n, \CoreLibs\ACL\Login $login, array $options @@ -63,7 +63,7 @@ class EditBase $options['compile_id'] ?? '', ); // turn off set log per class - $log->setLogPer('class', false); + $log->unsetLogFlag(\CoreLibs\Logging\Logger\Flag::per_class); // create form class $this->form = new \CoreLibs\Output\Form\Generate( diff --git a/src/Basic.php b/src/Basic.php index 7e1882e..d069486 100644 --- a/src/Basic.php +++ b/src/Basic.php @@ -58,39 +58,39 @@ class Basic { // page and host name /** @var string */ - public $page_name; + public string $page_name; /** @var string */ - public $host_name; + public string $host_name; /** @var int */ - public $host_port; + public int $host_port; // logging interface, Debug\Logging class - /** @var \CoreLibs\Debug\Logging */ - public $log; + /** @var \CoreLibs\Logging\Logging */ + public \CoreLibs\Logging\Logging $log; /** @var \CoreLibs\Create\Session */ - public $session; + public \CoreLibs\Create\Session $session; // email valid checks /** @var array */ - public $email_regex_check = []; + public array $email_regex_check = []; /** @var string */ - public $email_regex; // regex var for email check + public string $email_regex; // regex var for email check // data path for files /** @var array */ - public $data_path = []; + public array $data_path = []; // ajax flag /** @var bool */ - protected $ajax_page_flag = false; + protected bool $ajax_page_flag = false; /** * main Basic constructor to init and check base settings - * @param \CoreLibs\Debug\Logging|null $log Logging class + * @param \CoreLibs\Logging\Logging|null $log Logging class * @param string|null $session_name Set session name * @deprecated DO NOT USE Class\Basic anymore. Use dedicated logger and sub classes */ public function __construct( - \CoreLibs\Debug\Logging $log = null, + \CoreLibs\Logging\Logging $log = null, ?string $session_name = null ) { trigger_error('Class \CoreLibs\Basic is deprected', E_USER_DEPRECATED); @@ -120,7 +120,10 @@ class Basic } // logging interface moved here (->debug is now ->log->debug) - $this->log = $log ?? new \CoreLibs\Debug\Logging(); + $this->log = $log ?? new \CoreLibs\Logging\Logging([ + 'log_folder' => BASE . LOG, + 'log_file_id' => 'ClassBasic-DEPRECATED', + ]); // set ajax page flag based on the AJAX_PAGE varaibles // convert to true/false so if AJAX_PAGE is 0 or false it is @@ -176,8 +179,9 @@ class Basic */ public function basicSetLogId(string $string): string { - trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->basicSetLogId() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED); - return $this->log->setLogId($string); + trigger_error('Method ' . __METHOD__ . ' is deprecated, use log->setLogId() or use \CoreLibs\Logging\Logging() class', E_USER_DEPRECATED); + $this->log->setLogFileId($string); + return $this->log->getLogFileId(); } // ****** DEBUG/ERROR FUNCTIONS ****** @@ -252,7 +256,7 @@ class Basic } // ****** DEBUG LOGGING FUNCTIONS ****** - // Moved to \CoreLibs\Debug\Logging + // Moved to \CoreLibs\Logging\Logging /** * passes list of level names, to turn on debug @@ -265,68 +269,9 @@ class Basic */ public function debugFor(string $type, string $flag): void { - trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->debugFor() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED); - /** @phan-suppress-next-line PhanTypeMismatchArgumentReal, PhanParamTooFew @phpstan-ignore-next-line */ - $this->log->setLogLevel(...[func_get_args()]); + trigger_error('Method ' . __METHOD__ . ' functionaility is fully deprecated', E_USER_DEPRECATED); } - /** - * checks if we have a need to work on certain debug output - * Needs debug/echo/print ad target for which of the debug flag groups we check - * also needs level string to check in the per level output flag check. - * In case we have invalid target it will return false - * @param string $target target group to check debug/echo/print - * @param string $level level to check in detailed level flag - * @return bool true on access allowed or false on no access - */ - /* private function doDebugTrigger(string $target, string $level): bool - { - $access = false; - // check if we do debug, echo or print - switch ($target) { - case 'debug': - if (( - (isset($this->debug_output[$level]) && $this->debug_output[$level]) || - $this->debug_output_all - ) && - (!isset($this->debug_output_not[$level]) || - (isset($this->debug_output_not[$level]) && !$this->debug_output_not[$level]) - ) - ) { - $access = true; - } - break; - case 'echo': - if (( - (isset($this->echo_output[$level]) && $this->echo_output[$level]) || - $this->echo_output_all - ) && - (!isset($this->echo_output_not[$level]) || - (isset($this->echo_output_not[$level]) && !$this->echo_output_not[$level]) - ) - ) { - $access = true; - } - break; - case 'print': - if (( - (isset($this->print_output[$level]) && $this->print_output[$level]) || - $this->print_output_all - ) && - (!isset($this->print_output_not[$level]) || - (isset($this->print_output_not[$level]) && !$this->print_output_not[$level]) - ) - ) { - $access = true; - } - break; - default: - // fall through with access false - break; - } - return $access; - } */ - /** * write debug data to error_msg array * @param string $level id for error message, groups messages together @@ -335,11 +280,12 @@ class Basic * all html tags will be stripped and
changed to \n * this is only used for debug output * @return void has no return - * @deprecated Use $basic->log->debug() instead + * @deprecated Use Logger\Logger->debug() instead */ public function debug(string $level, string $string, bool $strip = false): void { - $this->log->debug($level, $string, $strip); + trigger_error('Method ' . __METHOD__ . ' has moved to Logger\Logger->debug()', E_USER_DEPRECATED); + $this->log->debug($level, $string); } /** @@ -351,8 +297,7 @@ class Basic */ public function mergeErrors(array $error_msg = []): void { - trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->mergeErrors() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED); - $this->log->mergeErrors($error_msg); + trigger_error('Method ' . __METHOD__ . ' is fully deprecated', E_USER_DEPRECATED); } /** @@ -363,7 +308,8 @@ class Basic */ public function printErrorMsg(string $string = ''): string { - return $this->log->printErrorMsg($string); + trigger_error('Method ' . __METHOD__ . ' is fully deprecated', E_USER_DEPRECATED); + return ''; } /** @@ -376,8 +322,7 @@ class Basic */ public function resetErrorMsg(string $level = ''): void { - trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->resetErrorMsg() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED); - $this->log->resetErrorMsg($level); + trigger_error('Method ' . __METHOD__ . ' is fully deprecated', E_USER_DEPRECATED); } // ****** DEBUG SUPPORT FUNCTIONS ****** @@ -388,11 +333,11 @@ class Basic * prints a html formatted (pre) array * @param array $array any array * @return string formatted array for output with
 tag added
-	 * @deprecated Use $this->log->prAr() instead
+	 * @deprecated Use \CoreLibs\Debug\Support::prAr() instead
 	 */
 	public function printAr(array $array): string
 	{
-		return $this->log->prAr($array);
+		return \CoreLibs\Debug\Support::prAr($array);
 	}
 
 	/**
diff --git a/src/Check/Email.php b/src/Check/Email.php
index 8c8c843..6e78bee 100644
--- a/src/Check/Email.php
+++ b/src/Check/Email.php
@@ -8,7 +8,7 @@ class Email
 {
 	// this is for error check parts in where the email regex failed
 	/** @var array */
-	private static $email_regex_check = [
+	private static array $email_regex_check = [
 		0 => "^[A-Za-z0-9!#$%&'*+\-\/=?^_`{|}~][A-Za-z0-9!#$%:\(\)&'*+\-\/=?^_`{|}~\.]{0,63}@"
 			. "[a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]{1,})*\.([a-zA-Z]{2,}){1}$", // MASTER
 		1 => "@(.*)@(.*)", // double @
@@ -21,7 +21,7 @@ class Email
 	];
 	// for above position, description string below
 	/** @var array */
-	private static $email_regex_check_message = [
+	private static array $email_regex_check_message = [
 		0 => 'Invalid email address',
 		1 => 'Double @ mark in email address',
 		2 => 'Invalid email part before @ sign',
@@ -33,7 +33,7 @@ class Email
 	];
 	// the array with the mobile types that are valid
 	/** @var array */
-	private static $mobile_email_type = [
+	private static array $mobile_email_type = [
 		'.*@docomo\.ne\.jp$' => 'keitai_docomo',
 		// correct are a[2-4], b2, c[1-9], e[2-9], h[2-4], t[1-9]
 		'.*@([a-z0-9]{2}\.)?ezweb\.ne\.jp$' => 'keitai_kddi_ezweb',
@@ -72,7 +72,7 @@ class Email
 	];
 	// short list for mobile email types
 	/** @var array */
-	private static $mobile_email_type_short = [
+	private static array $mobile_email_type_short = [
 		'keitai_docomo' => 'docomo',
 		'keitai_kddi_ezweb' => 'kddi',
 		'keitai_kddi' => 'kddi',
diff --git a/src/Check/Encoding.php b/src/Check/Encoding.php
index 782b479..3141e43 100644
--- a/src/Check/Encoding.php
+++ b/src/Check/Encoding.php
@@ -11,7 +11,7 @@ namespace CoreLibs\Check;
 class Encoding
 {
 	/** @var int|int<1, max>|string */
-	private static $mb_error_char = '';
+	private static int|string $mb_error_char = '';
 
 	/**
 	 * set error char
diff --git a/src/Convert/MimeAppName.php b/src/Convert/MimeAppName.php
index 07fc54b..422ea4a 100644
--- a/src/Convert/MimeAppName.php
+++ b/src/Convert/MimeAppName.php
@@ -12,7 +12,7 @@ namespace CoreLibs\Convert;
 class MimeAppName
 {
 	/** @var array */
-	private static $mime_apps = [];
+	private static array $mime_apps = [];
 
 	/**
 	 * constructor: init mime list
diff --git a/src/Create/Email.php b/src/Create/Email.php
index def7437..5e0c6f7 100644
--- a/src/Create/Email.php
+++ b/src/Create/Email.php
@@ -14,7 +14,7 @@ namespace CoreLibs\Create;
 class Email
 {
 	/** @var array allowed list for encodings that can do KV folding */
-	private static $encoding_kv_allowed = [
+	private static array $encoding_kv_allowed = [
 		'UTF-8',
 		'EUC-JP',
 		'SJIS',
@@ -25,7 +25,7 @@ class Email
 		'JIS-ms',
 	];
 	/** @var string normaly this does not need to be changed */
-	private static $mb_convert_kana_mode = 'KV';
+	private static string $mb_convert_kana_mode = 'KV';
 
 	/**
 	 * create mime encoded email part for to/from emails.
@@ -137,7 +137,7 @@ class Email
 	 * @param  bool                 $kv_folding      If set to true and a valid encoding,
 	 *                                               do KV folding
 	 * @param  bool                 $test            test flag, default off
-	 * @param  \CoreLibs\Debug\Logging|null $log     Logging class,
+	 * @param  \CoreLibs\Logging\Logging|null $log     Logging class,
 	 *                                               only used if test flag is true
 	 * @return int                  2 test only, no sent
 	 *                              1 for ok,
@@ -156,7 +156,7 @@ class Email
 		string $encoding = 'UTF-8',
 		bool $kv_folding = false,
 		bool $test = false,
-		?\CoreLibs\Debug\Logging $log = null
+		?\CoreLibs\Logging\Logging $log = null
 	): int {
 		/** @var array */
 		$to_emails = [];
@@ -259,11 +259,11 @@ class Email
 				$mail_delivery_status = 2;
 			}
 			// log if an log instance exists
-			if ($log instanceof \CoreLibs\Debug\Logging) {
+			if ($log instanceof \CoreLibs\Logging\Logging) {
 				// build debug strings: convert to UTF-8 if not utf-8
-				$log->debug('SEND EMAIL', 'HEADERS: ' . $log->prAr($headers) . ', '
+				$log->debug('SEND EMAIL', 'HEADERS: ' . \CoreLibs\Debug\Support::prAr($headers) . ', '
 					. 'ENCODING: ' . $encoding . ',  '
-					. 'KV FOLDING: ' . $log->prBl($kv_folding) . ',  '
+					. 'KV FOLDING: ' . \CoreLibs\Debug\Support::prBl($kv_folding) . ',  '
 					. 'TO: ' . $to_email . ', '
 					. 'SUBJECT: ' . $out_subject . ', '
 					. 'BODY: ' . ($encoding == 'UTF-8' ?
diff --git a/src/Create/Hash.php b/src/Create/Hash.php
index beadac6..bf83afe 100644
--- a/src/Create/Hash.php
+++ b/src/Create/Hash.php
@@ -10,6 +10,7 @@ namespace CoreLibs\Create;
 
 class Hash
 {
+	public const DEFAULT_HASH = 'adler32';
 	public const STANDARD_HASH_LONG = 'ripemd160';
 	public const STANDARD_HASH_SHORT = 'adler32';
 
@@ -58,7 +59,7 @@ class Hash
 	/**
 	 * replacemend for __crc32b call (alternate)
 	 * defaults to adler 32
-	 * allowed crc32b, adler32, fnv132, fnv1a32, joaat
+	 * allowed: any in hash algos list, default to adler 32
 	 * all that create 8 char long hashes
 	 *
 	 * @param  string $string    string to hash
@@ -67,15 +68,15 @@ class Hash
 	 */
 	public static function __hash(
 		string $string,
-		string $hash_type = self::STANDARD_HASH_SHORT
+		string $hash_type = self::DEFAULT_HASH
 	): string {
+		// if not empty, check if in valid list
 		if (
-			!in_array(
-				$hash_type,
-				['crc32b', 'adler32', 'fnv132', 'fnv1a32', 'joaat']
-			)
+			empty($hash_type) ||
+			!in_array($hash_type, hash_algos())
 		) {
-			$hash_type = 'adler32';
+			// fallback to default hash type if none set or invalid
+			$hash_type = self::DEFAULT_HASH;
 		}
 		return hash($hash_type, $string);
 	}
diff --git a/src/Create/RandomKey.php b/src/Create/RandomKey.php
index 3d34079..6d57f75 100644
--- a/src/Create/RandomKey.php
+++ b/src/Create/RandomKey.php
@@ -12,13 +12,13 @@ class RandomKey
 {
 	// key generation
 	/** @var string */
-	private static $key_range = '';
+	private static string $key_range = '';
 	/** @var int */
-	private static $one_key_length;
+	private static int $one_key_length;
 	/** @var int */
-	private static $key_length = 4; // default key length
+	private static int $key_length = 4; // default key length
 	/** @var int */
-	private static $max_key_length = 256; // max allowed length
+	private static int $max_key_length = 256; // max allowed length
 
 	/**
 	 * if launched as class, init random key data first
@@ -100,7 +100,9 @@ class RandomKey
 	public static function randomKeyGen(int $key_length = -1): string
 	{
 		// init random key strings if not set
-		if (!is_numeric(self::$one_key_length)) {
+		if (
+			!isset(self::$one_key_length)
+		) {
 			self::initRandomKeyData();
 		}
 		$use_key_length = 0;
diff --git a/src/Create/Session.php b/src/Create/Session.php
index 46468cc..f7a0f7f 100644
--- a/src/Create/Session.php
+++ b/src/Create/Session.php
@@ -16,7 +16,7 @@ namespace CoreLibs\Create;
 class Session
 {
 	/** @var string list for errors */
-	private $session_intern_error_str = '';
+	private string $session_intern_error_str = '';
 
 	/**
 	 * init a session, if array is empty or array does not have session_name set
diff --git a/src/Create/Uids.php b/src/Create/Uids.php
index a8b1bba..4769133 100644
--- a/src/Create/Uids.php
+++ b/src/Create/Uids.php
@@ -1,5 +1,12 @@
  8)
+	 * @param  bool   $force_length [default=false] if set to true and we have
+	 *                              uneven length, then we shorten to this length
+	 * @return string         Uniq id
+	 */
+	private static function uniqIdL(int $length = 64, bool $force_length = false): string
+	{
+		$uniqid_length = ($length < 4) ? 4 : $length;
+		if ($force_length) {
+			$uniqid_length++;
+		}
+		/** @var int<1,max> make sure that internal this is correct */
+		$random_bytes_length = ($uniqid_length - ($uniqid_length % 2)) / 2;
+		$uniqid = bin2hex(random_bytes($random_bytes_length));
+		// if not forced shorten return next lower length
+		if (!$force_length) {
+			return $uniqid;
+		}
+		return substr($uniqid, 0, $length);
+	}
+
 	/**
 	 * creates psuedo random uuid v4
 	 * Code take from class here:
@@ -20,7 +56,7 @@ class Uids
 	 */
 	public static function uuidv4(): string
 	{
-		return sprintf(
+		/* return sprintf(
 			'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
 			// 32 bits for "time_low"
 			mt_rand(0, 0xffff),
@@ -38,49 +74,62 @@ class Uids
 			mt_rand(0, 0xffff),
 			mt_rand(0, 0xffff),
 			mt_rand(0, 0xffff)
-		);
+		); */
+
+		$data = random_bytes(16);
+		assert(strlen($data) == 16);
+
+		// 0-1: 32 bits for "time_low"
+		//   2: 16 bits for "time_mid"
+		//   3: 16 bits for "time_hi_and_version",
+		//      four most significant bits holds version number 4
+		$data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
+		//   4: 16 bits, 8 bits for "clk_seq_hi_res",
+		//      8 bits for "clk_seq_low",
+		//      two most significant bits holds zero and one for variant DCE1.1
+		$data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
+		// 5-7: 48 bits for "node"
+
+		return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
 	}
 
 	/**
-	 * TODO: make this a proper uniq ID creation
-	 *       add uuidv4 subcall to the uuid function too
-	 * creates a uniq id
+	 * creates a uniq id based on lengths
 	 *
-	 * @param  string $type uniq id type, currently md5 or sha256 allowed
-	 *                      if not set will use DEFAULT_HASH if set
-	 * @return string       uniq id
+	 * @param  int|string $length Either length in int, or fallback type for length
+	 *                            for string type md5 (32), sha256 (64)
+	 *                            STANDARD_HASH_LONG: ripemd160 (40)
+	 *                            STANDARD_HASH_SHORT: adler32 (8)
+	 *                            It is recommended to use the integer
+	 * @param  bool       $force_length [default=false] if set to true and we have
+	 *                                  uneven length, then we shorten to this length
+	 * @return string             Uniq id
 	 */
-	public static function uniqId(string $type = ''): string
-	{
-		$uniq_id = '';
-		switch ($type) {
+	public static function uniqId(
+		int|string $length = self::DEFAULT_UNNIQ_ID_LENGTH,
+		bool $force_length = false
+	): string {
+		if (is_int($length)) {
+			return self::uniqIdL($length, $force_length);
+		}
+		switch ($length) {
 			case 'md5':
-				$uniq_id = md5(uniqid((string)rand(), true));
+				$length = 32;
 				break;
-			case self::DEFAULT_HASH:
-				$uniq_id = hash(self::DEFAULT_HASH, uniqid((string)rand(), true));
+			case 'sha256':
+				$length = 64;
 				break;
 			case self::STANDARD_HASH_LONG:
-				$uniq_id = hash(self::STANDARD_HASH_LONG, uniqid((string)rand(), true));
+				$length = 40;
 				break;
 			case self::STANDARD_HASH_SHORT:
-				$uniq_id = hash(self::STANDARD_HASH_SHORT, uniqid((string)rand(), true));
+				$length = 8;
 				break;
 			default:
-				// if not empty, check if in valid list
-				if (
-					!empty($type) &&
-					in_array($type, hash_algos())
-				) {
-					$hash = $type;
-				} else {
-					// fallback to default hash type if none set or invalid
-					$hash = self::DEFAULT_HASH;
-				}
-				$uniq_id = hash($hash, uniqid((string)rand(), true));
+				$length = 64;
 				break;
 		}
-		return $uniq_id;
+		return self::uniqIdL($length);
 	}
 
 	/**
diff --git a/src/DB/Extended/ArrayIO.php b/src/DB/Extended/ArrayIO.php
index 5abeac9..2dce7bb 100644
--- a/src/DB/Extended/ArrayIO.php
+++ b/src/DB/Extended/ArrayIO.php
@@ -39,16 +39,16 @@ class ArrayIO extends \CoreLibs\DB\IO
 {
 	// main calss variables
 	/** @var array */
-	public $table_array; // the array from the table to work on
+	public array $table_array; // the array from the table to work on
 	/** @var string */
-	public $table_name; // the table_name
+	public string $table_name; // the table_name
 	/** @var string */
-	public $pk_name = ''; // the primary key from this table
+	public string $pk_name = ''; // the primary key from this table
 	/** @var int|string|null */
-	public $pk_id; // the PK id
+	public int|string|null $pk_id; // the PK id
 	// security values
 	/** @var int base acl for current page */
-	private $base_acl_level = 0;
+	private int $base_acl_level = 0;
 
 	/**
 	 * constructor for the array io class, set the
@@ -57,7 +57,7 @@ class ArrayIO extends \CoreLibs\DB\IO
 	 * @param array $db_config      db connection config
 	 * @param array $table_array    table array config
 	 * @param string       $table_name     table name string
-	 * @param \CoreLibs\Debug\Logging $log Logging class
+	 * @param \CoreLibs\Logging\Logging $log Logging class
 	 * @param int          $base_acl_level Set base acl level, if needed
 	 * @param int          $acl_admin      Flag if this is an admin ACL access level
 	 */
@@ -65,7 +65,7 @@ class ArrayIO extends \CoreLibs\DB\IO
 		array $db_config,
 		array $table_array,
 		string $table_name,
-		\CoreLibs\Debug\Logging $log,
+		\CoreLibs\Logging\Logging $log,
 		int $base_acl_level = 0,
 		int $acl_admin = 0
 	) {
@@ -243,7 +243,7 @@ class ArrayIO extends \CoreLibs\DB\IO
 			return $this->table_array;
 		}
 		if ($acl_limit === true && $this->base_acl_level < 100) {
-			$this->log->debug('DB DELETE ERROR', 'ACL Limit on, Delete, '
+			$this->log->error('DB DELETE ERROR: ACL Limit on, Delete, '
 				. 'but base ACL level of 100 not met: ' . $this->base_acl_level);
 			return $this->table_array;
 		}
@@ -406,7 +406,7 @@ class ArrayIO extends \CoreLibs\DB\IO
 		}
 		// early abort for new write with not enough ACL level
 		if ($insert && $acl_limit === true && $this->base_acl_level < 100) {
-			$this->log->debug('DB WRITE ERROR', 'ACL Limit on, Insert, '
+			$this->log->error('DB WRITE ERROR: ACL Limit on, Insert, '
 				. 'but base ACL level of 100 not met: ' . $this->base_acl_level);
 			return $this->table_array;
 		}
@@ -579,7 +579,7 @@ class ArrayIO extends \CoreLibs\DB\IO
 		} // while ...
 
 		if (empty($q_data)) {
-			$this->log->debug('DB WRITE ERROR', 'No data to write, possible through ACL');
+			$this->log->error('DB WRITE ERROR: No data to write, possible through ACL');
 			return $this->table_array;
 		}
 
diff --git a/src/DB/IO.php b/src/DB/IO.php
index 6d0f1e5..29b0b19 100644
--- a/src/DB/IO.php
+++ b/src/DB/IO.php
@@ -298,111 +298,108 @@ class IO
 	// can bet set from outside
 	// encoding to
 	/** @var string */
-	private $to_encoding = '';
-	/** @var string */
-	private $query; // the query string at the moment
-	/** @var array */
-	private $params; // current params for query
+	private string $to_encoding = '';
+	/** @var string the query string at the moment */
+	private string $query;
+	/** @var array current params for query */
+	private array $params;
 	// only inside
 	// basic vars
-	/** @var \PgSql\Connection|false|null */ // replace object with PgSql\Connection|
-	private $dbh; // the dbh handler, if disconnected by command is null, bool:false on error,
-	/** @var bool */
-	private $db_debug = false; // DB_DEBUG ... (if set prints out debug msgs)
-	/** @var string */
-	private $db_name; // the DB connected to
-	/** @var string */
-	private $db_user; // the username used
-	/** @var string */
-	private $db_pwd; // the password used
-	/** @var string */
-	private $db_host; // the hostname
-	/** @var int */
-	private $db_port; // default db port
-	/** @var string */
-	private $db_schema; // optional DB schema, if not set uses public
-	/** @var string */
-	private $db_encoding; // optional auto encoding convert, not used if not set
-	/** @var string */
-	private $db_type; // type of db (mysql,postgres,...)
-	/** @var string */
-	private $db_ssl; // ssl flag (for postgres only), disable, allow, prefer, require
+	// the dbh handler, if disconnected by command is null, bool:false on error,
+	/** @var \PgSql\Connection|false|null */
+	private \PgSql\Connection|false|null $dbh;
+	/** @var bool DB_DEBUG ... (if set prints out debug msgs) */
+	private bool $db_debug = false;
+	/** @var string the DB connected to */
+	private string $db_name;
+	/** @var string the username used */
+	private string $db_user;
+	/** @var string the password used*/
+	private string $db_pwd;
+	/** @var string the hostname */
+	private string $db_host;
+	/** @var int default db port */
+	private int $db_port;
+	/** @var string optional DB schema, if not set uses public*/
+	private string $db_schema;
+	/** @var string optional auto encoding convert, not used if not set */
+	private string $db_encoding;
+	/** @var string type of db (mysql,postgres,...) */
+	private string $db_type;
+	/** @var string ssl flag (for postgres only), disable, allow, prefer, require */
+	private string $db_ssl;
 	// FOR BELOW: (This should be private and only readable through some method)
 	// cursor array for cached readings
-	/** @var array */
-	private $cursor_ext; // hash of hashes
+	/** @var array extended cursoers string index with content */
+	private array $cursor_ext;
 	// per query vars
-	/** @var \PgSql\Result|false */ // replace object with PgSql\Result
-	private $cursor; // actual cursor (DBH)
-	/** @var int */
-	private $num_rows; // how many rows have been found
-	/** @var int */
-	private $num_fields; // how many fields has the query
+	/** @var \PgSql\Result|false actual cursor (DBH) */
+	private \PgSql\Result|false $cursor;
+	/** @var int how many rows have been found */
+	private int $num_rows;
+	/** @var int how many fields has the query */
+	private int $num_fields;
 	/** @var array array with the field names of the current query */
-	private $field_names = [];
+	private array $field_names = [];
 	/** @var array field type names */
-	private $field_types = [];
-	/** @var array */
-	private $insert_id_arr = []; // always return as array, even if only one
-	/** @var string */
-	private $insert_id_pk_name; // primary key name for insert recovery from insert_id_arr
+	private array $field_types = [];
+	/** @var array always return as array, even if only one */
+	private array $insert_id_arr = [];
+	/** @var string primary key name for insert recovery from insert_id_arr */
+	private string $insert_id_pk_name;
 	// other vars
-	/** @var string */
-	private $nbsp = ''; // used by print_array recursion function
+	/** @var string used by print_array recursion function */
+	private string $nbsp = '';
 	// error & warning id
 	/** @var string */
-	private $error_id;
+	private string $error_id;
 	/** @var string */
-	private $warning_id;
+	private string $warning_id;
 	/** @var string */
-	private $error_history_id;
+	private string $error_history_id;
 	/** @var array Stores warning and errors combinded with detail info */
-	private $error_history_long = [];
-	// error thrown on class init if we cannot connect to db
-	/** @var bool */
-	protected $db_connection_closed = false;
+	private array $error_history_long = [];
+	/** @var bool error thrown on class init if we cannot connect to db */
+	protected bool $db_connection_closed = false;
 	// sub include with the database functions
 	/** @var \CoreLibs\DB\SQL\PgSQL if we have other DB types we need to add them here */
-	private $db_functions;
+	private \CoreLibs\DB\SQL\PgSQL $db_functions;
 	// endless loop protection
 	/** @var int */
-	private $MAX_QUERY_CALL;
-	/** @var int */
-	public const DEFAULT_MAX_QUERY_CALL = 20; // default
+	private int $MAX_QUERY_CALL;
+	/** @var int maxium query calls allowed in a dbReturnRow loop before we error out */
+	public const DEFAULT_MAX_QUERY_CALL = 20;
 	/** @var array */
-	private $query_called = [];
+	private array $query_called = [];
 	// error string
 	/** @var array */
-	protected $error_string = [];
+	protected array $error_string = [];
 	// prepared list
 	/** @var array */
-	private $prepare_cursor = [];
+	private array $prepare_cursor = [];
 	// primary key per table list
 	// format is 'table' => 'pk_name'
 	/** @var array */
-	private $pk_name_table = [];
-	// internal primary key name, for cross calls in async
-	/** @var string */
-	private $pk_name;
-	// if we use RETURNING in the INSERT call
-	/** @var bool */
-	private $returning_id = false;
-	// if a sync is running holds the hash key of the query
-	/** @var string */
-	private $async_running;
+	private array $pk_name_table = [];
+	/** @var string internal primary key name, for cross calls in async */
+	private string $pk_name;
+	/** @var bool if we use RETURNING in the INSERT call */
+	private bool $returning_id = false;
+	/** @var string if a sync is running holds the hash key of the query */
+	private string $async_running;
 	// logging class, must be public so settings can be changed
-	/** @var \CoreLibs\Debug\Logging */
-	public $log;
+	/** @var \CoreLibs\Logging\Logging */
+	public \CoreLibs\Logging\Logging $log;
 
 	/**
 	 * main DB concstructor with auto connection to DB and failure set on failed connection
 	 * @param array $db_config DB configuration array
-	 * @param \CoreLibs\Debug\Logging $log Logging class
+	 * @param \CoreLibs\Logging\Logging $log Logging class
 	 * @param bool|null $db_debug_override Overrides debug settings in db_config
 	 */
 	public function __construct(
 		array $db_config,
-		\CoreLibs\Debug\Logging $log,
+		\CoreLibs\Logging\Logging $log,
 		?bool $db_debug_override = null
 	) {
 		// attach logger
@@ -703,10 +700,20 @@ class IO
 		}
 		if ($error_data !== []) {
 			$error_string .= '
[' - . $this->log->prAr($error_data) + . \CoreLibs\Debug\Support::prAr($error_data) . ']'; } - $this->log->debug($debug_id, $error_string, true, $prefix); + switch ($id) { + case 'DB_ERROR': + $this->log->error($debug_id . ' :' . $prefix . $error_string); + break; + case 'DB_WARNING': + $this->log->warning($debug_id . ' :' . $prefix . $error_string); + break; + default: + $this->log->debug($debug_id, $error_string, $prefix); + break; + } } /** @@ -1366,7 +1373,10 @@ class IO */ public function dbClose(): void { - if ($this->dbh) { + if ( + !empty($this->dbh) && + $this->dbh instanceof \PgSql\Connection + ) { // reset any client encodings set $this->dbResetEncoding(); // calls db close @@ -2735,9 +2745,9 @@ class IO } $result = $this->db_functions->__dbExecute($stm_name, $data); if ($result === false) { - $this->log->debug('ExecuteData', 'ERROR in STM[' . $stm_name . '|' + $this->log->error('ExecuteData: ERROR in STM[' . $stm_name . '|' . $this->prepare_cursor[$stm_name]['result'] . ']: ' - . $this->log->prAr($data)); + . \CoreLibs\Debug\Support::prAr($data)); $this->__dbError( 22, $this->prepare_cursor[$stm_name]['result'], @@ -3398,6 +3408,9 @@ class IO */ public function dbGetInsertPKName(): string { + if (!isset($this->insert_id_pk_name)) { + return ''; + } return (string)$this->insert_id_pk_name; } @@ -3506,6 +3519,9 @@ class IO */ public function dbGetNumFields(): ?int { + if (!isset($this->num_fields)) { + return null; + } return $this->num_fields; } diff --git a/src/DB/SQL/PgSQL.php b/src/DB/SQL/PgSQL.php index 2d9b34e..fa4c7e8 100644 --- a/src/DB/SQL/PgSQL.php +++ b/src/DB/SQL/PgSQL.php @@ -59,9 +59,9 @@ namespace CoreLibs\DB\SQL; class PgSQL implements Interface\SqlFunctions { /** @var string */ - private $last_error_query; + private string $last_error_query; /** @var \PgSql\Connection|false */ - private $dbh = false; + private \PgSql\Connection|false $dbh = false; /** * queries last error query and returns true or false if error was set diff --git a/src/Debug/FileWriter.php b/src/Debug/FileWriter.php index 27fe3e1..c7105bb 100644 --- a/src/Debug/FileWriter.php +++ b/src/Debug/FileWriter.php @@ -12,9 +12,9 @@ namespace CoreLibs\Debug; class FileWriter { /** @var string */ - private static $debug_filename = 'debug_file.log'; // where to write output + private static string $debug_filename = 'debug_file.log'; // where to write output /** @var string */ - private static $debug_folder; + private static string $debug_folder; /** * Set a debug log folder, if not set BASE+LOG folders are set @@ -77,7 +77,7 @@ class FileWriter ) { /** @deprecated Do not use this anymore, define path with fsetFolder */ trigger_error( - 'fsetFolder must be set first. Setting via LOG_FILE_ID and LOg constants is deprecated', + 'fsetFolder must be set first. Setting via LOG_FILE_ID and LOG constants is deprecated', E_USER_DEPRECATED ); self::$debug_folder = BASE . LOG; diff --git a/src/Debug/Logging.php b/src/Debug/Logging.php index de4e710..e961aab 100644 --- a/src/Debug/Logging.php +++ b/src/Debug/Logging.php @@ -1,895 +1,26 @@ */ - private $options = []; - // page and host name - /** @var string */ - private $page_name; - /** @var string */ - private $host_name; - /** @var int */ - private $host_port; - // internal error reporting vars - /** @var array */ - private $error_msg = []; // the "connection" to the outside errors - // debug output prefix - /** @var string */ - private $error_msg_prefix = ''; // prefix to the error string (the class name) - // debug flags - /** @var array */ - private $debug_output = []; // if this is true, show debug on desconstructor - /** @var array */ - private $debug_output_not = []; - /** @var bool */ - private $debug_output_all = false; - /** @var array */ - private $echo_output = []; // errors: echo out, default is 1 - /** @var array */ - private $echo_output_not = []; - /** @var bool */ - private $echo_output_all = false; - /** @var array */ - private $print_output = []; // errors: print to file, default is 0 - /** @var array */ - private $print_output_not = []; - /** @var bool */ - private $print_output_all = false; - // debug flags/settings - /** @var string */ - private $running_uid = ''; // unique ID set on class init and used in logging as prefix - // log file name - /** @var string */ - 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 */ - private $log_file_id = ''; // a alphanumeric name that has to be set as global definition - /** @var bool */ - private $log_per_level = false; // set, it will split per level (first parameter in debug call) - /** @var bool */ - private $log_per_class = false; // set, will split log per class - /** @var bool */ - private $log_per_page = false; // set, will split log per called file - /** @var bool */ - private $log_per_run = false; // create a new log file per run (time stamp + unique ID) - // script running time - /** @var float */ - private $script_starttime; - /** - * 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 $options Array with settings options */ public function __construct(array $options = []) { - // 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')) { - /** @deprecated Do not use this anymore, define path on class load */ - trigger_error( - 'options: log_folder must be set. Setting via BASE and LOG constants is deprecated', - E_USER_DEPRECATED - ); - // make sure this is writeable, else skip - $this->log_folder = BASE . LOG; - } - // 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 = Uids::uniqIdShort(); - // set the page name - $this->page_name = System::getPageName(); - // set host name - 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 later - if (!empty($this->options['file_id'])) { - $this->setLogId($this->options['file_id']); - } elseif (!empty($GLOBALS['LOG_FILE_ID'])) { - /** @deprecated Do not use this anymore, define file_id on class load */ - trigger_error( - 'options: file_id must be set. Setting via LOG_FILE_ID global variable is deprecated', - E_USER_DEPRECATED - ); - // legacy flow, should be removed and only set via options - $this->setLogId($GLOBALS['LOG_FILE_ID']); - // TODO trigger deprecation error - // trigger_error( - // 'Debug\Logging: Do not use globals LOG_FILE_ID to set log id for Logging', - // E_USER_DEPRECATED - // ); - } elseif (defined('LOG_FILE_ID')) { - /** @deprecated Do not use this anymore, define file_id on class load */ - trigger_error( - 'options: file_id must be set. Setting via LOG_FILE_ID constant is deprecated', - E_USER_DEPRECATED - ); - // legacy flow, should be removed and only set via options - $this->setLogId(LOG_FILE_ID); - // trigger deprecation error - // trigger_error( - // 'Debug\Logging: Do not use constant LOG_FILE_ID to set log id for Logging', - // E_USER_DEPRECATED - // ); - } - - // init the log levels - $this->initLogLevels(); - } - - // *** PRIVATE *** - - /** - * init the basic log levels based on global set variables - * - * @return void - */ - private function initLogLevels(): void - { - // if given via parameters, only for all - // globals overrule given settings, for one (array), eg $ECHO['db'] = 1; - foreach (['debug', 'echo', 'print'] as $type) { - // include or exclude (off) from output - foreach (['on', 'off'] as $flag) { - $in_type = $type; - if ($flag == 'off') { - $in_type .= '_not'; - } - $up_type = strtoupper($in_type); - if ( - isset($this->options[$in_type]) && - is_array($this->options[$in_type]) - ) { - $this->setLogLevel($type, $flag, $this->options[$in_type]); - } elseif ( - isset($GLOBALS[$up_type]) && - is_array($GLOBALS[$up_type]) - ) { - // TODO trigger deprecation error - $this->setLogLevel($type, $flag, $GLOBALS[$up_type]); - } - } - } - - // TODO remove all $GLOBALS call and only use options - // all overrule - $this->setLogLevelAll( - 'debug', - $this->options['debug_all'] ?? - // for user login, should be handled outside like globals - $_SESSION['DEBUG_ALL'] ?? // DEPRECATED - $GLOBALS['DEBUG_ALL'] ?? // DEPRECATED - false - ); - $this->setLogLevelAll( - 'print', - $this->options['print_all'] ?? - // for user login, should be handled outside like globals - $_SESSION['DEBUG_ALL'] ?? // DEPRECATED - $GLOBALS['PRINT_ALL'] ?? // DEPRECATED - false - ); - $this->setLogLevelAll( - 'echo', - $this->options['echo_all'] ?? - $GLOBALS['ECHO_ALL'] ?? // DEPRECATED - false - ); - - // GLOBAL rules for log writing - // add file date is default on - $this->setGetLogPrintFileDate( - $this->options['print_file_date'] ?? - $GLOBALS['LOG_PRINT_FILE_DATE'] ?? // DEPRECATED - true - ); - // all other logging file name flags are off - $this->setLogPer( - 'level', - $this->options['per_level'] ?? - $GLOBALS['LOG_PER_LEVEL'] ?? // DEPRECATED - false - ); - $this->setLogPer( - 'class', - $this->options['per_class'] ?? - $GLOBALS['LOG_PER_CLASS'] ?? // DEPRECATED - false - ); - $this->setLogPer( - 'page', - $this->options['per_page'] ?? - $GLOBALS['LOG_PER_PAGE'] ?? // DEPRECATED - false - ); - $this->setLogPer( - 'run', - $this->options['per_run'] ?? - $GLOBALS['LOG_PER_RUN'] ?? // DEPRECATED - false - ); - // set log per date - if ($this->setGetLogPrintFileDate()) { - $this->log_file_date = date('Y-m-d'); - } - // set per run ID - if ($this->log_per_run) { - $this->setLogUniqueId(); - } - } - - /** - * checks if we have a need to work on certain debug output - * Needs debug/echo/print ad target for which of the debug flag groups we check - * also needs level string to check in the per level output flag check. - * In case we have invalid target it will return false - * - * @param string $target target group to check debug/echo/print - * @param string $level level to check in detailed level flag - * @return bool true on access allowed or false on no access - */ - private function doDebugTrigger(string $target, string $level): bool - { - $access = false; - // check if we do debug, echo or print - if ( - ( - $this->getLogLevel($target, 'on', $level) || - $this->getLogLevelAll($target) - ) && - !$this->getLogLevel($target, 'off', $level) - ) { - $access = true; - } - return $access; - } - - /** - * writes error msg data to file for current level - * - * @param string $level the level to write - * @param string $error_string error string to write - * @return bool True if message written, FAlse if not - */ - private function writeErrorMsg(string $level, string $error_string): bool - { - // only write if write is requested - if ( - !($this->doDebugTrigger('debug', $level) && - $this->doDebugTrigger('print', $level)) - ) { - return false; - } - - // 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 (!empty($this->log_file_id)) { - $rpl_string = '_' . $this->log_file_id; - } else { - $rpl_string = ''; - } - $fn = str_replace('##LOGID##', $rpl_string, $fn); // log id (like a log file prefix) - - if ($this->log_per_run) { - $rpl_string = '_' . $this->log_file_unique_id; // add 8 char unique string - } elseif ($this->setGetLogPrintFileDate()) { - $rpl_string = '_' . $this->log_file_date; // add date to file - } else { - $rpl_string = ''; - } - $fn = str_replace('##DATE##', $rpl_string, $fn); // create output filename - - // write per level - $rpl_string = !$this->log_per_level ? '' : - // normalize level, replace all non alphanumeric characters with - - '_' . ( - // if return is only - then set error string - preg_match( - "/^-+$/", - $level_string = preg_replace("/[^A-Za-z0-9-_]/", '-', $level) ?? '' - ) ? - 'INVALID-LEVEL-STRING' : - $level_string - ); - $fn = str_replace('##LEVEL##', $rpl_string, $fn); // create output filename - // 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('\\', '-', 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 ? - '' : - '_' . System::getPageName(System::NO_EXTENSION); - $fn = str_replace('##PAGENAME##', $rpl_string, $fn); // create output filename - - // write to file - // first check if max file size is is set and file is bigger - if ( - $this->log_max_filesize > 0 && - ((filesize($fn) / 1024) > $this->log_max_filesize) - ) { - // for easy purpose, rename file only to attach timestamp, nur sequence numbering - rename($fn, $fn . '.' . date("YmdHis")); - } - $this->log_file_name = $fn; - $fp = fopen($this->log_file_name, 'a'); - if ($fp !== false) { - fwrite($fp, $error_string); - fclose($fp); - return true; - } else { - echo ""; - return false; - } - } - - // *** PUBLIC *** - - /** - * Temporary method to read all class variables for testing purpose - * - * @param string $name what variable to return - * @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 - * if non valid string is given it returns the previous set one only - * - * @param string $string log file id string value - * @return string returns the set log file id string - * @deprecated Use $log->setLogId() - */ - public function basicSetLogId(string $string): string - { - return $this->setLogId($string); - } - - /** - * sets the internal log file prefix id - * string must be a alphanumeric string - * if non valid string is given it returns the previous set one only - * - * @param string $string log file id string value - * @return string returns the set log file id string - */ - public function setLogId(string $string): 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 - * @deprecated Use setLogLevel - */ - 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 - * @return bool False on failure, or the boolean flag from the all var - */ - public function getLogLevelAll(string $type): bool - { - // type check for debug/echo/print - if (!in_array($type, ['debug', 'echo', 'print'])) { - return false; - } - return $this->{$type . '_output_all'}; - } - - /** - * passes list of level names, to turn on debug - * eg $foo->debugFor('print', 'on', ['LOG', 'DEBUG', 'INFO']); - * - * @param string $type debug, echo, print - * @param string $flag on/off - * @param array $debug_on Array of levels to turn on/off debug - * To turn off a level set 'Level' => false, - * If not set, switches to on - * @return bool Return false if type or flag invalid - * also false if debug array is empty - */ - public function setLogLevel(string $type, string $flag, array $debug_on): bool - { - // abort if not valid type - if (!in_array($type, ['debug', 'echo', 'print'])) { - return false; - } - // invalid flag type - if (!in_array($flag, ['on', 'off'])) { - return false; - } - if (count($debug_on) >= 1) { - foreach ($debug_on as $level => $set) { - $switch = $type . '_output' . ($flag == 'off' ? '_not' : ''); - if (!is_bool($set)) { - $level = $set; - $set = true; - } - $this->{$switch}[$level] = $set; - } - } else { - return false; - } - return true; - } - - /** - * return the log level for the array type normal and not (disable) - * - * @param string $type debug, echo, print - * @param string $flag on/off - * @param string|null $level if not null then check if this array entry is set - * else return false - * @return array|bool if $level is null, return array, else boolean true/false - */ - public function getLogLevel(string $type, string $flag, ?string $level = null): array|bool - { - // abort if not valid type - if (!in_array($type, ['debug', 'echo', 'print'])) { - return false; - } - // invalid flag type - if (!in_array($flag, ['on', 'off'])) { - return false; - } - $switch = $type . '_output' . ($flag == 'off' ? '_not' : ''); - // log level direct check must be not null or not empty string - if (!empty($level)) { - return $this->{$switch}[$level] ?? false; - } - // array - return $this->{$switch}; - } - - /** - * set flags for per log level type - * - level: set per sub group level - * - class: split by class - * - page: split per page called - * - run: for each run - * - * @param string $type Type to get: level, class, page, run - * @param bool $set True or False - * @return bool Return false if type invalid - */ - public function setLogPer(string $type, bool $set): bool - { - if (!in_array($type, ['level', 'class', 'page', 'run'])) { - return false; - } - $this->{'log_per_' . $type} = $set; - // if per run set unique id - if ($type == 'run' && $set == true) { - $this->setLogUniqueId(); - } - return true; - } - - /** - * return current set log per flag in bool - * - * @param string $type Type to get: level, class, page, run - * @return bool True of false for turned on or off - */ - public function getLogPer(string $type): bool - { - if (!in_array($type, ['level', 'class', 'page', 'run'])) { - return false; - } - return $this->{'log_per_' . $type}; - } - - /** - * Sets a unique id based on current date (y/m/d, h:i:s) and a unique id (8 chars) - * if override is set to true it will be newly set, else if already set nothing changes - * - * @param bool $override True to force new set - * @return void - */ - public function setLogUniqueId(bool $override = false): void - { - if (!$this->log_file_unique_id || $override == true) { - $this->log_file_unique_id = - date('Y-m-d_His') . '_U_' - . substr(hash('sha1', uniqid((string)mt_rand(), true)), 0, 8); - } - } - - /** - * Return current set log file unique id, - * empty string for not set - * - * @return string - */ - public function getLogUniqueId(): string - { - return $this->log_file_unique_id; - } - - /** - * Set or get the log file date extension flag - * if null or empty parameter gets current flag - * - * @param boolean|null $set Set the date suffix for log files - * If set to null return current set - * @return boolean Current set flag - */ - public function setGetLogPrintFileDate(?bool $set = null): bool - { - if ($set !== null) { - $this->log_print_file_date = $set; - } - return $this->log_print_file_date; - } - - /** - * Return current set log file name - * - * @return string Filename set set after the last time debug was called - */ - public function getLogFileName(): string - { - return $this->log_file_name; - } - - /** - * A replacement for the \CoreLibs\Debug\Support::printAr - * But this does not wrap it in

-	 * It uses some special code sets so we can convert that to pre flags
-	 * for echo output {##HTMLPRE##} ... {##/HTMLPRE##}
-	 * Do not use this without using it in a string in debug function
-	 *
-	 * @param  array $a Array to format
-	 * @return string          print_r formated
-	 */
-	public function prAr(array $a): string
-	{
-		return '##HTMLPRE##' . print_r($a, true) . '##/HTMLPRE##';
-	}
-
-	/**
-	 * Convert bool value to string value
-	 *
-	 * @param  bool   $bool  Bool value to be transformed
-	 * @param  string $true  Override default string 'true'
-	 * @param  string $false Override default string 'false'
-	 * @return string        $true or $false string for true/false bool
-	 */
-	public function prBl(
-		bool $bool,
-		string $true = 'true',
-		string $false = 'false'
-	): string {
-		return $bool ? $true : $false;
-	}
-
-	/**
-	 * write debug data to error_msg array
-	 *
-	 * @param  string $level  id for error message, groups messages together
-	 * @param  string $string the actual error message
-	 * @param  bool   $strip  default on false, if set to true,
-	 *                        all html tags will be stripped and 
changed to \n - * this is only used for debug output - * @param string $prefix Attach some block before $string. - * Will not be stripped even - * when strip is true - * if strip is false, recommended to add that to $string - * @return bool True if logged, false if not logged - */ - public function debug( - string $level, - string $string, - bool $strip = false, - string $prefix = '' - ): bool { - $status = false; - // must be debug on and either echo or print on - if ( - !$this->doDebugTrigger('debug', $level) || - ( - // if debug is on, either print or echo must be set to on - !$this->doDebugTrigger('print', $level) && - !$this->doDebugTrigger('echo', $level) - ) - ) { - return $status; - } - // get the last class entry and wrie that - $class = Support::getCallerClass(); - // get timestamp - $timestamp = Support::printTime(); - // same string put for print (no html data inside) - // write to file if set - $status = $this->writeErrorMsg( - $level, - '[' . $timestamp . '] ' - . '[' . $this->host_name . '] ' - . '[' . System::getPageName(System::FULL_PATH) . '] ' - . '[' . $this->running_uid . '] ' - . '{' . $class . '} ' - . '<' . $level . '> - ' - // strip the htmlpre special tags if exist - . str_replace( - ['##HTMLPRE##', '##/HTMLPRE##'], - '', - // if stripping all html, etc is requested, only for write error msg - ($strip ? - // find any
and replace them with \n - // strip rest of html elements (base only) - preg_replace( - "/(<\/?)(\w+)([^>]*>)/", - '', - str_replace('
', "\n", $prefix . $string) - ) : - $prefix . $string - ) ?: '' - ) - . "\n" - ); - // write to error level msg array if there is an echo request - if ($this->doDebugTrigger('echo', $level)) { - // init if not set - if (!isset($this->error_msg[$level])) { - $this->error_msg[$level] = []; - } - // HTML string - $this->error_msg[$level][] = '
' - . '[' . $timestamp . '] ' - . '[' . $level . '] ' - . '[' . $this->host_name . '] ' - . '[' . $this->page_name . '] ' - . '[' . $this->running_uid . '] ' - . '{' . $class . '} - ' - // as is prefix, allow HTML - . $prefix - // we replace special HTMLPRE with
 entries
-				. str_replace(
-					['##HTMLPRE##', '##/HTMLPRE##'],
-					['
', '
'], - Html::htmlent($string) - ) - . "
"; - $status = true; - } - return $status; - } - - /** - * for ECHO ON only - * returns error data as string so it can be echoed out - * - * @param string $header_prefix prefix string for header - * @return string error msg for all levels - */ - public function printErrorMsg(string $header_prefix = ''): string - { - $string_output = ''; - // if not debug && echo on, do not return anything - if ( - !$this->getLogLevelAll('debug') || - !$this->getLogLevelAll('echo') - ) { - return $string_output; - } - if ($this->error_msg_prefix) { - $header_prefix = $this->error_msg_prefix; - } - $script_end = microtime(true) - $this->script_starttime; - foreach ($this->error_msg as $level => $temp_debug_output) { - if ($this->doDebugTrigger('debug', $level)) { - if ($this->doDebugTrigger('echo', $level)) { - $string_output .= '
' - . '[' . $level . '] ' - . ($header_prefix ? "**** " . Html::htmlent($header_prefix) . " ****
\n" : '') - . '
' - . join('', $temp_debug_output); - } // echo it out - } // do printout - } // for each level - // create the output wrapper around - // so we have a nice formated output per class - if ($string_output) { - $string_prefix = '
' - . '
{' - . Support::getCallerClass() . '}
'; - $string_output = $string_prefix . $string_output - . '
Script Run Time: ' - . $script_end . '
' - . '
'; - } - // } - return $string_output; - } - - /** - * for ECHO ON only - * unsests the error message array - * can be used if writing is primary to file - * if no level given resets all - * - * @param string $level optional level - * @return void has no return - */ - public function resetErrorMsg(string $level = ''): void - { - if (!$level) { - $this->error_msg = []; - } elseif (isset($this->error_msg[$level])) { - unset($this->error_msg[$level]); - } - } - - /** - * for ECHO ON only - * Get current error message array - * - * @return array error messages collected - */ - public function getErrorMsg(): array - { - return $this->error_msg; - } - - /** - * for ECHO ON only - * merges the given error array with the one from this class - * only merges visible ones - * - * @param array $error_msg error array - * @return void has no return - */ - public function mergeErrors(array $error_msg = []): void - { - array_push($this->error_msg, ...$error_msg); + parent::__construct($options); } } diff --git a/src/Debug/LoggingLegacy.php b/src/Debug/LoggingLegacy.php new file mode 100644 index 0000000..6d3a602 --- /dev/null +++ b/src/Debug/LoggingLegacy.php @@ -0,0 +1,911 @@ + */ + private $options = []; + // page and host name + /** @var string */ + private $page_name; + /** @var string */ + private $host_name; + /** @var int */ + private $host_port; + // internal error reporting vars + /** @var array */ + private $error_msg = []; // the "connection" to the outside errors + // debug output prefix + /** @var string */ + private $error_msg_prefix = ''; // prefix to the error string (the class name) + + // debug flags/settings + /** @var string */ + private $running_uid = ''; // unique ID set on class init and used in logging as prefix + // log file name + /** @var string */ + 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_RUNID}'; + /** @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 */ + private $log_file_id = ''; // a alphanumeric name that has to be set as global definition + /** @var bool */ + private $log_per_level = false; // set, it will split per level (first parameter in debug call) + /** @var bool */ + private $log_per_class = false; // set, will split log per class + /** @var bool */ + private $log_per_page = false; // set, will split log per called file + /** @var bool */ + private $log_per_run = false; // create a new log file per run (time stamp + unique ID) + // script running time + /** @var float */ + private $script_starttime; + + /** @var string[] current log levels */ + private $log_levels = ['debug', 'echo', 'print']; + /** @var string[] log group per what for writing to file */ + private $log_grouping = ['level', 'class', 'page', 'run']; + + // debug flags [they must exist or we get a warning] + /** @var array */ + private $debug_output = []; // if this is true, show debug on desconstructor + /** @var array */ + private $debug_output_not = []; + /** @var bool */ + private $debug_output_all = false; + /** @var array */ + private $echo_output = []; // errors: echo out, default is 1 + /** @var array */ + private $echo_output_not = []; + /** @var bool */ + private $echo_output_all = false; + /** @var array */ + private $print_output = []; // errors: print to file, default is 0 + /** @var array */ + private $print_output_not = []; + /** @var bool */ + private $print_output_all = false; + + /** + * Init logger + * + * global vars that can be used + * - BASE + * - LOG + * - LOG_FILE_ID + * options array layout + * - log_folder: + * - file_id: + * - unique_id: + * - print_file_date: + * - 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 $options Array with settings options + */ + public function __construct(array $options = []) + { + // 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')) { + /** @deprecated Do not use this anymore, define path on class load */ + trigger_error( + 'options: log_folder must be set. Setting via BASE and LOG constants is deprecated', + E_USER_DEPRECATED + ); + // make sure this is writeable, else skip + $this->log_folder = BASE . LOG; + } + // 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 = Uids::uniqIdShort(); + // set the page name + $this->page_name = System::getPageName(); + // set host name + 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 later + if (!empty($this->options['file_id'])) { + $this->setLogId($this->options['file_id']); + } elseif (!empty($GLOBALS['LOG_FILE_ID'])) { + /** @deprecated Do not use this anymore, define file_id on class load */ + trigger_error( + 'options: file_id must be set. Setting via LOG_FILE_ID global variable is deprecated', + E_USER_DEPRECATED + ); + // legacy flow, should be removed and only set via options + $this->setLogId($GLOBALS['LOG_FILE_ID']); + // TODO trigger deprecation error + // trigger_error( + // 'Debug\Logging: Do not use globals LOG_FILE_ID to set log id for Logging', + // E_USER_DEPRECATED + // ); + } elseif (defined('LOG_FILE_ID')) { + /** @deprecated Do not use this anymore, define file_id on class load */ + trigger_error( + 'options: file_id must be set. Setting via LOG_FILE_ID constant is deprecated', + E_USER_DEPRECATED + ); + // legacy flow, should be removed and only set via options + $this->setLogId((string)LOG_FILE_ID); + // trigger deprecation error + // trigger_error( + // 'Debug\Logging: Do not use constant LOG_FILE_ID to set log id for Logging', + // E_USER_DEPRECATED + // ); + } + + // init the log levels + $this->initLogLevels(); + } + + // *** PRIVATE *** + + /** + * init the basic log levels based on global set variables + * + * @return void + */ + private function initLogLevels(): void + { + // if given via parameters, only for all + // globals overrule given settings, for one (array), eg $ECHO['db'] = 1; + foreach ($this->log_levels as $type) { + // include or exclude (off) from output + foreach (['on', 'off'] as $flag) { + $in_type = $type; + if ($flag == 'off') { + $in_type .= '_not'; + } + $up_type = strtoupper($in_type); + if ( + isset($this->options[$in_type]) && + is_array($this->options[$in_type]) + ) { + $this->setLogLevel($type, $flag, $this->options[$in_type]); + } elseif ( + isset($GLOBALS[$up_type]) && + is_array($GLOBALS[$up_type]) + ) { + // TODO trigger deprecation error + $this->setLogLevel($type, $flag, $GLOBALS[$up_type]); + } + } + } + + // TODO remove all $GLOBALS call and only use options + // all overrule + $this->setLogLevelAll( + 'debug', + $this->options['debug_all'] ?? + // for user login, should be handled outside like globals + $_SESSION['DEBUG_ALL'] ?? // DEPRECATED + $GLOBALS['DEBUG_ALL'] ?? // DEPRECATED + false + ); + $this->setLogLevelAll( + 'print', + $this->options['print_all'] ?? + // for user login, should be handled outside like globals + $_SESSION['DEBUG_ALL'] ?? // DEPRECATED + $GLOBALS['PRINT_ALL'] ?? // DEPRECATED + false + ); + $this->setLogLevelAll( + 'echo', + $this->options['echo_all'] ?? + $GLOBALS['ECHO_ALL'] ?? // DEPRECATED + false + ); + + // GLOBAL rules for log writing + // add file date is default on + $this->setGetLogPrintFileDate( + $this->options['print_file_date'] ?? + $GLOBALS['LOG_PRINT_FILE_DATE'] ?? // DEPRECATED + true + ); + // all other logging file name flags are off + $this->setLogPer( + 'level', + $this->options['per_level'] ?? + $GLOBALS['LOG_PER_LEVEL'] ?? // DEPRECATED + false + ); + $this->setLogPer( + 'class', + $this->options['per_class'] ?? + $GLOBALS['LOG_PER_CLASS'] ?? // DEPRECATED + false + ); + $this->setLogPer( + 'page', + $this->options['per_page'] ?? + $GLOBALS['LOG_PER_PAGE'] ?? // DEPRECATED + false + ); + $this->setLogPer( + 'run', + $this->options['per_run'] ?? + $GLOBALS['LOG_PER_RUN'] ?? // DEPRECATED + false + ); + // set log per date + if ($this->setGetLogPrintFileDate()) { + $this->log_file_date = date('Y-m-d'); + } + // set per run ID + if ($this->log_per_run) { + $this->setLogUniqueId(); + } + } + + /** + * checks if we have a need to work on certain debug output + * Needs debug/echo/print ad target for which of the debug flag groups we check + * also needs level string to check in the per level output flag check. + * In case we have invalid target it will return false + * + * @param string $target target group to check debug/echo/print + * @param string $level level to check in detailed level flag + * @return bool true on access allowed or false on no access + */ + private function doDebugTrigger(string $target, string $level): bool + { + $access = false; + // check if we do debug, echo or print + if ( + ( + $this->getLogLevel($target, 'on', $level) || + $this->getLogLevelAll($target) + ) && + !$this->getLogLevel($target, 'off', $level) + ) { + $access = true; + } + return $access; + } + + /** + * writes error msg data to file for current level + * + * @param string $level the level to write + * @param string $error_string error string to write + * @return bool True if message written, False if not + */ + private function writeErrorMsg(string $level, string $error_string): bool + { + // only write if write is requested + if ( + !($this->doDebugTrigger('debug', $level) && + $this->doDebugTrigger('print', $level)) + ) { + return false; + } + + // 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 (!empty($this->log_file_id)) { + $rpl_string = '_' . $this->log_file_id; + } else { + $rpl_string = ''; + } + $fn = str_replace('{LOGID}', $rpl_string, $fn); // log id (like a log file prefix) + + // if run id, we auto add ymd, so we ignore the log file date + if ($this->log_per_run) { + $rpl_string = '_' . $this->log_file_unique_id; // add 8 char unique string + } elseif ($this->setGetLogPrintFileDate()) { + $rpl_string = '_' . $this->log_file_date; // add date to file + } else { + $rpl_string = ''; + } + $fn = str_replace('{DATE_RUNID}', $rpl_string, $fn); // create output filename + + // write per level + $rpl_string = !$this->log_per_level ? '' : + // normalize level, replace all non alphanumeric characters with - + '_' . ( + // if return is only - then set error string + preg_match( + "/^-+$/", + $level_string = preg_replace("/[^A-Za-z0-9-_]/", '-', $level) ?? '' + ) ? + 'INVALID-LEVEL-STRING' : + $level_string + ); + $fn = str_replace('{LEVEL}', $rpl_string, $fn); // create output filename + // 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('\\', '-', 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 ? + '' : + '_' . System::getPageName(System::NO_EXTENSION); + $fn = str_replace('{PAGENAME}', $rpl_string, $fn); // create output filename + + // write to file + // first check if max file size is is set and file is bigger + if ( + $this->log_max_filesize > 0 && + ((filesize($fn) / 1024) > $this->log_max_filesize) + ) { + // for easy purpose, rename file only to attach timestamp, nur sequence numbering + rename($fn, $fn . '.' . date("YmdHis")); + } + $this->log_file_name = $fn; + $fp = fopen($this->log_file_name, 'a'); + if ($fp !== false) { + fwrite($fp, $error_string); + fclose($fp); + return true; + } else { + echo ""; + return false; + } + } + + // *** PUBLIC *** + + /** + * Temporary method to read all class variables for testing purpose + * + * @param string $name what variable to return + * @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 + * if non valid string is given it returns the previous set one only + * + * @param string $string log file id string value + * @return string returns the set log file id string + * @deprecated Use $log->setLogId() + */ + public function basicSetLogId(string $string): string + { + return $this->setLogId($string); + } + + /** + * sets the internal log file prefix id + * string must be a alphanumeric string + * if non valid string is given it returns the previous set one only + * + * @param string $string log file id string value + * @return string returns the set log file id string + */ + public function setLogId(string $string): 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 + * @deprecated Use setLogLevel + */ + 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, $this->log_levels)) { + 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 + * @return bool False on failure, or the boolean flag from the all var + */ + public function getLogLevelAll(string $type): bool + { + // type check for debug/echo/print + if (!in_array($type, $this->log_levels)) { + return false; + } + return $this->{$type . '_output_all'}; + } + + /** + * passes list of level names, to turn on debug + * eg $foo->debugFor('print', 'on', ['LOG', 'DEBUG', 'INFO']); + * + * @param string $type debug, echo, print + * @param string $flag on/off + * @param array $debug_on Array of levels to turn on/off debug + * To turn off a level set 'Level' => false, + * If not set, switches to on + * @return bool Return false if type or flag invalid + * also false if debug array is empty + */ + public function setLogLevel(string $type, string $flag, array $debug_on): bool + { + // abort if not valid type + if (!in_array($type, $this->log_levels)) { + return false; + } + // invalid flag type + if (!in_array($flag, ['on', 'off'])) { + return false; + } + if (count($debug_on) >= 1) { + foreach ($debug_on as $level => $set) { + $switch = $type . '_output' . ($flag == 'off' ? '_not' : ''); + if (!is_bool($set)) { + $level = $set; + $set = true; + } + $this->{$switch}[$level] = $set; + } + } else { + return false; + } + return true; + } + + /** + * return the log level for the array type normal and not (disable) + * + * @param string $type debug, echo, print + * @param string $flag on/off + * @param string|null $level if not null then check if this array entry is set + * else return false + * @return array|bool if $level is null, return array, else boolean true/false + */ + public function getLogLevel(string $type, string $flag, ?string $level = null): array|bool + { + // abort if not valid type + if (!in_array($type, $this->log_levels)) { + return false; + } + // invalid flag type + if (!in_array($flag, ['on', 'off'])) { + return false; + } + $switch = $type . '_output' . ($flag == 'off' ? '_not' : ''); + // log level direct check must be not null or not empty string + if (!empty($level)) { + return $this->{$switch}[$level] ?? false; + } + // array + return $this->{$switch}; + } + + /** + * set flags for per log level type + * - level: set per sub group level + * - class: split by class + * - page: split per page called + * - run: for each run + * + * @param string $type Type to get: level, class, page, run + * @param bool $set True or False + * @return bool Return false if type invalid + */ + public function setLogPer(string $type, bool $set): bool + { + if (!in_array($type, $this->log_grouping)) { + return false; + } + $this->{'log_per_' . $type} = $set; + // if per run set unique id + if ($type == 'run' && $set == true) { + $this->setLogUniqueId(); + } + return true; + } + + /** + * return current set log per flag in bool + * + * @param string $type Type to get: level, class, page, run + * @return bool True of false for turned on or off + */ + public function getLogPer(string $type): bool + { + if (!in_array($type, $this->log_grouping)) { + return false; + } + return $this->{'log_per_' . $type}; + } + + /** + * Sets a unique id based on current date (y/m/d, h:i:s) and a unique id (8 chars) + * if override is set to true it will be newly set, else if already set nothing changes + * + * @param bool $override True to force new set + * @return void + */ + public function setLogUniqueId(bool $override = false): void + { + if (!$this->log_file_unique_id || $override == true) { + $this->log_file_unique_id = + date('Y-m-d_His') . '_U_' + . substr(hash('sha1', uniqid((string)mt_rand(), true)), 0, 8); + } + } + + /** + * Return current set log file unique id, + * empty string for not set + * + * @return string + */ + public function getLogUniqueId(): string + { + return $this->log_file_unique_id; + } + + /** + * Set or get the log file date extension flag + * if null or empty parameter gets current flag + * + * @param boolean|null $set Set the date suffix for log files + * If set to null return current set + * @return boolean Current set flag + */ + public function setGetLogPrintFileDate(?bool $set = null): bool + { + if ($set !== null) { + $this->log_print_file_date = $set; + } + return $this->log_print_file_date; + } + + /** + * Return current set log file name + * + * @return string Filename set set after the last time debug was called + */ + public function getLogFileName(): string + { + return $this->log_file_name; + } + + /** + * A replacement for the \CoreLibs\Debug\Support::printAr + * But this does not wrap it in

+	 * It uses some special code sets so we can convert that to pre flags
+	 * for echo output {##HTMLPRE##} ... {##/HTMLPRE##}
+	 * Do not use this without using it in a string in debug function
+	 *
+	 * @param  array $a Array to format
+	 * @return string          print_r formated
+	 */
+	public function prAr(array $a): string
+	{
+		return '##HTMLPRE##' . print_r($a, true) . '##/HTMLPRE##';
+	}
+
+	/**
+	 * Convert bool value to string value
+	 *
+	 * @param  bool   $bool  Bool value to be transformed
+	 * @param  string $true  Override default string 'true'
+	 * @param  string $false Override default string 'false'
+	 * @return string        $true or $false string for true/false bool
+	 */
+	public function prBl(
+		bool $bool,
+		string $true = 'true',
+		string $false = 'false'
+	): string {
+		return $bool ? $true : $false;
+	}
+
+	/**
+	 * write debug data to error_msg array
+	 *
+	 * @param  string $level  id for error message, groups messages together
+	 * @param  string $string the actual error message
+	 * @param  bool   $strip  default on false, if set to true,
+	 *                        all html tags will be stripped and 
changed to \n + * this is only used for debug output + * @param string $prefix Attach some block before $string. + * Will not be stripped even + * when strip is true + * if strip is false, recommended to add that to $string + * @return bool True if logged, false if not logged + */ + public function debug( + string $level, + string $string, + bool $strip = false, + string $prefix = '' + ): bool { + $status = false; + // must be debug on and either echo or print on + if ( + !$this->doDebugTrigger('debug', $level) || + ( + // if debug is on, either print or echo must be set to on + !$this->doDebugTrigger('print', $level) && + !$this->doDebugTrigger('echo', $level) + ) + ) { + return $status; + } + // get the last class entry and wrie that + $class = Support::getCallerClass(); + // get timestamp + $timestamp = Support::printTime(); + // same string put for print (no html data inside) + // write to file if set + $status = $this->writeErrorMsg( + $level, + '[' . $timestamp . '] ' + . '[' . $this->host_name . '] ' + . '[' . System::getPageName(System::FULL_PATH) . '] ' + . '[' . $this->running_uid . '] ' + . '{' . $class . '} ' + . '<' . $level . '> - ' + // strip the htmlpre special tags if exist + . str_replace( + ['##HTMLPRE##', '##/HTMLPRE##'], + '', + // if stripping all html, etc is requested, only for write error msg + ($strip ? + // find any
and replace them with \n + // strip rest of html elements (base only) + preg_replace( + "/(<\/?)(\w+)([^>]*>)/", + '', + str_replace('
', "\n", $prefix . $string) + ) : + $prefix . $string + ) ?: '' + ) + . "\n" + ); + // write to error level msg array if there is an echo request + if ($this->doDebugTrigger('echo', $level)) { + // init if not set + if (!isset($this->error_msg[$level])) { + $this->error_msg[$level] = []; + } + // HTML string + $this->error_msg[$level][] = '
' + . '[' . $timestamp . '] ' + . '[' . $level . '] ' + . '[' . $this->host_name . '] ' + . '[' . $this->page_name . '] ' + . '[' . $this->running_uid . '] ' + . '{' . $class . '} - ' + // as is prefix, allow HTML + . $prefix + // we replace special HTMLPRE with
 entries
+				. str_replace(
+					['##HTMLPRE##', '##/HTMLPRE##'],
+					['
', '
'], + Html::htmlent($string) + ) + . "
"; + $status = true; + } + return $status; + } + + /** + * for ECHO ON only + * returns error data as string so it can be echoed out + * + * @param string $header_prefix prefix string for header + * @return string error msg for all levels + */ + public function printErrorMsg(string $header_prefix = ''): string + { + $string_output = ''; + // if not debug && echo on, do not return anything + if ( + !$this->getLogLevelAll('debug') || + !$this->getLogLevelAll('echo') + ) { + return $string_output; + } + if ($this->error_msg_prefix) { + $header_prefix = $this->error_msg_prefix; + } + $script_end = microtime(true) - $this->script_starttime; + foreach ($this->error_msg as $level => $temp_debug_output) { + if ($this->doDebugTrigger('debug', $level)) { + if ($this->doDebugTrigger('echo', $level)) { + $string_output .= '
' + . '[' . $level . '] ' + . ($header_prefix ? "**** " . Html::htmlent($header_prefix) . " ****
\n" : '') + . '
' + . join('', $temp_debug_output); + } // echo it out + } // do printout + } // for each level + // create the output wrapper around + // so we have a nice formated output per class + if ($string_output) { + $string_prefix = '
' + . '
{' + . Support::getCallerClass() . '}
'; + $string_output = $string_prefix . $string_output + . '
Script Run Time: ' + . $script_end . '
' + . '
'; + } + // } + return $string_output; + } + + /** + * for ECHO ON only + * unsests the error message array + * can be used if writing is primary to file + * if no level given resets all + * + * @param string $level optional level + * @return void has no return + */ + public function resetErrorMsg(string $level = ''): void + { + if (!$level) { + $this->error_msg = []; + } elseif (isset($this->error_msg[$level])) { + unset($this->error_msg[$level]); + } + } + + /** + * for ECHO ON only + * Get current error message array + * + * @return array error messages collected + */ + public function getErrorMsg(): array + { + return $this->error_msg; + } + + /** + * for ECHO ON only + * merges the given error array with the one from this class + * only merges visible ones + * + * @param array $error_msg error array + * @return void has no return + */ + public function mergeErrors(array $error_msg = []): void + { + array_push($this->error_msg, ...$error_msg); + } +} + +// __END__ diff --git a/src/Debug/MemoryUsage.php b/src/Debug/MemoryUsage.php index f6090b2..d1416ea 100644 --- a/src/Debug/MemoryUsage.php +++ b/src/Debug/MemoryUsage.php @@ -13,13 +13,13 @@ use CoreLibs\Convert\Byte; class MemoryUsage { /** @var int */ - private static $start_memory = 0; + private static int $start_memory = 0; /** @var int */ - private static $set_memory = 0; + private static int $set_memory = 0; /** @var int */ - private static $previous_memory = 0; + private static int $previous_memory = 0; /** @var bool */ - private static $debug_memory = false; + private static bool $debug_memory = false; /** * set memory flag, or return set memory flag diff --git a/src/Debug/RunningTime.php b/src/Debug/RunningTime.php index 7058ef1..25faa86 100644 --- a/src/Debug/RunningTime.php +++ b/src/Debug/RunningTime.php @@ -12,18 +12,18 @@ class RunningTime { // hr /** @var float */ - private static $hr_start_time; + private static float $hr_start_time; /** @var float */ - private static $hr_end_time; + private static float $hr_end_time; /** @var float */ - private static $hr_last_time; + private static float $hr_last_time; // normal /** @var float */ - private static $start_time; + private static float $start_time; /** @var float */ - private static $end_time; + private static float $end_time; /** @var string */ - private static $running_time_string; + private static string $running_time_string; /** * sub calculation for running time based on out time. @@ -79,7 +79,7 @@ class RunningTime public static function hrRunningTime(string $out_time = 'ms'): float { // if start time not set, set start time - if (!self::$hr_start_time) { + if (empty(self::$hr_start_time)) { self::$hr_start_time = hrtime(true); self::$hr_last_time = self::$hr_start_time; $run_time = 0; @@ -137,7 +137,7 @@ class RunningTime list($micro, $timestamp) = explode(' ', microtime()); $running_time = 0; // set start & end time - if (!self::$start_time) { + if (empty(self::$start_time)) { // always reset running time string on first call self::$running_time_string = ''; self::$start_time = ((float)$micro + (float)$timestamp); @@ -149,7 +149,7 @@ class RunningTime self::$running_time_string .= date('Y-m-d H:i:s', (int)$timestamp); self::$running_time_string .= ' ' . $micro . ($simple ? ', ' : '
'); // if both are set - if (self::$start_time && self::$end_time) { + if (!empty(self::$start_time) && !empty(self::$end_time)) { $running_time = self::$end_time - self::$start_time; self::$running_time_string .= ($simple ? 'Run: ' : "Script running time: ") . $running_time . " s"; // reset start & end time after run diff --git a/src/Debug/Support.php b/src/Debug/Support.php index c4a322b..ef492c0 100644 --- a/src/Debug/Support.php +++ b/src/Debug/Support.php @@ -21,7 +21,7 @@ class Support */ public static function printTime(int $set_microtime = -1): string { - list($microtime, $timestamp) = explode(' ', microtime()); + [$microtime, $timestamp] = explode(' ', microtime()); $string = date("Y-m-d H:i:s", (int)$timestamp); // if microtime flag is -1 no round, if 0, no microtime, if >= 1, round that size if ($set_microtime == -1) { @@ -37,23 +37,21 @@ class Support * prints a html formatted (pre) array * * @param array $array any array - * @param bool $no_html set to true to use ##HTMLPRE## + * @param bool $no_html default add
 	 * @return string                formatted array for output with 
 tag added
 	 */
 	public static function printAr(array $array, bool $no_html = false): string
 	{
-		if ($no_html === false) {
-			return "
" . print_r($array, true) . "
"; - } else { - return '##HTMLPRE##' . print_r($array, true) . '##/HTMLPRE##'; - } + return $no_html ? + print_r($array, true) : + '
' . print_r($array, true) . '
'; } /** * alternate name for printAr function * * @param array $array any array - * @param bool $no_html set to true to use ##HTMLPRE## + * @param bool $no_html default add
 	 * @return string                formatted array for output with 
 tag added
 	 */
 	public static function printArray(array $array, bool $no_html = false): string
@@ -61,26 +59,61 @@ class Support
 		return self::printAr($array, $no_html);
 	}
 
+	/**
+	 * A replacement for the \CoreLibs\Debug\Support::printAr
+	 * But this does not wrap it in 

+	 * Do not use this without using it in a string in debug function
+	 * Note: for full data debug dumps use Support::dumpVar()
+	 *
+	 * @param  array $a Array to format
+	 * @return string          print_r formated
+	 */
+	public static function prAr(array $a): string
+	{
+		return self::printAr($a, true);
+	}
+
 	/**
 	 * convert bool value to string
 	 * if $name is set prefix with nae
 	 * default true: true, false: false
 	 *
-	 * @param  bool   $bool  Variable to convert
-	 * @param  string $name  [default: ''] Prefix name
-	 * @param  string $true  [default: true] True string
-	 * @param  string $false [default: false] False string
-	 * @return string        String with converted bool text for debug
+	 * @param  bool   $bool    Variable to convert
+	 * @param  string $name    [default: ''] Prefix name
+	 * @param  string $true    [default: 'true'] True string
+	 * @param  string $false   [default: 'false'] False string
+	 * @param  bool   $no_html [default: false] if true do not print html
+	 * @return string          String with converted bool text for debug
 	 */
 	public static function printBool(
 		bool $bool,
 		string $name = '',
 		string $true = 'true',
+		string $false = 'false',
+		bool $no_html = false,
+	): string {
+		return
+			(!empty($name) ?
+				($no_html ?
+					$name : '' . $name . '') . ': '
+				: '')
+			. ($bool ? $true : $false);
+	}
+
+	/**
+	 * Convert bool value to string value. Short name alias for printBool
+	 *
+	 * @param  bool   $bool  Bool value to be transformed
+	 * @param  string $true  [default: 'true'] Override default string 'true'
+	 * @param  string $false [default: 'false'] Override default string 'false'
+	 * @return string        $true or $false string for true/false bool
+	 */
+	public static function prBl(
+		bool $bool,
+		string $true = 'true',
 		string $false = 'false'
 	): string {
-		$string = (!empty($name) ? '' . $name . ': ' : '')
-			. ($bool ? $true : $false);
-		return $string;
+		return self::printBool($bool, '', $true, $false, true);
 	}
 
 	/**
@@ -89,9 +122,10 @@ class Support
 	 * if object return get_class
 	 * for array use printAr function, can be controlled with no_html for
 	 * Debug\Logging compatible output
+	 * Recommended to use Support::dumpVar()
 	 *
 	 * @param  mixed  $mixed
-	 * @param  bool   $no_html set to true to use ##HTMLPRE##or html escape
+	 * @param  bool   $no_html set to true to strip 
 tags
 	 * @return string
 	 */
 	public static function printToString(mixed $mixed, bool $no_html = false): string
@@ -119,12 +153,93 @@ class Support
 		}
 	}
 
+	/**
+	 * Dumps var data and returns it as string
+	 * var_dump based
+	 * Recommended debug output
+	 *
+	 * @param  mixed  $data         Anything
+	 * @param  bool   $no_html      [default=false] If true strip all html tags
+	 *                              (for text print)
+	 * @return string               A text string
+	 */
+	public static function dumpVar(
+		mixed $data,
+		bool $no_html = false,
+	): string {
+		// dump data
+		ob_start();
+		var_dump($data);
+		$debug_dump = ob_get_clean() ?: '[FAILED TO GET var_dump() data]';
+		// check if the original caller is dV, if yes, up the caller level for
+		// the file line get by 1, so we get file + pos from the dV call and
+		// not this call
+		$caller_level = 1;
+		$caller_list = self::getCallerMethodList();
+		if ($caller_list[0] == 'dV') {
+			echo "Raise caller level
: " . $caller_list[0] . "
"; + $caller_level = 2; + } + // we need to strip the string in : + // and replace it with the caller methods and location + $caller_file_number = self::getCallerFileLine($caller_level); + $debug_dump = preg_replace( + '|(/.*:\d+:)|', + '' . $caller_file_number . ':', + $debug_dump + ) ?? $debug_dump; // in case of failure keep original + // if strip is ture, remove all HTML tags and convert any html entities back + return $no_html ? + str_replace( + // things to replace in the string if set + ['>', '<', ' ', ' '], + ['>', '<', "\r", "\n"], + strip_tags($debug_dump) + ) : + $debug_dump; + } + + /** + * exports (dumps) var, in more printable design, but without detail info + * + * @param mixed $data Anything + * @param bool $no_html If true true do not add
 tags
+	 * @return string          A text string
+	 */
+	public static function exportVar(mixed $data, bool $no_html = false): string
+	{
+		return $no_html ?
+			var_export($data, true) :
+			'
' . var_export($data, true) . '
'; + } + + /** + * Return file name and line number where this was called + * One level up + * + * @param int $level trace level, default 1 + * @return string|null null or file name:line number + */ + public static function getCallerFileLine(int $level = 1): ?string + { + $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + // print \CoreLibs\Debug\Support::printAr($traces); + // We should check from top down if unset? + // sets the start point here, and in level two (the sub call) we find this + if (isset($traces[$level])) { + return ($traces[$level]['file'] ?? $traces[$level]['function']) + . ':' . ($traces[$level]['line'] ?? '-'); + } + return null; + } + /** * if there is a need to find out which parent method called a child method, * eg for debugging, this function does this * * call this method in the child method and you get the parent function that called - * @param int $level debug level, default 1 + * @param int $level trace level, default 1 * @return ?string null or the function that called the function * where this method is called */ diff --git a/src/Get/System.php b/src/Get/System.php index 4984564..690b43b 100644 --- a/src/Get/System.php +++ b/src/Get/System.php @@ -54,14 +54,15 @@ class System /** * get the host name without the port as given by the SELF var + * if no host name found will set to NOHOST:0 * - * @return array host name/port name + * @return array{string,int} host name/port number */ public static function getHostName(): array { - $host = $_SERVER['HTTP_HOST'] ?? 'NOHOST:NOPORT'; - list($host_name, $port) = array_pad(explode(':', $host), 2, self::DEFAULT_PORT); - return [$host_name, $port]; + $host = $_SERVER['HTTP_HOST'] ?? 'NOHOST:0'; + [$host_name, $port] = array_pad(explode(':', $host), 2, self::DEFAULT_PORT); + return [$host_name, (int)$port]; } /** diff --git a/src/Language/Core/CachedFileReader.php b/src/Language/Core/CachedFileReader.php index adcd535..95721bb 100644 --- a/src/Language/Core/CachedFileReader.php +++ b/src/Language/Core/CachedFileReader.php @@ -29,9 +29,9 @@ namespace CoreLibs\Language\Core; class CachedFileReader extends \CoreLibs\Language\Core\StringReader { /** @var int */ - public $error = 0; + public int $error = 0; /** @var string */ - public $fd_str = ''; + public string $fd_str = ''; /** * Undocumented function diff --git a/src/Language/Core/FileReader.php b/src/Language/Core/FileReader.php index 8488fa3..ae4f6e1 100644 --- a/src/Language/Core/FileReader.php +++ b/src/Language/Core/FileReader.php @@ -27,13 +27,13 @@ namespace CoreLibs\Language\Core; class FileReader { /** @var int */ - public $fr_pos; + public int $fr_pos; /** @var resource|bool */ - public $fr_fd; + public mixed $fr_fd; // no resource type yet /** @var int */ - public $fr_length; + public int $fr_length; /** @var int */ - public $error = 0; + public int $error = 0; /** * file read constructor diff --git a/src/Language/Core/GetTextReader.php b/src/Language/Core/GetTextReader.php index 3fa7404..0a5715a 100644 --- a/src/Language/Core/GetTextReader.php +++ b/src/Language/Core/GetTextReader.php @@ -41,31 +41,31 @@ class GetTextReader { // public: /** @var int */ - public $error = 0; // public variable that holds error code (0 if no error) + public int $error = 0; // public variable that holds error code (0 if no error) // private: /** @var int */ - private $BYTEORDER = 0; // 0: low endian, 1: big endian + private int $BYTEORDER = 0; // 0: low endian, 1: big endian /** @var FileReader */ - private $STREAM; + private FileReader $STREAM; /** @var bool */ - private $short_circuit = false; + private bool $short_circuit = false; /** @var bool */ - private $enable_cache = false; + private bool $enable_cache = false; /** @var int */ - private $originals = 0; // offset of original table + private int $originals = 0; // offset of original table /** @var int */ - private $translations = 0; // offset of translation table + private int $translations = 0; // offset of translation table /** @var string */ - private $pluralheader = ''; // cache header field for plural forms + private string $pluralheader = ''; // cache header field for plural forms /** @var int */ - private $total = 0; // total string count + private int $total = 0; // total string count /** @var array|null */ - private $table_originals = null; // table for original strings (offsets) + private array|null $table_originals = null; // table for original strings (offsets) /** @var array|null */ - private $table_translations = null; // table for translated strings (offsets) + private array|null $table_translations = null; // table for translated strings (offsets) /** @var array */ - private $cache_translations = []; // original -> translation mapping + private array $cache_translations = []; // original -> translation mapping /* Methods */ diff --git a/src/Language/Core/StringReader.php b/src/Language/Core/StringReader.php index 90766e9..063647d 100644 --- a/src/Language/Core/StringReader.php +++ b/src/Language/Core/StringReader.php @@ -27,9 +27,9 @@ namespace CoreLibs\Language\Core; class StringReader { /** @var int */ - public $sr_pos; + public int $sr_pos; /** @var string */ - public $sr_str; + public string $sr_str; /** * constructor for string reader diff --git a/src/Language/L10n.php b/src/Language/L10n.php index 75db228..dcf97a7 100644 --- a/src/Language/L10n.php +++ b/src/Language/L10n.php @@ -35,42 +35,42 @@ class L10n /** @var string the default fallback encoding if nothing is set */ public const DEFAULT_CHARSET = 'UTF-8'; /** @var string the current locale */ - private $locale = ''; + private string $locale = ''; /** @var string the SET locale as WHERE the domain file is */ - private $locale_set = ''; + private string $locale_set = ''; /** @var string the default selected/active domain */ - private $domain = ''; + private string $domain = ''; /** @var string encoding, as from locale or set from outside */ - private $override_encoding = self::DEFAULT_CHARSET; + private string $override_encoding = self::DEFAULT_CHARSET; /** @var string encoding set during the parse Locale */ - private $encoding = ''; + private string $encoding = ''; /** @var array> locale > domain = translator */ - private $domains = []; + private array $domains = []; /** @var array bound paths for domains */ - private $paths = ['' => './']; + private array $paths = ['' => './']; // files /** @var string the full path to the mo file to loaded */ - private $mofile = ''; + private string $mofile = ''; /** @var string base path to search level */ - private $base_locale_path = ''; + private string $base_locale_path = ''; /** @var string dynamic set path to where the mo file is actually */ - private $base_content_path = ''; + private string $base_content_path = ''; // errors /** @var bool if load of mo file was unsuccessful */ - private $load_failure = false; + private bool $load_failure = false; // object holders /** @var FileReader|bool reader class for file reading, false for short circuit */ - private $input = false; + private FileReader|bool $input = false; /** @var GetTextReader reader class for MO data */ - private $l10n; + private GetTextReader|null $l10n = null; /** * @static * @var L10n self class */ - private static $instance; + private static L10n $instance; /** * class constructor call for language getstring @@ -124,7 +124,6 @@ class L10n */ public static function getInstance(): L10n { - /** @phpstan-ignore-next-line */ if (empty(self::$instance)) { self::$instance = new self(); } @@ -253,6 +252,13 @@ class L10n // dummy $this->l10n = new GetTextReader($this->input); } + // if this is still null here, we abort + if ($this->l10n === null) { + throw new \Exception( + "Could not create CoreLibs\Language\Core\GetTextReader object", + E_USER_ERROR + ); + } return $this->l10n; } @@ -673,6 +679,7 @@ class L10n // fallback passthrough if ($this->l10n === null) { echo $text; + return; } echo $this->l10n->translate($text); } diff --git a/src/Logging/Logger/Flag.php b/src/Logging/Logger/Flag.php new file mode 100644 index 0000000..6fb8fc4 --- /dev/null +++ b/src/Logging/Logger/Flag.php @@ -0,0 +1,107 @@ + per_date, cannot be used at the same time) + * per_group: for debug level, group per group id (old level) + * per_page: per file name logging + * per_class: log per class + * per_level: per logging level file split +*/ + +declare(strict_types=1); + +namespace CoreLibs\Logging\Logger; + +enum Flag: int +{ + /** all off flag */ + case all_off = 0; + + /** write per run */ + case per_run = 1; + + /** write per date */ + case per_date = 2; + + /** was PER_LEVEL, write per group id (debug) */ + case per_group = 4; + + /** write per page (filename) */ + case per_page = 8; + + /** write per class */ + case per_class = 16; + + /** write per log level name */ + case per_level = 32; + + /** + * get internal name from string value + * + * @param non-empty-string $name + * @return self + */ + public static function fromName(string $name): self + { + return match ($name) { + 'Run', 'run', 'per_run', 'PER_RUN' => self::per_run, + 'Date', 'date', 'per_date', 'PER_DATE' => self::per_date, + 'Group', 'group', 'per_group', 'PER_GROUP' => self::per_group, + 'Page', 'page', 'per_page', 'PER_PAGE' => self::per_page, + 'Class', 'class', 'per_class', 'PER_CLASS' => self::per_class, + 'Level', 'level', 'per_level', 'PER_LEVEL' => self::per_level, + default => self::all_off, + }; + } + + /** + * Get internal name from int value + * + * @param int $value + * @return self + */ + public static function fromValue(int $value): self + { + return self::from($value); + } + + /** + * convert current set level to name (upper case) + * + * @return string + */ + public function getName(): string + { + return strtoupper($this->name); + } + + /** @var int[] */ + public const VALUES = [ + 0, + 1, + 2, + 4, + 8, + 16, + 32, + ]; + + /** @var string[] */ + public const NAMES = [ + 'ALL_OFF', + 'PER_RUN', + 'PER_DATE', + 'PER_GROUP', + 'PER_PAGE', + 'PER_CLASS', + 'PER_LEVEL', + ]; +} + +// __END__ diff --git a/src/Logging/Logger/Level.php b/src/Logging/Logger/Level.php new file mode 100644 index 0000000..355dce4 --- /dev/null +++ b/src/Logging/Logger/Level.php @@ -0,0 +1,216 @@ +getName() to get the standard Monolog name which is full uppercased (e.g. "DEBUG") + * - Use ->toPsrLogLevel() to get the standard PSR-3 name which is full lowercased (e.g. "debug") + * - Use ->toRFC5424Level() to get the standard RFC 5424 value (e.g. 7 for debug, 0 for emergency) + * - Use ->name to get the enum case's name which is capitalized (e.g. "Debug") + * + * To get the internal value for filtering, if the includes/isLowerThan/isHigherThan methods are + * not enough, you can use ->value to get the enum case's integer value. + */ +enum Level: int +{ + /** + * Detailed debug information + */ + case Debug = 100; + + /** + * Interesting events + * + * Examples: User logs in, SQL logs. + */ + case Info = 200; + + /** + * Uncommon events + */ + case Notice = 250; + + /** + * Exceptional occurrences that are not errors + * + * Examples: Use of deprecated APIs, poor use of an API, + * undesirable things that are not necessarily wrong. + */ + case Warning = 300; + + /** + * Runtime errors + */ + case Error = 400; + + /** + * Critical conditions + * + * Example: Application component unavailable, unexpected exception. + */ + case Critical = 500; + + /** + * Action must be taken immediately + * + * Example: Entire website down, database unavailable, etc. + * This should trigger the SMS alerts and wake you up. + */ + case Alert = 550; + + /** + * Urgent alert. + */ + case Emergency = 600; + + /** + * @param value-of|LogLevel::*|'Debug'|'Info'|'Notice'|'Warning'|'Error'|'Critical'|'Alert'|'Emergency' $name + * @return static + */ + public static function fromName(string $name): self + { + return match ($name) { + 'debug', 'Debug', 'DEBUG' => self::Debug, + 'info', 'Info', 'INFO' => self::Info, + 'notice', 'Notice', 'NOTICE' => self::Notice, + 'warning', 'Warning', 'WARNING' => self::Warning, + 'error', 'Error', 'ERROR' => self::Error, + 'critical', 'Critical', 'CRITICAL' => self::Critical, + 'alert', 'Alert', 'ALERT' => self::Alert, + 'emergency', 'Emergency', 'EMERGENCY' => self::Emergency, + }; + } + + /** + * @param value-of $value + * @return static + */ + public static function fromValue(int $value): self + { + return self::from($value); + } + + /** + * Returns true if the passed $level is higher or equal to $this + */ + public function includes(Level $level): bool + { + return $this->value <= $level->value; + } + + public function isHigherThan(Level $level): bool + { + return $this->value > $level->value; + } + + public function isLowerThan(Level $level): bool + { + return $this->value < $level->value; + } + + /** + * Returns the monolog standardized all-capitals name of the level + * + * Use this instead of $level->name which returns the enum case name (e.g. Debug vs DEBUG if you use getName()) + * + * @phan-suppress-next-line PhanTypeMismatchDeclaredReturn + * @return value-of + */ + public function getName(): string + { + return match ($this) { + self::Debug => 'DEBUG', + self::Info => 'INFO', + self::Notice => 'NOTICE', + self::Warning => 'WARNING', + self::Error => 'ERROR', + self::Critical => 'CRITICAL', + self::Alert => 'ALERT', + self::Emergency => 'EMERGENCY', + }; + } + + /** + * Returns the PSR-3 level matching this instance + * + * @phpstan-return \Psr\Log\LogLevel::* + */ + public function toPsrLogLevel(): string + { + return match ($this) { + self::Debug => LogLevel::DEBUG, + self::Info => LogLevel::INFO, + self::Notice => LogLevel::NOTICE, + self::Warning => LogLevel::WARNING, + self::Error => LogLevel::ERROR, + self::Critical => LogLevel::CRITICAL, + self::Alert => LogLevel::ALERT, + self::Emergency => LogLevel::EMERGENCY, + }; + } + + /** + * Returns the RFC 5424 level matching this instance + * + * @phpstan-return int<0, 7> + */ + public function toRFC5424Level(): int + { + return match ($this) { + self::Debug => 7, + self::Info => 6, + self::Notice => 5, + self::Warning => 4, + self::Error => 3, + self::Critical => 2, + self::Alert => 1, + self::Emergency => 0, + }; + } + + public const VALUES = [ + 100, + 200, + 250, + 300, + 400, + 500, + 550, + 600, + ]; + + public const NAMES = [ + 'DEBUG', + 'INFO', + 'NOTICE', + 'WARNING', + 'ERROR', + 'CRITICAL', + 'ALERT', + 'EMERGENCY', + ]; +} + + +// __END__ diff --git a/src/Logging/Logging.php b/src/Logging/Logging.php new file mode 100644 index 0000000..81630a3 --- /dev/null +++ b/src/Logging/Logging.php @@ -0,0 +1,1334 @@ +>|array{string:array{type:string,type_info?:string,mandatory:true,alias?:string,default:string|bool|Level,deprecated:bool,use?:string}} */ + private const OPTIONS = [ + 'log_folder' => [ + 'type' => 'string', 'mandatory' => true, + 'default' => '', 'deprecated' => false + ], + 'log_file_id' => [ + 'type' => 'string', 'mandatory' => true, 'alias' => 'file_id', + 'default' => '', 'deprecated' => false + ], + 'file_id' => [ + 'type' => 'string', 'mandatory' => false, + 'default' => '', 'deprecated' => true, 'use' => 'log_file_id' + ], + 'log_level' => [ + 'type' => 'instance', + 'type_info' => '\CoreLibs\Logging\Logger\Level', + 'mandatory' => false, + 'default' => Level::Debug, + 'deprecated' => false + ], + // options + 'log_per_run' => [ + 'type' => 'bool', 'mandatory' => false, + 'default' => false, 'deprecated' => false + ], + 'log_per_date' => [ + 'type' => 'bool', 'mandatory' => false, + 'default' => false, 'deprecated' => false + ], + 'log_per_group' => [ + 'type' => 'bool', 'mandatory' => false, + 'default' => false, 'deprecated' => false + ], + 'log_per_page' => [ + 'type' => 'bool', 'mandatory' => false, + 'default' => false, 'deprecated' => false + ], + 'log_per_class' => [ + 'type' => 'bool', 'mandatory' => false, + 'default' => false, 'deprecated' => false + ], + 'log_per_level' => [ + 'type' => 'bool', 'mandatory' => false, + 'default' => false, 'deprecated' => false + ], + 'print_file_date' => [ + 'type' => 'bool', 'mandatory' => false, + 'default' => false, 'deprecated' => true, 'use' => 'log_per_date' + ], + ]; + + // options + /** @var array */ + private array $options = []; + + /** @var Level set level */ + private Level $log_level; + + // page and host name + /** @var string */ + private string $host_name; + /** @var int */ + private int $host_port; + /** @var string unique ID set on class init and used in logging as prefix */ + private string $running_uid = ''; + + // log file name + /** @var string */ + private string $log_folder = ''; + /** @var string a alphanumeric name that has to be set as global definition */ + private string $log_file_id = ''; + /** @var string log file name extension */ + private string $log_file_name_ext = 'log'; + /** @var string log file name with folder, for actual writing */ + private string $log_file_name = ''; + /** @var int set in bytes */ + private int $log_max_filesize = 0; + /** @var string used if no log id set or found */ + private string $log_file_prefix = 'error_msg'; + /** @var string */ + private string $log_print_file = '{LOGID}{LEVEL}{GROUP}{CLASS}{PAGENAME}{DATE_RUNID}'; + /** @var string a unique ID set only once for call derived from this class */ + private string $log_file_unique_id = ''; + /** @var string Y-m-d file in file name */ + private string $log_file_date = ''; + + /** + * 1: create a new log file per run (time stamp + unique ID) + * 2: add Y-m-d and do automatic daily rotation + * 4: split per group (first parameter in debug call, group id, former level) + * 8: split log per called file + * 16: split log per class + * 32: split log per set log level + */ + /** @var int bitwise set for log flags */ + private int $log_flags = 0; + /** @var array valid log flag names */ + private array $log_valid_flags = [ + 'log_per_run' => Flag::per_run, + 'log_per_date' => Flag::per_date, + 'log_per_group' => Flag::per_group, + 'log_per_page' => Flag::per_page, + 'log_per_class' => Flag::per_class, + // not before it was PER_GROUP type + 'log_per_level' => Flag::per_level, + // below are old & deprecated + 'print_file_date' => Flag::per_date, + ]; + + /** + * Init logger + * + * options array layout + * - log_folder: + * - log_file_id / file_id (will be deprecated): + * - log_level: + * + * - log_per_run: + * - log_per_date: (was print_file_date) + * - log_per_group + * - log_per_page: + * - log_per_class: + * - log_per_level: + * + * @param array $options Array with settings options + */ + public function __construct(array $options = []) + { + // options chekc + // must set values + // * path + // * file id + // * log level + $this->optionsCheck($options); + + // set log level + $this->initLogLevel(); + // set log folder from options + $this->initLogFolder(); + // set per run UID for logging + $this->running_uid = Uids::uniqIdShort(); + // set host name + $this->initHostName(); + // set file id + $this->initLogFileId(); + // set max file size for logging, 0 = no limit + $this->setLogMaxFileSize($this->options['log_max_file_size'] ?? 0); + // set flags and values needed for those flags + $this->initLogFlagsAndValues(); + } + + // ********************************************************************* + // PRIVATE METHODS + // ********************************************************************* + + /** + * Undocumented function + * + * @param array $options + * @return bool + */ + private function optionsCheck(array $options): bool + { + // make sure only valid ones are in the options list, + // drop all others + // check for missing (trigger warning?) + foreach (self::OPTIONS as $name => $settings) { + // first deprecation warnings + if (isset($options[$name]) && $settings['deprecated']) { + trigger_error( + 'options: "' . $name . '" is deprecated use: "' + . ($settings['use'] ?? 'NO_REPLACEMENT') . '".', + E_USER_DEPRECATED + ); + } + // if mandatory and not set -> warning + if ( + $settings['mandatory'] && !isset($options[$name]) && + empty($settings['alias']) + ) { + throw new \InvalidArgumentException( + 'Missing mandatory option: "' . $name . '"', + E_USER_WARNING + ); + } elseif ( + // if not mandatory and not set -> default + !$settings['mandatory'] && !isset($options[$name]) + ) { + $this->options[$name] = $settings['default']; + } else { + // else set from options + $this->options[$name] = $options[$name] ?? $settings['default']; + } + // check valid type (only type not content) + switch ($settings['type']) { + case 'bool': + if (!is_bool($this->options[$name])) { + throw new \InvalidArgumentException( + 'Option: "' . $name . '" is not of type bool', + E_USER_ERROR + ); + } + break; + case 'string': + if (!is_string($this->options[$name])) { + throw new \InvalidArgumentException( + 'Option: "' . $name . '" is not of type string', + E_USER_ERROR + ); + } + break; + case 'instance': + if ( + empty($settings['type_info']) || + !$this->options[$name] instanceof $settings['type_info'] + ) { + throw new \InvalidArgumentException( + 'Option: "' . $name . '" is not of instance ' + . ($settings['type_info'] ?? 'NO INSTANCE DEFINED'), + E_USER_ERROR + ); + } + break; + } + } + return true; + } + + /** + * init log level, just a wrapper to auto set from options + * + * @return void + */ + private function initLogLevel() + { + // if this is not a valid instance of Level Enum then set to Debug + if ( + empty($this->options['log_level']) || + !$this->options['log_level'] instanceof Level + ) { + $this->options['log_level'] = Level::Debug; + } + $this->setLoggingLevel($this->options['log_level']); + } + + /** + * Set the log folder + * If folder is not writeable the script will throw an E_USER_ERROR + * + * @return bool True on proper set, False on not proper set folder + */ + private function initLogFolder(): bool + { + $status = true; + // set log folder from options + $log_folder = $this->options['log_folder'] ?? ''; + // legacy flow, check must set constants + if (empty($log_folder) && defined('BASE') && defined('LOG')) { + /** @deprecated Do not use this anymore, define path on class load */ + trigger_error( + 'options: log_folder must be set. Setting via BASE and LOG constants is deprecated', + E_USER_DEPRECATED + ); + // make sure this is writeable, else skip + $log_folder = BASE . LOG; + $status = false; + } + // fallback + notice + if (empty($log_folder)) { + /* trigger_error( + 'option log_folder is empty. fallback to: ' . getcwd(), + E_USER_NOTICE + ); */ + $log_folder = getcwd() . DIRECTORY_SEPARATOR; + $status = false; + } + // if folder is not writeable, abort + if (!$this->setLogFolder($log_folder)) { + throw new InvalidArgumentException( + 'Folder: "' . $log_folder . '" is not writeable for logging', + E_USER_ERROR + ); + } + return $status; + } + + /** + * Set the hostname and port + * If port is not defaul 80 it will be added to the host name + * + * @return void + */ + private function initHostName(): void + { + // set host name + [$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 .= ':' . (string)$this->host_port; + } + } + + /** + * set log file prefix id + * + * @return bool + */ + private function initLogFileId(): bool + { + $status = true; + + // alert of log_file_id and file_id is, log_file_id is prefered + if ( + !empty($this->options['log_file_id']) && + !empty($this->options['file_id']) + ) { + trigger_error( + 'options: both log_file_id and log_id are set at the same time, will use log_file_id', + E_USER_WARNING + ); + $this->options['log_file_id'] = $this->options['file_id']; + unset($this->options['file_id']); + } + if ( + empty($this->options['log_file_id']) && + !empty($this->options['file_id']) + ) { + // will trigger deprecation in future + $this->options['log_file_id'] = $this->options['file_id']; + unset($this->options['file_id']); + } + + // can be overridden with basicSetLogFileId later + if (!empty($this->options['log_file_id'])) { + $this->setLogFileId($this->options['log_file_id']); + } elseif (!empty($GLOBALS['LOG_FILE_ID'])) { + /** @deprecated Do not use this anymore, define file_id on class load */ + trigger_error( + 'options: log_file_id must be set. Setting via LOG_FILE_ID global variable is deprecated', + E_USER_DEPRECATED + ); + $status = false; + // legacy flow, should be removed and only set via options + $this->setLogFileId($GLOBALS['LOG_FILE_ID']); + } else { + // auto set (should be deprecated in future) + $this->setLogFileId( + str_replace(':', '-', $this->host_name) . '_' + . str_replace('\\', '-', Support::getCallerClass()) + ); + } + if (empty($this->getLogFileId())) { + throw new InvalidArgumentException( + 'LogFileId: no log file id set', + E_USER_ERROR + ); + } + return $status; + } + + /** + * set flags from options and option flags connection internal settings + * + * @return void + */ + private function initLogFlagsAndValues(): void + { + // first set all flags + foreach ($this->log_valid_flags as $log_flag => $log_flag_key) { + if (empty($this->options[$log_flag])) { + continue; + } + $this->setLogFlag($log_flag_key); + } + // init per run uid + if ($this->getLogFlag(Flag::per_run)) { + $this->setLogUniqueId(); + } elseif ($this->getLogFlag(Flag::per_date)) { + // init file date + $this->log_file_date = date('Y-m-d'); + } + } + + /** + * check if set log level is equal or higher than + * requested one + * + * @param Level $level + * @return bool True to allow write, False for not + */ + private function checkLogLevel(Level $level): bool + { + return $this->log_level->includes($level); + } + + /** + * Build the file name for writing + * + * @param Level $level Request log level + * @param string $group_id Debug level group name id + * @return string + */ + private function buildLogFileName(Level $level, string $group_id = ''): string + { + // init base file path + $fn = $this->log_print_file . '.' . $this->log_file_name_ext; + // log ID prefix settings, if not valid, replace with empty + if (!empty($this->log_file_id)) { + $rpl_string = $this->log_file_id; + } else { + $rpl_string = $this->log_file_prefix; + } + $fn = str_replace('{LOGID}', $rpl_string, $fn); // log id (like a log file prefix) + + $rpl_string = !$this->getLogFlag(Flag::per_level) ? '' : + '_' . $level->getName(); + $fn = str_replace('{LEVEL}', $rpl_string, $fn); // create output filename + + // write per level + $rpl_string = !$this->getLogFlag(Flag::per_group) ? '' : + // normalize level, replace all non alphanumeric characters with - + '_' . ( + // if return is only - then set error string + preg_match( + "/^-+$/", + $level_string = preg_replace("/[^A-Za-z0-9-_]/", '-', $group_id) ?? '' + ) ? + 'INVALID-LEVEL-STRING' : + $level_string + ); + $fn = str_replace('{GROUP}', $rpl_string, $fn); // create output filename + // set per class, but don't use get_class as we will only get self + $rpl_string = !$this->getLogFlag(Flag::per_class) ? '' : '_' + // set sub class settings + . str_replace('\\', '-', Support::getCallerClass()); + $fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename + + // if request to write to one file + $rpl_string = !$this->getLogFlag(Flag::per_page) ? + '' : + '_' . System::getPageName(System::NO_EXTENSION); + $fn = str_replace('{PAGENAME}', $rpl_string, $fn); // create output filename + + // if run id, we auto add ymd, so we ignore the log file date + if ($this->getLogFlag(Flag::per_run)) { + $rpl_string = '_' . $this->getLogUniqueId(); // add 8 char unique string + } elseif ($this->getLogFlag(Flag::per_date)) { + $rpl_string = '_' . $this->getLogDate(); // add date to file + } else { + $rpl_string = ''; + } + $fn = str_replace('{DATE_RUNID}', $rpl_string, $fn); // create output filename + $this->log_file_name = $fn; + + return $fn; + } + + /** + * writes error msg data to file for current level + * + * @param Level $level Log Level we wnat to write to + * @param string|Stringable $message Log message to write + * @param string $group_id A group + * @return bool True if message written, False if not + */ + private function writeErrorMsg( + Level $level, + string|\Stringable $message, + string $group_id = '' + ): bool { + // only write if write is requested + if (!$this->checkLogLevel($level)) { + return false; + } + + // build logging file name + // fn is log folder + file name + $fn = $this->log_folder . $this->buildLogFileName($level, $group_id); + + // write to file + // first check if max file size is is set and file is bigger + if ( + $this->log_max_filesize > 0 && + (filesize($fn) > $this->log_max_filesize) + ) { + // for easy purpose, rename file only to attach timestamp, no sequence numbering + rename($fn, $fn . '.' . date("YmdHis")); + } + $fp = fopen($fn, 'a'); + if ($fp === false) { + echo ""; + return false; + } + fwrite($fp, $message . "\n"); + fclose($fp); + return true; + } + + /** + * Prepare the log message with all needed info blocks: + * [timestamp] [host name] [file path + file] [running uid] {class} - message + * + * @param string $level_str Log level we will write to + * @param string|Stringable $message The message to write + * @param mixed[] $context Any additional info we want to attach in any format + * @param string $group_id A group id, only used in DEBUG level, + * if empty set to log level + * @return string + */ + private function prepareLog( + string $level_str, + string|\Stringable $message, + array $context = [], + string $group_id = '', + ): string { + // file + line: call not this but one before (the one that calls this) + $file_line = Support::getCallerFileLine(2) ?? + System::getPageName(System::FULL_PATH); + // get the last class entry and wrie that + $class = Support::getCallerClass(); + // method/function: prepareLog->(debug|info|...)->[THIS] + $method = Support::getCallerMethod(3); + if ($method !== null) { + $class .= '::' . $method; + } + // get timestamp + $timestamp = Support::printTime(); + + // if group id is empty replace it with current level + $group_str = $level_str; + if (!empty($group_id)) { + $group_str .= ':' . $group_id; + } + // additional context + $context_str = ''; + if ($context != []) { + // TODO this here has to be changed to something better + $context_str = ' ' . print_r($context, true); + } + // build log string + return '[' . $timestamp . '] ' + . '[' . $this->host_name . '] ' + . '[' . $file_line . '] ' + . '[' . $this->running_uid . '] ' + . '{' . $class . '} ' + . '<' . strtoupper($group_str) . '> ' + . $message + . $context_str; + } + + // ********************************************************************* + // PUBLIC STATIC METHJODS + // ********************************************************************* + + /** + * set the log level + * + * from Monolog\Logger + * + * @param string|int|Level $level + * @return Level + */ + public static function processLogLevel(string|int|Level $level): Level + { + if ($level instanceof Level) { + return $level; + } + + if (\is_string($level)) { + if (\is_numeric($level)) { + $levelEnum = Level::tryFrom((int)$level); + if ($levelEnum === null) { + throw new InvalidArgumentException( + 'Level "' . $level . '" is not defined, use one of: ' + /** @phan-suppress-next-line PhanUselessBinaryAddRight */ + . implode(', ', Level::NAMES + Level::VALUES) + ); + } + return $levelEnum; + } + + // Contains first char of all log levels and avoids using strtoupper() which may have + // strange results depending on locale (for example, "i" will become "İ" in Turkish locale) + $upper = strtr(substr($level, 0, 1), 'dinweca', 'DINWECA') + . strtolower(substr($level, 1)); + if (defined(Level::class . '::' . $upper)) { + return constant(Level::class . '::' . $upper); + } + + throw new InvalidArgumentException( + 'Level "' . $level . '" is not defined, use one of: ' + /** @phan-suppress-next-line PhanUselessBinaryAddRight */ + . implode(', ', Level::NAMES + Level::VALUES) + ); + } + + $levelEnum = Level::tryFrom($level); + if ($levelEnum === null) { + throw new InvalidArgumentException( + 'Level "' . var_export($level, true) . '" is not defined, use one of: ' + /** @phan-suppress-next-line PhanUselessBinaryAddRight */ + . implode(', ', Level::NAMES + Level::VALUES) + ); + } + + return $levelEnum; + } + + // ********************************************************************* + // PUBLIC METHODS + // ********************************************************************* + + // **** GET/SETTER + + // log level set and get + + /** + * set new log level + * + * @param string|int|Level $level + * @return void + */ + public function setLoggingLevel(string|int|Level $level): void + { + $this->log_level = $this->processLogLevel($level); + } + + /** + * return current set log level + * + * @return Level + */ + public function getLoggingLevel(): Level + { + return $this->log_level; + } + + /** + * this is for older JS_DEBUG flags + * + * @return bool True, we are at debug level + */ + public function getJsDebug(): bool + { + return $this->log_level === Level::Debug ? true : false; + } + + // log file id set (file name prefix) + + /** + * sets the internal log file prefix id + * string must be a alphanumeric string + * + * @param string $string log file id string value + * @return bool + */ + public function setLogFileId(string $string): bool + { + if (!preg_match("/^[\w\.\-]+$/", $string)) { + return false; + } + $this->log_file_id = $string; + return true; + } + + /** + * return current set log file id + * + * @return string + */ + public function getLogFileId(): string + { + return $this->log_file_id; + } + + // log unique id set (for per run) + + /** + * Sets a unique id based on current date (y/m/d, h:i:s) and a unique id (8 chars) + * if override is set to true it will be newly set, else if already set nothing changes + * + * @param bool $override True to force new set + * @return void + */ + public function setLogUniqueId(bool $override = false): void + { + if (empty($this->log_file_unique_id) || $override == true) { + $this->log_file_unique_id = + date('Y-m-d_His') . '_U_' + . substr(hash( + 'sha1', + random_bytes(63) + ), 0, 8); + } + } + + /** + * Return current set log file unique id, + * empty string for not set + * + * @return string + */ + public function getLogUniqueId(): string + { + return $this->log_file_unique_id; + } + + // general log date + + /** + * set the log file date to Y-m-d + * must be set if log_per_date is set + * + * @return void + */ + public function setLogDate(): void + { + $this->log_file_date = date('Y-m-d'); + } + + /** + * get the current set log file_date + * + * @return string + */ + public function getLogDate(): string + { + return $this->log_file_date; + } + + // general flag set + + /** + * set one of the basic flags + * + * @param Flag $flag flag level to set + * @return void + */ + public function setLogFlag(Flag $flag): void + { + $this->log_flags |= $flag->value; + } + + /** + * unset given from the log flags + * + * @param Flag $flag flag level to unset + * @return void + */ + public function unsetLogFlag(Flag $flag): void + { + $this->log_flags &= ~$flag->value; + } + + /** + * check if a given flag is set + * + * @param Flag $flag + * @return bool + */ + public function getLogFlag(Flag $flag): bool + { + if ($this->log_flags & $flag->value) { + return true; + } + return false; + } + + /** + * Return all set log flags as int + * + * @return int + */ + public function getLogFlags(): int + { + return $this->log_flags; + } + + // log folder/file + + /** + * set new log folder, check that folder is writeable + * If not setable keep older log folder setting + * + * @param string $log_folder Folder to set + * @return bool If not setable, return false + */ + public function setLogFolder(string $log_folder): bool + { + if (!is_writeable($log_folder)) { + return false; + } + // check if log_folder has a trailing / + if (substr($log_folder, -1, 1) != DIRECTORY_SEPARATOR) { + $log_folder .= DIRECTORY_SEPARATOR; + } + $this->log_folder = $log_folder; + return true; + } + + /** + * get current set log folder + * + * @return string + */ + public function getLogFolder(): string + { + return $this->log_folder; + } + + // note that set log filder is dynamic during log write + + /** + * get last set log file name + * + * @return string + */ + public function getLogFile(): string + { + return $this->log_file_name; + } + + // max log file size + + /** + * set mag log file size + * + * @param int $file_size Set max file size in bytes, 0 for no limit + * @return bool False for invalid number + */ + public function setLogMaxFileSize(int $file_size): bool + { + if ($file_size < 0) { + return false; + } + if ($file_size < self::MIN_LOG_MAX_FILESIZE) { + return false; + } + $this->log_max_filesize = $file_size; + return true; + } + + /** + * Return current set log max file size in bytes + * + * @return int Max size in bytes, 0 for no limit + */ + public function getLogMaxFileSize(): int + { + return $this->log_max_filesize; + } + + // ********************************************************************* + // OPTIONS CALLS + // ********************************************************************* + + /** + * get option + * + * @param string $option_key Which option key to search + * @return string|bool|int|null Returns null on not found + */ + public function getOption(string $option_key): string|bool|int|null + { + return $this->options[$option_key] ?? null; + } + + // ********************************************************************* + // MAIN CALLS + // ********************************************************************* + + /** + * DEBUG: 100 + * + * write debug data to error_msg array + * + * @param string $group_id id for error message, groups messages together + * @param string|Stringable $message the actual error message + * @param string $prefix Attach some block before $string. + * Will not be stripped even + * when strip is true + * if strip is false, recommended to add that to $string + * @param mixed[] $context + * @return bool True if logged, false if not logged + */ + public function debug( + string $group_id, + string|\Stringable $message, + string $prefix = '', + array $context = [] + ): bool { + return $this->writeErrorMsg( + $this->log_level, + $this->prepareLog( + Level::Debug->getName(), + $prefix . $message, + $context, + $group_id + ), + $group_id + ); + } + + /** + * INFO: 200 + * + * @param string|Stringable $message + * @param mixed[] $context + * @return bool + */ + public function info(string|\Stringable $message, array $context = []): bool + { + return $this->writeErrorMsg( + Level::Info, + $this->prepareLog( + Level::Info->getName(), + $message, + $context, + ) + ); + } + + /** + * NOTICE: 250 + * + * @param string|Stringable $message + * @param mixed[] $context + * @return bool + */ + public function notice(string|\Stringable $message, array $context = []): bool + { + return $this->writeErrorMsg( + Level::Notice, + $this->prepareLog( + Level::Notice->getName(), + $message, + $context, + ) + ); + } + + /** + * WARNING: 300 + * + * @param string|Stringable $message + * @param mixed[] $context + * @return bool + */ + public function warning(string|\Stringable $message, array $context = []): bool + { + return $this->writeErrorMsg( + Level::Warning, + $this->prepareLog( + Level::Warning->getName(), + $message, + $context, + ) + ); + } + + /** + * ERROR: 400 + * + * @param string|Stringable $message + * @param mixed[] $context + * @return bool + */ + public function error(string|\Stringable $message, array $context = []): bool + { + return $this->writeErrorMsg( + Level::Error, + $this->prepareLog( + Level::Error->getName(), + $message, + $context, + ) + ); + } + + /** + * CTRITICAL: 500 + * + * @param string|Stringable $message + * @param mixed[] $context + * @return bool + */ + public function critical(string|\Stringable $message, array $context = []): bool + { + return $this->writeErrorMsg( + Level::Critical, + $this->prepareLog( + Level::Critical->getName(), + $message, + $context, + ) + ); + } + + /** + * ALERT: 550 + * + * @param string|Stringable $message + * @param mixed[] $context + * @return bool + */ + public function alert(string|\Stringable $message, array $context = []): bool + { + return $this->writeErrorMsg( + Level::Alert, + $this->prepareLog( + Level::Alert->getName(), + $message, + $context, + ) + ); + } + + /** + * EMERGENCY: 600 + * + * @param string|Stringable $message + * @param mixed[] $context + * @return bool + */ + public function emergency(string|\Stringable $message, array $context = []): bool + { + return $this->writeErrorMsg( + Level::Emergency, + $this->prepareLog( + Level::Emergency->getName(), + $message, + $context, + ) + ); + } + + // ********************************************************************* + // DEPRECATED SUPPORT CALLS + // ********************************************************************* + + // legacy, but there are too many implemented + + /** + * A replacement for the \CoreLibs\Debug\Support::printAr + * But this does not wrap it in

+	 * Do not use this without using it in a string in debug function
+	 *
+	 * @param  array $a Array to format
+	 * @return string          print_r formated
+	 */
+	public function prAr(array $a): string
+	{
+		return Support::printArray($a, true);
+	}
+
+	/**
+	 * Convert bool value to string value
+	 *
+	 * @param  bool   $bool  Bool value to be transformed
+	 * @param  string $true  Override default string 'true'
+	 * @param  string $false Override default string 'false'
+	 * @return string        $true or $false string for true/false bool
+	 */
+	public function prBl(
+		bool $bool,
+		string $true = 'true',
+		string $false = 'false'
+	): string {
+		return Support::printBool($bool, '', $true, $false, true);
+	}
+
+	/**
+	 * Dump data as string without html
+	 *
+	 * @param  mixed  $data  Any data
+	 * @param  bool   $strip If false, do not strip, default is true
+	 * @return string        Output data for debug
+	 */
+	public function dV(mixed $data, bool $strip = true): string
+	{
+		return Support::dumpVar($data, $strip);
+	}
+
+	/**
+	 * Export var data to string
+	 *
+	 * @param  mixed  $data
+	 * @return string
+	 */
+	public function eV(mixed $data): string
+	{
+		return Support::exportVar($data, true);
+	}
+
+	// *********************************************************************
+	// DEPRECATED METHODS
+	// *********************************************************************
+
+	/**
+	 * Everything below here is deprecated and will be removed
+	 */
+
+	/**
+	 * Temporary method to read all class variables for testing purpose
+	 *
+	 * @param  string $name what variable to return
+	 * @return mixed        can be anything, bool, string, int, array
+	 * @deprecated Use either log->getOption or log->get[Content] to fetch info
+	 */
+	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
+	 * if non valid string is given it returns the previous set one only
+	 *
+	 * @param  string $string log file id string value
+	 * @return string        returns the set log file id string
+	 * @deprecated Use Debug\Logging->setLogId() and Debug\Logging->getLogId()
+	 */
+	public function basicSetLogId(string $string): string
+	{
+		$this->setLogFileId($string);
+		return $this->getLogFileId();
+	}
+
+	/**
+	 * 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
+	 * @deprecated Use setLogLevel
+	 */
+	public function debugFor(string $type, string $flag): bool
+	{
+		trigger_error(
+			'debugFor() is deprecated',
+			E_USER_DEPRECATED
+		);
+		return false;
+	}
+
+	/**
+	 * 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
+	 * @deprecated Log levels (group id) are no longer supported
+	 */
+	public function setLogLevelAll(string $type, bool $set): bool
+	{
+		trigger_error(
+			'setLogLevelAll() is deprecated',
+			E_USER_DEPRECATED
+		);
+		return false;
+	}
+
+	/**
+	 * get the current log level setting for All level blocks
+	 *
+	 * @param  string $type Type to get: debug, echo, print
+	 * @return bool         False on failure, or the boolean flag from the all var
+	 * @deprecated Log levels (group id) are no longer supported
+	 */
+	public function getLogLevelAll(string $type): bool
+	{
+		trigger_error(
+			'getLogLevelAll() is deprecated',
+			E_USER_DEPRECATED
+		);
+		return false;
+	}
+
+	/**
+	 * passes list of level names, to turn on debug
+	 * eg $foo->debugFor('print', 'on', ['LOG', 'DEBUG', 'INFO']);
+	 *
+	 * @param  string        $type     debug, echo, print
+	 * @param  string        $flag     on/off
+	 * @param  array  $debug_on Array of levels to turn on/off debug
+	 *                                 To turn off a level set 'Level' => false,
+	 *                                 If not set, switches to on
+	 * @return bool          Return false if type or flag invalid
+	 *                       also false if debug array is empty
+	 * @deprecated Log levels (group id) are no longer supported
+	 */
+	public function setLogLevel(string $type, string $flag, array $debug_on): bool
+	{
+		trigger_error(
+			'setLogLevel() is deprecated',
+			E_USER_DEPRECATED
+		);
+		return false;
+	}
+
+	/**
+	 * return the log level for the array type normal and not (disable)
+	 *
+	 * @param  string      $type  debug, echo, print
+	 * @param  string      $flag  on/off
+	 * @param  string|null $level if not null then check if this array entry is set
+	 *                            else return false
+	 * @return array|bool  if $level is null, return array, else boolean true/false
+	 * @deprecated Log levels (group id) are no longer supported
+	 */
+	public function getLogLevel(string $type, string $flag, ?string $level = null): array|bool
+	{
+		trigger_error(
+			'getLogLevel() is deprecated',
+			E_USER_DEPRECATED
+		);
+		return false;
+	}
+
+	/**
+	 * set flags for per log level type
+	 * - level: set per sub group level
+	 * - class: split by class
+	 * - page: split per page called
+	 * - run: for each run
+	 *
+	 * @param  string $type Type to get: level, class, page, run
+	 * @param  bool   $set  True or False
+	 * @return bool         Return false if type invalid
+	 * @deprecated Set flags with setLogFlag
+	 */
+	public function setLogPer(string $type, bool $set): bool
+	{
+		trigger_error(
+			'setLogPer() is deprecated',
+			E_USER_DEPRECATED
+		);
+		return false;
+	}
+
+	/**
+	 * return current set log per flag in bool
+	 *
+	 * @param  string $type Type to get: level, class, page, run
+	 * @return bool         True of false for turned on or off
+	 * @deprecated Get flags with setLogFlag
+	 */
+	public function getLogPer(string $type): bool
+	{
+		trigger_error(
+			'getLogPer() is deprecated',
+			E_USER_DEPRECATED
+		);
+		return false;
+	}
+
+	// *********************************************************************
+	// DEBUG METHODS
+	// *********************************************************************
+
+	/**
+	 * only for debug
+	 *
+	 * @return void
+	 */
+	public function logger2Debug(): void
+	{
+		print "Options: " . Support::dumpVar($this->options) . "
"; + print "OPT set level: " . $this->getLoggingLevel()->getName() . "
"; + $this->setLoggingLevel(Level::Info); + print "NEW set level: " . $this->getLoggingLevel()->getName() . "
"; + foreach ( + [ + Level::Debug, Level::Info, Level::Notice, Level::Warning, + Level::Error, Level::Critical, Level::Alert, Level::Emergency + ] as $l + ) { + if ($this->log_level->isHigherThan($l)) { + print "L: " . $this->log_level->getName() . " > " . $l->getName() . "
"; + } + if ($this->log_level->includes($l)) { + print "L: " . $this->log_level->getName() . " <= " . $l->getName() . "
"; + } + if ($this->log_level->isLowerThan($l)) { + print "L: " . $this->log_level->getName() . " < " . $l->getName() . "
"; + } + echo "
"; + } + // back to options level + $this->initLogLevel(); + print "OPT set level: " . $this->getLoggingLevel()->getName() . "
"; + } +} + +// __END__ diff --git a/src/Output/Form/Generate.php b/src/Output/Form/Generate.php index 90daccc..6e7e9df 100644 --- a/src/Output/Form/Generate.php +++ b/src/Output/Form/Generate.php @@ -219,96 +219,97 @@ declare(strict_types=1); namespace CoreLibs\Output\Form; use CoreLibs\Get\System; +use CoreLibs\Debug\Support; class Generate extends \CoreLibs\DB\Extended\ArrayIO { // for the load statetment describes which elements from // the load query should be shown and i which format /** @var array */ - public $field_array = []; + public array $field_array = []; /** @var string */ - public $load_query; // the query needed for loading a data set (one row in the table) + public string $load_query; // the query needed for loading a data set (one row in the table) /** @var string */ - public $col_name; // the name of the columen (before _) [used for order button] + public string $col_name; // the name of the columen (before _) [used for order button] /** @var int */ - public $yes; // the yes flag that triggers the template to show ALL and not only new/load + public int $yes; // the yes flag that triggers the template to show ALL and not only new/load /** @var string */ - public $msg; // the error msg + public string $msg; // the error msg /** @var int */ - public $error; // the error flag set for printing red error msg + public int $error; // the error flag set for printing red error msg /** @var int */ - public $warning; // warning flag, for information (saved, loaded, etc) + public int $warning; // warning flag, for information (saved, loaded, etc) /** @var string */ - public $archive_pk_name; // the pk name for the load select form + public string $archive_pk_name; // the pk name for the load select form /** @var string */ - private $int_pk_name; // primary key, only internal usage + private string $int_pk_name; // primary key, only internal usage /** @var array */ - public $reference_array = []; // reference arrays -> stored in $this->reference_array[$table_name] => []; + public array $reference_array = []; // reference arrays -> stored in $this->reference_array[$table_name] => []; // NOTE: should be changed to this @var mixed[] /** @var array */ - public $element_list; // element list for elements next to each other as a special sub group + public array $element_list; // element list for elements next to each other as a special sub group /** @var array */ - public $table_array = []; + public array $table_array = []; /** @var string */ - public $my_page_name; // the name of the page without .php extension + public string $my_page_name; // the name of the page without .php extension /** @var bool */ - public $mobile_phone = false; + public bool $mobile_phone = false; /** @var string */ - public $email_regex; + public string $email_regex; // buttons and checkboxes /** @var string */ - public $archive; + public string $archive; /** @var string */ - public $new; + public string $new; /** @var string */ - public $really_new; + public string $really_new; /** @var string */ - public $delete; + public string $delete; /** @var string */ - public $really_delete; + public string $really_delete; /** @var string */ - public $save; + public string $save; /** @var string */ - public $remove_button; + public string $remove_button; // security values /** @var int base acl for current page */ - private $base_acl_level = 0; + private int $base_acl_level = 0; /** @var int admin master flag (1/0) */ - private $acl_admin = 0; + private int $acl_admin = 0; /** @var array */ - public $security_level; + public array $security_level; /** @var array Login ACL */ - public $login_acl = []; + public array $login_acl = []; // layout publics /** @var int */ - public $table_width; + public int $table_width; // internal lang & encoding vars /** @var string */ - public $lang_dir = ''; + public string $lang_dir = ''; /** @var string */ - public $lang; + public string $lang; /** @var string */ - public $lang_short; + public string $lang_short; /** @var string */ - public $domain; + public string $domain; /** @var string */ - public $encoding; + public string $encoding; // language /** @var \CoreLibs\Language\L10n */ - public $l; + public \CoreLibs\Language\L10n $l; // log - /** @var \CoreLibs\Debug\Logging */ - public $log; + /** @var \CoreLibs\Logging\Logging */ + public \CoreLibs\Logging\Logging $log; // now some default error msgs (english) /** @var array */ - public $language_array = []; + public array $language_array = []; /** * construct form generator * * @param array $db_config db config array, mandatory - * @param \CoreLibs\Debug\Logging $log Logging class + * @param \CoreLibs\Logging\Logging $log Logging class * @param \CoreLibs\Language\L10n $l10n l10n language class * @param array $login_acl Login ACL array, * at least base/admin should be set @@ -319,7 +320,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO */ public function __construct( array $db_config, - \CoreLibs\Debug\Logging $log, + \CoreLibs\Logging\Logging $log, \CoreLibs\Language\L10n $l10n, array $login_acl, ?array $table_arrays = null, @@ -327,7 +328,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO // init logger if not set $this->log = $log; // don't log per class - $this->log->setLogPer('class', false); + $this->log->unsetLogFlag(\CoreLibs\Logging\Logger\Flag::per_class); // init the language class $this->l = $l10n; // parse and read, legacy stuff @@ -388,7 +389,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO $this->load_query = $config_array['load_query']; } if (empty($this->load_query)) { - $this->log->debug('INIT ERROR', 'Missing Load Query for: ' . $this->my_page_name); + $this->log->error('Missing Load Query for: ' . $this->my_page_name); } $this->archive_pk_name = 'a_' . $this->pk_name; $this->col_name = str_replace('_id', '', $this->pk_name); @@ -485,7 +486,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO /** @var TableArrays\Interface\TableArraysInterface|false $class */ $class = new $class_string($this); } catch (\Throwable $t) { - $this->log->debug('CLASS LOAD', 'Failed loading: ' . $class_string . ' => ' . $t->getMessage()); + $this->log->critical('CLASS LOADING: Failed loading: ' . $class_string . ' => ' . $t->getMessage()); return false; } if (is_object($class)) { @@ -827,7 +828,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO return $return_array; } if (empty($this->load_query)) { - $this->log->debug('LOAD LIST ERROR', 'Missing load list query'); + $this->log->error('Missing load list query'); return $return_array; } @@ -2617,8 +2618,8 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO } } // add lost error ones - $this->log->debug('ERROR', 'P: ' . $data['prefix'] . ', ' - . $this->log->prAr($_POST['ERROR'][$data['prefix']] ?? [])); + $this->log->error('P: ' . $data['prefix'] . ', ' + . Support::prAr($_POST['ERROR'][$data['prefix']] ?? [])); if ($this->error && !empty($_POST['ERROR'][$data['prefix']])) { $prfx = $data['prefix']; // short $_post_data = []; diff --git a/src/Output/Form/TableArrays/EditAccess.php b/src/Output/Form/TableArrays/EditAccess.php index 3701e54..53cad37 100644 --- a/src/Output/Form/TableArrays/EditAccess.php +++ b/src/Output/Form/TableArrays/EditAccess.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditAccess implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/Form/TableArrays/EditGroups.php b/src/Output/Form/TableArrays/EditGroups.php index 0ff66eb..9ad6413 100644 --- a/src/Output/Form/TableArrays/EditGroups.php +++ b/src/Output/Form/TableArrays/EditGroups.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditGroups implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/Form/TableArrays/EditLanguages.php b/src/Output/Form/TableArrays/EditLanguages.php index b2a3ba9..0c4b1e0 100644 --- a/src/Output/Form/TableArrays/EditLanguages.php +++ b/src/Output/Form/TableArrays/EditLanguages.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditLanguages implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/Form/TableArrays/EditMenuGroup.php b/src/Output/Form/TableArrays/EditMenuGroup.php index 48826bb..e8945be 100644 --- a/src/Output/Form/TableArrays/EditMenuGroup.php +++ b/src/Output/Form/TableArrays/EditMenuGroup.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditMenuGroup implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/Form/TableArrays/EditPages.php b/src/Output/Form/TableArrays/EditPages.php index 6ecd26e..1ac9039 100644 --- a/src/Output/Form/TableArrays/EditPages.php +++ b/src/Output/Form/TableArrays/EditPages.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditPages implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/Form/TableArrays/EditSchemas.php b/src/Output/Form/TableArrays/EditSchemas.php index 8417ac1..c81a0d1 100644 --- a/src/Output/Form/TableArrays/EditSchemas.php +++ b/src/Output/Form/TableArrays/EditSchemas.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditSchemas implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/Form/TableArrays/EditUsers.php b/src/Output/Form/TableArrays/EditUsers.php index a85cb0e..6d87753 100644 --- a/src/Output/Form/TableArrays/EditUsers.php +++ b/src/Output/Form/TableArrays/EditUsers.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditUsers implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/Form/TableArrays/EditVisibleGroup.php b/src/Output/Form/TableArrays/EditVisibleGroup.php index 98a2f22..91da1ca 100644 --- a/src/Output/Form/TableArrays/EditVisibleGroup.php +++ b/src/Output/Form/TableArrays/EditVisibleGroup.php @@ -7,7 +7,7 @@ namespace CoreLibs\Output\Form\TableArrays; class EditVisibleGroup implements Interface\TableArraysInterface { /** @var \CoreLibs\Output\Form\Generate */ - private $form; + private \CoreLibs\Output\Form\Generate $form; /** * constructor diff --git a/src/Output/ProgressBar.php b/src/Output/ProgressBar.php index 03c09ef..6affd99 100644 --- a/src/Output/ProgressBar.php +++ b/src/Output/ProgressBar.php @@ -23,13 +23,13 @@ class ProgressBar // private vars /** @var string */ - public $code; // unique code + public string $code; // unique code /** @var string */ - public $status = 'new'; // current status (new,show,hide) + public string $status = 'new'; // current status (new,show,hide) /** @var float|int */ - public $step = 0; // current step + public float|int $step = 0; // current step /** @var array */ - public $position = [ // current bar position + public array $position = [ // current bar position 'left' => null, 'top' => null, 'width' => null, @@ -37,43 +37,43 @@ class ProgressBar ]; /** @var int */ - public $clear_buffer_size = 1; // we need to send this before the lfush to get browser output + public int $clear_buffer_size = 1; // we need to send this before the lfush to get browser output /** @var int */ - public $clear_buffer_size_init = 1024 * 1024; // if I don't send that junk, it won't send anything + public int $clear_buffer_size_init = 1024 * 1024; // if I don't send that junk, it won't send anything // public vars /** @var int */ - public $min = 0; // minimal steps + public int $min = 0; // minimal steps /** @var int */ - public $max = 100; // maximal steps + public int $max = 100; // maximal steps /** @var int */ - public $left = 5; // bar position from left + public int $left = 5; // bar position from left /** @var int */ - public $top = 5; // bar position from top + public int $top = 5; // bar position from top /** @var int */ - public $width = 300; // bar width + public int $width = 300; // bar width /** @var int */ - public $height = 25; // bar height + public int $height = 25; // bar height /** @var int */ - public $pedding = 0; // bar pedding + public int $pedding = 0; // bar pedding /** @var string */ - public $color = '#0033ff'; // bar color + public string $color = '#0033ff'; // bar color /** @var string */ - public $bgr_color = '#c0c0c0'; // bar background color + public string $bgr_color = '#c0c0c0'; // bar background color /** @var string */ - public $bgr_color_master = '#ffffff'; // master div background color + public string $bgr_color_master = '#ffffff'; // master div background color /** @var int */ - public $border = 1; // bar border width + public int $border = 1; // bar border width /** @var string */ - public $brd_color = '#000000'; // bar border color + public string $brd_color = '#000000'; // bar border color /** @var string */ - public $direction = 'right'; // direction of motion (right,left,up,down) + public string $direction = 'right'; // direction of motion (right,left,up,down) /** @var array */ - public $frame = ['show' => false]; // ProgressBar Frame + public array $frame = ['show' => false]; // ProgressBar Frame /* 'show' => false, # frame show (true/false) 'left' => 200, # frame position from left 'top' => 100, # frame position from top @@ -86,7 +86,7 @@ class ProgressBar /** @#var array{string}{string: string|int} */ /** @var mixed[][] */ - public $label = []; // ProgressBar Labels + public array $label = []; // ProgressBar Labels /* 'name' => [ # label name 'type' => 'text', # label type (text,button,step,percent,crossbar) 'value' => 'Please wait ...', # label value @@ -105,7 +105,7 @@ class ProgressBar /** @var string */ // output strings - public $prefix_message = ''; + public string $prefix_message = ''; /** * progress bar constructor diff --git a/src/Security/SymmetricEncryption.php b/src/Security/SymmetricEncryption.php index cd99f58..b106cea 100644 --- a/src/Security/SymmetricEncryption.php +++ b/src/Security/SymmetricEncryption.php @@ -2,7 +2,9 @@ /** * very simple symmetric encryption - * Better use: https://paragonie.com/project/halite + * Better use: + * https://paragonie.com/project/halite + * https://github.com/paragonie/halite * * current code is just to encrypt and decrypt * diff --git a/src/Template/SmartyExtend.php b/src/Template/SmartyExtend.php index 9b2d916..3d926b1 100644 --- a/src/Template/SmartyExtend.php +++ b/src/Template/SmartyExtend.php @@ -24,134 +24,132 @@ class SmartyExtend extends \Smarty { // internal translation engine /** @var \CoreLibs\Language\L10n */ - public $l10n; + public \CoreLibs\Language\L10n $l10n; // lang & encoding /** @var string */ - public $lang_dir = ''; + public string $lang_dir = ''; /** @var string */ - public $lang; + public string $lang; /** @var string */ - public $locale_set; + public string $lang_short; /** @var string */ - public $lang_short; + public string $domain; /** @var string */ - public $domain; - /** @var string */ - public $encoding; + public string $encoding; // page name /** @var string */ - public $page_name; + public string $page_name; // array for data parsing /** @var array */ - public $HEADER = []; + public array $HEADER = []; /** @var array */ - public $DATA = []; + public array $DATA = []; /** @var array */ - public $DEBUG_DATA = []; + public array $DEBUG_DATA = []; /** @var array */ - private $CONTENT_DATA = []; + private array $CONTENT_DATA = []; // control vars /** @var bool */ - public $USE_PROTOTYPE = USE_PROTOTYPE; + public bool $USE_PROTOTYPE = USE_PROTOTYPE; /** @var bool */ - public $USE_JQUERY = USE_JQUERY; + public bool $USE_JQUERY = USE_JQUERY; /** @var bool */ - public $USE_SCRIPTACULOUS = USE_SCRIPTACULOUS; + public bool $USE_SCRIPTACULOUS = USE_SCRIPTACULOUS; // sub content input vars /** @var bool */ - public $USE_TINY_MCE = false; + public bool $USE_TINY_MCE = false; /** @var bool */ - public $JS_DATEPICKR = false; + public bool $JS_DATEPICKR = false; /** @var bool */ - public $JS_FLATPICKR = false; + public bool $JS_FLATPICKR = false; /** @var bool */ - public $JS_FILE_UPLOADER = false; + public bool $JS_FILE_UPLOADER = false; /** @var bool */ - public $DEBUG_TMPL = false; + public bool $DEBUG_TMPL = false; /** @var bool */ - public $USE_INCLUDE_TEMPLATE = false; + public bool $USE_INCLUDE_TEMPLATE = false; // cache & compile /** @var string */ - public $CACHE_ID = ''; + public string $CACHE_ID = ''; /** @var string */ - public $COMPILE_ID = ''; + public string $COMPILE_ID = ''; // template vars /** @var string */ - public $MASTER_TEMPLATE_NAME; + public string $MASTER_TEMPLATE_NAME; /** @var string */ - public $PAGE_FILE_NAME; + public string $PAGE_FILE_NAME; /** @var string */ - public $CONTENT_INCLUDE; + public string $CONTENT_INCLUDE; /** @var string */ - public $FORM_NAME; + public string $FORM_NAME; /** @var string */ - public $FORM_ACTION; + public string $FORM_ACTION; /** @var string */ - public $L_TITLE; + public string $L_TITLE; /** @var string|int */ - public $PAGE_WIDTH; + public string|int $PAGE_WIDTH; // smarty include/set var /** @var string */ - public $TEMPLATE_PATH; + public string $TEMPLATE_PATH; /** @var string */ - public $TEMPLATE_NAME; + public string $TEMPLATE_NAME; /** @var string */ - public $INC_TEMPLATE_NAME; + public string $INC_TEMPLATE_NAME; /** @var string */ - public $JS_TEMPLATE_NAME; + public string $JS_TEMPLATE_NAME; /** @var string */ - public $CSS_TEMPLATE_NAME; + public string $CSS_TEMPLATE_NAME; /** @var string|null */ - public $TEMPLATE_TRANSLATE; + public string|null $TEMPLATE_TRANSLATE; /** @var string|null */ - public $JS_TRANSLATE; + public string|null $JS_TRANSLATE; // core group /** @var string */ - public $JS_CORE_TEMPLATE_NAME; + public string $JS_CORE_TEMPLATE_NAME; /** @var string */ - public $CSS_CORE_TEMPLATE_NAME; + public string $CSS_CORE_TEMPLATE_NAME; /** @var string */ - public $JS_CORE_INCLUDE; + public string $JS_CORE_INCLUDE; /** @var string */ - public $CSS_CORE_INCLUDE; + public string $CSS_CORE_INCLUDE; // local names /** @var string */ - public $JS_SPECIAL_TEMPLATE_NAME = ''; + public string $JS_SPECIAL_TEMPLATE_NAME = ''; /** @var string */ - public $CSS_SPECIAL_TEMPLATE_NAME = ''; + public string $CSS_SPECIAL_TEMPLATE_NAME = ''; /** @var string */ - public $JS_INCLUDE; + public string $JS_INCLUDE; /** @var string */ - public $CSS_INCLUDE; + public string $CSS_INCLUDE; /** @var string */ - public $JS_SPECIAL_INCLUDE; + public string $JS_SPECIAL_INCLUDE; /** @var string */ - public $CSS_SPECIAL_INCLUDE; + public string $CSS_SPECIAL_INCLUDE; /** @var string */ - public $ADMIN_JAVASCRIPT; + public string $ADMIN_JAVASCRIPT; /** @var string */ - public $ADMIN_STYLESHEET; + public string $ADMIN_STYLESHEET; /** @var string */ - public $FRONTEND_JAVASCRIPT; + public string $FRONTEND_JAVASCRIPT; /** @var string */ - public $FRONTEND_STYLESHEET; + public string $FRONTEND_STYLESHEET; // other smarty folder vars /** @var string */ - public $INCLUDES; + public string $INCLUDES; /** @var string */ - public $JAVASCRIPT; + public string $JAVASCRIPT; /** @var string */ - public $CSS; + public string $CSS; /** @var string */ - public $FONT; + public string $FONT; /** @var string */ - public $PICTURES; + public string $PICTURES; /** @var string */ - public $CACHE_PICTURES; + public string $CACHE_PICTURES; /** @var string */ - public $CACHE_PICTURES_ROOT; + public string $CACHE_PICTURES_ROOT; // constructor class, just sets the language stuff /** @@ -222,6 +220,7 @@ class SmartyExtend extends \Smarty // core CS $this->CSS_CORE_INCLUDE = ''; if ( + !empty($this->CSS_CORE_TEMPLATE_NAME) && file_exists($this->CSS . $this->CSS_CORE_TEMPLATE_NAME) && is_file($this->CSS . $this->CSS_CORE_TEMPLATE_NAME) ) { @@ -230,6 +229,7 @@ class SmartyExtend extends \Smarty // core JS $this->JS_CORE_INCLUDE = ''; if ( + !empty($this->JS_CORE_TEMPLATE_NAME) && file_exists($this->JAVASCRIPT . $this->JS_CORE_TEMPLATE_NAME) && is_file($this->JAVASCRIPT . $this->JS_CORE_TEMPLATE_NAME) ) { @@ -398,7 +398,7 @@ class SmartyExtend extends \Smarty // javascript translate data as template for auto translate if (empty($this->TEMPLATE_TRANSLATE)) { $this->TEMPLATE_TRANSLATE = 'jsTranslate-' - . $this->locale_set . '.' . $this->encoding + . $this->l10n->getLocaleSet() . '.' . $this->encoding . '.tpl'; } else { // we assume we have some fixed set @@ -408,12 +408,12 @@ class SmartyExtend extends \Smarty if (strpos($this->TEMPLATE_TRANSLATE, '.tpl')) { $this->TEMPLATE_TRANSLATE = str_replace( '.tpl', - '-' . $this->locale_set . '.' . $this->encoding . '.tpl', + '-' . $this->l10n->getLocaleSet() . '.' . $this->encoding . '.tpl', $this->TEMPLATE_TRANSLATE ); } else { $this->TEMPLATE_TRANSLATE .= '-' - . $this->locale_set . '.' . $this->encoding + . $this->l10n->getLocaleSet() . '.' . $this->encoding . '.tpl'; } } @@ -423,7 +423,7 @@ class SmartyExtend extends \Smarty } if (empty($this->JS_TRANSLATE)) { $this->JS_TRANSLATE = 'translate-' - . $this->locale_set . '.' . $this->encoding . '.js'; + . $this->l10n->getLocaleSet() . '.' . $this->encoding . '.js'; } else { // we assume we have some fixed set // we must add _. @@ -432,12 +432,12 @@ class SmartyExtend extends \Smarty if (strpos($this->JS_TRANSLATE, '.js')) { $this->JS_TRANSLATE = str_replace( '.js', - '-' . $this->locale_set . '.' . $this->encoding . '.js', + '-' . $this->l10n->getLocaleSet() . '.' . $this->encoding . '.js', $this->JS_TRANSLATE ); } else { $this->JS_TRANSLATE .= '-' - . $this->locale_set . '.' . $this->encoding + . $this->l10n->getLocaleSet() . '.' . $this->encoding . '.js'; } } @@ -675,10 +675,12 @@ class SmartyExtend extends \Smarty $this->HEADER['DEFAULT_ENCODING'] = $set_default_encoding; // form name - $this->DATA['FORM_NAME'] = !$this->FORM_NAME ? + $this->DATA['FORM_NAME'] = empty($this->FORM_NAME) ? str_replace('.php', '', $this->page_name) : $this->FORM_NAME; - $this->DATA['FORM_ACTION'] = $this->FORM_ACTION; + $this->DATA['FORM_ACTION'] = empty($this->FORM_ACTION) ? + '' : + $this->FORM_ACTION; // special for admin if ($admin_call === true) { // depreacte call globals cms on null 4mcs @@ -735,7 +737,7 @@ class SmartyExtend extends \Smarty } // html title // set local page title - $this->HEADER['HTML_TITLE'] = !$this->L_TITLE ? + $this->HEADER['HTML_TITLE'] = empty($this->L_TITLE) ? ucfirst(str_replace('_', ' ', \CoreLibs\Get\System::getPageName(1))) . (!empty($set_g_title) ? '-' . $this->l10n->__($set_g_title) : '') : $this->l10n->__($this->L_TITLE); diff --git a/test/phpunit/ACL/CoreLibsACLLoginTest.php b/test/phpunit/ACL/CoreLibsACLLoginTest.php index 5ca8925..60958dc 100644 --- a/test/phpunit/ACL/CoreLibsACLLoginTest.php +++ b/test/phpunit/ACL/CoreLibsACLLoginTest.php @@ -68,13 +68,10 @@ final class CoreLibsACLLoginTest extends TestCase // logger is always needed // define basic connection set valid and one invalid - self::$log = new \CoreLibs\Debug\Logging([ + self::$log = new \CoreLibs\Logging\Logging([ // 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp', - 'file_id' => 'CoreLibs-ACL-Login-Test', - 'debug_all' => true, - 'echo_all' => false, - 'print_all' => true, + 'log_file_id' => 'CoreLibs-ACL-Login-Test', ]); // test database we need to connect do, if not possible this test is skipped self::$db = new \CoreLibs\DB\IO( diff --git a/test/phpunit/Create/CoreLibsCreateEmailTest.php b/test/phpunit/Create/CoreLibsCreateEmailTest.php index c030100..3d170be 100644 --- a/test/phpunit/Create/CoreLibsCreateEmailTest.php +++ b/test/phpunit/Create/CoreLibsCreateEmailTest.php @@ -22,12 +22,9 @@ final class CoreLibsCreateEmailTest extends TestCase */ public static function setUpBeforeClass(): void { - self::$log = new \CoreLibs\Debug\Logging([ + self::$log = new \CoreLibs\Logging\Logging([ 'log_folder' => DIRECTORY_SEPARATOR . 'tmp', - 'file_id' => 'CoreLibs-Create-Email-Test', - 'debug_all' => true, - 'echo_all' => false, - 'print_all' => true, + 'log_file_id' => 'CoreLibs-Create-Email-Test', ]); } @@ -624,7 +621,7 @@ final class CoreLibsCreateEmailTest extends TestCase // force new set for each run self::$log->setLogUniqueId(true); // set on of unique log id - self::$log->setLogPer('run', true); + self::$log->setLogFlag(\CoreLibs\Logging\Logger\Flag::per_run); // init logger $status = \CoreLibs\Create\Email::sendEmail( $subject, @@ -646,7 +643,9 @@ final class CoreLibsCreateEmailTest extends TestCase // assert content: must load JSON from log file if ($status == 2) { // open file, get last entry with 'SEND EMAIL JSON' key - $file = file_get_contents(self::$log->getLogFileName()); + $file = file_get_contents( + self::$log->getLogFolder() . self::$log->getLogFile() + ); if ($file !== false) { // extract SEND EMAIL JSON line $found = preg_match_all("/^.* - (.*)$/m", $file, $matches); diff --git a/test/phpunit/Create/CoreLibsCreateUidsTest.php b/test/phpunit/Create/CoreLibsCreateUidsTest.php index a914cb9..3612ee8 100644 --- a/test/phpunit/Create/CoreLibsCreateUidsTest.php +++ b/test/phpunit/Create/CoreLibsCreateUidsTest.php @@ -21,45 +21,83 @@ final class CoreLibsCreateUidsTest extends TestCase public function uniqIdProvider(): array { return [ + // number length + 'too short' => [ + 0 => 1, + 1 => 4, + 2 => null + ], + 'valid length: 10' => [ + 0 => 10, + 1 => 10, + 2 => null + ], + 'valid length: 9, auto length' => [ + 0 => 9, + 1 => 8, + 2 => null + ], + 'valid length: 9, force length' => [ + 0 => 9, + 1 => 9, + 2 => true, + ], + 'very long: 512' => [ + 0 => 512, + 1 => 512, + 2 => null + ], + // below is all legacy 'md5 hash' => [ 0 => 'md5', 1 => 32, + 2 => null ], 'sha256 hash' => [ 0 => 'sha256', - 1 => 64 + 1 => 64, + 2 => null ], 'ripemd160 hash' => [ 0 => 'ripemd160', - 1 => 40 + 1 => 40, + 2 => null ], 'adler32 hash' => [ 0 => 'adler32', - 1 => 8 + 1 => 8, + 2 => null ], - 'not in list hash but valid' => [ + 'not in list, set default length' => [ 0 => 'sha3-512', - 1 => strlen(hash('sha3-512', 'A')) + 1 => 64, + 2 => null ], 'default hash not set' => [ 0 => null, 1 => 64, + 2 => null ], 'invalid name' => [ 0 => 'iamnotavalidhash', 1 => 64, + 2 => null ], - 'auto: ' . \CoreLibs\Create\Uids::DEFAULT_HASH => [ - 0 => \CoreLibs\Create\Uids::DEFAULT_HASH, - 1 => strlen(hash(\CoreLibs\Create\Uids::DEFAULT_HASH, 'A')) + // auto calls + 'auto: ' . \CoreLibs\Create\Uids::DEFAULT_UNNIQ_ID_LENGTH => [ + 0 => \CoreLibs\Create\Uids::DEFAULT_UNNIQ_ID_LENGTH, + 1 => 64, + 2 => null ], 'auto: ' . \CoreLibs\Create\Uids::STANDARD_HASH_LONG => [ 0 => \CoreLibs\Create\Uids::STANDARD_HASH_LONG, - 1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_LONG, 'A')) + 1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_LONG, 'A')), + 2 => null ], 'auto: ' . \CoreLibs\Create\Uids::STANDARD_HASH_SHORT => [ 0 => \CoreLibs\Create\Uids::STANDARD_HASH_SHORT, - 1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_SHORT, 'A')) + 1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_SHORT, 'A')), + 2 => null ], ]; } @@ -105,25 +143,26 @@ final class CoreLibsCreateUidsTest extends TestCase * * @covers ::uniqId * @dataProvider uniqIdProvider - * @testdox uniqId $input will be length $expected [$_dataName] + * @testdox uniqId $input will be length $expected (Force $flag) [$_dataName] * - * @param string|null $input + * @param int|string|null $input * @param string $expected + * @param bool|null $flag * @return void */ - public function testUniqId(?string $input, int $expected): void + public function testUniqId(int|string|null $input, int $expected, ?bool $flag): void { if ($input === null) { - $this->assertEquals( - $expected, - strlen(\CoreLibs\Create\Uids::uniqId()) - ); + $uniq_id_length = strlen(\CoreLibs\Create\Uids::uniqId()); + } elseif ($flag === null) { + $uniq_id_length = strlen(\CoreLibs\Create\Uids::uniqId($input)); } else { - $this->assertEquals( - $expected, - strlen(\CoreLibs\Create\Uids::uniqId($input)) - ); + $uniq_id_length = strlen(\CoreLibs\Create\Uids::uniqId($input, $flag)); } + $this->assertEquals( + $expected, + $uniq_id_length + ); } /** diff --git a/test/phpunit/DB/CoreLibsDBIOTest.php b/test/phpunit/DB/CoreLibsDBIOTest.php index 20e90fd..b60d454 100644 --- a/test/phpunit/DB/CoreLibsDBIOTest.php +++ b/test/phpunit/DB/CoreLibsDBIOTest.php @@ -132,13 +132,10 @@ final class CoreLibsDBIOTest extends TestCase ); } // define basic connection set valid and one invalid - self::$log = new \CoreLibs\Debug\Logging([ + self::$log = new \CoreLibs\Logging\Logging([ // 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp', - 'file_id' => 'CoreLibs-DB-IO-Test', - 'debug_all' => false, - 'echo_all' => false, - 'print_all' => false, + 'log_file_id' => 'CoreLibs-DB-IO-Test', ]); $db = new \CoreLibs\DB\IO( self::$db_config['valid'], diff --git a/test/phpunit/Debug/CoreLibsDebugLoggingTest.php b/test/phpunit/Debug/CoreLibsDebugLoggingLegacyTest.php similarity index 96% rename from test/phpunit/Debug/CoreLibsDebugLoggingTest.php rename to test/phpunit/Debug/CoreLibsDebugLoggingLegacyTest.php index 6b7daad..b06c86b 100644 --- a/test/phpunit/Debug/CoreLibsDebugLoggingTest.php +++ b/test/phpunit/Debug/CoreLibsDebugLoggingLegacyTest.php @@ -10,12 +10,13 @@ use PHPUnit\Framework\TestCase; /** * Test class for Debug\Logging - * @coversDefaultClass \CoreLibs\Debug\Logging - * @testdox \CoreLibs\Debug\Logging method tests + * @coversDefaultClass \CoreLibs\Debug\LoggingLegacy + * @testdox \CoreLibs\Debug\LoggingLegacy method tests */ -final class CoreLibsDebugLoggingTest extends TestCase +final class CoreLibsDebugLoggingLegacyTest extends TestCase { private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR; + /** * test set for options BASIC * @@ -24,7 +25,7 @@ final class CoreLibsDebugLoggingTest extends TestCase * 1: expected * 2: override * override: - * - constant for COSNTANTS + * - constant for CONSTANTS * - global for _GLOBALS * * @return array @@ -138,7 +139,7 @@ final class CoreLibsDebugLoggingTest extends TestCase // catch this with the message $this->expectExceptionMessage($deprecation_message); } - $log = new \CoreLibs\Debug\Logging($options); + $log = new \CoreLibs\Debug\LoggingLegacy($options); // reset error handler restore_error_handler(); // check that settings match @@ -308,7 +309,7 @@ final class CoreLibsDebugLoggingTest extends TestCase // catch this with the message $this->expectExceptionMessage($deprecation_message); } - $log = new \CoreLibs\Debug\Logging($options); + $log = new \CoreLibs\Debug\LoggingLegacy($options); // reset error handler restore_error_handler(); // check current @@ -385,7 +386,7 @@ final class CoreLibsDebugLoggingTest extends TestCase bool $expected_get ): void { // neutral start with default - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testSetGetLogLevelAll', 'log_folder' => self::LOG_FOLDER ]); @@ -510,7 +511,7 @@ final class CoreLibsDebugLoggingTest extends TestCase $expected_get ): void { // neutral start with default - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testSetGetLogLevel', 'log_folder' => self::LOG_FOLDER ]); @@ -592,7 +593,7 @@ final class CoreLibsDebugLoggingTest extends TestCase bool $expected_get ): void { // neutral start with default - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testSetGetLogPer', 'log_folder' => self::LOG_FOLDER ]); @@ -624,7 +625,7 @@ final class CoreLibsDebugLoggingTest extends TestCase public function testSetGetLogPrintFileDate(bool $input, bool $expected_set, bool $expected_get): void { // neutral start with default - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testSetGetLogPrintFileDate', 'log_folder' => self::LOG_FOLDER ]); @@ -693,7 +694,7 @@ final class CoreLibsDebugLoggingTest extends TestCase */ public function testPrAr(array $input, string $expected): void { - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testPrAr', 'log_folder' => self::LOG_FOLDER ]); @@ -757,7 +758,7 @@ final class CoreLibsDebugLoggingTest extends TestCase */ public function testPrBl(bool $input, ?string $true, ?string $false, string $expected): void { - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testPrBl', 'log_folder' => self::LOG_FOLDER ]); @@ -932,7 +933,7 @@ final class CoreLibsDebugLoggingTest extends TestCase // remove any files named /tmp/error_log_TestDebug*.log array_map('unlink', glob($options['log_folder'] . 'error_msg_' . $options['file_id'] . '*.log')); // init logger - $log = new \CoreLibs\Debug\Logging($options); + $log = new \CoreLibs\Debug\LoggingLegacy($options); // * debug (A/B) // NULL check for strip/prefix $this->assertEquals( @@ -1046,13 +1047,13 @@ final class CoreLibsDebugLoggingTest extends TestCase public function testLogUniqueId(bool $option, bool $override): void { if ($option === true) { - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testLogUniqueId', 'log_folder' => self::LOG_FOLDER, 'per_run' => $option ]); } else { - $log = new \CoreLibs\Debug\Logging([ + $log = new \CoreLibs\Debug\LoggingLegacy([ 'file_id' => 'testLogUniqueId', 'log_folder' => self::LOG_FOLDER ]); diff --git a/test/phpunit/Debug/CoreLibsDebugSupportTest.php b/test/phpunit/Debug/CoreLibsDebugSupportTest.php index e5bc52a..f846323 100644 --- a/test/phpunit/Debug/CoreLibsDebugSupportTest.php +++ b/test/phpunit/Debug/CoreLibsDebugSupportTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace tests; use PHPUnit\Framework\TestCase; +use CoreLibs\Debug\Support; /** * Test class for Debug\Support @@ -40,6 +41,32 @@ final class CoreLibsDebugSupportTest extends TestCase ]; } + /** + * Undocumented function + * + * @cover ::printTime + * @dataProvider printTimeProvider + * @testdox printTime test with $microtime and match to regex [$_dataName] + * + * @param int|null $mircrotime + * @param string $expected + * @return void + */ + public function testPrintTime(?int $microtime, string $regex): void + { + if ($microtime === null) { + $this->assertMatchesRegularExpression( + $regex, + Support::printTime() + ); + } else { + $this->assertMatchesRegularExpression( + $regex, + Support::printTime($microtime) + ); + } + } + /** * Undocumented function * @@ -50,18 +77,55 @@ final class CoreLibsDebugSupportTest extends TestCase return [ 'empty array' => [ 0 => [], - 1 => "
Array\n(\n)\n
" + 1 => "
Array\n(\n)\n
", + 2 => "Array\n(\n)\n", ], 'simple array' => [ 0 => ['a', 'b'], 1 => "
Array\n(\n"
 					. "    [0] => a\n"
 					. "    [1] => b\n"
-					. ")\n
" + . ")\n
", + 2 => "Array\n(\n" + . " [0] => a\n" + . " [1] => b\n" + . ")\n", ], ]; } + /** + * Undocumented function + * + * @cover ::printAr + * @cover ::printArray + * @dataProvider printArrayProvider + * @testdox printAr/printArray $input will be $expected [$_dataName] + * + * @param array $input + * @param string $expected + * @param string $expected_strip + * @return void + */ + public function testPrintAr(array $input, string $expected, string $expected_strip): void + { + $this->assertEquals( + $expected, + Support::printAr($input), + 'assert printAr' + ); + $this->assertEquals( + $expected, + Support::printArray($input), + 'assert printArray' + ); + $this->assertEquals( + $expected_strip, + Support::prAr($input), + 'assert prAr' + ); + } + /** * Undocumented function * @@ -73,27 +137,31 @@ final class CoreLibsDebugSupportTest extends TestCase 'true input default' => [ 0 => true, 1 => [], - 2 => 'true' + 2 => 'true', + 3 => 'true', ], 'false input default' => [ 0 => false, 1 => [], - 2 => 'false' + 2 => 'false', + 3 => 'false' ], 'false input param name' => [ 0 => false, 1 => [ 'name' => 'param test' ], - 2 => 'param test: false' + 2 => 'param test: false', + 3 => 'false' ], 'true input param name, true override' => [ 0 => true, 1 => [ 'name' => 'param test', - 'true' => 'ok' + 'true' => 'ok', ], - 2 => 'param test: ok' + 2 => 'param test: ok', + 3 => 'ok', ], 'false input param name, true override, false override' => [ 0 => false, @@ -102,11 +170,77 @@ final class CoreLibsDebugSupportTest extends TestCase 'true' => 'ok', 'false' => 'not', ], - 2 => 'param test: not' + 2 => 'param test: not', + 3 => 'not' ], ]; } + /** + * Undocumented function + * + * @cover ::printBool + * @dataProvider printBoolProvider + * @testdox printBool $input will be $expected [$_dataName] + * + * @param bool $input + * @param array $params + * @param string $expected + * @param string $expected_strip + * @return void + */ + public function testPrintBool(bool $input, array $params, string $expected, string $expected_strip): void + { + if ( + isset($params['name']) && + isset($params['true']) && + isset($params['false']) + ) { + $string = Support::printBool( + $input, + $params['name'], + $params['true'], + $params['false'] + ); + $string_strip = Support::prBl( + $input, + $params['true'], + $params['false'] + ); + } elseif (isset($params['name']) && isset($params['true'])) { + $string = Support::printBool( + $input, + $params['name'], + $params['true'] + ); + $string_strip = Support::prBl( + $input, + $params['true'], + ); + } elseif (isset($params['name'])) { + $string = Support::printBool( + $input, + $params['name'] + ); + $string_strip = Support::prBl( + $input + ); + } else { + $string = Support::printBool($input); + $string_strip = Support::prBl($input); + } + $this->assertEquals( + $expected, + $string, + 'assert printBool' + ); + $this->assertEquals( + $expected_strip, + $string_strip, + 'assert prBl' + ); + } + /** * Undocumented function * @@ -169,12 +303,10 @@ final class CoreLibsDebugSupportTest extends TestCase 'an array, no html' => [ ['a', 'b'], true, - "##HTMLPRE##" - . "Array\n(\n" + "Array\n(\n" . " [0] => a\n" . " [1] => b\n" - . ")\n" - . "##/HTMLPRE##", + . ")\n", ], // resource 'a resource' => [ @@ -191,6 +323,253 @@ final class CoreLibsDebugSupportTest extends TestCase ]; } + /** + * Undocumented function + * + * @cover ::printToString + * @dataProvider printToStringProvider + * @testdox printToString $input with $flag will be $expected [$_dataName] + * + * @param mixed $input anything + * @param boolean|null $flag html flag, only for string and array + * @param string $expected always string + * @return void + */ + public function testPrintToString(mixed $input, ?bool $flag, string $expected): void + { + if ($flag === null) { + // if expected starts with / and ends with / then this is a regex compare + if ( + substr($expected, 0, 1) == '/' && + substr($expected, -1, 1) == '/' + ) { + $this->assertMatchesRegularExpression( + $expected, + Support::printToString($input) + ); + } else { + $this->assertEquals( + $expected, + Support::printToString($input) + ); + } + } else { + $this->assertEquals( + $expected, + Support::printToString($input, $flag) + ); + } + } + + /** + * Undocumented function + * + * @return array + */ + public function providerDumpExportVar(): array + { + return [ + 'string' => [ + 'input' => 'string', + 'flag' => null, + 'expected_dump' => 'string(6) "string"' . "\n", + 'expected_export' => "
'string'
", + ], + 'string, no html' => [ + 'input' => 'string', + 'flag' => true, + 'expected_dump' => 'string(6) "string"' . "\n", + 'expected_export' => "'string'", + ], + // int + 'int' => [ + 'input' => 6, + 'flag' => null, + 'expected_dump' => 'int(6)' . "\n", + 'expected_export' => "
6
", + ], + // float + 'float' => [ + 'input' => 1.6, + 'flag' => null, + 'expected_dump' => 'float(1.6)' . "\n", + 'expected_export' => "
1.6
", + ], + // bool + 'bool' => [ + 'input' => true, + 'flag' => null, + 'expected_dump' => 'bool(true)' . "\n", + 'expected_export' => "
true
", + ], + // array + 'array' => [ + 'input' => ['string', true], + 'flag' => null, + 'expected_dump' => "array(2) {\n" + . " [0]=>\n" + . " string(6) \"string\"\n" + . " [1]=>\n" + . " bool(true)\n" + . "}\n", + 'expected_export' => "
array (\n"
+					. "  0 => 'string',\n"
+					. "  1 => true,\n"
+					. ")
", + ], + // more + ]; + } + + /** + * Undocumented function + * + * @cover ::dumpVar + * @cover ::exportVar + * @dataProvider providerDumpExportVar + * @testdox dump/exportVar $input with $flag will be $expected_dump / $expected_export [$_dataName] + * + * @param mixed $input + * @param bool|null $flag + * @param string $expected_dump + * @param string $expected_export + * @return void + */ + public function testDumpExportVar(mixed $input, ?bool $flag, string $expected_dump, string $expected_export): void + { + if ($flag === null) { + $dump = Support::dumpVar($input); + $export = Support::exportVar($input); + } else { + $dump = Support::dumpVar($input, $flag); + $export = Support::exportVar($input, $flag); + } + $this->assertEquals( + $expected_dump, + $dump, + 'assert dumpVar' + ); + $this->assertEquals( + $expected_export, + $export, + 'assert dumpVar' + ); + } + + /** + * Undocumented function + * + * @cover ::getCallerFileLine + * @testWith ["/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/www/vendor/phpunit/phpunit/src/Framework/TestCase.php:1608"] + * @testdox getCallerFileLine check if it returns $expected [$_dataName] + * + * @param string $expected + * @return void + */ + public function testGetCallerFileLine(string $expected): void + { + $this->assertEquals( + $expected, + Support::getCallerFileLine() + ); + } + + /** + * Undocumented function + * + * @cover ::getCallerMethod + * @testWith ["testGetCallerMethod"] + * @testdox getCallerMethod check if it returns $expected [$_dataName] + * + * @return void + */ + public function testGetCallerMethod(string $expected): void + { + $this->assertEquals( + $expected, + Support::getCallerMethod() + ); + } + + /** + * Undocumented function + * + * @cover ::getCallerMethodList + * @testWith [["main", "run", "run", "run", "run", "run", "run", "runBare", "runTest", "testGetCallerMethodList"]] + * @testdox getCallerMethodList check if it returns $expected [$_dataName] + * + * @param array $expected + * @return void + */ + public function testGetCallerMethodList(array $expected): void + { + $compare = Support::getCallerMethodList(); + // 10: legact + // 11: direct + // 12: full call + switch (count($compare)) { + case 10: + // add nothing + $this->assertEquals( + $expected, + Support::getCallerMethodList(), + 'assert expected 10' + ); + break; + case 11: + // add one "run" before "runBare" + array_splice( + $expected, + 7, + 0, + ['run'] + ); + $this->assertEquals( + $expected, + Support::getCallerMethodList(), + 'assert expected 11' + ); + break; + case 12: + // add two "run" before "runBare" + array_splice( + $expected, + 7, + 0, + ['run'] + ); + array_splice( + $expected, + 0, + 0, + ['include'] + ); + $this->assertEquals( + $expected, + Support::getCallerMethodList(), + 'assert expected 12' + ); + break; + } + } + + /** + * Undocumented function + * + * @cover ::getCallerClass + * @testWith ["PHPUnit\\TextUI\\Command"] + * @testdox getCallerClass check if it returns $expected [$_dataName] + * + * @return void + */ + public function testGetCallerClass(string $expected): void + { + $this->assertEquals( + $expected, + Support::getCallerClass() + ); + } + /** * Undocumented function * @@ -236,205 +615,6 @@ final class CoreLibsDebugSupportTest extends TestCase ]; } - /** - * Undocumented function - * - * @cover ::printTime - * @dataProvider printTimeProvider - * @testdox printTime test with $microtime and match to regex [$_dataName] - * - * @param int|null $mircrotime - * @param string $expected - * @return void - */ - public function testPrintTime(?int $microtime, string $regex): void - { - if ($microtime === null) { - $this->assertMatchesRegularExpression( - $regex, - \CoreLibs\Debug\Support::printTime() - ); - } else { - $this->assertMatchesRegularExpression( - $regex, - \CoreLibs\Debug\Support::printTime($microtime) - ); - } - } - - /** - * Undocumented function - * - * @cover ::printAr - * @cover ::printArray - * @dataProvider printArrayProvider - * @testdox printAr/printArray $input will be $expected [$_dataName] - * - * @param array $input - * @param string $expected - * @return void - */ - public function testPrintAr(array $input, string $expected): void - { - $this->assertEquals( - $expected, - \CoreLibs\Debug\Support::printAr($input), - 'assert printAr' - ); - $this->assertEquals( - $expected, - \CoreLibs\Debug\Support::printArray($input), - 'assert printArray' - ); - } - - /** - * Undocumented function - * - * @cover ::printBool - * @dataProvider printBoolProvider - * @testdox printBool $input will be $expected [$_dataName] - * - * @param bool $input - * @param array $params - * @param string $expected - * @return void - */ - public function testPrintBool(bool $input, array $params, string $expected): void - { - if ( - isset($params['name']) && - isset($params['true']) && - isset($params['false']) - ) { - $string = \CoreLibs\Debug\Support::printBool( - $input, - $params['name'], - $params['true'], - $params['false'] - ); - } elseif (isset($params['name']) && isset($params['true'])) { - $string = \CoreLibs\Debug\Support::printBool( - $input, - $params['name'], - $params['true'] - ); - } elseif (isset($params['name'])) { - $string = \CoreLibs\Debug\Support::printBool( - $input, - $params['name'] - ); - } else { - $string = \CoreLibs\Debug\Support::printBool($input); - } - $this->assertEquals( - $expected, - $string, - 'assert printBool' - ); - } - - /** - * Undocumented function - * - * @cover ::printToString - * @dataProvider printToStringProvider - * @testdox printToString $input with $flag will be $expected [$_dataName] - * - * @param mixed $input anything - * @param boolean|null $flag html flag, only for string and array - * @param string $expected always string - * @return void - */ - public function testPrintToString(mixed $input, ?bool $flag, string $expected): void - { - if ($flag === null) { - // if expected starts with / and ends with / then this is a regex compare - if ( - substr($expected, 0, 1) == '/' && - substr($expected, -1, 1) == '/' - ) { - $this->assertMatchesRegularExpression( - $expected, - \CoreLibs\Debug\Support::printToString($input) - ); - } else { - $this->assertEquals( - $expected, - \CoreLibs\Debug\Support::printToString($input) - ); - } - } else { - $this->assertEquals( - $expected, - \CoreLibs\Debug\Support::printToString($input, $flag) - ); - } - } - - /** - * Undocumented function - * - * @cover ::getCallerMethod - * @testWith ["testGetCallerMethod"] - * @testdox getCallerMethod check if it returns $expected [$_dataName] - * - * @return void - */ - public function testGetCallerMethod(string $expected): void - { - $this->assertEquals( - $expected, - \CoreLibs\Debug\Support::getCallerMethod() - ); - } - - /** - * Undocumented function - * - * @cover ::getCallerMethodList - * @testWith [["main", "run", "run", "run", "run", "run", "run", "runBare", "runTest", "testGetCallerMethodList"],["include", "main", "run", "run", "run", "run", "run", "run", "run", "runBare", "runTest", "testGetCallerMethodList"]] - * @testdox getCallerMethodList check if it returns $expected [$_dataName] - * - * @param array $expected - * @return void - */ - public function testGetCallerMethodList(array $expected, array $expected_group): void - { - $compare = \CoreLibs\Debug\Support::getCallerMethodList(); - // if we direct call we have 10, if we call as folder we get 11 - if (count($compare) == 10) { - $this->assertEquals( - $expected, - \CoreLibs\Debug\Support::getCallerMethodList(), - 'assert expected 10' - ); - } else { - $this->assertEquals( - $expected_group, - \CoreLibs\Debug\Support::getCallerMethodList(), - 'assert expected group' - ); - } - } - - /** - * Undocumented function - * - * @cover ::getCallerClass - * @testWith ["PHPUnit\\TextUI\\Command"] - * @testdox getCallerClass check if it returns $expected [$_dataName] - * - * @return void - */ - public function testGetCallerClass(string $expected): void - { - $this->assertEquals( - $expected, - \CoreLibs\Debug\Support::getCallerClass() - ); - } - /** * Undocumented function * @@ -453,19 +633,19 @@ final class CoreLibsDebugSupportTest extends TestCase if ($replace === null && $flag === null) { $this->assertEquals( $expected, - \CoreLibs\Debug\Support::debugString($input), + Support::debugString($input), 'assert all default' ); } elseif ($flag === null) { $this->assertEquals( $expected, - \CoreLibs\Debug\Support::debugString($input, $replace), + Support::debugString($input, $replace), 'assert flag default' ); } else { $this->assertEquals( $expected, - \CoreLibs\Debug\Support::debugString($input, $replace, $flag), + Support::debugString($input, $replace, $flag), 'assert all set' ); } diff --git a/test/phpunit/Get/CoreLibsGetSystemTest.php b/test/phpunit/Get/CoreLibsGetSystemTest.php index eef6aec..221553c 100644 --- a/test/phpunit/Get/CoreLibsGetSystemTest.php +++ b/test/phpunit/Get/CoreLibsGetSystemTest.php @@ -67,17 +67,17 @@ final class CoreLibsGetSystemTest extends TestCase 'original set' => [ 0 => null, 1 => 'NOHOST', - 2 => 'NOPORT', + 2 => 0, ], 'override set no port' => [ 0 => 'foo.org', 1 => 'foo.org', - 2 => '80' + 2 => 80 ], 'override set with port' => [ 0 => 'foo.org:443', 1 => 'foo.org', - 2 => '443' + 2 => 443 ] ]; } @@ -138,10 +138,10 @@ final class CoreLibsGetSystemTest extends TestCase * * @param string|null $input * @param string $expected_host - * @param string $expected_port + * @param int $expected_port * @return void */ - public function testGetHostNanme(?string $input, string $expected_host, string $expected_port): void + public function testGetHostNanme(?string $input, string $expected_host, int $expected_port): void { // print "HOSTNAME: " . $_SERVER['HTTP_HOST'] . "
"; // print "SERVER: " . print_r($_SERVER, true) . "\n"; diff --git a/test/phpunit/Logging/CoreLibsLoggingLoggingTest.php b/test/phpunit/Logging/CoreLibsLoggingLoggingTest.php new file mode 100644 index 0000000..fd75ebd --- /dev/null +++ b/test/phpunit/Logging/CoreLibsLoggingLoggingTest.php @@ -0,0 +1,797 @@ + [ + 'options' => [ + 'log_folder' => DIRECTORY_SEPARATOR . 'tmp', + 'log_file_id' => 'testClassInit', + ], + 'expected' => [ + 'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + 'log_level' => Level::Debug, + 'log_file_id' => 'testClassInit', + ], + 'override' => [], + ], + // -> deprecation warning, log_folder must be set + 'no log folder set' => [ + 'options' => [ + 'log_file_id' => 'testClassInit' + ], + 'expected' => [ + 'log_folder' => getcwd() . DIRECTORY_SEPARATOR, + 'log_level' => Level::Debug, + 'log_file_id' => 'testClassInit', + ], + 'override' => [] + ], + // -> upcoming deprecated + 'file_id set but not log_file_id' => [ + 'options' => [ + 'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + 'file_id' => 'testClassInit', + ], + 'expected' => [ + 'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + 'log_level' => Level::Debug, + 'log_file_id' => 'testClassInit', + ], + 'override' => [], + ], + // both file_id and log_file_id set -> WARNING + 'file_id and log_file_id set' => [ + 'options' => [ + 'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + 'file_id' => 'testClassInit', + 'log_file_id' => 'testClassInit', + ], + 'expected' => [ + 'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + 'log_level' => Level::Debug, + 'log_file_id' => 'testClassInit', + ], + 'override' => [], + ], + // no log file id set -> error, + 'nothing set' => [ + 'options' => [], + 'expected' => [ + 'log_folder' => getcwd() . DIRECTORY_SEPARATOR, + 'log_level' => Level::Debug, + 'log_file_id' => 'NOHOST-0_PHPUnit-TextUI-Command', + ], + 'override' => [] + ] + ]; + } + + /** + * init logging class + * + * @dataProvider optionsProvider + * @testdox init test [$_dataName] + * + * @param array $options + * @param array $expected + * @param array $override + * @return void + */ + public function testClassInit(array $options, array $expected, array $override): void + { + if (!empty($override['constant'])) { + foreach ($override['constant'] as $var => $value) { + if (!defined($var)) { + define($var, $value); + } + } + // for deprecated no log_folder set + // if base is defined and it does have AAASetupData set + // change the log_folder "Debug" to "AAASetupData" + if ( + defined('BASE') && + strpos(BASE, DIRECTORY_SEPARATOR . 'AAASetupData') !== false + ) { + $expected['log_folder'] = str_replace( + DIRECTORY_SEPARATOR . 'Debug', + DIRECTORY_SEPARATOR . 'AAASetupData', + $expected['log_folder'] + ); + } + } + // if not log folder and constant set -> expect E_USER_DEPRECATION + if (!empty($override['constant']) && empty($options['log_folder'])) { + // the deprecation message + $deprecation_message = 'options: log_folder must be set. ' + . 'Setting via BASE and LOG constants is deprecated'; + // convert E_USER_DEPRECATED to a exception + set_error_handler( + static function (int $errno, string $errstr): never { + throw new \Exception($errstr, $errno); + }, + E_USER_DEPRECATED + ); + // catch this with the message + $this->expectExceptionMessage($deprecation_message); + } + // alert for log file id with globals + if (!empty($override['constant']) && empty($options['log_file_id'])) { + // + } + // alert for log file id and file id set + if ( + !empty($options['log_file_id']) && + !empty($options['file_id']) + ) { + set_error_handler( + static function (int $errno, string $errstr): never { + throw new \InvalidArgumentException($errstr, $errno); + }, + E_USER_WARNING + ); + $error_message = 'options: "file_id" is deprecated use: "log_file_id".'; + $this->expectExceptionMessage($error_message); + $this->expectException(\InvalidArgumentException::class); + set_error_handler( + static function (int $errno, string $errstr): never { + throw new \Exception($errstr, $errno); + }, + E_USER_DEPRECATED + ); + $this->expectException(\Exception::class); + // $error_message = 'options: both log_file_id and log_id are set at the same time, will use log_file_id'; + // $this->expectExceptionMessage($error_message); + } + // empty log folder + if (empty($override['constant']) && empty($options['log_folder'])) { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessageMatches("/^Missing mandatory option: \"/"); + } elseif (empty($options['log_file_id']) && !empty($options['file_id'])) { + // the deprecation message + $deprecation_message = 'options: "file_id" is deprecated use: "log_file_id".'; + // convert E_USER_DEPRECATED to a exception + set_error_handler( + static function (int $errno, string $errstr): never { + throw new \Exception($errstr, $errno); + }, + E_USER_DEPRECATED + ); + // catch this with the message + $this->expectExceptionMessage($deprecation_message); + } + $log = new \CoreLibs\Logging\Logging($options); + // reset error handler + restore_error_handler(); + // check that settings match + $this->assertEquals( + $expected['log_folder'], + $log->getLogFolder(), + 'log folder not matching' + ); + $this->assertEquals( + $expected['log_file_id'], + $log->getLogFileId(), + 'log file id not matching' + ); + } + + // test all setters/getters + + // setLoggingLevel + // getLoggingLevel + // getJsDebug + + /** + * Undocumented function + * + * @covers ::setLoggingLevel + * @covers ::getLoggingLevel + * @covers ::getJsDebug + * @testdox setLoggingLevel set/get checks + * + * @return void + */ + public function testSetLoggingLevel(): void + { + // valid that is not Debug + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLoggingLevel', + 'log_folder' => self::LOG_FOLDER, + 'log_level' => Level::Info + ]); + $this->assertEquals( + Level::Info, + $log->getLoggingLevel() + ); + $this->assertFalse( + $log->getJsDebug() + ); + // not set, should be debug] + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLoggingLevel', + 'log_folder' => self::LOG_FOLDER, + ]); + $this->assertEquals( + Level::Debug, + $log->getLoggingLevel() + ); + $this->assertTrue( + $log->getJsDebug() + ); + // invalid, should be debug, will throw excpetion too + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Option: "log_level" is not of instance \CoreLibs\Logging\Logger\Level'); + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLoggingLevel', + 'log_folder' => self::LOG_FOLDER, + 'log_level' => 'I' + ]); + $this->assertEquals( + Level::Debug, + $log->getLoggingLevel() + ); + $this->assertTrue( + $log->getJsDebug() + ); + // set valid, then change + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLoggingLevel', + 'log_folder' => self::LOG_FOLDER, + 'log_level' => Level::Info + ]); + $this->assertEquals( + Level::Info, + $log->getLoggingLevel() + ); + $log->setLoggingLevel(Level::Notice); + $this->assertEquals( + Level::Notice, + $log->getLoggingLevel() + ); + // illegal logging level + $this->expectException(\Psr\Log\InvalidArgumentException::class); + $this->expectExceptionMessageMatches("/^Level \"NotGood\" is not defined, use one of: /"); + $log->setLoggingLevel('NotGood'); + } + + // setLogFileId + // getLogFileId + + /** + * Undocumented function + * + * @covers ::setLogFileId + * @covers ::getLogFileId + * @testdox setLogFileId set/get checks + * + * @return void + */ + public function testLogFileId(): void + { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testLogFileId', + 'log_folder' => self::LOG_FOLDER + ]); + // bad, keep same + $log->setLogFileId('$$##$%#$%&'); + $this->assertEquals( + 'testLogFileId', + $log->getLogFileId() + ); + // good, change + $log->setLogFileId('validID'); + $this->assertEquals( + 'validID', + $log->getLogFileId() + ); + // invalid on init + $this->expectException(\Psr\Log\InvalidArgumentException::class); + $this->expectExceptionMessage('LogFileId: no log file id set'); + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => '$$$"#"#$"#$', + 'log_folder' => self::LOG_FOLDER + ]); + } + + // setLogUniqueId + // getLogUniqueId + + /** + * Undocumented function + * + * @return array + */ + public function logUniqueIdProvider(): array + { + return [ + 'option set' => [ + 'option' => true, + 'override' => false, + ], + 'direct set' => [ + 'option' => false, + 'override' => false, + ], + 'override set' => [ + 'option' => false, + 'override' => true, + ], + 'option and override set' => [ + 'option' => false, + 'override' => true, + ], + ]; + } + + /** + * Undocumented function + * + * @covers ::setLogUniqueId + * @covers ::getLogUniqueId + * @dataProvider logUniqueIdProvider + * @testdox per run log id set test: option: $option, override: $override [$_dataName] + * + * @param bool $option + * @param bool $override + * @return void + */ + public function testLogUniqueId(bool $option, bool $override): void + { + if ($option === true) { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testLogUniqueId', + 'log_folder' => self::LOG_FOLDER, + 'log_per_run' => $option + ]); + } else { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testLogUniqueId', + 'log_folder' => self::LOG_FOLDER + ]); + $log->setLogUniqueId(); + } + $per_run_id = $log->getLogUniqueId(); + $this->assertMatchesRegularExpression( + "/^\d{4}-\d{2}-\d{2}_\d{6}_U_[a-z0-9]{8}$/", + $per_run_id, + 'assert per log run id 1st' + ); + if ($override === true) { + $log->setLogUniqueId(true); + $per_run_id_2nd = $log->getLogUniqueId(); + $this->assertMatchesRegularExpression( + "/^\d{4}-\d{2}-\d{2}_\d{6}_U_[a-z0-9]{8}$/", + $per_run_id_2nd, + 'assert per log run id 2nd' + ); + $this->assertNotEquals( + $per_run_id, + $per_run_id_2nd, + '1st and 2nd don\'t match' + ); + } + } + + // setLogDate + // getLogDate + + /** + * Undocumented function + * + * @covers ::setLogDate + * @covers ::getLogDate + * @testdox setLogDate set/get checks + * + * @return void + */ + public function testSetLogDate(): void + { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testLogFileId', + 'log_folder' => self::LOG_FOLDER, + 'log_per_date' => true, + ]); + $this->assertEquals( + date('Y-m-d'), + $log->getLogDate() + ); + } + + // setLogFlag + // getLogFlag + // unsetLogFlag + // getLogFlags + // Logger\Flag + + /** + * Undocumented function + * + * @covers Logger\Flag + * @testdox Logger\Flag enum test + * + * @return void + */ + public function testLoggerFlag(): void + { + // logger flags to check that they exist + $flags = [ + 'all_off' => 0, + 'per_run' => 1, + 'per_date' => 2, + 'per_group' => 4, + 'per_page' => 8, + 'per_class' => 16, + 'per_level' => 32, + ]; + // from int -> return value + foreach ($flags as $name => $value) { + $this->assertEquals( + Flag::fromName($name), + Flag::fromValue($value) + ); + } + } + + /** + * Undocumented function + * + * @covers ::setLogFlag + * @covers ::getLogFlag + * @covers ::unsetLogFlag + * @covers ::getLogFlags + * @testdox setLogDate set/get checks + * + * @return void + */ + public function testSetLogFlag(): void + { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLogFlag', + 'log_folder' => self::LOG_FOLDER, + ]); + // set valid log flag + $log->setLogFlag(Flag::per_run); + $this->assertTrue( + $log->getLogFlag(Flag::per_run) + ); + // flags seum + $this->assertEquals( + Flag::per_run->value, + $log->getLogFlags(), + ); + // unset valid log flag + $log->unsetLogFlag(Flag::per_run); + $this->assertFalse( + $log->getLogFlag(Flag::per_run) + ); + // illegal Flags cannot be set, they will throw eerros onrun + + // test multi set and sum is equals set + $log->setLogFlag(Flag::per_date); + $log->setLogFlag(Flag::per_group); + $this->assertEquals( + Flag::per_date->value + Flag::per_group->value, + $log->getLogFlags() + ); + } + + // setLogFolder + // getLogFolder + + /** + * Undocumented function + * + * @covers ::setLogFolder + * @covers ::getLogFolder + * @testdox setLogFolder set/get checks, init check + * + * @return void + */ + public function testSetLogFolder(): void + { + // set to good folder + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLogFolder', + 'log_folder' => self::LOG_FOLDER, + ]); + $this->assertEquals( + self::LOG_FOLDER, + $log->getLogFolder() + ); + // set to a good other folder + $log->setLogFolder(DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR); + $this->assertEquals( + DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + $log->getLogFolder() + ); + // good other folder with missing trailing slash + $log->setLogFolder(DIRECTORY_SEPARATOR . 'tmp'); + $this->assertEquals( + DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + $log->getLogFolder() + ); + // a bad folder -> last good folder + $log->setLogFolder('I-am-not existing'); + $this->assertEquals( + DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR, + $log->getLogFolder() + ); + // init with a bad folder + $this->expectException(\Psr\Log\InvalidArgumentException::class); + $this->expectExceptionMessage('Folder: "I-am-bad" is not writeable for logging'); + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLogFolderInvalid', + 'log_folder' => 'I-am-bad', + ]); + } + + // getLogFile (no set, only correct after log run) + + // setLogMaxFileSize + // getLogMaxFileSize + + /** + * Undocumented function + * + * @covers ::setLogMaxFileSize + * @covers ::getLogMaxFileSize + * @testdox setLogMaxFileSize set/get checks, init check + * + * @return void + */ + public function testSetLogMaxFileSize(): void + { + // init set to 0 + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testSetLogMaxFileSize', + 'log_folder' => self::LOG_FOLDER, + ]); + $this->assertEquals( + 0, + $log->getLogMaxFileSize() + ); + // set to new, valid size + $file_size = 200 * 1024; + $valid = $log->setLogMaxFileSize($file_size); + $this->assertTrue($valid); + $this->assertEquals( + $file_size, + $log->getLogMaxFileSize() + ); + // invalid size, < 0, will be last and return false + $valid = $log->setLogMaxFileSize(-1); + $this->assertFalse($valid); + $this->assertEquals( + $file_size, + $log->getLogMaxFileSize() + ); + // too small (< MIN_LOG_MAX_FILESIZE) + $valid = $log->setLogMaxFileSize($log::MIN_LOG_MAX_FILESIZE - 1); + $this->assertFalse($valid); + $this->assertEquals( + $file_size, + $log->getLogMaxFileSize() + ); + } + + // getOption (option params) + + /** + * Undocumented function + * + * @covers ::getOption + * @testdox getOption checks + * + * @return void + */ + public function testGetOption(): void + { + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testGetOption', + 'log_folder' => self::LOG_FOLDER, + ]); + $this->assertEquals( + self::LOG_FOLDER, + $log->getOption('log_folder') + ); + // not found + $this->assertNull( + $log->getOption('I_do not exist') + ); + } + + // test all logger functions + // debug (special) + // info + // notice + // warning + // error + // critical + // alert + // emergency + + /** + * Undocumented function + * + * @covers ::debug + * @testdox debug checks + * + * @return void + */ + public function testDebug(): void + { + // init logger + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'testDebug', + 'log_folder' => self::LOG_FOLDER, + ]); + // clean all data in folder first + array_map('unlink', glob($log->getLogFolder() . $log->getLogFileId() . '*.log')); + + $group_id = 'G'; + $message = 'D'; + $log_status = $log->debug($group_id, $message); + $this->assertTrue($log_status, 'debug write successful'); + $file_content = file_get_contents( + $log->getLogFolder() . $log->getLogFile() + ) ?: ''; + $log_level = $log->getLoggingLevel()->getName(); + // [2023-05-30 15:51:39.36128800] [NOHOST:0] + // [www/vendor/bin/phpunit] [7b9d0747] {PHPUnit\TextUI\Command} + // D + $this->assertMatchesRegularExpression( + "/" . self::REGEX_BASE + . "<$log_level:$group_id>\s{1}" // log level / group id + . "$message" // message + . "/", + $file_content + ); + } + + public function providerLoggingLevelWrite(): array + { + return [ + 'info' => [ + 'message' => 'I', + 'file_id' => Level::Info->name, + 'level' => Level::Info + ], + 'notice' => [ + 'message' => 'N', + 'file_id' => Level::Notice->name, + 'level' => Level::Notice + ], + 'warning' => [ + 'message' => 'W', + 'file_id' => Level::Warning->name, + 'level' => Level::Warning + ], + 'error' => [ + 'message' => 'E', + 'file_id' => Level::Error->name, + 'level' => Level::Error + ], + 'crticial' => [ + 'message' => 'C', + 'file_id' => Level::Critical->name, + 'level' => Level::Critical + ], + 'alert' => [ + 'message' => 'A', + 'file_id' => Level::Alert->name, + 'level' => Level::Alert + ], + 'emergency' => [ + 'message' => 'Em', + 'file_id' => Level::Emergency->name, + 'level' => Level::Emergency + ], + ]; + } + + /** + * Undocumented function + * + * @covers ::info + * @covers ::notice + * @covers ::warning + * @covers ::error + * @covers ::critical + * @covers ::alert + * @covers ::emergency + * @dataProvider providerLoggingLevelWrite + * @testdox logging level write checks for $level [$_dataName] + * + * @return void + */ + public function testLoggingLevelWrite(string $message, string $file_id, Level $level): void + { + // init logger + $log = new \CoreLibs\Logging\Logging([ + 'log_file_id' => 'test' . $file_id, + 'log_folder' => self::LOG_FOLDER, + 'log_level' => $level, + ]); + // clean all data in folder first + array_map('unlink', glob($log->getLogFolder() . $log->getLogFileId() . '*.log')); + + switch ($level->value) { + case 200: + $log_status = $log->info($message); + break; + case 250: + $log_status = $log->notice($message); + break; + case 300: + $log_status = $log->warning($message); + break; + case 400: + $log_status = $log->error($message); + break; + case 500: + $log_status = $log->critical($message); + break; + case 550: + $log_status = $log->alert($message); + break; + case 600: + $log_status = $log->emergency($message); + break; + } + $this->assertTrue($log_status, 'log write successful'); + $file_content = file_get_contents( + $log->getLogFolder() . $log->getLogFile() + ) ?: ''; + $log_level = $log->getLoggingLevel()->getName(); + $this->assertMatchesRegularExpression( + "/" . self::REGEX_BASE + . "<$log_level>\s{1}" // log level / group id + . "$message" // message + . "/", + $file_content, + 'log message regex' + ); + } + + // deprecated calls check? +} + +// __END__ diff --git a/test/phpunit/Logging/log/.gitignore b/test/phpunit/Logging/log/.gitignore new file mode 100644 index 0000000..2a50fc0 --- /dev/null +++ b/test/phpunit/Logging/log/.gitignore @@ -0,0 +1,3 @@ +*log +*LOG +!.gitignore