Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16e12b5b8f | ||
|
|
73063d28b2 | ||
|
|
e80d8006a2 | ||
|
|
d648e4339a | ||
|
|
4b084f8785 | ||
|
|
d0d088b354 | ||
|
|
e0d42af1d2 | ||
|
|
c1d26f122e | ||
|
|
2c2826ac24 | ||
|
|
72f0810898 | ||
|
|
b69539b340 | ||
|
|
0b133133dd | ||
|
|
8fbe855fd4 | ||
|
|
d7410dfe78 | ||
|
|
5d36ac2f3e | ||
|
|
2e4ace1a39 | ||
|
|
aa5c3b9dcc | ||
|
|
24f7a903ef | ||
|
|
72993925f0 | ||
|
|
29d5ef92d4 | ||
|
|
f66f8f282e | ||
|
|
c010673705 | ||
|
|
b16ff4c613 | ||
|
|
e9c791c164 | ||
|
|
c7ec1300b7 | ||
|
|
064710324e | ||
|
|
e0356dcadf | ||
|
|
62a5992e3a | ||
|
|
6bb957fcb3 | ||
|
|
0c1f060759 | ||
|
|
aad46ec80a | ||
|
|
f5e9f0610d | ||
|
|
14a5250cd7 | ||
|
|
6e6edef57d | ||
|
|
d3810db965 | ||
|
|
187a012284 |
@@ -109,7 +109,10 @@ return [
|
||||
'PhanWriteOnlyPublicProperty',
|
||||
'PhanUnreferencedConstant',
|
||||
'PhanWriteOnlyPublicProperty',
|
||||
'PhanReadOnlyPublicProperty'
|
||||
'PhanReadOnlyPublicProperty',
|
||||
// start ignore annotations
|
||||
'PhanUnextractableAnnotationElementName',
|
||||
'PhanUnextractableAnnotationSuffix',
|
||||
],
|
||||
|
||||
// Override to hardcode existence and types of (non-builtin) globals in the global scope.
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
"php": ">=8.1",
|
||||
"psr/log": "^3.0@dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.10",
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.1.3
|
||||
9.0.5
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
BASE_FOLDER=$(dirname $(readlink -f $0))"/";
|
||||
VERSION=$(git tag --list | sort -V | tail -n1 | sed -e "s/^v//");
|
||||
file_last_published="${BASE_FOLDER}last.published";
|
||||
go_flag="$1";
|
||||
|
||||
if [ -z "${VERSION}" ]; then
|
||||
echo "Version must be set in the form x.y.z without any leading characters";
|
||||
@@ -20,7 +21,11 @@ fi;
|
||||
# read in the .env.deploy file and we must have
|
||||
# GITLAB_USER
|
||||
# GITLAB_TOKEN
|
||||
# GITLAB_URL
|
||||
# GITEA_USER
|
||||
# GITEA_DEPLOY_TOKEN
|
||||
# GITEA_URL_DL
|
||||
# GITEA_URL_PUSH
|
||||
if [ ! -f "${BASE_FOLDER}.env.deploy" ]; then
|
||||
echo "Deploy enviroment file .env.deploy is missing";
|
||||
exit;
|
||||
@@ -31,28 +36,36 @@ source .env.deploy;
|
||||
cd -;
|
||||
set +o allexport;
|
||||
|
||||
if [ "${go_flag}" != "go" ]; then
|
||||
echo "No go flag given";
|
||||
echo "Would publish ${VERSION} on ${file_last_published}";
|
||||
echo "[END]";
|
||||
exit;
|
||||
fi;
|
||||
|
||||
echo "[START]";
|
||||
# gitea
|
||||
if [ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then
|
||||
if [ ! -z "${GITEA_URL_DL}" ] && [ ! -z "${GITEA_URL_PUSH}" ] &&
|
||||
[ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then
|
||||
curl -LJO \
|
||||
--output-dir "${BASE_FOLDER}" \
|
||||
https://git.egplusww.jp/Composer/CoreLibs-Composer-All/archive/v${VERSION}.zip;
|
||||
${GITEA_URL_DL}/v${VERSION}.zip;
|
||||
curl --user ${GITEA_USER}:${GITEA_TOKEN} \
|
||||
--upload-file "${BASE_FOLDER}/CoreLibs-Composer-All-v${VERSION}.zip" \
|
||||
https://git.egplusww.jp/api/packages/Composer/composer?version=${VERSION};
|
||||
${GITEA_URL_PUSH}?version=${VERSION};
|
||||
echo "${VERSION}" > "${file_last_published}";
|
||||
else
|
||||
echo "Missing either GITEA_USER or GITEA_TOKEN environment variable";
|
||||
fi;
|
||||
|
||||
# gitlab
|
||||
if [ ! -z "${GITLAB_DEPLOY_TOKEN}" ]; then
|
||||
if [ ! -z "${GITLAB_URL}" ] && [ ! -z "${GITLAB_DEPLOY_TOKEN}" ]; then
|
||||
curl --data tag=v${VERSION} \
|
||||
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
||||
"https://gitlab-na.factory.tools/api/v4/projects/950/packages/composer";
|
||||
"${GITLAB_URL}";
|
||||
curl --data branch=master \
|
||||
--header "Deploy-Token: ${GITLAB_DEPLOY_TOKEN}" \
|
||||
"https://gitlab-na.factory.tools/api/v4/projects/950/packages/composer";
|
||||
"${GITLAB_URL}";
|
||||
echo "${VERSION}" > "${file_last_published}";
|
||||
else
|
||||
echo "Missing GITLAB_DEPLOY_TOKEN environment variable";
|
||||
|
||||
@@ -68,69 +68,70 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\ACL;
|
||||
|
||||
use CoreLibs\Check\Password;
|
||||
use CoreLibs\Security\Password;
|
||||
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<string> 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<string> */
|
||||
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;
|
||||
@@ -157,7 +158,7 @@ class Login
|
||||
. "$/";
|
||||
|
||||
/** @var array<string> 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,}',
|
||||
];
|
||||
@@ -165,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<mixed> 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<mixed> */
|
||||
private $login_template = [
|
||||
private array $login_template = [
|
||||
'strings' => [],
|
||||
'password_change' => '',
|
||||
'template' => ''
|
||||
@@ -179,59 +180,59 @@ class Login
|
||||
|
||||
// acl vars
|
||||
/** @var array<mixed> */
|
||||
private $acl = [];
|
||||
private array $acl = [];
|
||||
/** @var array<mixed> */
|
||||
private $default_acl_list = [];
|
||||
private array $default_acl_list = [];
|
||||
/** @var array<string,int> 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<string,mixed> options */
|
||||
private $options = [];
|
||||
private array $options = [];
|
||||
/** @var array<string,string> 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<string,mixed> $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
|
||||
@@ -753,7 +754,10 @@ class Login
|
||||
// we have to get the themes in here too
|
||||
$q = "SELECT eu.edit_user_id, eu.username, eu.password, "
|
||||
. "eu.edit_group_id, "
|
||||
. "eg.name AS edit_group_name, admin, "
|
||||
. "eg.name AS edit_group_name, eu.admin, "
|
||||
// additinal acl lists
|
||||
. "eu.additional_acl AS user_additional_acl, "
|
||||
. "eg.additional_acl AS group_additional_acl, "
|
||||
// login error + locked
|
||||
. "eu.login_error_count, eu.login_error_date_last, "
|
||||
. "eu.login_error_date_first, eu.strict, eu.locked, "
|
||||
@@ -879,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) {
|
||||
@@ -901,8 +905,10 @@ class Login
|
||||
$_SESSION['GROUP_NAME'] = $res['edit_group_name'];
|
||||
$_SESSION['USER_ACL_LEVEL'] = $res['user_level'];
|
||||
$_SESSION['USER_ACL_TYPE'] = $res['user_type'];
|
||||
$_SESSION['USER_ADDITIONAL_ACL'] = Json::jsonConvertToArray($res['user_additional_acl']);
|
||||
$_SESSION['GROUP_ACL_LEVEL'] = $res['group_level'];
|
||||
$_SESSION['GROUP_ACL_TYPE'] = $res['group_type'];
|
||||
$_SESSION['GROUP_ADDITIONAL_ACL'] = Json::jsonConvertToArray($res['group_additional_acl']);
|
||||
// deprecated TEMPLATE setting
|
||||
$_SESSION['TEMPLATE'] = $res['template'] ? $res['template'] : '';
|
||||
$_SESSION['HEADER_COLOR'] = !empty($res['second_header_color']) ?
|
||||
@@ -1021,7 +1027,8 @@ class Login
|
||||
$_SESSION['PAGES'] = $pages;
|
||||
$_SESSION['PAGES_ACL_LEVEL'] = $pages_acl;
|
||||
// load the edit_access user rights
|
||||
$q = "SELECT ea.edit_access_id, level, type, ea.name, ea.color, ea.uid, edit_default "
|
||||
$q = "SELECT ea.edit_access_id, level, type, ea.name, "
|
||||
. "ea.color, ea.uid, edit_default, ea.additional_acl "
|
||||
. "FROM edit_access_user eau, edit_access_right ear, edit_access ea "
|
||||
. "WHERE eau.edit_access_id = ea.edit_access_id "
|
||||
. "AND eau.edit_access_right_id = ear.edit_access_right_id "
|
||||
@@ -1041,13 +1048,14 @@ 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'],
|
||||
'uid' => $res['uid'],
|
||||
'color' => $res['color'],
|
||||
'default' => $res['edit_default'],
|
||||
'additional_acl' => Json::jsonConvertToArray($res['additional_acl']),
|
||||
'data' => $ea_data
|
||||
];
|
||||
// set the default unit
|
||||
@@ -1122,6 +1130,11 @@ class Login
|
||||
// username (login), group name
|
||||
$this->acl['user_name'] = $_SESSION['USER_NAME'];
|
||||
$this->acl['group_name'] = $_SESSION['GROUP_NAME'];
|
||||
// set additional acl
|
||||
$this->acl['additional_acl'] = [
|
||||
'user' => $_SESSION['USER_ADDITIONAL_ACL'],
|
||||
'group' => $_SESSION['GROUP_ADDITIONAL_ACL'],
|
||||
];
|
||||
// we start with the default acl
|
||||
$this->acl['base'] = $this->default_acl_level;
|
||||
|
||||
@@ -1166,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
|
||||
@@ -1184,7 +1203,8 @@ class Login
|
||||
'uid' => $unit['uid'],
|
||||
'level' => $this->default_acl_list[$this->acl['unit'][$ea_id]]['name'] ?? -1,
|
||||
'default' => $unit['default'],
|
||||
'data' => $unit['data']
|
||||
'data' => $unit['data'],
|
||||
'additional_acl' => $unit['additional_acl']
|
||||
];
|
||||
// set default
|
||||
if (!empty($unit['default'])) {
|
||||
@@ -1594,7 +1614,7 @@ class Login
|
||||
// TODO: submit or JS to set target page as ajax call
|
||||
// NOTE: for the HTML block I ignore line lengths
|
||||
// phpcs:disable
|
||||
$this->login_template['password_change'] = <<<EOM
|
||||
$this->login_template['password_change'] = <<<HTML
|
||||
<div id="pw_change_div" class="hidden" style="position: absolute; top: 30px; left: 50px; width: 400px; height: 220px; background-color: white; border: 1px solid black; padding: 25px;">
|
||||
<table>
|
||||
<tr><td class="norm" align="center" colspan="2"><h3>{TITLE_PASSWORD_CHANGE}</h3></td></tr>
|
||||
@@ -1612,7 +1632,7 @@ class Login
|
||||
</table>
|
||||
</div>
|
||||
{PASSWORD_CHANGE_SHOW}
|
||||
EOM;
|
||||
HTML;
|
||||
// phpcs:enable
|
||||
}
|
||||
if ($this->password_forgot) {
|
||||
@@ -1636,7 +1656,7 @@ EOM;
|
||||
// now check templates
|
||||
// TODO: submit or JS to set target page as ajax call
|
||||
if (!$this->login_template['template']) {
|
||||
$this->login_template['template'] = <<<EOM
|
||||
$this->login_template['template'] = <<<HTML
|
||||
<!DOCTYPE html>
|
||||
<html lang="{LANGUAGE}">
|
||||
<head>
|
||||
@@ -1698,7 +1718,7 @@ h3 { font-size: 18px; }
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
EOM;
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1835,13 +1855,13 @@ EOM;
|
||||
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 . ')');
|
||||
}
|
||||
}
|
||||
// if there is none, there is none, saves me POST/GET check
|
||||
$this->euid = array_key_exists('EUID', $_SESSION) ? $_SESSION['EUID'] : 0;
|
||||
$this->euid = array_key_exists('EUID', $_SESSION) ? (int)$_SESSION['EUID'] : 0;
|
||||
// get login vars, are so, can't be changed
|
||||
// prepare
|
||||
// pass on vars to Object vars
|
||||
@@ -1897,21 +1917,6 @@ EOM;
|
||||
// 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 {
|
||||
@@ -2105,7 +2110,7 @@ EOM;
|
||||
// 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;
|
||||
}
|
||||
@@ -2493,7 +2498,7 @@ EOM;
|
||||
*/
|
||||
public function loginGetEuid(): string
|
||||
{
|
||||
return $this->euid;
|
||||
return (string)$this->euid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,97 +35,97 @@ class Backend
|
||||
{
|
||||
// page name
|
||||
/** @var array<mixed> */
|
||||
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<string> */
|
||||
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<mixed> */
|
||||
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<mixed> */
|
||||
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<mixed> */
|
||||
public $DATA;
|
||||
public array $DATA = [];
|
||||
/** @var array<mixed> */
|
||||
public $HEADER;
|
||||
public array $HEADER = [];
|
||||
/** @var array<mixed> */
|
||||
public $DEBUG_DATA;
|
||||
public array $DEBUG_DATA = [];
|
||||
/** @var array<mixed> */
|
||||
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
|
||||
|
||||
@@ -20,36 +20,36 @@ use SmartyException;
|
||||
class EditBase
|
||||
{
|
||||
/** @var array<mixed> */
|
||||
private $HEADER = [];
|
||||
private array $HEADER = [];
|
||||
/** @var array<mixed> */
|
||||
private $DATA = [];
|
||||
private array $DATA = [];
|
||||
/** @var array<mixed> */
|
||||
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<mixed> $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<string,mixed> $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(
|
||||
|
||||
121
src/Basic.php
121
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<mixed> */
|
||||
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<mixed> */
|
||||
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 <br> 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<mixed> $array any array
|
||||
* @return string formatted array for output with <pre> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1164,7 +1109,7 @@ class Basic
|
||||
public function passwordSet(string $password): string
|
||||
{
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordSet()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Check\Password::passwordSet($password);
|
||||
return \CoreLibs\Security\Password::passwordSet($password);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1177,7 +1122,7 @@ class Basic
|
||||
public function passwordVerify(string $password, string $hash): bool
|
||||
{
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordVerify()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Check\Password::passwordVerify($password, $hash);
|
||||
return \CoreLibs\Security\Password::passwordVerify($password, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1189,7 +1134,7 @@ class Basic
|
||||
public function passwordRehashCheck(string $hash): bool
|
||||
{
|
||||
trigger_error('Method ' . __METHOD__ . ' is deprecated, use \CoreLibs\Check\Password::passwordRehashCheck()', E_USER_DEPRECATED);
|
||||
return \CoreLibs\Check\Password::passwordRehashCheck($hash);
|
||||
return \CoreLibs\Security\Password::passwordRehashCheck($hash);
|
||||
}
|
||||
|
||||
// *** BETTER PASSWORD OPTIONS END ***
|
||||
|
||||
@@ -8,7 +8,7 @@ class Email
|
||||
{
|
||||
// this is for error check parts in where the email regex failed
|
||||
/** @var array<int,string> */
|
||||
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<int,string> */
|
||||
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<string,string> */
|
||||
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<string,string> */
|
||||
private static $mobile_email_type_short = [
|
||||
private static array $mobile_email_type_short = [
|
||||
'keitai_docomo' => 'docomo',
|
||||
'keitai_kddi_ezweb' => 'kddi',
|
||||
'keitai_kddi' => 'kddi',
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace CoreLibs\Check;
|
||||
class Encoding
|
||||
{
|
||||
/** @var int<min, -1>|int<1, max>|string */
|
||||
private static $mb_error_char = '';
|
||||
private static int|string $mb_error_char = '';
|
||||
|
||||
/**
|
||||
* set error char
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* NOTE: this is deprecated and all moved \CoreLibs\Security\Password
|
||||
*
|
||||
* core password set, check and rehash check wrapper functions
|
||||
*/
|
||||
|
||||
@@ -8,6 +10,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Check;
|
||||
|
||||
use CoreLibs\Security\Password as PasswordNew;
|
||||
|
||||
class Password
|
||||
{
|
||||
/**
|
||||
@@ -15,13 +19,16 @@ class Password
|
||||
*
|
||||
* @param string $password password
|
||||
* @return string hashed password
|
||||
* @deprecated v9.0 Moved to \CoreLibs\Security\Password::passwordSet
|
||||
*/
|
||||
public static function passwordSet(string $password): string
|
||||
{
|
||||
// always use the PHP default for the password
|
||||
// password options ca be set in the password init,
|
||||
// but should be kept as default
|
||||
return password_hash($password, PASSWORD_DEFAULT);
|
||||
trigger_error(
|
||||
'Method ' . __METHOD__ . ' is deprecated, use '
|
||||
. '\CoreLibs\Security\Password::passwordSet',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
return PasswordNew::passwordSet($password);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,14 +37,16 @@ class Password
|
||||
* @param string $password password
|
||||
* @param string $hash password hash
|
||||
* @return bool true or false
|
||||
* @deprecated v9.0 Moved to \CoreLibs\Security\Password::passwordVerify
|
||||
*/
|
||||
public static function passwordVerify(string $password, string $hash): bool
|
||||
{
|
||||
if (password_verify($password, $hash)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
trigger_error(
|
||||
'Method ' . __METHOD__ . ' is deprecated, use '
|
||||
. '\CoreLibs\Security\Password::passwordVerify',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
return PasswordNew::passwordVerify($password, $hash);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -45,14 +54,16 @@ class Password
|
||||
*
|
||||
* @param string $hash password hash
|
||||
* @return bool true or false
|
||||
* @deprecated v9.0 Moved to \CoreLibs\Security\Password::passwordRehashCheck
|
||||
*/
|
||||
public static function passwordRehashCheck(string $hash): bool
|
||||
{
|
||||
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
trigger_error(
|
||||
'Method ' . __METHOD__ . ' is deprecated, use '
|
||||
. '\CoreLibs\Security\Password::passwordRehashCheck',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
return PasswordNew::passwordRehashCheck($hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +177,65 @@ class ArrayHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for one or many keys in array and return matching values
|
||||
* If flat is set to true, return flat array with found values only
|
||||
* If prefix is turned on each found group will be prefixed with the
|
||||
* search key
|
||||
*
|
||||
* @param array<mixed> $array array to search in
|
||||
* @param array<mixed> $needles keys to find in array
|
||||
* @param bool $flat [false] Turn on flat output
|
||||
* @param bool $prefix [false] Prefix found with needle key
|
||||
* @return array<mixed> Found values
|
||||
*/
|
||||
public static function arraySearchKey(
|
||||
array $array,
|
||||
array $needles,
|
||||
bool $flat = false,
|
||||
bool $prefix = false
|
||||
): array {
|
||||
$iterator = new \RecursiveArrayIterator($array);
|
||||
$recursive = new \RecursiveIteratorIterator(
|
||||
$iterator,
|
||||
\RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
$hit_list = [];
|
||||
if ($prefix === true) {
|
||||
$hit_list = array_fill_keys($needles, []);
|
||||
}
|
||||
$key_path = [];
|
||||
$prev_depth = 0;
|
||||
foreach ($recursive as $key => $value) {
|
||||
if ($prev_depth > $recursive->getDepth()) {
|
||||
// remove all trailing to ne depth
|
||||
$diff = $prev_depth - $recursive->getDepth();
|
||||
array_splice($key_path, -$diff, $diff);
|
||||
}
|
||||
$prev_depth = $recursive->getDepth();
|
||||
if ($flat === false) {
|
||||
$key_path[$recursive->getDepth()] = $key;
|
||||
}
|
||||
if (in_array($key, $needles, true)) {
|
||||
ksort($key_path);
|
||||
if ($flat === true) {
|
||||
$hit = $value;
|
||||
} else {
|
||||
$hit = [
|
||||
'value' => $value,
|
||||
'path' => $key_path
|
||||
];
|
||||
}
|
||||
if ($prefix === true) {
|
||||
$hit_list[$key][] = $hit;
|
||||
} else {
|
||||
$hit_list[] = $hit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $hit_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* correctly recursive merges as an array as array_merge_recursive
|
||||
* just glues things together
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace CoreLibs\Convert;
|
||||
class MimeAppName
|
||||
{
|
||||
/** @var array<string,string> */
|
||||
private static $mime_apps = [];
|
||||
private static array $mime_apps = [];
|
||||
|
||||
/**
|
||||
* constructor: init mime list
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace CoreLibs\Create;
|
||||
class Email
|
||||
{
|
||||
/** @var array<string> 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<string> */
|
||||
$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' ?
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Create uniqIds
|
||||
*
|
||||
* If convert ID to hash:
|
||||
* https://github.com/vinkla/hashids
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Create;
|
||||
@@ -7,10 +14,39 @@ namespace CoreLibs\Create;
|
||||
class Uids
|
||||
{
|
||||
// what to use as a default hash if non ise set and no DEFAULT_HASH is defined
|
||||
public const DEFAULT_HASH = 'sha256';
|
||||
|
||||
/** @var int */
|
||||
public const DEFAULT_UNNIQ_ID_LENGTH = 64;
|
||||
/** @var string */
|
||||
public const STANDARD_HASH_LONG = 'ripemd160';
|
||||
/** @var string */
|
||||
public const STANDARD_HASH_SHORT = 'adler32';
|
||||
|
||||
/**
|
||||
* Create unique id, lower length is for
|
||||
*
|
||||
* @param int $length Length for uniq id, min is 4 characters
|
||||
* Uneven lengths will return lower bound (9 -> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,16 +39,16 @@ class ArrayIO extends \CoreLibs\DB\IO
|
||||
{
|
||||
// main calss variables
|
||||
/** @var array<mixed> */
|
||||
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<mixed> $db_config db connection config
|
||||
* @param array<mixed> $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;
|
||||
}
|
||||
|
||||
|
||||
383
src/DB/IO.php
383
src/DB/IO.php
@@ -298,112 +298,107 @@ 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<mixed> */
|
||||
private $params; // current params for query
|
||||
private string $to_encoding = '';
|
||||
/** @var string the query string at the moment */
|
||||
private string $query;
|
||||
/** @var array<mixed> 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<mixed,mixed> */
|
||||
private $cursor_ext; // hash of hashes
|
||||
/** @var array<string,mixed> 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<string> array with the field names of the current query */
|
||||
private $field_names = [];
|
||||
private array $field_names = [];
|
||||
/** @var array<string> field type names */
|
||||
private $field_types = [];
|
||||
/** @var array<mixed> */
|
||||
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<mixed> 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<mixed> 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<mixed> */
|
||||
private $query_called = [];
|
||||
private array $query_called = [];
|
||||
// error string
|
||||
/** @var array<mixed> */
|
||||
protected $error_string = [];
|
||||
protected array $error_string = [];
|
||||
// prepared list
|
||||
/** @var array<mixed> */
|
||||
private $prepare_cursor = [];
|
||||
private array $prepare_cursor = [];
|
||||
// primary key per table list
|
||||
// format is 'table' => 'pk_name'
|
||||
/** @var array<mixed> */
|
||||
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<mixed> $db_config DB configuration array
|
||||
* @param \CoreLibs\Debug\Logging $log Logging class
|
||||
* @param bool|null $db_debug_override Overrides debug settings in db_config
|
||||
* @param \CoreLibs\Logging\Logging $log Logging class
|
||||
*/
|
||||
public function __construct(
|
||||
array $db_config,
|
||||
\CoreLibs\Debug\Logging $log,
|
||||
?bool $db_debug_override = null
|
||||
\CoreLibs\Logging\Logging $log
|
||||
) {
|
||||
// attach logger
|
||||
$this->log = $log;
|
||||
@@ -420,15 +415,10 @@ class IO
|
||||
$this->db_ssl = !empty($db_config['db_ssl']) ? $db_config['db_ssl'] : 'allow';
|
||||
// set debug, either via global var, or from config, else set to false
|
||||
$this->dbSetDebug(
|
||||
// override
|
||||
$db_debug_override ??
|
||||
// from db config setting
|
||||
$db_config['db_debug'] ??
|
||||
// [DEPRECATED] should be handled from outside
|
||||
$_SESSION['DB_DEBUG'] ??
|
||||
// [DEPRECATED] globals should be deprecated
|
||||
$GLOBALS['DB_DEBUG'] ??
|
||||
false
|
||||
// set if logging level is Debug
|
||||
$this->log->getLoggingLevel()->includes(
|
||||
\CoreLibs\Logging\Logger\Level::Debug
|
||||
)
|
||||
);
|
||||
|
||||
// set loop protection max count
|
||||
@@ -667,6 +657,8 @@ class IO
|
||||
|
||||
/**
|
||||
* calls the basic class debug with strip command
|
||||
* for internal calls, will always create a message
|
||||
*
|
||||
* @param string $debug_id group id for debug
|
||||
* @param string $error_string error message or debug data
|
||||
* @param string $id db debug group
|
||||
@@ -675,7 +667,7 @@ class IO
|
||||
* Will be printed after main error string
|
||||
* @return void
|
||||
*/
|
||||
protected function __dbDebug(
|
||||
private function __dbDebugMessage(
|
||||
string $debug_id,
|
||||
string $error_string,
|
||||
string $id = '',
|
||||
@@ -685,28 +677,62 @@ class IO
|
||||
// NOTE prefix allows html for echo output, will be stripped on file print
|
||||
$prefix = '';
|
||||
if ($id) {
|
||||
$prefix .= '[<span style="color: #920069;">' . $id . '</span>] ';
|
||||
$prefix .= '[' . $id . '] ';
|
||||
}
|
||||
if ($type) {
|
||||
$prefix .= '{<span style="font-style: italic; color: #3f0092;">' . $type . '</span>} ';
|
||||
$prefix .= '{' . $type . '} ';
|
||||
}
|
||||
switch ($id) {
|
||||
case 'DB_ERROR':
|
||||
$prefix .= '<span style="color: red;"><b>DB-Error</b>:</span>';
|
||||
$prefix .= 'DB-Error:';
|
||||
break;
|
||||
case 'DB_WARNING':
|
||||
$prefix .= '<span style="color: orange;"><b>DB-Warning</b>:</span>';
|
||||
$prefix .= 'DB-Warning:';
|
||||
break;
|
||||
}
|
||||
if ($prefix) {
|
||||
$prefix .= '- ';
|
||||
}
|
||||
if ($error_data !== []) {
|
||||
$error_string .= '<br>['
|
||||
. $this->log->prAr($error_data)
|
||||
$error_string .= "\n" . '['
|
||||
. \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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* main call from anywhere in all classes for launching debug messages
|
||||
* will abort if dbDebug not set
|
||||
*
|
||||
* @param string $debug_id group id for debug
|
||||
* @param string $error_string error message or debug data
|
||||
* @param string $id db debug group
|
||||
* @param string $type query identifier (Q, I, etc)
|
||||
* @param array<mixed> $error_data Optional error data as array
|
||||
* @return void
|
||||
*/
|
||||
protected function __dbDebug(
|
||||
string $debug_id,
|
||||
string $error_string,
|
||||
string $id = '',
|
||||
string $type = '',
|
||||
array $error_data = []
|
||||
): void {
|
||||
if (!$this->dbGetDebug()) {
|
||||
return;
|
||||
}
|
||||
$this->__dbDebugMessage($debug_id, $error_string, $id, $type, $error_data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -735,7 +761,10 @@ class IO
|
||||
*/
|
||||
private function __dbErrorPreprocessor(\PgSql\Result|false $cursor = false): array
|
||||
{
|
||||
$pg_error_string = '';
|
||||
$db_prefix = '';
|
||||
$db_error_string = '';
|
||||
$db_prefix_last = '';
|
||||
$db_error_string_last = '';
|
||||
// 1 = self/__dbErrorPreprocessor, 2 = __dbError, __dbWarning,
|
||||
// 3+ == actual source
|
||||
// loop until we get a null, build where called chain
|
||||
@@ -749,16 +778,31 @@ class IO
|
||||
if ($where_called === null) {
|
||||
$where_called = '[Unknown Method]';
|
||||
}
|
||||
[$db_prefix_last, $db_error_string_last] = $this->db_functions->__dbPrintLastError();
|
||||
if ($cursor !== false) {
|
||||
$pg_error_string = $this->db_functions->__dbPrintError($cursor);
|
||||
[$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError($cursor);
|
||||
}
|
||||
if ($cursor === false && method_exists($this->db_functions, '__dbPrintError')) {
|
||||
$pg_error_string = $this->db_functions->__dbPrintError();
|
||||
[$db_prefix, $db_error_string] = $this->db_functions->__dbPrintError();
|
||||
}
|
||||
if ($pg_error_string) {
|
||||
$this->__dbDebug('db', $pg_error_string, 'DB_ERROR', $where_called);
|
||||
// prefix the master if not the same
|
||||
if (
|
||||
!empty($db_error_string_last) &&
|
||||
trim($db_error_string) != trim($db_error_string_last)
|
||||
) {
|
||||
$db_error_string =
|
||||
$db_prefix_last . ' ' . $db_error_string_last . ';'
|
||||
. $db_prefix . ' ' . $db_error_string;
|
||||
} elseif (!empty($db_error_string)) {
|
||||
$db_error_string = $db_prefix . ' ' . $db_error_string;
|
||||
}
|
||||
return [$where_called, $pg_error_string];
|
||||
if ($db_error_string) {
|
||||
$this->__dbDebugMessage('db', $db_error_string, 'DB_ERROR', $where_called);
|
||||
}
|
||||
return [
|
||||
$where_called,
|
||||
$db_error_string
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -810,7 +854,7 @@ class IO
|
||||
$error_id = (string)$error_id;
|
||||
[$where_called, $pg_error_string] = $this->__dbErrorPreprocessor($cursor);
|
||||
// write error msg ...
|
||||
$this->__dbDebug(
|
||||
$this->__dbDebugMessage(
|
||||
'db',
|
||||
$error_id . ': ' . ($this->error_string[$error_id] ?? '[UNKNOWN ERROR]')
|
||||
. ($msg ? ', ' . $msg : ''),
|
||||
@@ -836,7 +880,7 @@ class IO
|
||||
): void {
|
||||
$warning_id = (string)$warning_id;
|
||||
[$where_called, $pg_error_string] = $this->__dbErrorPreprocessor($cursor);
|
||||
$this->__dbDebug(
|
||||
$this->__dbDebugMessage(
|
||||
'db',
|
||||
$warning_id . ': ' . ($this->error_string[$warning_id] ?? '[UNKNOWN WARNING')
|
||||
. ($msg ? ', ' . $msg : ''),
|
||||
@@ -902,11 +946,14 @@ class IO
|
||||
// because the placeholders start with $ and at 1,
|
||||
// we need to increase each key and prefix it with a $ char
|
||||
for ($i = 0, $iMax = count($keys); $i < $iMax; $i++) {
|
||||
$keys[$i] = '$' . ($keys[$i] + 1);
|
||||
// note: if I use $ here, the str_replace will
|
||||
// replace it again. eg $11 '$1'1would be replaced with $1 again
|
||||
// prefix data set with parameter pos
|
||||
$data[$i] = $keys[$i] . ':' . ($data[$i] === null ?
|
||||
$data[$i] = '#' . ($keys[$i] + 1) . ':' . ($data[$i] === null ?
|
||||
'"NULL"' : (string)$data[$i]
|
||||
);
|
||||
// search part
|
||||
$keys[$i] = '$' . ($keys[$i] + 1);
|
||||
}
|
||||
// simply replace the $1, $2, ... with the actual data and return it
|
||||
return str_replace(
|
||||
@@ -1138,17 +1185,15 @@ class IO
|
||||
}
|
||||
// $this->debug('DB IO', 'Q: '.$this->query.', RETURN: '.$this->returning_id);
|
||||
// for DEBUG, only on first time ;)
|
||||
if ($this->db_debug) {
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->query,
|
||||
$this->params
|
||||
),
|
||||
'__dbPrepareExec',
|
||||
($this->params === [] ? 'Q' : 'Qp'),
|
||||
);
|
||||
}
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->query,
|
||||
$this->params
|
||||
),
|
||||
'__dbPrepareExec',
|
||||
($this->params === [] ? 'Q' : 'Qp')
|
||||
);
|
||||
// import protection, hash needed
|
||||
$query_hash = $this->dbGetQueryHash($this->query, $this->params);
|
||||
// if the array index does not exists set it 0
|
||||
@@ -1166,7 +1211,15 @@ class IO
|
||||
$this->query_called[$query_hash] > $this->MAX_QUERY_CALL
|
||||
) {
|
||||
$this->__dbError(30, false, $this->query);
|
||||
$this->__dbDebug('db', $this->query, 'dbExec', 'Q[nc]');
|
||||
$this->__dbDebugMessage(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->query,
|
||||
$this->params
|
||||
),
|
||||
'dbExec',
|
||||
($this->params === [] ? 'Q[nc]' : 'Qp[nc]')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$this->query_called[$query_hash] ++;
|
||||
@@ -1186,9 +1239,7 @@ class IO
|
||||
// if either the cursor is false
|
||||
if ($this->cursor === false || $this->db_functions->__dbLastErrorQuery()) {
|
||||
// printout Query if debug is turned on
|
||||
if ($this->db_debug) {
|
||||
$this->__dbDebug('db', $this->query, 'dbExec', 'Q[nc]');
|
||||
}
|
||||
$this->__dbDebug('db', $this->query, 'dbExec', 'Q[nc]');
|
||||
// internal error handling
|
||||
$this->__dbError(13, $this->cursor);
|
||||
return false;
|
||||
@@ -1216,7 +1267,7 @@ class IO
|
||||
// ONLY insert with set pk name
|
||||
($this->__checkQueryForInsert($this->query, true) && $this->pk_name != 'NULL') ||
|
||||
// insert or update with returning add
|
||||
($this->__checkQueryForInsert($this->query) && $this->returning_id)
|
||||
($this->__checkQueryForInsert($this->query) && $this->returning_id)
|
||||
) {
|
||||
$this->__dbSetInsertId(
|
||||
$this->returning_id,
|
||||
@@ -1337,7 +1388,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
|
||||
@@ -1421,10 +1475,11 @@ class IO
|
||||
$string .= 'at host {b}\'' . $this->db_host . '\'{/b} ';
|
||||
$string .= 'on port {b}\'' . $this->db_port . '\'{/b} ';
|
||||
$string .= 'with ssl mode {b}\'' . $this->db_ssl . '\'{/b}{br}';
|
||||
$string .= '{b}-DB-info->{/b} DB IO Class debug output: {b}' . ($this->db_debug ? 'Yes' : 'No') . '{/b}';
|
||||
$string .= '{b}-DB-info->{/b} DB IO Class debug output: {b}'
|
||||
. ($this->dbGetDebug() ? 'Yes' : 'No') . '{/b}';
|
||||
if ($log === true) {
|
||||
// if debug, remove / change b
|
||||
$this->__dbDebug('db', str_replace(
|
||||
$this->__dbDebugMessage('db', str_replace(
|
||||
$html_tags,
|
||||
$replace_text,
|
||||
$string
|
||||
@@ -1566,7 +1621,7 @@ class IO
|
||||
if (is_array($array)) {
|
||||
$this->nbsp = '';
|
||||
$string .= $this->__printArray($array);
|
||||
$this->__dbDebug('db', $string, 'dbDumpData');
|
||||
$this->__dbDebugMessage('db', $string, 'dbDumpData');
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
@@ -1945,6 +2000,16 @@ class IO
|
||||
// check if params count matches
|
||||
// checks if the params count given matches the expected count
|
||||
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
|
||||
// in case we got an error print out query
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->query,
|
||||
$this->params
|
||||
),
|
||||
'dbReturn',
|
||||
($this->params === [] ? 'Q[e]' : 'Qp[e]')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// set first call to false
|
||||
@@ -1967,9 +2032,15 @@ class IO
|
||||
if (!$this->cursor_ext[$query_hash]['cursor']) {
|
||||
$this->cursor_ext[$query_hash]['log'][] = 'No cursor';
|
||||
// for DEBUG, print out each query executed
|
||||
if ($this->db_debug) {
|
||||
$this->__dbDebug('db', $this->cursor_ext[$query_hash]['query'], 'dbReturn', 'Q');
|
||||
}
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->cursor_ext[$query_hash]['query'],
|
||||
$this->cursor_ext[$query_hash]['params']
|
||||
),
|
||||
'dbReturn',
|
||||
($this->cursor_ext[$query_hash]['params'] === [] ? 'Q' : 'Qp'),
|
||||
);
|
||||
// if no DB Handler try to reconnect
|
||||
if (!$this->dbh) {
|
||||
// if reconnect fails drop out
|
||||
@@ -1996,9 +2067,15 @@ class IO
|
||||
}
|
||||
// if still no cursor ...
|
||||
if (!$this->cursor_ext[$query_hash]['cursor']) {
|
||||
if ($this->db_debug) {
|
||||
$this->__dbDebug('db', $this->cursor_ext[$query_hash]['query'], 'dbReturn', 'Q');
|
||||
}
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->cursor_ext[$query_hash]['query'],
|
||||
$this->cursor_ext[$query_hash]['params']
|
||||
),
|
||||
'dbReturn',
|
||||
($this->cursor_ext[$query_hash]['params'] === [] ? 'Q[e]' : 'Qp[e]'),
|
||||
);
|
||||
// internal error handling
|
||||
$this->__dbError(13, $this->cursor_ext[$query_hash]['cursor']);
|
||||
return false;
|
||||
@@ -2300,10 +2377,6 @@ class IO
|
||||
$this->__dbError(17, false, $query);
|
||||
return false;
|
||||
}
|
||||
// checks if the params count given matches the expected count
|
||||
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
|
||||
return false;
|
||||
}
|
||||
$cursor = $this->dbExecParams($query, $params);
|
||||
if ($cursor === false) {
|
||||
return false;
|
||||
@@ -2348,10 +2421,6 @@ class IO
|
||||
$this->__dbError(17, false, $query);
|
||||
return false;
|
||||
}
|
||||
// checks if the params count given matches the expected count
|
||||
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
|
||||
return false;
|
||||
}
|
||||
$cursor = $this->dbExecParams($query, $params);
|
||||
if ($cursor === false) {
|
||||
return false;
|
||||
@@ -2661,6 +2730,15 @@ class IO
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->prepare_cursor[$stm_name]['query'],
|
||||
$data
|
||||
),
|
||||
'dbExecPrep',
|
||||
'Qpe'
|
||||
);
|
||||
// if the count does not match
|
||||
if ($this->prepare_cursor[$stm_name]['count'] != count($data)) {
|
||||
$this->__dbError(
|
||||
@@ -2673,22 +2751,11 @@ class IO
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($this->db_debug) {
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
$this->__dbDebugPrepare(
|
||||
$this->prepare_cursor[$stm_name]['query'],
|
||||
$data
|
||||
),
|
||||
'dbExecPrep',
|
||||
'Qp'
|
||||
);
|
||||
}
|
||||
$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'],
|
||||
@@ -3056,16 +3123,13 @@ class IO
|
||||
|
||||
/**
|
||||
* switches the debug flag on or off
|
||||
* if none given, then return current set only
|
||||
* @param bool|null $debug true/false or null for just getting current set
|
||||
* @return bool Current debug flag as set
|
||||
*
|
||||
* @param bool $debug True/False to turn debugging in this calss on or off
|
||||
* @return void
|
||||
*/
|
||||
public function dbSetDebug(?bool $debug = null): bool
|
||||
public function dbSetDebug(bool $debug): void
|
||||
{
|
||||
if ($debug !== null) {
|
||||
$this->db_debug = $debug;
|
||||
}
|
||||
return $this->db_debug;
|
||||
$this->db_debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3073,9 +3137,11 @@ class IO
|
||||
* OR
|
||||
* with the optional parameter fix sets debug
|
||||
* returns current set stats
|
||||
*
|
||||
* @param bool|null $debug Flag to turn debug on off or null for toggle
|
||||
* @return bool Current debug status
|
||||
* True for debug is on, False for off
|
||||
* @deprecated Use dbSetDebug and dbGetDebug
|
||||
*/
|
||||
public function dbToggleDebug(?bool $debug = null): bool
|
||||
{
|
||||
@@ -3089,6 +3155,7 @@ class IO
|
||||
|
||||
/**
|
||||
* Return current set db debug flag status
|
||||
*
|
||||
* @return bool Current debug status
|
||||
*/
|
||||
public function dbGetDebug(): bool
|
||||
@@ -3349,6 +3416,9 @@ class IO
|
||||
*/
|
||||
public function dbGetInsertPKName(): string
|
||||
{
|
||||
if (!isset($this->insert_id_pk_name)) {
|
||||
return '';
|
||||
}
|
||||
return (string)$this->insert_id_pk_name;
|
||||
}
|
||||
|
||||
@@ -3457,6 +3527,9 @@ class IO
|
||||
*/
|
||||
public function dbGetNumFields(): ?int
|
||||
{
|
||||
if (!isset($this->num_fields)) {
|
||||
return null;
|
||||
}
|
||||
return $this->num_fields;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,10 +209,17 @@ interface SqlFunctions
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param \PgSql\Result|false $cursor
|
||||
* @return string
|
||||
* @return array{0:string,1:string}
|
||||
*/
|
||||
public function __dbPrintError(\PgSql\Result|false $cursor = false): string;
|
||||
public function __dbPrintLastError(): array;
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param \PgSql\Result|false $cursor
|
||||
* @return array{0:string,1:string}
|
||||
*/
|
||||
public function __dbPrintError(\PgSql\Result|false $cursor = false): array;
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
|
||||
@@ -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;
|
||||
private \PgSql\Connection|false $dbh = false;
|
||||
|
||||
/**
|
||||
* queries last error query and returns true or false if error was set
|
||||
@@ -532,18 +532,37 @@ class PgSQL implements Interface\SqlFunctions
|
||||
return $this->dbh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last error for active cursor
|
||||
*
|
||||
* @return array{0:string,1:string} prefix, error string
|
||||
*/
|
||||
public function __dbPrintLastError(): array
|
||||
{
|
||||
if (is_bool($this->dbh)) {
|
||||
return ['', ''];
|
||||
}
|
||||
if (!empty($error_message = pg_last_error($this->dbh))) {
|
||||
return [
|
||||
'-PostgreSQL-Error-Last-',
|
||||
$error_message
|
||||
];
|
||||
}
|
||||
return ['', ''];
|
||||
}
|
||||
|
||||
/**
|
||||
* reads the last error for this cursor and returns
|
||||
* html formatted string with error name
|
||||
*
|
||||
* @param \PgSql\Result|false $cursor cursor
|
||||
* or null
|
||||
* @return string error string
|
||||
* or null
|
||||
* @return array{0:string,1:string} prefix, error string
|
||||
*/
|
||||
public function __dbPrintError(\PgSql\Result|false $cursor = false): string
|
||||
public function __dbPrintError(\PgSql\Result|false $cursor = false): array
|
||||
{
|
||||
if (is_bool($this->dbh)) {
|
||||
return '';
|
||||
return ['', ''];
|
||||
}
|
||||
// run the query again for the error result here
|
||||
if ((is_bool($cursor)) && $this->last_error_query) {
|
||||
@@ -552,10 +571,12 @@ class PgSQL implements Interface\SqlFunctions
|
||||
$cursor = pg_get_result($this->dbh);
|
||||
}
|
||||
if ($cursor && $error_str = pg_result_error($cursor)) {
|
||||
return '-PostgreSQL-Error- '
|
||||
. $error_str;
|
||||
return [
|
||||
'-PostgreSQL-Error-',
|
||||
$error_str
|
||||
];
|
||||
} else {
|
||||
return '';
|
||||
return ['', ''];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,895 +1,26 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Debug support functions
|
||||
*
|
||||
* These are if there is any debug to print out at all at the end
|
||||
* debug_output_all - general yes no
|
||||
* It's recommended to use the method "debug_for" to turn on of the array vars
|
||||
* debug_output - turn on for one level (Array)
|
||||
* debug_output_not - turn off for one level (array)
|
||||
*
|
||||
* Print out the debug at thend of the html
|
||||
* echo_output_all
|
||||
* echo_output
|
||||
* echo_output_not
|
||||
*
|
||||
* Write debug to file
|
||||
* print_output_all
|
||||
* print_output
|
||||
* print_output_not
|
||||
* This is a wrapper placeholder for
|
||||
* \CoreLibs\Logging\Logger
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Debug;
|
||||
|
||||
use CoreLibs\Debug\Support;
|
||||
use CoreLibs\Create\Uids;
|
||||
use CoreLibs\Get\System;
|
||||
use CoreLibs\Convert\Html;
|
||||
|
||||
class Logging
|
||||
/**
|
||||
* @deprecated Use \CoreLibs\Logger\Logging
|
||||
*/
|
||||
class Logging extends \CoreLibs\Logging\Logging
|
||||
{
|
||||
// options
|
||||
/** @var array<mixed> */
|
||||
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<mixed> */
|
||||
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<mixed> */
|
||||
private $debug_output = []; // if this is true, show debug on desconstructor
|
||||
/** @var array<mixed> */
|
||||
private $debug_output_not = [];
|
||||
/** @var bool */
|
||||
private $debug_output_all = false;
|
||||
/** @var array<mixed> */
|
||||
private $echo_output = []; // errors: echo out, default is 1
|
||||
/** @var array<mixed> */
|
||||
private $echo_output_not = [];
|
||||
/** @var bool */
|
||||
private $echo_output_all = false;
|
||||
/** @var array<mixed> */
|
||||
private $print_output = []; // errors: print to file, default is 0
|
||||
/** @var array<mixed> */
|
||||
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<mixed> $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 "<!-- could not open file: " . $this->log_file_name . " //-->";
|
||||
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<mixed> $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<mixed>|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 <pre></pre>
|
||||
* 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<mixed> $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 <br> 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 <br> and replace them with \n
|
||||
// strip rest of html elements (base only)
|
||||
preg_replace(
|
||||
"/(<\/?)(\w+)([^>]*>)/",
|
||||
'',
|
||||
str_replace('<br>', "\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][] = '<div>'
|
||||
. '[<span style="font-weight: bold; color: #5e8600;">' . $timestamp . '</span>] '
|
||||
. '[<span style="font-weight: bold; color: #c56c00;">' . $level . '</span>] '
|
||||
. '[<span style="color: #b000ab;">' . $this->host_name . '</span>] '
|
||||
. '[<span style="color: #08b369;">' . $this->page_name . '</span>] '
|
||||
. '[<span style="color: #0062A2;">' . $this->running_uid . '</span>] '
|
||||
. '{<span style="font-style: italic; color: #928100;">' . $class . '</span>} - '
|
||||
// as is prefix, allow HTML
|
||||
. $prefix
|
||||
// we replace special HTMLPRE with <pre> entries
|
||||
. str_replace(
|
||||
['##HTMLPRE##', '##/HTMLPRE##'],
|
||||
['<pre>', '</pre>'],
|
||||
Html::htmlent($string)
|
||||
)
|
||||
. "</div><!--#BR#-->";
|
||||
$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 .= '<div style="font-size: 12px;">'
|
||||
. '[<span style="font-style: italic; color: #c56c00;">' . $level . '</span>] '
|
||||
. ($header_prefix ? "<b>**** " . Html::htmlent($header_prefix) . " ****</br>\n" : '')
|
||||
. '</div>'
|
||||
. 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 = '<div style="text-align: left; padding: 5px; font-size: 10px; '
|
||||
. 'font-family: sans-serif; border-top: 1px solid black; '
|
||||
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
|
||||
. 'background-color: white; color: black;">'
|
||||
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
|
||||
. Support::getCallerClass() . '</span>}</div>';
|
||||
$string_output = $string_prefix . $string_output
|
||||
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
|
||||
. $script_end . '</div>'
|
||||
. '</div>';
|
||||
}
|
||||
// }
|
||||
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<mixed> 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<mixed> $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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
911
src/Debug/LoggingLegacy.php
Normal file
911
src/Debug/LoggingLegacy.php
Normal file
@@ -0,0 +1,911 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* THIS IS LEGACY LOGGING AND WILL BE FULLY REMOVED IN FUTURE VERSION.
|
||||
* use \CoreLibs\Logger\Logging instead
|
||||
* for the need to reference old:
|
||||
* use CoreLibs\Debug\LoggingLegacy as Logging;
|
||||
*/
|
||||
|
||||
/*
|
||||
* Debug support functions
|
||||
*
|
||||
* These are if there is any debug to print out at all at the end
|
||||
* debug_output_all - general yes no
|
||||
* It's recommended to use the method "debug_for" to turn on of the array vars
|
||||
* debug_output - turn on for one level (Array)
|
||||
* debug_output_not - turn off for one level (array)
|
||||
*
|
||||
* Print out the debug at thend of the html
|
||||
* echo_output_all
|
||||
* echo_output
|
||||
* echo_output_not
|
||||
*
|
||||
* Write debug to file
|
||||
* print_output_all
|
||||
* print_output
|
||||
* print_output_not
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Debug;
|
||||
|
||||
use CoreLibs\Debug\Support;
|
||||
use CoreLibs\Create\Uids;
|
||||
use CoreLibs\Get\System;
|
||||
use CoreLibs\Convert\Html;
|
||||
|
||||
class LoggingLegacy
|
||||
{
|
||||
// options
|
||||
/** @var array<mixed> */
|
||||
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<mixed> */
|
||||
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<mixed> */
|
||||
private $debug_output = []; // if this is true, show debug on desconstructor
|
||||
/** @var array<mixed> */
|
||||
private $debug_output_not = [];
|
||||
/** @var bool */
|
||||
private $debug_output_all = false;
|
||||
/** @var array<mixed> */
|
||||
private $echo_output = []; // errors: echo out, default is 1
|
||||
/** @var array<mixed> */
|
||||
private $echo_output_not = [];
|
||||
/** @var bool */
|
||||
private $echo_output_all = false;
|
||||
/** @var array<mixed> */
|
||||
private $print_output = []; // errors: print to file, default is 0
|
||||
/** @var array<mixed> */
|
||||
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<mixed> $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 "<!-- could not open file: " . $this->log_file_name . " //-->";
|
||||
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<mixed> $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<mixed>|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 <pre></pre>
|
||||
* 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<mixed> $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 <br> 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 <br> and replace them with \n
|
||||
// strip rest of html elements (base only)
|
||||
preg_replace(
|
||||
"/(<\/?)(\w+)([^>]*>)/",
|
||||
'',
|
||||
str_replace('<br>', "\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][] = '<div>'
|
||||
. '[<span style="font-weight: bold; color: #5e8600;">' . $timestamp . '</span>] '
|
||||
. '[<span style="font-weight: bold; color: #c56c00;">' . $level . '</span>] '
|
||||
. '[<span style="color: #b000ab;">' . $this->host_name . '</span>] '
|
||||
. '[<span style="color: #08b369;">' . $this->page_name . '</span>] '
|
||||
. '[<span style="color: #0062A2;">' . $this->running_uid . '</span>] '
|
||||
. '{<span style="font-style: italic; color: #928100;">' . $class . '</span>} - '
|
||||
// as is prefix, allow HTML
|
||||
. $prefix
|
||||
// we replace special HTMLPRE with <pre> entries
|
||||
. str_replace(
|
||||
['##HTMLPRE##', '##/HTMLPRE##'],
|
||||
['<pre>', '</pre>'],
|
||||
Html::htmlent($string)
|
||||
)
|
||||
. "</div><!--#BR#-->";
|
||||
$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 .= '<div style="font-size: 12px;">'
|
||||
. '[<span style="font-style: italic; color: #c56c00;">' . $level . '</span>] '
|
||||
. ($header_prefix ? "<b>**** " . Html::htmlent($header_prefix) . " ****</br>\n" : '')
|
||||
. '</div>'
|
||||
. 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 = '<div style="text-align: left; padding: 5px; font-size: 10px; '
|
||||
. 'font-family: sans-serif; border-top: 1px solid black; '
|
||||
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
|
||||
. 'background-color: white; color: black;">'
|
||||
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
|
||||
. Support::getCallerClass() . '</span>}</div>';
|
||||
$string_output = $string_prefix . $string_output
|
||||
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
|
||||
. $script_end . '</div>'
|
||||
. '</div>';
|
||||
}
|
||||
// }
|
||||
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<mixed> 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<mixed> $error_msg error array
|
||||
* @return void has no return
|
||||
*/
|
||||
public function mergeErrors(array $error_msg = []): void
|
||||
{
|
||||
array_push($this->error_msg, ...$error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
@@ -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
|
||||
|
||||
@@ -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 ? ', ' : '<br>');
|
||||
// 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: ' : "<b>Script running time</b>: ") . $running_time . " s";
|
||||
// reset start & end time after run
|
||||
|
||||
@@ -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) {
|
||||
@@ -34,31 +34,43 @@ class Support
|
||||
}
|
||||
|
||||
/**
|
||||
* prints a html formatted (pre) array
|
||||
* prints a html formatted (pre) data
|
||||
*
|
||||
* @param array<mixed> $array any array
|
||||
* @param bool $no_html set to true to use ##HTMLPRE##
|
||||
* @return string formatted array for output with <pre> tag added
|
||||
* @param mixed $data any data
|
||||
* @param bool $no_html default add <pre>
|
||||
* @return string formatted array for output with <pre> tag added
|
||||
*/
|
||||
public static function printAr(array $array, bool $no_html = false): string
|
||||
public static function printAr(mixed $data, bool $no_html = false): string
|
||||
{
|
||||
if ($no_html === false) {
|
||||
return "<pre>" . print_r($array, true) . "</pre>";
|
||||
} else {
|
||||
return '##HTMLPRE##' . print_r($array, true) . '##/HTMLPRE##';
|
||||
}
|
||||
return $no_html ?
|
||||
print_r($data, true) :
|
||||
'<pre>' . print_r($data, true) . '</pre>';
|
||||
}
|
||||
|
||||
/**
|
||||
* alternate name for printAr function
|
||||
*
|
||||
* @param array<mixed> $array any array
|
||||
* @param bool $no_html set to true to use ##HTMLPRE##
|
||||
* @return string formatted array for output with <pre> tag added
|
||||
* @param mixed $data any array
|
||||
* @param bool $no_html default add <pre>
|
||||
* @return string formatted array for output with <pre> tag added
|
||||
*/
|
||||
public static function printArray(array $array, bool $no_html = false): string
|
||||
public static function printArray(mixed $data, bool $no_html = false): string
|
||||
{
|
||||
return self::printAr($array, $no_html);
|
||||
return self::printAr($data, $no_html);
|
||||
}
|
||||
|
||||
/**
|
||||
* A replacement for the \CoreLibs\Debug\Support::printAr
|
||||
* But this does not wrap it in <pre></pre>
|
||||
* Do not use this without using it in a string in debug function
|
||||
* Note: for full data debug dumps use Support::dumpVar()
|
||||
*
|
||||
* @param mixed $data Data to print
|
||||
* @return string print_r formated
|
||||
*/
|
||||
public static function prAr(mixed $data): string
|
||||
{
|
||||
return self::printAr($data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,21 +78,42 @@ class Support
|
||||
* 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 : '<b>' . $name . '</b>') . ': '
|
||||
: '')
|
||||
. ($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) ? '<b>' . $name . '</b>: ' : '')
|
||||
. ($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 <pre> tags
|
||||
* @return string
|
||||
*/
|
||||
public static function printToString(mixed $mixed, bool $no_html = false): string
|
||||
@@ -119,12 +153,92 @@ 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') {
|
||||
$caller_level = 2;
|
||||
}
|
||||
// we need to strip the string in <small></small that is
|
||||
// "path ... CoreLibs/Debug/Support.php:<number>:
|
||||
// and replace it with the caller methods and location
|
||||
$caller_file_number = self::getCallerFileLine($caller_level);
|
||||
$debug_dump = preg_replace(
|
||||
'|<small>(/.*:\d+:)</small>|',
|
||||
'<small>' . $caller_file_number . ':</small>',
|
||||
$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 <pre> tags
|
||||
* @return string A text string
|
||||
*/
|
||||
public static function exportVar(mixed $data, bool $no_html = false): string
|
||||
{
|
||||
return $no_html ?
|
||||
var_export($data, true) :
|
||||
'<pre>' . var_export($data, true) . '</pre>';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
@@ -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<mixed> 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];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<mixed>|null */
|
||||
private $table_originals = null; // table for original strings (offsets)
|
||||
private array|null $table_originals = null; // table for original strings (offsets)
|
||||
/** @var array<mixed>|null */
|
||||
private $table_translations = null; // table for translated strings (offsets)
|
||||
private array|null $table_translations = null; // table for translated strings (offsets)
|
||||
/** @var array<mixed> */
|
||||
private $cache_translations = []; // original -> translation mapping
|
||||
private array $cache_translations = []; // original -> translation mapping
|
||||
|
||||
/* Methods */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<string,array<string,GetTextReader>> locale > domain = translator */
|
||||
private $domains = [];
|
||||
private array $domains = [];
|
||||
/** @var array<string,string> 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);
|
||||
}
|
||||
|
||||
107
src/Logging/Logger/Flag.php
Normal file
107
src/Logging/Logger/Flag.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/5/29
|
||||
* DESCRIPTION:
|
||||
* Logging options flags for output file name building
|
||||
*
|
||||
* per_run: and timestamp + uid will be added
|
||||
* per_date: ymd will be added (per_run > 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__
|
||||
216
src/Logging/Logger/Level.php
Normal file
216
src/Logging/Logger/Level.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php // phpcs:disable Generic.Files.LineLength
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023-05-25
|
||||
* DESCRIPTION:
|
||||
* Debug levels
|
||||
*
|
||||
* They are based on the Mono log ones
|
||||
* FC 5424 {@see https://datatracker.ietf.org/doc/html/rfc5424}
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Logging\Logger;
|
||||
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* Represents the log levels
|
||||
*
|
||||
* Monolog supports the logging levels described by RFC 5424 {@see https://datatracker.ietf.org/doc/html/rfc5424}
|
||||
* but due to BC the severity values used internally are not 0-7.
|
||||
*
|
||||
* To get the level name/value out of a Level there are several options:
|
||||
*
|
||||
* - Use ->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<self::NAMES>|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<self::VALUES> $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<self::NAMES>
|
||||
*/
|
||||
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__
|
||||
1336
src/Logging/Logging.php
Normal file
1336
src/Logging/Logging.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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<mixed> */
|
||||
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 _<type>) [used for order button]
|
||||
public string $col_name; // the name of the columen (before _<type>) [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 = 0; // 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 = 0; // the error flag set for printing red error msg
|
||||
/** @var int */
|
||||
public $warning; // warning flag, for information (saved, loaded, etc)
|
||||
public int $warning = 0; // 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<mixed> */
|
||||
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<mixed> */
|
||||
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<mixed> */
|
||||
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<mixed> */
|
||||
public $security_level;
|
||||
public array $security_level;
|
||||
/** @var array<string,mixed> Login ACL */
|
||||
public $login_acl = [];
|
||||
public array $login_acl = [];
|
||||
// layout publics
|
||||
/** @var int */
|
||||
public $table_width;
|
||||
public int $table_width = 0;
|
||||
// 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<mixed> */
|
||||
public $language_array = [];
|
||||
public array $language_array = [];
|
||||
|
||||
/**
|
||||
* construct form generator
|
||||
*
|
||||
* @param array<mixed> $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<string,mixed> $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;
|
||||
}
|
||||
|
||||
@@ -1954,7 +1955,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
|
||||
if ($this->table_array[$key]['value']) {
|
||||
// use the better new passwordSet instead of crypt based
|
||||
$this->table_array[$key]['value'] =
|
||||
\CoreLibs\Check\Password::passwordSet($this->table_array[$key]['value']);
|
||||
\CoreLibs\Security\Password::passwordSet($this->table_array[$key]['value']);
|
||||
$this->table_array[$key]['HIDDEN_value'] = $this->table_array[$key]['value'];
|
||||
} else {
|
||||
// $this->table_array[$key]['HIDDEN_value'] =
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<string,null|int|float> */
|
||||
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<string,string|bool|int> */
|
||||
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
|
||||
|
||||
61
src/Security/CreateKey.php
Normal file
61
src/Security/CreateKey.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* very simple symmetric encryption
|
||||
* better use: https://paragonie.com/project/halite
|
||||
*
|
||||
* this is for creating secret keys for
|
||||
* Security\SymmetricEncryption
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Security;
|
||||
|
||||
class CreateKey
|
||||
{
|
||||
/**
|
||||
* Create a random key that is a hex string
|
||||
*
|
||||
* @return string Hex string key for encrypting
|
||||
*/
|
||||
public static function generateRandomKey(): string
|
||||
{
|
||||
return self::bin2hex(self::randomKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* create a random string as binary to encrypt data
|
||||
* to store it in clear text in some .env file use bin2hex
|
||||
*
|
||||
* @return string Binary string for encryption
|
||||
*/
|
||||
public static function randomKey(): string
|
||||
{
|
||||
return random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert binary key to hex string
|
||||
*
|
||||
* @param string $hex_key Convert binary key string to hex
|
||||
* @return string
|
||||
*/
|
||||
public static function bin2hex(string $hex_key): string
|
||||
{
|
||||
return sodium_bin2hex($hex_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert hex string to binary key
|
||||
*
|
||||
* @param string $string_key Convery hex key string to binary
|
||||
* @return string
|
||||
*/
|
||||
public static function hex2bin(string $string_key): string
|
||||
{
|
||||
return sodium_hex2bin($string_key);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
59
src/Security/Password.php
Normal file
59
src/Security/Password.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* core password set, check and rehash check wrapper functions
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Security;
|
||||
|
||||
class Password
|
||||
{
|
||||
/**
|
||||
* creates the password hash
|
||||
*
|
||||
* @param string $password password
|
||||
* @return string hashed password
|
||||
*/
|
||||
public static function passwordSet(string $password): string
|
||||
{
|
||||
// always use the PHP default for the password
|
||||
// password options ca be set in the password init,
|
||||
// but should be kept as default
|
||||
return password_hash($password, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the entered password matches the hash
|
||||
*
|
||||
* @param string $password password
|
||||
* @param string $hash password hash
|
||||
* @return bool true or false
|
||||
*/
|
||||
public static function passwordVerify(string $password, string $hash): bool
|
||||
{
|
||||
if (password_verify($password, $hash)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if the password needs to be rehashed
|
||||
*
|
||||
* @param string $hash password hash
|
||||
* @return bool true or false
|
||||
*/
|
||||
public static function passwordRehashCheck(string $hash): bool
|
||||
{
|
||||
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
98
src/Security/SymmetricEncryption.php
Normal file
98
src/Security/SymmetricEncryption.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* very simple symmetric encryption
|
||||
* Better use:
|
||||
* https://paragonie.com/project/halite
|
||||
* https://github.com/paragonie/halite
|
||||
*
|
||||
* current code is just to encrypt and decrypt
|
||||
*
|
||||
* must use a valid encryption key created with
|
||||
* Secruty\CreateKey class
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Security;
|
||||
|
||||
use CoreLibs\Security\CreateKey;
|
||||
use SodiumException;
|
||||
|
||||
class SymmetricEncryption
|
||||
{
|
||||
/**
|
||||
* Encrypt a message
|
||||
*
|
||||
* @param string $message Message to encrypt
|
||||
* @param string $key Encryption key (as hex string)
|
||||
* @return string
|
||||
* @throws \RangeException
|
||||
*/
|
||||
public static function encrypt(string $message, string $key): string
|
||||
{
|
||||
try {
|
||||
$key = CreateKey::hex2bin($key);
|
||||
} catch (SodiumException $e) {
|
||||
throw new \Exception('Invalid hex key');
|
||||
}
|
||||
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
|
||||
throw new \RangeException(
|
||||
'Key is not the correct size (must be '
|
||||
. 'SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long).'
|
||||
);
|
||||
}
|
||||
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||
|
||||
$cipher = base64_encode(
|
||||
$nonce
|
||||
. sodium_crypto_secretbox(
|
||||
$message,
|
||||
$nonce,
|
||||
$key
|
||||
)
|
||||
);
|
||||
sodium_memzero($message);
|
||||
sodium_memzero($key);
|
||||
return $cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a message
|
||||
*
|
||||
* @param string $encrypted Message encrypted with safeEncrypt()
|
||||
* @param string $key Encryption key (as hex string)
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function decrypt(string $encrypted, string $key): string
|
||||
{
|
||||
try {
|
||||
$key = CreateKey::hex2bin($key);
|
||||
} catch (SodiumException $e) {
|
||||
throw new \Exception('Invalid hex key');
|
||||
}
|
||||
$decoded = base64_decode($encrypted);
|
||||
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
|
||||
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
|
||||
|
||||
$plain = false;
|
||||
try {
|
||||
$plain = sodium_crypto_secretbox_open(
|
||||
$ciphertext,
|
||||
$nonce,
|
||||
$key
|
||||
);
|
||||
} catch (SodiumException $e) {
|
||||
throw new \Exception('Invalid ciphertext (too short)');
|
||||
}
|
||||
if (!is_string($plain)) {
|
||||
throw new \Exception('Invalid Key');
|
||||
}
|
||||
sodium_memzero($ciphertext);
|
||||
sodium_memzero($key);
|
||||
return $plain;
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
@@ -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<mixed> */
|
||||
public $HEADER = [];
|
||||
public array $HEADER = [];
|
||||
/** @var array<mixed> */
|
||||
public $DATA = [];
|
||||
public array $DATA = [];
|
||||
/** @var array<mixed> */
|
||||
public $DEBUG_DATA = [];
|
||||
public array $DEBUG_DATA = [];
|
||||
/** @var array<mixed> */
|
||||
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)
|
||||
) {
|
||||
@@ -373,7 +373,7 @@ class SmartyExtend extends \Smarty
|
||||
// check for template include
|
||||
if (
|
||||
$this->USE_INCLUDE_TEMPLATE === true &&
|
||||
!$this->TEMPLATE_NAME
|
||||
empty($this->TEMPLATE_NAME)
|
||||
) {
|
||||
$this->TEMPLATE_NAME = $this->CONTENT_INCLUDE;
|
||||
// add to cache & compile id
|
||||
@@ -390,7 +390,7 @@ class SmartyExtend extends \Smarty
|
||||
exit('MASTER TEMPLATE: ' . $this->MASTER_TEMPLATE_NAME . ' could not be found');
|
||||
}
|
||||
if (
|
||||
$this->TEMPLATE_NAME &&
|
||||
!empty($this->TEMPLATE_NAME) &&
|
||||
!file_exists($this->getTemplateDir()[0] . DIRECTORY_SEPARATOR . $this->TEMPLATE_NAME)
|
||||
) {
|
||||
exit('INCLUDE TEMPLATE: ' . $this->TEMPLATE_NAME . ' could not be found');
|
||||
@@ -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,22 +408,27 @@ 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';
|
||||
}
|
||||
}
|
||||
// if we can't find it, dump it
|
||||
if (!file_exists($this->getTemplateDir()[0] . DIRECTORY_SEPARATOR . $this->TEMPLATE_TRANSLATE)) {
|
||||
if (
|
||||
!file_exists(
|
||||
$this->getTemplateDir()[0] . DIRECTORY_SEPARATOR
|
||||
. $this->TEMPLATE_TRANSLATE
|
||||
)
|
||||
) {
|
||||
$this->TEMPLATE_TRANSLATE = null;
|
||||
}
|
||||
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 _<locale>.<encoding>
|
||||
@@ -432,12 +437,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 +680,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 +742,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);
|
||||
|
||||
@@ -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(
|
||||
@@ -267,6 +264,8 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'GROUP_ACL_LEVEL' => -1,
|
||||
'PAGES_ACL_LEVEL' => [],
|
||||
'USER_ACL_LEVEL' => -1,
|
||||
'USER_ADDITIONAL_ACL' => [],
|
||||
'GROUP_ADDITIONAL_ACL' => [],
|
||||
'UNIT_UID' => [
|
||||
'AdminAccess' => 1,
|
||||
],
|
||||
@@ -280,6 +279,7 @@ final class CoreLibsACLLoginTest extends TestCase
|
||||
'data' => [
|
||||
'test' => 'value',
|
||||
],
|
||||
'additional_acl' => []
|
||||
],
|
||||
],
|
||||
// 'UNIT_DEFAULT' => '',
|
||||
|
||||
@@ -31,6 +31,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
|
||||
4,
|
||||
'b',
|
||||
'c' => 'test',
|
||||
'single' => 'single',
|
||||
'same' => 'same',
|
||||
'deep' => [
|
||||
'sub' => [
|
||||
@@ -288,6 +289,188 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function arraySearchKeyProvider(): array
|
||||
{
|
||||
/*
|
||||
0: search in array
|
||||
1: search keys
|
||||
2: flat flag
|
||||
3: prefix flag
|
||||
4: expected array
|
||||
*/
|
||||
return [
|
||||
// single
|
||||
'find single, standard' => [
|
||||
0 => self::$array,
|
||||
1 => ['single'],
|
||||
2 => null,
|
||||
3 => null,
|
||||
4 => [
|
||||
0 => [
|
||||
'value' => 'single',
|
||||
'path' => ['single'],
|
||||
],
|
||||
],
|
||||
],
|
||||
'find single, prefix' => [
|
||||
0 => self::$array,
|
||||
1 => ['single'],
|
||||
2 => null,
|
||||
3 => true,
|
||||
4 => [
|
||||
'single' => [
|
||||
0 => [
|
||||
'value' => 'single',
|
||||
'path' => ['single'],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'find single, flat' => [
|
||||
0 => self::$array,
|
||||
1 => ['single'],
|
||||
2 => true,
|
||||
3 => null,
|
||||
4 => [
|
||||
'single',
|
||||
],
|
||||
],
|
||||
'find single, flat, prefix' => [
|
||||
0 => self::$array,
|
||||
1 => ['single'],
|
||||
2 => true,
|
||||
3 => true,
|
||||
4 => [
|
||||
'single' => [
|
||||
'single',
|
||||
],
|
||||
],
|
||||
],
|
||||
// not found
|
||||
'not found, standard' => [
|
||||
0 => self::$array,
|
||||
1 => ['NOT FOUND'],
|
||||
2 => null,
|
||||
3 => null,
|
||||
4 => [],
|
||||
],
|
||||
'not found, standard, prefix' => [
|
||||
0 => self::$array,
|
||||
1 => ['NOT FOUND'],
|
||||
2 => null,
|
||||
3 => true,
|
||||
4 => [
|
||||
'NOT FOUND' => [],
|
||||
],
|
||||
],
|
||||
'not found, flat' => [
|
||||
0 => self::$array,
|
||||
1 => ['NOT FOUND'],
|
||||
2 => true,
|
||||
3 => null,
|
||||
4 => [],
|
||||
],
|
||||
'not found, flat, prefix' => [
|
||||
0 => self::$array,
|
||||
1 => ['NOT FOUND'],
|
||||
2 => true,
|
||||
3 => true,
|
||||
4 => [
|
||||
'NOT FOUND' => [],
|
||||
],
|
||||
],
|
||||
// multi
|
||||
'multiple found, standard' => [
|
||||
0 => self::$array,
|
||||
1 => ['same'],
|
||||
2 => null,
|
||||
3 => null,
|
||||
4 => [
|
||||
[
|
||||
'value' => 'same',
|
||||
'path' => ['a', 'same', ],
|
||||
],
|
||||
[
|
||||
'value' => 'same',
|
||||
'path' => ['same', ],
|
||||
],
|
||||
[
|
||||
'value' => 'same',
|
||||
'path' => ['deep', 'sub', 'same', ],
|
||||
],
|
||||
]
|
||||
],
|
||||
'multiple found, flat' => [
|
||||
0 => self::$array,
|
||||
1 => ['same'],
|
||||
2 => true,
|
||||
3 => null,
|
||||
4 => ['same', 'same', 'same', ],
|
||||
],
|
||||
// search with multiple
|
||||
'search multiple, standard' => [
|
||||
0 => self::$array,
|
||||
1 => ['single', 'nested'],
|
||||
2 => null,
|
||||
3 => null,
|
||||
4 => [
|
||||
[
|
||||
'value' => 'single',
|
||||
'path' => ['single'],
|
||||
],
|
||||
[
|
||||
'value' => 'bar',
|
||||
'path' => ['deep', 'sub', 'nested', ],
|
||||
],
|
||||
],
|
||||
],
|
||||
'search multiple, prefix' => [
|
||||
0 => self::$array,
|
||||
1 => ['single', 'nested'],
|
||||
2 => null,
|
||||
3 => true,
|
||||
4 => [
|
||||
'single' => [
|
||||
[
|
||||
'value' => 'single',
|
||||
'path' => ['single'],
|
||||
],
|
||||
],
|
||||
'nested' => [
|
||||
[
|
||||
'value' => 'bar',
|
||||
'path' => ['deep', 'sub', 'nested', ],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'search multiple, flat' => [
|
||||
0 => self::$array,
|
||||
1 => ['single', 'nested'],
|
||||
2 => true,
|
||||
3 => null,
|
||||
4 => [
|
||||
'single', 'bar',
|
||||
],
|
||||
],
|
||||
'search multiple, flat, prefix' => [
|
||||
0 => self::$array,
|
||||
1 => ['single', 'nested'],
|
||||
2 => true,
|
||||
3 => true,
|
||||
4 => [
|
||||
'single' => ['single', ],
|
||||
'nested' => ['bar', ],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* provides array listing for the merge test
|
||||
*
|
||||
@@ -691,6 +874,44 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers::arraySearchKey
|
||||
* @dataProvider arraySearchKeyProvider
|
||||
* @testdox arraySearchKey Search array with keys and flat: $flat, prefix: $prefix [$_dataName]
|
||||
*
|
||||
* @param array $input
|
||||
* @param array $needles
|
||||
* @param bool|null $flat
|
||||
* @param bool|null $prefix
|
||||
* @param array $expected
|
||||
* @return void
|
||||
*/
|
||||
public function testArraySearchKey(
|
||||
array $input,
|
||||
array $needles,
|
||||
?bool $flat,
|
||||
?bool $prefix,
|
||||
array $expected
|
||||
): void {
|
||||
if ($flat === null && $prefix === null) {
|
||||
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles);
|
||||
} elseif ($flat === null) {
|
||||
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, prefix: $prefix);
|
||||
} elseif ($prefix === null) {
|
||||
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, flat: $flat);
|
||||
} else {
|
||||
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, $flat, $prefix);
|
||||
}
|
||||
// print "E: " . print_r($expected, true) . "\n";
|
||||
// print "R: " . print_r($result, true) . "\n";
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$result
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
|
||||
@@ -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("/^.* <SEND EMAIL JSON> - (.*)$/m", $file, $matches);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use CoreLibs\Logging\Logger\Level;
|
||||
|
||||
/**
|
||||
* Test class for DB\IO + DB\SQL\PgSQL
|
||||
@@ -59,20 +60,6 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'db_type' => 'pgsql',
|
||||
'db_encoding' => '',
|
||||
'db_ssl' => 'allow', // allow, disable, require, prefer
|
||||
'db_debug' => true,
|
||||
],
|
||||
// same as valid, but db debug is off
|
||||
'valid_debug_false' => [
|
||||
'db_name' => 'corelibs_db_io_test',
|
||||
'db_user' => 'corelibs_db_io_test',
|
||||
'db_pass' => 'corelibs_db_io_test',
|
||||
'db_host' => 'localhost',
|
||||
'db_port' => 5432,
|
||||
'db_schema' => 'public',
|
||||
'db_type' => 'pgsql',
|
||||
'db_encoding' => '',
|
||||
'db_ssl' => 'allow', // allow, disable, require, prefer
|
||||
'db_debug' => false,
|
||||
],
|
||||
// same as valid, but encoding is set
|
||||
'valid_with_encoding_utf8' => [
|
||||
@@ -85,7 +72,6 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'db_type' => 'pgsql',
|
||||
'db_encoding' => 'UTF-8',
|
||||
'db_ssl' => 'allow', // allow, disable, require, prefer
|
||||
'db_debug' => true,
|
||||
],
|
||||
// valid with no schema set
|
||||
'valid_no_schema' => [
|
||||
@@ -98,7 +84,6 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'db_type' => 'pgsql',
|
||||
'db_encoding' => '',
|
||||
'db_ssl' => 'allow', // allow, disable, require, prefer
|
||||
'db_debug' => true,
|
||||
],
|
||||
// invalid (missing db name)
|
||||
'invalid' => [
|
||||
@@ -111,7 +96,6 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'db_type' => 'pgsql',
|
||||
'db_encoding' => '',
|
||||
'db_ssl' => 'allow', // allow, disable, require, prefer
|
||||
'db_debug' => true,
|
||||
],
|
||||
];
|
||||
private static $log;
|
||||
@@ -132,14 +116,12 @@ 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',
|
||||
]);
|
||||
// will be true, default logging is true
|
||||
$db = new \CoreLibs\DB\IO(
|
||||
self::$db_config['valid'],
|
||||
self::$log
|
||||
@@ -156,7 +138,7 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
$db->dbExec("DROP TABLE test_meta");
|
||||
}
|
||||
// uid is for internal reference tests
|
||||
$base_table = <<<EOM
|
||||
$base_table = <<<SQL
|
||||
uid VARCHAR,
|
||||
row_int INT,
|
||||
row_numeric NUMERIC,
|
||||
@@ -172,36 +154,36 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
row_array_varchar VARCHAR ARRAY
|
||||
)
|
||||
WITHOUT OIDS
|
||||
EOM;
|
||||
SQL;
|
||||
// create the tables
|
||||
$db->dbExec(
|
||||
// primary key name is table + '_id'
|
||||
<<<EOM
|
||||
<<<SQL
|
||||
CREATE TABLE table_with_primary_key (
|
||||
table_with_primary_key_id SERIAL PRIMARY KEY,
|
||||
$base_table
|
||||
EOM
|
||||
SQL
|
||||
/* "CREATE TABLE table_with_primary_key ("
|
||||
// primary key name is table + '_id'
|
||||
. "table_with_primary_key_id SERIAL PRIMARY KEY, "
|
||||
. $base_table */
|
||||
);
|
||||
$db->dbExec(
|
||||
<<<EOM
|
||||
<<<SQL
|
||||
CREATE TABLE table_without_primary_key (
|
||||
$base_table
|
||||
EOM
|
||||
SQL
|
||||
/* "CREATE TABLE table_without_primary_key ("
|
||||
. $base_table */
|
||||
);
|
||||
// create simple table for meta test
|
||||
$db->dbExec(
|
||||
<<<EOM
|
||||
<<<SQL
|
||||
CREATE TABLE test_meta (
|
||||
row_1 VARCHAR,
|
||||
row_2 INT
|
||||
) WITHOUT OIDS
|
||||
EOM
|
||||
SQL
|
||||
/* "CREATE TABLE test_meta ("
|
||||
. "row_1 VARCHAR, "
|
||||
. "row_2 INT"
|
||||
@@ -537,6 +519,9 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
*/
|
||||
public function debugSetProvider(): array
|
||||
{
|
||||
// 0: db connecdtion
|
||||
// 1: override log flag, null for default
|
||||
// 2: set flag
|
||||
return [
|
||||
'default debug set' => [
|
||||
// what base connection
|
||||
@@ -544,11 +529,6 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
// actions (set)
|
||||
null,
|
||||
// set exepected
|
||||
self::$db_config['valid']['db_debug'],
|
||||
],
|
||||
'set debug to true' => [
|
||||
'valid_debug_false',
|
||||
true,
|
||||
true,
|
||||
],
|
||||
'set debug to false' => [
|
||||
@@ -559,99 +539,46 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test set for toggleDEbug
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function debugToggleProvider(): array
|
||||
{
|
||||
return [
|
||||
'default debug set' => [
|
||||
// what base connection
|
||||
'valid',
|
||||
// actions
|
||||
null,
|
||||
// toggle is inverse
|
||||
self::$db_config['valid']['db_debug'] ? false : true,
|
||||
],
|
||||
'toggle debug to true' => [
|
||||
'valid_debug_false',
|
||||
true,
|
||||
true,
|
||||
],
|
||||
'toggle debug to false' => [
|
||||
'valid',
|
||||
false,
|
||||
false,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test dbSetDbug, dbGetDebug
|
||||
*
|
||||
* @covers ::dbGetDbug
|
||||
* @covers ::dbSetDebug
|
||||
* @dataProvider debugSetProvider
|
||||
* @testdox Setting debug $set will be $expected [$_dataName]
|
||||
* @testdox Set and Get Debug flag
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDbSetDebug(
|
||||
string $connection,
|
||||
?bool $set,
|
||||
bool $expected
|
||||
): void {
|
||||
public function testDbSetDebug(): void
|
||||
{
|
||||
$connection = 'valid';
|
||||
// default set, expect true
|
||||
$db = new \CoreLibs\DB\IO(
|
||||
self::$db_config[$connection],
|
||||
self::$log
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$set === null ?
|
||||
$db->dbSetDebug() :
|
||||
$db->dbSetDebug($set)
|
||||
$this->assertTrue(
|
||||
$db->dbGetDebug()
|
||||
);
|
||||
// must always match
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
// switch off
|
||||
$db->dbSetDebug(false);
|
||||
$this->assertFalse(
|
||||
$db->dbGetDebug()
|
||||
);
|
||||
$db->dbClose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test dbToggleDebug, dbGetDebug
|
||||
*
|
||||
* @covers ::dbGetDbug
|
||||
* @covers ::dbSetDebug
|
||||
* @dataProvider debugToggleProvider
|
||||
* @testdox Toggle debug $toggle will be $expected [$_dataName]
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testDbToggleDebug(
|
||||
string $connection,
|
||||
?bool $toggle,
|
||||
bool $expected
|
||||
): void {
|
||||
// second conenction with log set NOT debug
|
||||
$log = new \CoreLibs\Logging\Logging([
|
||||
// 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log',
|
||||
'log_folder' => DIRECTORY_SEPARATOR . 'tmp',
|
||||
'log_file_id' => 'CoreLibs-DB-IO-Test',
|
||||
'log_level' => \CoreLibs\Logging\Logger\Level::Notice,
|
||||
]);
|
||||
$db = new \CoreLibs\DB\IO(
|
||||
self::$db_config[$connection],
|
||||
self::$log
|
||||
$log
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$toggle === null ?
|
||||
$db->dbToggleDebug() :
|
||||
$db->dbToggleDebug($toggle)
|
||||
);
|
||||
// must always match
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$this->assertFalse(
|
||||
$db->dbGetDebug()
|
||||
);
|
||||
$db->dbClose();
|
||||
}
|
||||
|
||||
// - set max query call sets
|
||||
@@ -809,7 +736,6 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'host' => 'db_host',
|
||||
'port' => 'db_port',
|
||||
'ssl' => 'db_ssl',
|
||||
'debug' => 'db_debug',
|
||||
'password' => '***',
|
||||
] as $read => $compare
|
||||
) {
|
||||
@@ -1342,10 +1268,10 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'has default' => false,
|
||||
'array dims' => 0,
|
||||
'is enum' => false,
|
||||
'is base' => 1,
|
||||
'is base' => true,
|
||||
'is composite' => false,
|
||||
'is pesudo' => false,
|
||||
'description' => '',
|
||||
'is pseudo' => false
|
||||
],
|
||||
'row_2' => [
|
||||
'num' => 2,
|
||||
@@ -1355,10 +1281,10 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'has default' => false,
|
||||
'array dims' => 0,
|
||||
'is enum' => false,
|
||||
'is base' => 1,
|
||||
'is base' => true,
|
||||
'is composite' => false,
|
||||
'is pesudo' => false,
|
||||
'description' => '',
|
||||
'is pseudo' => false
|
||||
]
|
||||
]
|
||||
],
|
||||
@@ -1374,10 +1300,10 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'has default' => false,
|
||||
'array dims' => 0,
|
||||
'is enum' => false,
|
||||
'is base' => 1,
|
||||
'is base' => true,
|
||||
'is composite' => false,
|
||||
'is pesudo' => false,
|
||||
'description' => '',
|
||||
'is pseudo' => false
|
||||
],
|
||||
'row_2' => [
|
||||
'num' => 2,
|
||||
@@ -1387,10 +1313,10 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'has default' => false,
|
||||
'array dims' => 0,
|
||||
'is enum' => false,
|
||||
'is base' => 1,
|
||||
'is base' => true,
|
||||
'is composite' => false,
|
||||
'is pesudo' => false,
|
||||
'description' => '',
|
||||
'is pseudo' => false
|
||||
]
|
||||
]
|
||||
],
|
||||
@@ -4425,16 +4351,16 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
]
|
||||
]
|
||||
],
|
||||
// same but as EOM
|
||||
'single insert (PK), EOM string' => [
|
||||
<<<EOM
|
||||
// same but as heredoc
|
||||
'single insert (PK), heredoc string' => [
|
||||
<<<SQL
|
||||
INSERT INTO table_with_primary_key (
|
||||
row_varchar, row_varchar_literal, row_int, row_date
|
||||
) VALUES (
|
||||
'Text', 'Other', 123, '2022-03-01'
|
||||
)
|
||||
RETURNING row_varchar, row_varchar_literal, row_int, row_date
|
||||
EOM,
|
||||
SQL,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
@@ -4529,16 +4455,16 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
]
|
||||
]
|
||||
],
|
||||
// same as above but as EOM string
|
||||
'single insert (No PK), EOM string' => [
|
||||
<<<EOM
|
||||
// same as above but as heredoc string
|
||||
'single insert (No PK), heredoc string' => [
|
||||
<<<SQL
|
||||
INSERT INTO table_without_primary_key (
|
||||
row_varchar, row_varchar_literal, row_int, row_date
|
||||
) VALUES (
|
||||
'Text', 'Other', 123, '2022-03-01'
|
||||
)
|
||||
RETURNING row_varchar, row_varchar_literal, row_int, row_date
|
||||
EOM,
|
||||
SQL,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
|
||||
@@ -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
|
||||
]);
|
||||
@@ -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 => "<pre>Array\n(\n)\n</pre>"
|
||||
1 => "<pre>Array\n(\n)\n</pre>",
|
||||
2 => "Array\n(\n)\n",
|
||||
],
|
||||
'simple array' => [
|
||||
0 => ['a', 'b'],
|
||||
1 => "<pre>Array\n(\n"
|
||||
. " [0] => a\n"
|
||||
. " [1] => b\n"
|
||||
. ")\n</pre>"
|
||||
. ")\n</pre>",
|
||||
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 => '<b>param test</b>: false'
|
||||
2 => '<b>param test</b>: false',
|
||||
3 => 'false'
|
||||
],
|
||||
'true input param name, true override' => [
|
||||
0 => true,
|
||||
1 => [
|
||||
'name' => 'param test',
|
||||
'true' => 'ok'
|
||||
'true' => 'ok',
|
||||
],
|
||||
2 => '<b>param test</b>: ok'
|
||||
2 => '<b>param test</b>: 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 => '<b>param test</b>: not'
|
||||
2 => '<b>param test</b>: 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,261 @@ 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' => "<pre>'string'</pre>",
|
||||
],
|
||||
'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' => "<pre>6</pre>",
|
||||
],
|
||||
// float
|
||||
'float' => [
|
||||
'input' => 1.6,
|
||||
'flag' => null,
|
||||
'expected_dump' => 'float(1.6)' . "\n",
|
||||
'expected_export' => "<pre>1.6</pre>",
|
||||
],
|
||||
// bool
|
||||
'bool' => [
|
||||
'input' => true,
|
||||
'flag' => null,
|
||||
'expected_dump' => 'bool(true)' . "\n",
|
||||
'expected_export' => "<pre>true</pre>",
|
||||
],
|
||||
// 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' => "<pre>array (\n"
|
||||
. " 0 => 'string',\n"
|
||||
. " 1 => true,\n"
|
||||
. ")</pre>",
|
||||
],
|
||||
// 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 ["vendor/phpunit/phpunit/src/Framework/TestCase.php:"]
|
||||
* @testdox getCallerFileLine check based on regex /[\w\-\/]/vendor/phpunit/phpunit/src/Framework/TestCase.php:\d+ [$_dataName]
|
||||
*
|
||||
* @param string $expected
|
||||
* @return void
|
||||
*/
|
||||
public function testGetCallerFileLine(): void
|
||||
{
|
||||
// regex prefix with path "/../" and then fixed vendor + \d+
|
||||
$regex = "/^\/[\w\-\/]+\/vendor\/phpunit\/phpunit\/src\/Framework\/TestCase.php:\d+$/";
|
||||
$this->assertMatchesRegularExpression(
|
||||
$regex,
|
||||
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']
|
||||
// );
|
||||
array_splice(
|
||||
$expected,
|
||||
0,
|
||||
0,
|
||||
['include']
|
||||
);
|
||||
$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 +623,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 +641,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'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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'] . "<br>";
|
||||
// print "SERVER: " . print_r($_SERVER, true) . "\n";
|
||||
|
||||
802
test/phpunit/Logging/CoreLibsLoggingLoggingTest.php
Normal file
802
test/phpunit/Logging/CoreLibsLoggingLoggingTest.php
Normal file
@@ -0,0 +1,802 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use CoreLibs\Logging\Logger\Level;
|
||||
use CoreLibs\Logging\Logger\Flag;
|
||||
|
||||
// TODO: setLogPer test log file written matches pattern
|
||||
|
||||
/**
|
||||
* Test class for Logging
|
||||
* @coversDefaultClass \CoreLibs\Logging\Logging
|
||||
* @testdox \CoreLibs\Logging\Logging method tests
|
||||
*/
|
||||
final class CoreLibsLoggingLoggingTest extends TestCase
|
||||
{
|
||||
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
|
||||
private const REGEX_BASE = "\[[\d\-\s\.:]+\]\s{1}" // date
|
||||
. "\[[\w\.]+(:\d+)?\]\s{1}" // host:port
|
||||
. "\[[\w\-\.\/]+:\d+\]\s{1}" // folder/file
|
||||
. "\[\w+\]\s{1}" // run id
|
||||
. "{[\w\\\\]+(::\w+)?}\s{1}"; // class
|
||||
|
||||
public static function tearDownAfterClass(): void
|
||||
{
|
||||
array_map('unlink', glob(self::LOG_FOLDER . '*.log'));
|
||||
}
|
||||
|
||||
/**
|
||||
* test set for options BASIC
|
||||
*
|
||||
* 0: options
|
||||
* - null for NOT set
|
||||
* 1: expected
|
||||
* 2: override
|
||||
* override:
|
||||
* - constant for COSNTANTS
|
||||
* - global for _GLOBALS
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function optionsProvider(): array
|
||||
{
|
||||
return [
|
||||
'log folder set' => [
|
||||
'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
|
||||
// loggingLevelIsDebug
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::setLoggingLevel
|
||||
* @covers ::getLoggingLevel
|
||||
* @covers ::loggingLevelIsDebug
|
||||
* @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->loggingLevelIsDebug()
|
||||
);
|
||||
// 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->loggingLevelIsDebug()
|
||||
);
|
||||
// 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->loggingLevelIsDebug()
|
||||
);
|
||||
// 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}
|
||||
// <DEBUG:G> 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__
|
||||
3
test/phpunit/Logging/log/.gitignore
vendored
Normal file
3
test/phpunit/Logging/log/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*log
|
||||
*LOG
|
||||
!.gitignore
|
||||
@@ -7,11 +7,11 @@ namespace tests;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test class for Check\Password
|
||||
* @coversDefaultClass \CoreLibs\Check\Password
|
||||
* @testdox \CoreLibs\Check\Password method tests
|
||||
* Test class for Security\Password
|
||||
* @coversDefaultClass \CoreLibs\Security\Password
|
||||
* @testdox \CoreLibs\Security\Password method tests
|
||||
*/
|
||||
final class CoreLibsCheckPasswordTest extends TestCase
|
||||
final class CoreLibsSecurityPasswordTest extends TestCase
|
||||
{
|
||||
public function passwordProvider(): array
|
||||
{
|
||||
@@ -46,7 +46,7 @@ final class CoreLibsCheckPasswordTest extends TestCase
|
||||
{
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
\CoreLibs\Check\Password::passwordVerify($input, \CoreLibs\Check\Password::passwordSet($input_hash))
|
||||
\CoreLibs\Security\Password::passwordVerify($input, \CoreLibs\Security\Password::passwordSet($input_hash))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ final class CoreLibsCheckPasswordTest extends TestCase
|
||||
{
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
\CoreLibs\Check\Password::passwordRehashCheck($input)
|
||||
\CoreLibs\Security\Password::passwordRehashCheck($input)
|
||||
);
|
||||
}
|
||||
}
|
||||
172
test/phpunit/Security/CoreLibsSecuritySymmetricEncryption.php
Normal file
172
test/phpunit/Security/CoreLibsSecuritySymmetricEncryption.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use CoreLibs\Security\CreateKey;
|
||||
use CoreLibs\Security\SymmetricEncryption;
|
||||
|
||||
/**
|
||||
* Test class for Security\SymmetricEncryption and Security\CreateKey
|
||||
* @coversDefaultClass \CoreLibs\Security\SymmetricEncryption
|
||||
* @testdox \CoreLibs\Security\SymmetricEncryption method tests
|
||||
*/
|
||||
final class CoreLibsSecuritySymmetricEncryption extends TestCase
|
||||
{
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerEncryptDecryptSuccess(): array
|
||||
{
|
||||
return [
|
||||
'valid string' => [
|
||||
'input' => 'I am a secret',
|
||||
'expected' => 'I am a secret',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test encrypt/decrypt produce correct output
|
||||
*
|
||||
* @covers ::generateRandomKey
|
||||
* @covers ::encrypt
|
||||
* @covers ::decrypt
|
||||
* @dataProvider providerEncryptDecryptSuccess
|
||||
* @testdox encrypt/decrypt $input must be $expected [$_dataName]
|
||||
*
|
||||
* @param string $input
|
||||
* @param string $expected
|
||||
* @return void
|
||||
*/
|
||||
public function testEncryptDecryptSuccess(string $input, string $expected): void
|
||||
{
|
||||
$key = CreateKey::generateRandomKey();
|
||||
$encrypted = SymmetricEncryption::encrypt($input, $key);
|
||||
$decrypted = SymmetricEncryption::decrypt($encrypted, $key);
|
||||
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$decrypted
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerEncryptFailed(): array
|
||||
{
|
||||
return [
|
||||
'wrong decryption key' => [
|
||||
'input' => 'I am a secret',
|
||||
'excpetion_message' => 'Invalid Key'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test decryption with wrong key
|
||||
*
|
||||
* @covers ::generateRandomKey
|
||||
* @covers ::encrypt
|
||||
* @covers ::decrypt
|
||||
* @dataProvider providerEncryptFailed
|
||||
* @testdox decrypt with wrong key $input throws $exception_message [$_dataName]
|
||||
*
|
||||
* @param string $input
|
||||
* @param string $exception_message
|
||||
* @return void
|
||||
*/
|
||||
public function testEncryptFailed(string $input, string $exception_message): void
|
||||
{
|
||||
$key = CreateKey::generateRandomKey();
|
||||
$encrypted = SymmetricEncryption::encrypt($input, $key);
|
||||
$wrong_key = CreateKey::generateRandomKey();
|
||||
$this->expectExceptionMessage($exception_message);
|
||||
SymmetricEncryption::decrypt($encrypted, $wrong_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerWrongKey(): array
|
||||
{
|
||||
return [
|
||||
'not hex key' => [
|
||||
'key' => 'not_a_hex_key',
|
||||
'exception_message' => 'Invalid hex key'
|
||||
],
|
||||
'too short hex key' => [
|
||||
'key' => '1cabd5cba9e042f12522f4ff2de5c31d233b',
|
||||
'excpetion_message' => 'Key is not the correct size (must be '
|
||||
. 'SODIUM_CRYPTO_SECRETBOX_KEYBYTES bytes long).'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* test invalid key provided to decrypt or encrypt
|
||||
*
|
||||
* @covers ::encrypt
|
||||
* @covers ::decrypt
|
||||
* @dataProvider providerWrongKey
|
||||
* @testdox wrong key $key throws $exception_message [$_dataName]
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $exception_message
|
||||
* @return void
|
||||
*/
|
||||
public function testWrongKey(string $key, string $exception_message): void
|
||||
{
|
||||
$this->expectExceptionMessage($exception_message);
|
||||
SymmetricEncryption::encrypt('test', $key);
|
||||
// we must encrypt valid thing first so we can fail with the wrong kjey
|
||||
$enc_key = CreateKey::generateRandomKey();
|
||||
$encrypted = SymmetricEncryption::encrypt('test', $enc_key);
|
||||
$this->expectExceptionMessage($exception_message);
|
||||
SymmetricEncryption::decrypt($encrypted, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerWrongCiphertext(): array
|
||||
{
|
||||
return [
|
||||
'too short ciphertext' => [
|
||||
'input' => 'short',
|
||||
'exception_message' => 'Invalid ciphertext (too short)'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::decrypt
|
||||
* @dataProvider providerWrongCiphertext
|
||||
* @testdox too short ciphertext $input throws $exception_message [$_dataName]
|
||||
*
|
||||
* @param string $input
|
||||
* @param string $exception_message
|
||||
* @return void
|
||||
*/
|
||||
public function testWrongCiphertext(string $input, string $exception_message): void
|
||||
{
|
||||
$key = CreateKey::generateRandomKey();
|
||||
$this->expectExceptionMessage($exception_message);
|
||||
SymmetricEncryption::decrypt($input, $key);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
Reference in New Issue
Block a user