Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0392187299 | ||
|
|
edcc65df3e | ||
|
|
5dde52a309 | ||
|
|
5f223fb50d | ||
|
|
2eaf80b1bd | ||
|
|
b5d601aec0 | ||
|
|
edcc77a6ab | ||
|
|
0b1df7a901 | ||
|
|
e0f8bad2d9 | ||
|
|
f5cd71cfbc | ||
|
|
1203164d7e | ||
|
|
b82e08ba05 | ||
|
|
6dfb68a6da | ||
|
|
5b944cd12d | ||
|
|
65cac4c6e2 | ||
|
|
1c1ace58db | ||
|
|
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 |
@@ -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.4
|
||||
9.3.2
|
||||
|
||||
@@ -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}";
|
||||
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,70 +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;
|
||||
@@ -158,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,}',
|
||||
];
|
||||
@@ -166,13 +166,13 @@ class Login
|
||||
// login error code, can be matched to the array login_error_msg,
|
||||
// which holds the string
|
||||
/** @var int */
|
||||
private $login_error = 0;
|
||||
private int $login_error = 0;
|
||||
/** @var array<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' => ''
|
||||
@@ -180,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
|
||||
@@ -883,7 +883,7 @@ class Login
|
||||
}
|
||||
// normal user processing
|
||||
// set class var and session var
|
||||
$_SESSION['EUID'] = $this->euid = $res['edit_user_id'];
|
||||
$_SESSION['EUID'] = $this->euid = (int)$res['edit_user_id'];
|
||||
// check if user is okay
|
||||
$this->loginCheckPermissions();
|
||||
if ($this->login_error == 0) {
|
||||
@@ -1048,7 +1048,7 @@ class Login
|
||||
}
|
||||
// build master unit array
|
||||
$unit_access[$res['edit_access_id']] = [
|
||||
'id' => $res['edit_access_id'],
|
||||
'id' => (int)$res['edit_access_id'],
|
||||
'acl_level' => $res['level'],
|
||||
'acl_type' => $res['type'],
|
||||
'name' => $res['name'],
|
||||
@@ -1179,6 +1179,12 @@ class Login
|
||||
$this->acl['page'] = $_SESSION['PAGES_ACL_LEVEL'][$this->page_name];
|
||||
}
|
||||
|
||||
$this->acl['unit_id'] = null;
|
||||
$this->acl['unit_name'] = null;
|
||||
$this->acl['unit_uid'] = null;
|
||||
$this->acl['unit'] = [];
|
||||
$this->acl['unit_detail'] = [];
|
||||
|
||||
// PER ACCOUNT (UNIT/edit access)->
|
||||
foreach ($_SESSION['UNIT'] as $ea_id => $unit) {
|
||||
// if admin flag is set, all units are set to 100
|
||||
@@ -1608,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>
|
||||
@@ -1626,7 +1632,7 @@ class Login
|
||||
</table>
|
||||
</div>
|
||||
{PASSWORD_CHANGE_SHOW}
|
||||
EOM;
|
||||
HTML;
|
||||
// phpcs:enable
|
||||
}
|
||||
if ($this->password_forgot) {
|
||||
@@ -1650,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>
|
||||
@@ -1712,7 +1718,7 @@ h3 { font-size: 18px; }
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
EOM;
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1849,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
|
||||
@@ -1911,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 {
|
||||
@@ -2119,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;
|
||||
}
|
||||
@@ -2507,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
|
||||
@@ -164,6 +164,10 @@ class Backend
|
||||
);
|
||||
}
|
||||
$this->default_acl = $set_default_acl_level ?? DEFAULT_ACL_LEVEL;
|
||||
// if negative or larger than 100, reset to 0
|
||||
if ($this->default_acl < 0 || $this->default_acl > 100) {
|
||||
$this->default_acl = 0;
|
||||
}
|
||||
|
||||
// queue key
|
||||
if (preg_match("/^(add|save|delete|remove|move|up|down|push_live)$/", $this->action)) {
|
||||
|
||||
@@ -20,36 +20,37 @@ 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
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config db config array, mandatory
|
||||
* @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 +64,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
|
||||
|
||||
@@ -452,6 +452,31 @@ class DateTime
|
||||
return $days;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if a weekend day (sat/sun) is in the given date range
|
||||
* Can have time too, but is not needed
|
||||
*
|
||||
* @param string $start_date Y-m-d
|
||||
* @param string $end_date Y-m-d
|
||||
* @return bool True for has weekend, False for has not
|
||||
*/
|
||||
public static function dateRangeHasWeekend(
|
||||
string $start_date,
|
||||
string $end_date,
|
||||
): bool {
|
||||
$dd_start = new \DateTime($start_date);
|
||||
$dd_end = new \DateTime($end_date);
|
||||
if (
|
||||
// starts with a weekend
|
||||
$dd_start->format('N') >= 6 ||
|
||||
// start day plus diff will be 6 and so fall into a weekend
|
||||
((int)$dd_start->format('w') + $dd_start->diff($dd_end)->days) >= 6
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
|
||||
@@ -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,25 +39,26 @@ 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
|
||||
* primary key name automatically (from array)
|
||||
*
|
||||
* @param array<mixed> $db_config db connection config
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $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 +66,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 +244,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 +407,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 +580,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;
|
||||
}
|
||||
|
||||
@@ -587,7 +588,7 @@ class ArrayIO extends \CoreLibs\DB\IO
|
||||
// get it at the end, cause now we can be more sure of no double IDs, etc
|
||||
reset($this->table_array);
|
||||
// create select part & addition FK part
|
||||
foreach ($this->table_array as $column => $data_array) {
|
||||
foreach (array_keys($this->table_array) as $column) {
|
||||
// check FK ...
|
||||
if (
|
||||
isset($this->table_array[$column]['fk']) &&
|
||||
|
||||
798
src/DB/IO.php
798
src/DB/IO.php
File diff suppressed because it is too large
Load Diff
63
src/DB/Options/Convert.php
Normal file
63
src/DB/Options/Convert.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/6/9
|
||||
* DESCRIPTION:
|
||||
* DB Options for convert type
|
||||
*
|
||||
* off: no conversion (all string)
|
||||
* on: int/bool only
|
||||
* json: json/jsonb to array
|
||||
* numeric: any numeric or float to float
|
||||
* bytes: decode bytea to string
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\DB\Options;
|
||||
|
||||
enum Convert: int
|
||||
{
|
||||
/** do not convert */
|
||||
case off = 0;
|
||||
/** convert only int/bool */
|
||||
case on = 1;
|
||||
/** also convert json to php array */
|
||||
case json = 2;
|
||||
/** also convert any float/real/numeric to php float */
|
||||
case numeric = 4;
|
||||
/** also decode bytea string to php string */
|
||||
case bytea = 8;
|
||||
|
||||
/**
|
||||
* get internal name from string value
|
||||
*
|
||||
* @param non-empty-string $name
|
||||
* @return self
|
||||
*/
|
||||
public static function fromName(string $name): self
|
||||
{
|
||||
return match ($name) {
|
||||
'Off', 'off', 'OFF', 'convert_off', 'CONVERT_OFF' => self::off,
|
||||
'On', 'on', 'ON', 'convert_on', 'CONVERT_ON' => self::on,
|
||||
'Json', 'json', 'JSON', 'convert_json', 'CONVERT_JSON' => self::json,
|
||||
'Numeric', 'numeric', 'NUMERIC', 'convert_numeric', 'CONVERT_NUMERIC' => self::numeric,
|
||||
'Bytea', 'bytea', 'BYTEA', 'convert_bytea', 'CONVERT_BYTEA' => self::bytea,
|
||||
default => self::off,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get internal name from int value
|
||||
*
|
||||
* @param int $value
|
||||
* @return self
|
||||
*/
|
||||
public static function fromValue(int $value): self
|
||||
{
|
||||
return self::from($value);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
@@ -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__
|
||||
1376
src/Logging/Logging.php
Normal file
1376
src/Logging/Logging.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -219,96 +219,98 @@ 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
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config db config array, mandatory
|
||||
* @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 +321,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 +329,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 +390,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 +487,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 +829,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 +1956,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 +2619,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
|
||||
|
||||
@@ -36,6 +36,7 @@ class Image
|
||||
): string|false {
|
||||
// get image type flags
|
||||
$image_types = [
|
||||
0 => 'UNKOWN-IMAGE',
|
||||
1 => 'gif',
|
||||
2 => 'jpg',
|
||||
3 => 'png'
|
||||
@@ -69,7 +70,7 @@ class Image
|
||||
}
|
||||
// does this picture exist and is it a picture
|
||||
if (file_exists($filename) && is_file($filename)) {
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [];
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
|
||||
$convert_prefix = '';
|
||||
$create_file = false;
|
||||
$delete_filename = '';
|
||||
@@ -98,7 +99,7 @@ class Image
|
||||
if (!is_file($filename)) {
|
||||
$filename .= '-0';
|
||||
}
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [];
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
|
||||
}
|
||||
// if no size given, set size to original
|
||||
if (!$size_x || $size_x < 1) {
|
||||
@@ -117,7 +118,7 @@ class Image
|
||||
$status = exec($convert_string, $output, $return);
|
||||
// get the size of the converted data, if converted
|
||||
if (is_file($thumbnail)) {
|
||||
[$width, $height, $type] = getimagesize($thumbnail) ?: [];
|
||||
[$width, $height, $type] = getimagesize($thumbnail) ?: [0, 0, 0];
|
||||
}
|
||||
}
|
||||
if ($height > $size_y) {
|
||||
@@ -217,7 +218,7 @@ class Image
|
||||
return $thumbnail;
|
||||
}
|
||||
// $this->debug('IMAGE PREPARE', "FILENAME OK, THUMB WIDTH/HEIGHT OK");
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [];
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [0, 0, null];
|
||||
$thumbnail_write_path = null;
|
||||
$thumbnail_web_path = null;
|
||||
// path set first
|
||||
@@ -447,7 +448,7 @@ class Image
|
||||
if (!function_exists('exif_read_data') || !is_writeable($filename)) {
|
||||
return;
|
||||
}
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [];
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [0, 0, null];
|
||||
// add @ to avoid "file not supported error"
|
||||
$exif = @exif_read_data($filename);
|
||||
$orientation = null;
|
||||
|
||||
@@ -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__
|
||||
264
src/Template/HtmlBuilder/Block.php
Normal file
264
src/Template/HtmlBuilder/Block.php
Normal file
@@ -0,0 +1,264 @@
|
||||
<?php // phpcs:disable Generic.Files.LineLength
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/6/1
|
||||
* DESCRIPTION:
|
||||
* html builder: array
|
||||
* static build for array lists (not objects)
|
||||
*
|
||||
* Recommended to use the Object one or for speed the String Replace
|
||||
*/
|
||||
|
||||
namespace CoreLibs\Template\HtmlBuilder;
|
||||
|
||||
use CoreLibs\Template\HtmlBuilder\General\Settings;
|
||||
use CoreLibs\Template\HtmlBuilder\General\Error;
|
||||
use CoreLibs\Template\HtmlBuilder\General\HtmlBuilderExcpetion;
|
||||
|
||||
class Block
|
||||
{
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param string $tag
|
||||
* @param string $id
|
||||
* @param string $content
|
||||
* @param array<string> $css,
|
||||
* @param array<string,string> $options
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public static function cel(
|
||||
string $tag,
|
||||
string $id = '',
|
||||
string $content = '',
|
||||
array $css = [],
|
||||
array $options = []
|
||||
): array {
|
||||
if (!preg_match("/^[A-Za-z]+$/", $tag)) {
|
||||
Error::setError(
|
||||
'201',
|
||||
'invalid or empty tag',
|
||||
['tag' => $tag]
|
||||
);
|
||||
throw new HtmlBuilderExcpetion('Invalid or empty tag');
|
||||
}
|
||||
return [
|
||||
'tag' => $tag,
|
||||
'id' => $id,
|
||||
'name' => $options['name'] ?? '',
|
||||
'content' => $content,
|
||||
'css' => $css,
|
||||
'options' => $options,
|
||||
'sub' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Search element tree for id and add
|
||||
* if id is empty add at current
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $base
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $attach
|
||||
* @param string $id
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
*/
|
||||
public static function ael(
|
||||
array $base,
|
||||
array $attach,
|
||||
string $id = ''
|
||||
): array {
|
||||
// no id or matching id
|
||||
if (
|
||||
empty($id) ||
|
||||
$base['id'] == $id
|
||||
) {
|
||||
self::addSub($base, $attach);
|
||||
return $base;
|
||||
}
|
||||
// find id in 'id' in all 'sub'
|
||||
foreach ($base['sub'] as $el) {
|
||||
$el = self::ael($el, $attach, $id);
|
||||
}
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $base
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} ...$attach
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
*/
|
||||
public static function aelx(
|
||||
array $base,
|
||||
array ...$attach
|
||||
): array {
|
||||
$base = self::addSub($base, ...$attach);
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $element
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $sub
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
*/
|
||||
public static function addSub(array $element, array ...$sub): array
|
||||
{
|
||||
if (!isset($element['sub'])) {
|
||||
$element['sub'] = [];
|
||||
}
|
||||
array_push($element['sub'], ...$sub);
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $element
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
*/
|
||||
public static function resetSub(array $element): array
|
||||
{
|
||||
$element['sub'] = [];
|
||||
return $element;
|
||||
}
|
||||
|
||||
// CSS Elements
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $element
|
||||
* @param string ...$css
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
*/
|
||||
public static function acssel(array $element, string ...$css): array
|
||||
{
|
||||
$element['css'] = array_unique(array_merge($element['css'] ?? [], $css));
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $element
|
||||
* @param string ...$css
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
*/
|
||||
public static function rcssel(array $element, string ...$css): array
|
||||
{
|
||||
$element['css'] = array_diff($element['css'] ?? [], $css);
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* scssel (switch) is not supported
|
||||
* use rcssel -> acssel
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $element
|
||||
* @param array<string> $rcss
|
||||
* @param array<string> $acss
|
||||
* @return array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}
|
||||
*/
|
||||
public static function scssel(array $element, array $rcss, array $acss): array
|
||||
{
|
||||
return self::acssel(
|
||||
self::rcssel($element, ...$rcss),
|
||||
...$acss
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* alias phfo
|
||||
*
|
||||
* @param array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>} $tree
|
||||
* @param bool $add_nl [default=false]
|
||||
* @return string
|
||||
*/
|
||||
public static function buildHtml(array $tree, bool $add_nl = false): string
|
||||
{
|
||||
if (empty($tree['tag'])) {
|
||||
return '';
|
||||
}
|
||||
// print "D01: " . microtime(true) . "<br>";
|
||||
$line = '<' . $tree['tag'];
|
||||
|
||||
if (!empty($tree['id'])) {
|
||||
$line .= ' id="' . $tree['id'] . '"';
|
||||
if (in_array($tree['tag'], Settings::NAME_ELEMENTS)) {
|
||||
$line .= ' name="'
|
||||
. (!empty($tree['name']) ? $tree['name'] : $tree['id'])
|
||||
. '"';
|
||||
}
|
||||
}
|
||||
if (count($tree['css'])) {
|
||||
$line .= ' class="' . join(' ', $tree['css']) . '"';
|
||||
}
|
||||
foreach ($tree['options'] ?? [] as $key => $item) {
|
||||
if (in_array($key, Settings::SKIP_OPTIONS)) {
|
||||
continue;
|
||||
}
|
||||
$line .= ' ' . $key . '="' . $item . '"';
|
||||
}
|
||||
$line .= '>';
|
||||
if (!empty($tree['content'])) {
|
||||
$line .= $tree['content'];
|
||||
}
|
||||
// sub nodes
|
||||
foreach ($tree['sub'] ?? [] as $sub) {
|
||||
if ($add_nl === true) {
|
||||
$line .= "\n";
|
||||
}
|
||||
$line .= self::buildHtml($sub, $add_nl);
|
||||
if ($add_nl === true) {
|
||||
$line .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// close line if needed
|
||||
if (!in_array($tree['tag'], Settings::NO_CLOSE)) {
|
||||
$line .= '</' . $tree['tag'] . '>';
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* alias phfa
|
||||
*
|
||||
* @param array<array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}> $list
|
||||
* @param bool $add_nl [default=false]
|
||||
* @return string
|
||||
*/
|
||||
public static function buildHtmlFromList(array $list, bool $add_nl = false): string
|
||||
{
|
||||
$output = '';
|
||||
foreach ($list as $el) {
|
||||
$output .= self::buildHtml($el, $add_nl);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* wrapper for buildHtmlFromList
|
||||
*
|
||||
* @param array<array{tag:string,id:string,name:string,content:string,css:array<string>,options:array<string,string>,sub:array<mixed>}> $list array of Elements to build string from
|
||||
* @param bool $add_nl [default=false] Optional output string line break
|
||||
* @return string build html as string
|
||||
*/
|
||||
public static function printHtmlFromArray(array $list, bool $add_nl = false): string
|
||||
{
|
||||
return self::buildHtmlFromList($list, $add_nl);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
559
src/Template/HtmlBuilder/Element.php
Normal file
559
src/Template/HtmlBuilder/Element.php
Normal file
@@ -0,0 +1,559 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/6/1
|
||||
* DESCRIPTION:
|
||||
* html builder: element
|
||||
* nested and connected objects
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Template\HtmlBuilder;
|
||||
|
||||
use CoreLibs\Template\HtmlBuilder\General\Settings;
|
||||
use CoreLibs\Template\HtmlBuilder\General\Error;
|
||||
use CoreLibs\Template\HtmlBuilder\General\HtmlBuilderExcpetion;
|
||||
|
||||
class Element
|
||||
{
|
||||
/** @var string */
|
||||
private string $tag = '';
|
||||
/** @var string */
|
||||
private string $id = '';
|
||||
/** @var string */
|
||||
private string $name = '';
|
||||
/** @var string */
|
||||
private string $content = '';
|
||||
/** @var array<string> */
|
||||
private array $css = [];
|
||||
/** @var array<string,mixed> */
|
||||
private array $options = [];
|
||||
/** @var array<Element> list of elements */
|
||||
private array $sub = [];
|
||||
|
||||
/**
|
||||
* create new html element
|
||||
*
|
||||
* @param string $tag html tag (eg div, button, etc)
|
||||
* @param string $id html tag id, used also for name if name
|
||||
* not set in $options
|
||||
* @param string $content content text inside, eg <div>Content</div>
|
||||
* if sub elements exist, they are added after content
|
||||
* @param array<string> $css array of css names, put style in $options
|
||||
* @param array<string,string> $options Additional element options in
|
||||
* key = value format
|
||||
* eg: onClick => 'something();'
|
||||
* id, css are skipped
|
||||
* name only set on input/button
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public function __construct(
|
||||
string $tag,
|
||||
string $id = '',
|
||||
string $content = '',
|
||||
array $css = [],
|
||||
array $options = []
|
||||
) {
|
||||
// exit if not valid tag
|
||||
try {
|
||||
$this->setTag($tag);
|
||||
} catch (HtmlBuilderExcpetion $e) {
|
||||
throw new HtmlBuilderExcpetion('Could not create Element', 0, $e);
|
||||
}
|
||||
$this->setId($id);
|
||||
$this->setName($options['name'] ?? '');
|
||||
$this->setContent($content);
|
||||
$this->addCss(...$css);
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* set tag
|
||||
*
|
||||
* @param string $tag
|
||||
* @return void
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public function setTag(string $tag): void
|
||||
{
|
||||
// tag must be letters only
|
||||
if (!preg_match("/^[A-Za-z]+$/", $tag)) {
|
||||
Error::setError(
|
||||
'201',
|
||||
'invalid or empty tag',
|
||||
['tag' => $tag]
|
||||
);
|
||||
throw new HtmlBuilderExcpetion('Invalid or empty tag: ' . $tag);
|
||||
}
|
||||
$this->tag = $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the tag name
|
||||
*
|
||||
* @return string HTML element tag
|
||||
*/
|
||||
public function getTag(): string
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the element id
|
||||
*
|
||||
* @param string $id
|
||||
* @return void
|
||||
*/
|
||||
public function setId(string $id): void
|
||||
{
|
||||
// invalid id and name check too
|
||||
// be strict: [a-zA-Z0-9], -, _
|
||||
// cannot start with digit, two hyphens or a hyphen with a digit:
|
||||
// 0abc
|
||||
// __abc
|
||||
// _0abc
|
||||
if (
|
||||
!empty($id) &&
|
||||
!preg_match("/^[A-Za-z][\w-]*$/", $id)
|
||||
) {
|
||||
Error::setWarning(
|
||||
'202',
|
||||
'possible invalid id',
|
||||
['id' => $id, 'tag' => $this->getTag()]
|
||||
);
|
||||
// TODO: shoud throw error
|
||||
}
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the html tag id
|
||||
*
|
||||
* @return string HTML element id
|
||||
*/
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name for elements
|
||||
* only for elements that need it (input/button/form)
|
||||
*
|
||||
* @param string $name
|
||||
* @return void
|
||||
*/
|
||||
public function setName(string $name): void
|
||||
{
|
||||
if (
|
||||
!empty($name) &&
|
||||
!preg_match("/^[A-Za-z][\w-]*$/", $name)
|
||||
) {
|
||||
Error::setWarning(
|
||||
'203',
|
||||
'possible invalid name',
|
||||
['name' => $name, 'id' => $this->getId(), 'tag' => $this->getTag()]
|
||||
);
|
||||
// TODO: shoud throw error
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the name if set
|
||||
*
|
||||
* @return string Optional HTML name (eg for input)
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new content for element
|
||||
*
|
||||
* @param string $content
|
||||
* @return void
|
||||
*/
|
||||
public function setContent(string $content): void
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the elment text content (not sub elements)
|
||||
*
|
||||
* @return string HTML content text as is
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* set or update options
|
||||
*
|
||||
* @param array<string,mixed> $options
|
||||
* @return void
|
||||
*/
|
||||
public function setOptions(array $options): void
|
||||
{
|
||||
foreach ($options as $key => $value) {
|
||||
if (empty($key)) {
|
||||
Error::setError(
|
||||
'110',
|
||||
'Cannot set option with empty key',
|
||||
['id' => $this->getId(), 'tag' => $this->getTag()]
|
||||
);
|
||||
// TODO: shoud throw error
|
||||
continue;
|
||||
}
|
||||
// if data is null
|
||||
if ($value === null) {
|
||||
if (isset($this->options[$key])) {
|
||||
unset($this->options[$key]);
|
||||
} else {
|
||||
Error::setError(
|
||||
'210',
|
||||
'Cannot set option with null value',
|
||||
['id' => $this->getId(), 'tag' => $this->getTag()]
|
||||
);
|
||||
}
|
||||
// TODO: shoud throw error
|
||||
continue;
|
||||
}
|
||||
$this->options[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the options array
|
||||
* also holds "name" option
|
||||
* anything like: style, javascript, value or any other html tag option
|
||||
* right side can be empty but not null
|
||||
*
|
||||
* @return array<string,string> get options as list html option name and value
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
// Sub Elements
|
||||
|
||||
/**
|
||||
* get the sub elements (array of Elements)
|
||||
*
|
||||
* @return array<Element> Array of Elements (that can have sub elements)
|
||||
*/
|
||||
public function getSub(): array
|
||||
{
|
||||
return $this->sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* add one or many sub elements (add at the end)
|
||||
*
|
||||
* @param Element $sub One or many elements to add
|
||||
* @return void
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public function addSub(Element ...$sub): void
|
||||
{
|
||||
foreach ($sub as $_sub) {
|
||||
// if one of the elements is the same as this class, ignore it
|
||||
// with this we avoid self reference loop
|
||||
if ($_sub == $this) {
|
||||
Error::setError(
|
||||
'100',
|
||||
'Cannot assign Element to itself, this would create an infinite loop',
|
||||
['id' => $this->getId(), 'tag' => $this->getTag()]
|
||||
);
|
||||
throw new HtmlBuilderExcpetion('Cannot assign Element to itself, this would create an infinite loop');
|
||||
}
|
||||
array_push($this->sub, $_sub);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element from the sub array
|
||||
* By pos in array or id set on first level
|
||||
*
|
||||
* @param int|string $id String id name or int pos number in array
|
||||
* @return void
|
||||
*/
|
||||
public function removeSub(int|string $id): void
|
||||
{
|
||||
// find element with id and remove it
|
||||
// or when number find pos in sub and remove it
|
||||
if (is_int($id)) {
|
||||
if (!isset($this->sub[$id])) {
|
||||
return;
|
||||
}
|
||||
unset($this->sub[$id]);
|
||||
return;
|
||||
}
|
||||
// only on first level
|
||||
foreach ($this->sub as $pos => $el) {
|
||||
if (
|
||||
$el->getId() === $id
|
||||
) {
|
||||
unset($this->sub[$pos]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove all sub elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetSub(): void
|
||||
{
|
||||
$this->sub = [];
|
||||
}
|
||||
|
||||
// CSS Elements
|
||||
|
||||
/**
|
||||
* get the current set css elements
|
||||
*
|
||||
* @return array<string> list of css element entries
|
||||
*/
|
||||
public function getCss(): array
|
||||
{
|
||||
return $this->css;
|
||||
}
|
||||
|
||||
/**
|
||||
* add one or many new css elements
|
||||
* Note that we can chain: add/remove/reset
|
||||
*
|
||||
* @param string ...$css one or more css strings to add
|
||||
* @return Element Current element for chaining
|
||||
*/
|
||||
public function addCss(string ...$css): Element
|
||||
{
|
||||
// should do check for empty/invalid css
|
||||
$_set_css = [];
|
||||
foreach ($css as $_css) {
|
||||
if (empty($_css)) {
|
||||
Error::setError(
|
||||
'204',
|
||||
'cannot have empty css string',
|
||||
);
|
||||
// TODO: shoud throw error
|
||||
continue;
|
||||
}
|
||||
// -?[_A-Za-z][_A-Za-z0-9-]*
|
||||
if (!preg_match("/^-?[_A-Za-z][_A-Za-z0-9-]*$/", $_css)) {
|
||||
Error::setWarning(
|
||||
'205',
|
||||
'possible invalid css string',
|
||||
['css' => $_css, 'id' => $this->id, 'tag' => $this->tag]
|
||||
);
|
||||
// TODO: shoud throw error
|
||||
}
|
||||
$_set_css[] = $_css;
|
||||
}
|
||||
$this->css = array_unique(array_merge($this->css, $_set_css));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove one or more css elements
|
||||
* Note that we can chain: add/remove/reset
|
||||
*
|
||||
* @param string ...$css one or more css strings to remove
|
||||
* @return Element Current element for chaining
|
||||
*/
|
||||
public function removeCss(string ...$css): Element
|
||||
{
|
||||
$this->css = array_diff($this->css, $css);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* unset all css elements
|
||||
* Note that we can chain: add/remove/reset
|
||||
*
|
||||
* @return Element
|
||||
*/
|
||||
public function resetCss(): Element
|
||||
{
|
||||
$this->css = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
// build output from tree
|
||||
|
||||
/**
|
||||
* build html string from the current element tree (self)
|
||||
* or from the Element tree given as parameter
|
||||
* if $add_nl is set then new lines are added before each sub element added
|
||||
* no indet is done (tab or other)
|
||||
*
|
||||
* @param Element|null $tree Different Element tree to build
|
||||
* if not set (null), self is used
|
||||
* @param bool $add_nl [default=false] Optional output string line breaks
|
||||
* @return string HTML as string
|
||||
*/
|
||||
public function buildHtml(Element $tree = null, bool $add_nl = false): string
|
||||
{
|
||||
// print "D01: " . microtime(true) . "<br>";
|
||||
if ($tree === null) {
|
||||
$tree = $this;
|
||||
}
|
||||
$line = '<' . $tree->getTag();
|
||||
|
||||
if ($tree->getId()) {
|
||||
$line .= ' id="' . $tree->getId() . '"';
|
||||
if (in_array($tree->getTag(), Settings::NAME_ELEMENTS)) {
|
||||
$line .= ' name="'
|
||||
. (!empty($tree->getName()) ? $tree->getName() : $tree->getId())
|
||||
. '"';
|
||||
}
|
||||
}
|
||||
if (count($tree->getCss())) {
|
||||
$line .= ' class="' . join(' ', $tree->getCss()) . '"';
|
||||
}
|
||||
foreach ($tree->getOptions() as $key => $item) {
|
||||
// skip
|
||||
if (in_array($key, Settings::SKIP_OPTIONS)) {
|
||||
continue;
|
||||
}
|
||||
$line .= ' ' . $key . '="' . $item . '"';
|
||||
}
|
||||
$line .= '>';
|
||||
if (strlen($tree->getContent()) > 0) {
|
||||
$line .= $tree->getContent();
|
||||
}
|
||||
// sub nodes
|
||||
foreach ($tree->getSub() as $sub) {
|
||||
if ($add_nl === true) {
|
||||
$line .= "\n";
|
||||
}
|
||||
$line .= $tree->buildHtml($sub, $add_nl);
|
||||
if ($add_nl === true) {
|
||||
$line .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// close line if needed
|
||||
if (!in_array($tree->getTag(), Settings::NO_CLOSE)) {
|
||||
$line .= '</' . $tree->getTag() . '>';
|
||||
}
|
||||
|
||||
return $line;
|
||||
}
|
||||
|
||||
// this is static
|
||||
|
||||
/**
|
||||
* Builds a single string from an array of elements
|
||||
* a new line can be added before each new element if $add_nl is set to true
|
||||
*
|
||||
* @param array<Element> $list array of Elements, uses buildHtml internal
|
||||
* @param bool $add_nl [default=false] Optional output string line breaks
|
||||
* @return string HTML as string
|
||||
*/
|
||||
public static function buildHtmlFromList(array $list, bool $add_nl = false): string
|
||||
{
|
||||
$output = '';
|
||||
foreach ($list as $el) {
|
||||
if (!empty($output) && $add_nl === true) {
|
||||
$output .= "\n";
|
||||
}
|
||||
$output .= $el->buildHtml();
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
// so we can call builder statically
|
||||
|
||||
/**
|
||||
* Search element tree for id and add
|
||||
* if id is empty add at element given in parameter $base
|
||||
*
|
||||
* @param Element $base Element to attach to
|
||||
* @param Element $attach Element to attach (single)
|
||||
* @param string $id Optional id, if empty then attached at the end
|
||||
* If set will loop through ALL sub elements until
|
||||
* matching id found. if not found, not added
|
||||
* @return Element Element with attached sub element
|
||||
*/
|
||||
public static function addElementWithId(
|
||||
Element $base,
|
||||
Element $attach,
|
||||
string $id = ''
|
||||
): Element {
|
||||
// no id or matching id
|
||||
if (
|
||||
empty($id) ||
|
||||
$base->getId() == $id
|
||||
) {
|
||||
$base->addSub($attach);
|
||||
return $base;
|
||||
}
|
||||
// find id in 'id' in all 'sub'
|
||||
foreach ($base->getSub() as $el) {
|
||||
self::addElementWithId($el, $attach, $id);
|
||||
}
|
||||
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* add one or more elemens to $base
|
||||
*
|
||||
* @param Element $base Element to attach to
|
||||
* @param Element ...$attach Element or Elements to attach
|
||||
* @return Element Element with attached sub elements
|
||||
*/
|
||||
public static function addElement(
|
||||
Element $base,
|
||||
Element ...$attach
|
||||
): Element {
|
||||
// we must make sure we do not self attach
|
||||
$base->addSub(...$attach);
|
||||
return $base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static call version for building
|
||||
* not recommended to be used, rather use "Element->buildHtml()"
|
||||
* wrapper for buildHtml
|
||||
*
|
||||
* @param ?Element $tree Element tree to build
|
||||
* if not set returns empty string
|
||||
* @param bool $add_nl [default=false] Optional output string line break
|
||||
* @return string build html as string
|
||||
* @deprecated Do not use, use Element->buildHtml() instead
|
||||
*/
|
||||
public static function printHtmlFromObject(Element $tree = null, bool $add_nl = false): string
|
||||
{
|
||||
// nothing ->bad
|
||||
if ($tree === null) {
|
||||
return '';
|
||||
}
|
||||
return $tree->buildHtml(add_nl: $add_nl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
* wrapper for buildHtmlFromList
|
||||
*
|
||||
* @param array<Element> $list array of Elements to build string from
|
||||
* @param bool $add_nl [default=false] Optional output string line break
|
||||
* @return string build html as string
|
||||
*/
|
||||
public static function printHtmlFromArray(array $list, bool $add_nl = false): string
|
||||
{
|
||||
return self::buildHtmlFromList($list, $add_nl);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
127
src/Template/HtmlBuilder/General/Error.php
Normal file
127
src/Template/HtmlBuilder/General/Error.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/6/27
|
||||
* DESCRIPTION:
|
||||
* Error logging for the HtmlBuilder systs
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Template\HtmlBuilder\General;
|
||||
|
||||
class Error
|
||||
{
|
||||
/** @var array<array{level:string,id:string,message:string,context:array<mixed>}> */
|
||||
private static array $messages = [];
|
||||
|
||||
/**
|
||||
* internal writer for messages
|
||||
*
|
||||
* @param string $level
|
||||
* @param string $id
|
||||
* @param string $message
|
||||
* @param array<mixed> $context
|
||||
* @return void
|
||||
*/
|
||||
private static function writeContent(
|
||||
string $level,
|
||||
string $id,
|
||||
string $message,
|
||||
array $context
|
||||
): void {
|
||||
self::$messages[] = [
|
||||
'level' => $level,
|
||||
'id' => $id,
|
||||
'message' => $message,
|
||||
'context' => $context,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* warning collector for all internal string errors
|
||||
* builds an warning with warning id, message text and array with optional content
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $message
|
||||
* @param array<mixed> $context
|
||||
* @return void
|
||||
*/
|
||||
public static function setWarning(string $id, string $message, array $context = []): void
|
||||
{
|
||||
self::writeContent('Warning', $id, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* error collector for all internal string errors
|
||||
* builds an error with error id, message text and array with optional content
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $message
|
||||
* @param array<mixed> $context
|
||||
* @return void
|
||||
*/
|
||||
public static function setError(string $id, string $message, array $context = []): void
|
||||
{
|
||||
self::writeContent('Error', $id, $message, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all set errors
|
||||
*
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public static function getMessages(): array
|
||||
{
|
||||
return self::$messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all errors
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function resetMessages(): void
|
||||
{
|
||||
self::$messages = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* internal level in message array exists check
|
||||
*
|
||||
* @param string $level
|
||||
* @return bool
|
||||
*/
|
||||
private static function hasLevel(string $level): bool
|
||||
{
|
||||
return array_filter(
|
||||
self::$messages,
|
||||
function ($var) use ($level) {
|
||||
return $var['level'] == $level ? true : false;
|
||||
}
|
||||
) === [] ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any error is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasError(): bool
|
||||
{
|
||||
return self::hasLevel('Error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any warning is set
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasWarning(): bool
|
||||
{
|
||||
return self::hasLevel('Warning');
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
21
src/Template/HtmlBuilder/General/HtmlBuilderExcpetion.php
Normal file
21
src/Template/HtmlBuilder/General/HtmlBuilderExcpetion.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/6/28
|
||||
* DESCRIPTION:
|
||||
* Exception class for the HtmlBuilder blocks
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Template\HtmlBuilder\General;
|
||||
|
||||
/**
|
||||
* Exception class for HtmlBuilder
|
||||
*/
|
||||
class HtmlBuilderExcpetion extends \Exception
|
||||
{
|
||||
}
|
||||
|
||||
// __END__
|
||||
69
src/Template/HtmlBuilder/General/Settings.php
Normal file
69
src/Template/HtmlBuilder/General/Settings.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/7/22
|
||||
* DESCRIPTION:
|
||||
* General settings for html elements
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Template\HtmlBuilder\General;
|
||||
|
||||
class Settings
|
||||
{
|
||||
/** @var array<string> list of html elements that can have the name tag */
|
||||
public const NAME_ELEMENTS = [
|
||||
'button',
|
||||
'fieldset',
|
||||
'form',
|
||||
'iframe',
|
||||
'input',
|
||||
'map',
|
||||
'meta',
|
||||
'object',
|
||||
'output',
|
||||
'param',
|
||||
'select',
|
||||
'textarea',
|
||||
];
|
||||
|
||||
/** @var array<string> options key entries to be skipped in build */
|
||||
public const SKIP_OPTIONS = [
|
||||
'id',
|
||||
'name',
|
||||
'class',
|
||||
];
|
||||
|
||||
/** @var array<string> html elements that don't need to be closed */
|
||||
public const NO_CLOSE = [
|
||||
'input',
|
||||
'br',
|
||||
'img',
|
||||
'hr',
|
||||
'area',
|
||||
'col',
|
||||
'keygen',
|
||||
'wbr',
|
||||
'track',
|
||||
'source',
|
||||
'param',
|
||||
'command',
|
||||
// only in header
|
||||
'base',
|
||||
'meta',
|
||||
'link',
|
||||
'embed',
|
||||
];
|
||||
|
||||
/** @var array<string> invalid tags, not allowed in body */
|
||||
public const NOT_IN_BODY_ALLOWED = [
|
||||
'base',
|
||||
'meta',
|
||||
'link',
|
||||
'embed', // not sure
|
||||
];
|
||||
}
|
||||
|
||||
// __END__
|
||||
194
src/Template/HtmlBuilder/StringReplace.php
Normal file
194
src/Template/HtmlBuilder/StringReplace.php
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/6/23
|
||||
* DESCRIPTION:
|
||||
* Simeple string replace calls for elements
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\Template\HtmlBuilder;
|
||||
|
||||
use CoreLibs\Template\HtmlBuilder\General\Error;
|
||||
use CoreLibs\Template\HtmlBuilder\General\HtmlBuilderExcpetion;
|
||||
|
||||
class StringReplace
|
||||
{
|
||||
/** @var array<string,string> */
|
||||
private static array $elements = [];
|
||||
/** @var array<string,string> */
|
||||
private static array $replace = [];
|
||||
|
||||
/**
|
||||
* load html blocks into array for repeated usage
|
||||
* each array group parameter has 0: index, 1: content
|
||||
* There is no content check done.
|
||||
* index must be non empty (but has no fixed format)
|
||||
* if same index is tried twice it will set an error and skip
|
||||
*
|
||||
* @param array{0:string,1:string} ...$element Elements to load
|
||||
* @return void
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public static function loadElements(array ...$element): void
|
||||
{
|
||||
foreach ($element as $el) {
|
||||
$index = $el[0] ?? '';
|
||||
if (empty($index)) {
|
||||
Error::setError(
|
||||
'310',
|
||||
'Index cannot be an empty string',
|
||||
[
|
||||
'element' => $index
|
||||
]
|
||||
);
|
||||
throw new HtmlBuilderExcpetion('Index cannot be an empty string');
|
||||
}
|
||||
if (isset(self::$elements[$index])) {
|
||||
Error::setError(
|
||||
'311',
|
||||
'Index already exists',
|
||||
[
|
||||
'element' => $index
|
||||
]
|
||||
);
|
||||
throw new HtmlBuilderExcpetion('Index already exists: ' . $index);
|
||||
}
|
||||
// content check?
|
||||
self::$elements[$index] = $el[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update an element at index
|
||||
* can also be used to reset (empty string)
|
||||
*
|
||||
* @param string $index
|
||||
* @param string $element
|
||||
* @return void
|
||||
*/
|
||||
public static function updateElement(string $index, string $element): void
|
||||
{
|
||||
if (!isset(self::$elements[$index])) {
|
||||
Error::setError(
|
||||
'312',
|
||||
'Index does not exists',
|
||||
[
|
||||
'element' => $index
|
||||
]
|
||||
);
|
||||
throw new HtmlBuilderExcpetion('Index does not exists: ' . $index);
|
||||
}
|
||||
// allow empty reset
|
||||
self::$elements[$index] = $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* get an element block at index
|
||||
* if not found will return false
|
||||
*
|
||||
* @param string $index
|
||||
* @return string
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public static function getElement(string $index): string
|
||||
{
|
||||
if (!isset(self::$elements[$index])) {
|
||||
Error::setError('321', 'Index not found in elements', ['element' => $index]);
|
||||
throw new HtmlBuilderExcpetion('Index not found in elements array: ' . $index);
|
||||
}
|
||||
return self::$elements[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* set a replacement block at index
|
||||
* can be used for setting one block and using it agai
|
||||
*
|
||||
* @param string $index
|
||||
* @param string $content
|
||||
* @return void
|
||||
*/
|
||||
public static function setReplaceBlock(string $index, string $content): void
|
||||
{
|
||||
self::$replace[$index] = $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* get replacement block at index, if not found return empty and set error
|
||||
*
|
||||
* @param string $index
|
||||
* @return string
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public static function getReplaceBlock(string $index): string
|
||||
{
|
||||
if (!isset(self::$replace[$index])) {
|
||||
Error::setError('331', 'Index not found in replace block', ['replace' => $index]);
|
||||
throw new HtmlBuilderExcpetion('Index not found in replace block array: ' . $index);
|
||||
}
|
||||
return self::$replace[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* build and element on an index and either returns it or also sets it
|
||||
* into the replace block array
|
||||
* if index not found in relement list will return false
|
||||
*
|
||||
* @param string $index index of set element
|
||||
* @param array<string,string> $replace array of text to search (key) and replace (value) for
|
||||
* @return string
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public static function buildElement(
|
||||
string $index,
|
||||
array $replace,
|
||||
string $replace_index = ''
|
||||
): string {
|
||||
try {
|
||||
self::getElement($index);
|
||||
} catch (HtmlBuilderExcpetion $e) {
|
||||
throw new HtmlBuilderExcpetion('Cannot fetch element with index: ' . $index, 0, $e);
|
||||
}
|
||||
if ($replace_index) {
|
||||
self::setReplaceBlock(
|
||||
$replace_index,
|
||||
self::replaceData(self::$elements[$index], $replace)
|
||||
);
|
||||
return self::getReplaceBlock($replace_index);
|
||||
} else {
|
||||
return self::replaceData(self::$elements[$index], $replace);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* main replace entries in text string
|
||||
* elements to be replaced are in {} brackets. if they are missing in the
|
||||
* replace array they will be added.
|
||||
* if the replace and content count is not the same then an error will be thrown
|
||||
*
|
||||
* @param string $data
|
||||
* @param array<string,string> $replace
|
||||
* @return string
|
||||
* @throws HtmlBuilderExcpetion
|
||||
*/
|
||||
public static function replaceData(string $data, array $replace): string
|
||||
{
|
||||
$to_replace = array_keys($replace);
|
||||
// all replace data must have {} around
|
||||
array_walk($to_replace, function (&$entry) {
|
||||
if (!str_starts_with($entry, '{')) {
|
||||
$entry = '{' . $entry;
|
||||
}
|
||||
if (!str_ends_with($entry, '}')) {
|
||||
$entry .= '}';
|
||||
}
|
||||
// do some validation?
|
||||
});
|
||||
// replace content
|
||||
return str_replace($to_replace, array_values($replace), $data);
|
||||
}
|
||||
}
|
||||
|
||||
// __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(
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -458,6 +458,47 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dateRangeHasWeekendProvider(): array
|
||||
{
|
||||
return [
|
||||
'no weekend' => [
|
||||
'2023-07-03',
|
||||
'2023-07-04',
|
||||
false
|
||||
],
|
||||
'start weekend sat' => [
|
||||
'2023-07-01',
|
||||
'2023-07-04',
|
||||
true
|
||||
],
|
||||
'start weekend sun' => [
|
||||
'2023-07-02',
|
||||
'2023-07-04',
|
||||
true
|
||||
],
|
||||
'end weekend sat' => [
|
||||
'2023-07-03',
|
||||
'2023-07-08',
|
||||
true
|
||||
],
|
||||
'end weekend sun' => [
|
||||
'2023-07-03',
|
||||
'2023-07-09',
|
||||
true
|
||||
],
|
||||
'long period > 6 days' => [
|
||||
'2023-07-03',
|
||||
'2023-07-27',
|
||||
true
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* date string convert test
|
||||
*
|
||||
@@ -780,6 +821,29 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
|
||||
$output
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::dateRangeHasWeekend
|
||||
* @dataProvider dateRangeHasWeekendProvider
|
||||
* @testdox dateRangeHasWeekend $start_date and $end_date are expected weekend $expected [$_dataName]
|
||||
*
|
||||
* @param string $start_date
|
||||
* @param string $end_date
|
||||
* @param bool $expected
|
||||
* @return void
|
||||
*/
|
||||
public function testDateRangeHasWeekend(
|
||||
string $start_date,
|
||||
string $end_date,
|
||||
bool $expected
|
||||
): void {
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
\CoreLibs\Combined\DateTime::dateRangeHasWeekend($start_date, $end_date)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
|
||||
@@ -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,8 @@ namespace tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use CoreLibs\Logging\Logger\Level;
|
||||
use CoreLibs\DB\Options\Convert;
|
||||
|
||||
/**
|
||||
* Test class for DB\IO + DB\SQL\PgSQL
|
||||
@@ -59,20 +61,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 +73,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 +85,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 +97,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 +117,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 +139,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 +155,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 +520,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 +530,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 +540,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 +737,6 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
'host' => 'db_host',
|
||||
'port' => 'db_port',
|
||||
'ssl' => 'db_ssl',
|
||||
'debug' => 'db_debug',
|
||||
'password' => '***',
|
||||
] as $read => $compare
|
||||
) {
|
||||
@@ -1342,10 +1269,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 +1282,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 +1301,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 +1314,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 +4352,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 +4456,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,
|
||||
@@ -4631,6 +4558,176 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
$db->dbClose();
|
||||
}
|
||||
|
||||
// testing auto convert
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::dbSetConvertFlag
|
||||
* @testdox Check convert type works
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testConvertType(): void
|
||||
{
|
||||
$db = new \CoreLibs\DB\IO(
|
||||
self::$db_config['valid'],
|
||||
self::$log
|
||||
);
|
||||
$bytea_data = $db->dbEscapeBytea(
|
||||
file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'CoreLibsDBIOTest.php') ?: ''
|
||||
);
|
||||
$query_insert = <<<SQL
|
||||
INSERT INTO table_with_primary_key (
|
||||
uid,
|
||||
row_int, row_numeric, row_varchar, row_varchar_literal,
|
||||
row_json, row_jsonb, row_bytea, row_timestamp,
|
||||
row_date, row_interval, row_array_int, row_array_varchar
|
||||
) VALUES (
|
||||
$1,
|
||||
$2, $3, $4, $5,
|
||||
$6, $7, $8, $9,
|
||||
$10, $11, $12, $13
|
||||
)
|
||||
SQL;
|
||||
$db->dbExecParams(
|
||||
$query_insert,
|
||||
[
|
||||
'CONVERT_TYPE_TEST',
|
||||
1, 1.5, 'varchar', 'varchar literla',
|
||||
json_encode(['json', 'a', 1, true, 'sub' => ['b', 'c']]),
|
||||
json_encode(['jsonb', 'a', 1, true, 'sub' => ['b', 'c']]),
|
||||
$bytea_data, date('Y-m-d H:i:s'), date('Y-m-d'), date('H:m:s'),
|
||||
'{1,2,3}', '{"a","b","c"}'
|
||||
]
|
||||
);
|
||||
$type_layout = [
|
||||
'uid' => 'string',
|
||||
'row_int' => 'int',
|
||||
'row_numeric' => 'float',
|
||||
'row_varchar' => 'string',
|
||||
'row_varchar_literal' => 'string',
|
||||
'row_json' => 'json',
|
||||
'row_jsonb' => 'json',
|
||||
'row_bytea' => 'bytea',
|
||||
'row_timestamp' => 'string',
|
||||
'row_date' => 'string',
|
||||
'row_interval' => 'string',
|
||||
'row_array_int' => 'string',
|
||||
'row_array_varchar' => 'string'
|
||||
];
|
||||
$query_select = <<<SQL
|
||||
SELECT
|
||||
uid,
|
||||
row_int, row_numeric, row_varchar, row_varchar_literal,
|
||||
row_json, row_jsonb, row_bytea, row_timestamp,
|
||||
row_date, row_interval, row_array_int, row_array_varchar
|
||||
FROM
|
||||
table_with_primary_key
|
||||
WHERE
|
||||
uid = $1
|
||||
SQL;
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
// all hast to be string
|
||||
foreach ($res as $key => $value) {
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key);
|
||||
}
|
||||
// convert base only
|
||||
$db->dbSetConvertFlag(Convert::on);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$db->dbSetConvertFlag(Convert::numeric);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'float':
|
||||
$this->assertIsFloat($value, 'Aseert float for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$db->dbSetConvertFlag(Convert::json);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'float':
|
||||
$this->assertIsFloat($value, 'Aseert float for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'json':
|
||||
case 'jsonb':
|
||||
$this->assertIsArray($value, 'Aseert array for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$db->dbSetConvertFlag(Convert::bytea);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'float':
|
||||
$this->assertIsFloat($value, 'Aseert float for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'json':
|
||||
case 'jsonb':
|
||||
$this->assertIsArray($value, 'Aseert array for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'bytea':
|
||||
// for hex types it must not start with \x
|
||||
$this->assertStringStartsNotWith(
|
||||
'\x',
|
||||
$value,
|
||||
'Aseert bytes not starts with \x for column: ' . $key . '/' . $name
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - internal read data (post exec)
|
||||
// dbGetNumRows, dbGetNumFields, dbGetFieldNames,
|
||||
// dbGetQuery, dbGetQueryHash, dbGetDbh
|
||||
@@ -4662,7 +4759,7 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
. "('Foxtrott', 'Tango', 789, '1982-10-15') ",
|
||||
null,
|
||||
//
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
['row_varchar', 'row_varchar_literal', 'row_int', 'row_date'],
|
||||
['varchar', 'varchar', 'int4', 'date'],
|
||||
@@ -4779,9 +4876,16 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
$db->dbExecParams($query, $params);
|
||||
}
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'PgSql\Result',
|
||||
$db->dbGetCursor(),
|
||||
'Failed assert dbGetCursor'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$compare_query ?? $query,
|
||||
$db->dbGetQuery()
|
||||
$db->dbGetQuery(),
|
||||
'Failed assert dbGetQuery'
|
||||
);
|
||||
$this->assertEquals(
|
||||
// perhaps move that somewhere else?
|
||||
@@ -4794,7 +4898,8 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
($params === null ?
|
||||
$db->dbGetQueryHash($query) :
|
||||
$db->dbGetQueryHash($query, $params)
|
||||
)
|
||||
),
|
||||
'Failed assertdbGetQueryHash '
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected_rows,
|
||||
@@ -4816,6 +4921,35 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
$db->dbGetFieldTypes(),
|
||||
'Failed assert dbGetFieldTypes'
|
||||
);
|
||||
// check FieldNameTypes matches
|
||||
$this->assertEquals(
|
||||
array_combine(
|
||||
$expected_col_names,
|
||||
$expected_col_types
|
||||
),
|
||||
$db->dbGetFieldNameTypes(),
|
||||
'Failed assert dbGetFieldNameTypes'
|
||||
);
|
||||
// check pos matches name
|
||||
// name matches type
|
||||
// pos matches type
|
||||
foreach ($expected_col_names as $pos => $name) {
|
||||
$this->assertEquals(
|
||||
$name,
|
||||
$db->dbGetFieldName($pos),
|
||||
'Failed assert dbGetFieldName: ' . $pos . ' => ' . $name
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected_col_types[$pos],
|
||||
$db->dbGetFieldType($name),
|
||||
'Failed assert dbGetFieldType: ' . $name . ' => ' . $expected_col_types[$pos]
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected_col_types[$pos],
|
||||
$db->dbGetFieldType($pos),
|
||||
'Failed assert dbGetFieldType: ' . $pos . ' => ' . $expected_col_types[$pos]
|
||||
);
|
||||
}
|
||||
$dbh = $db->dbGetDbh();
|
||||
$this->assertIsObject(
|
||||
$dbh
|
||||
|
||||
@@ -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";
|
||||
|
||||
847
test/phpunit/Logging/CoreLibsLoggingLoggingTest.php
Normal file
847
test/phpunit/Logging/CoreLibsLoggingLoggingTest.php
Normal file
@@ -0,0 +1,847 @@
|
||||
<?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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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'
|
||||
);
|
||||
}
|
||||
|
||||
// check log level that writer writes in correct level
|
||||
// also that non debug ignores prefix/group
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::log
|
||||
* @testdox log() general call test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLoggingLog(): void
|
||||
{
|
||||
// init logger
|
||||
$log = new \CoreLibs\Logging\Logging([
|
||||
'log_file_id' => 'testLoggingLog',
|
||||
'log_folder' => self::LOG_FOLDER,
|
||||
'log_per_level' => true,
|
||||
]);
|
||||
$log_ok = $log->log(Level::Debug, 'DEBUG', group_id: 'GROUP_ID', prefix: 'PREFIX:');
|
||||
$this->assertTrue($log_ok, 'assert ::log (debug) OK');
|
||||
$this->assertEquals(
|
||||
$log->getLogFile(),
|
||||
$log->getLogFileId() . '_DEBUG.log'
|
||||
);
|
||||
$log_ok = $log->log(Level::Info, 'INFO', group_id: 'GROUP_ID', prefix: 'PREFIX:');
|
||||
$this->assertTrue($log_ok, 'assert ::log (info) OK');
|
||||
$this->assertEquals(
|
||||
$log->getLogFile(),
|
||||
$log->getLogFileId() . '_INFO.log'
|
||||
);
|
||||
}
|
||||
|
||||
// must test flow:
|
||||
// init normal
|
||||
// log -> check file name
|
||||
// set per date
|
||||
// log -> check file name
|
||||
// and same for per_run
|
||||
|
||||
// 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 CoreLibsSecuritySymmetricEncryptionTest 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__
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use CoreLibs\Template\HtmlBuilder\Block;
|
||||
|
||||
/**
|
||||
* Test class for Template\HtmlBuilder\Block
|
||||
* @coversDefaultClass \CoreLibs\Template\HtmlBuilder\Block
|
||||
* @testdox \CoreLibs\Template\HtmlBuilder\Block method tests
|
||||
*/
|
||||
final class CoreLibsTemplateHtmlBuilderBlockTest extends TestCase
|
||||
{
|
||||
public function testCreateBlock(): void
|
||||
{
|
||||
$el = Block::cel('div', 'id', 'content', ['css'], ['onclick' => 'foo();']);
|
||||
$this->assertEquals(
|
||||
'<div id="id" class="css" onclick="foo();">content</div>',
|
||||
Block::buildHtml($el)
|
||||
);
|
||||
}
|
||||
|
||||
// ael
|
||||
// aelx|addSub
|
||||
// resetSub
|
||||
// acssel/rcssel/scssel
|
||||
// buildHtml
|
||||
// buildHtmlFromList|printHtmlFromArray
|
||||
}
|
||||
|
||||
// __END__
|
||||
546
test/phpunit/Template/CoreLibsTemplateHtmlBuilderElementTest.php
Normal file
546
test/phpunit/Template/CoreLibsTemplateHtmlBuilderElementTest.php
Normal file
@@ -0,0 +1,546 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use CoreLibs\Template\HtmlBuilder\Element;
|
||||
use CoreLibs\Template\HtmlBuilder\General\Error;
|
||||
use CoreLibs\Template\HtmlBuilder\General\HtmlBuilderExcpetion;
|
||||
|
||||
/**
|
||||
* Test class for Template\HtmlBuilder\Element
|
||||
* @coversDefaultClass \CoreLibs\Template\HtmlBuilder\Element
|
||||
* @testdox \CoreLibs\Template\HtmlBuilder\Element method tests
|
||||
*/
|
||||
final class CoreLibsTemplateHtmlBuilderElementTest extends TestCase
|
||||
{
|
||||
public function providerCreateElements(): array
|
||||
{
|
||||
return [
|
||||
'simple div' => [
|
||||
'tag' => 'div',
|
||||
'id' => 'id',
|
||||
'content' => 'content',
|
||||
'css' => ['css'],
|
||||
'options' => ['onclick' => 'foo();'],
|
||||
'expected' => '<div id="id" class="css" onclick="foo();">content</div>'
|
||||
],
|
||||
'simple input' => [
|
||||
'tag' => 'input',
|
||||
'id' => 'id',
|
||||
'content' => null,
|
||||
'css' => ['css'],
|
||||
'options' => ['name' => 'name', 'onclick' => 'foo();'],
|
||||
'expected' => '<input id="id" name="name" class="css" onclick="foo();">'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::Element
|
||||
* @covers ::buildHtml
|
||||
* @covers ::getTag
|
||||
* @covers ::getId
|
||||
* @covers ::getContent
|
||||
* @covers ::getOptions
|
||||
* @covers ::getCss
|
||||
* @dataProvider providerCreateElements
|
||||
* @testdox create single new Element test [$_dataName]
|
||||
*
|
||||
* @param string $tag
|
||||
* @param string|null $id
|
||||
* @param string|null $content
|
||||
* @param array|null $css
|
||||
* @param array|null $options
|
||||
* @param string $expected
|
||||
* @return void
|
||||
*/
|
||||
public function testCreateElement(
|
||||
string $tag,
|
||||
?string $id,
|
||||
?string $content,
|
||||
?array $css,
|
||||
?array $options,
|
||||
string $expected
|
||||
): void {
|
||||
$el = new Element($tag, $id ?? '', $content ?? '', $css ?? [], $options ?? []);
|
||||
$this->assertEquals(
|
||||
$expected,
|
||||
$el->buildHtml(),
|
||||
'element creation failed'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$tag,
|
||||
$el->getTag(),
|
||||
'get tag failed'
|
||||
);
|
||||
|
||||
if ($id !== null) {
|
||||
$this->assertEquals(
|
||||
$id,
|
||||
$el->getId(),
|
||||
'get id failed'
|
||||
);
|
||||
}
|
||||
if ($content !== null) {
|
||||
$this->assertEquals(
|
||||
$content,
|
||||
$el->getContent(),
|
||||
'get content failed'
|
||||
);
|
||||
}
|
||||
if ($css !== null) {
|
||||
$this->assertEquals(
|
||||
$css,
|
||||
$el->getCss(),
|
||||
'get css failed'
|
||||
);
|
||||
}
|
||||
if ($options !== null) {
|
||||
$this->assertEquals(
|
||||
$options,
|
||||
$el->getOptions(),
|
||||
'get options failed'
|
||||
);
|
||||
}
|
||||
if (!empty($options['name'])) {
|
||||
$this->assertEquals(
|
||||
$options['name'],
|
||||
$el->getName(),
|
||||
'get name failed'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* css add/remove
|
||||
*
|
||||
* @cover ::getCss
|
||||
* @cover ::addCss
|
||||
* @cover ::removeCss
|
||||
* @testdox test handling of adding and removing css classes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCssHandling(): void
|
||||
{
|
||||
$el = new Element('div', 'css-test', 'CSS content');
|
||||
$this->assertEqualsCanonicalizing(
|
||||
[],
|
||||
$el->getCss(),
|
||||
'check empty css'
|
||||
);
|
||||
$el->addCss('foo');
|
||||
$this->assertEqualsCanonicalizing(
|
||||
['foo'],
|
||||
$el->getCss(),
|
||||
'check added one css'
|
||||
);
|
||||
$el->removeCss('foo');
|
||||
$this->assertEqualsCanonicalizing(
|
||||
[],
|
||||
$el->getCss(),
|
||||
'check remove added css'
|
||||
);
|
||||
// add serveral
|
||||
// remove some of them
|
||||
$el->addCss('a', 'b', 'c');
|
||||
$this->assertEqualsCanonicalizing(
|
||||
['a', 'b', 'c'],
|
||||
$el->getCss(),
|
||||
'check added some css'
|
||||
);
|
||||
$el->removeCss('a', 'c');
|
||||
// $this->assertArray
|
||||
$this->assertEqualsCanonicalizing(
|
||||
['b'],
|
||||
$el->getCss(),
|
||||
'check remove some css'
|
||||
);
|
||||
// chained add and remove
|
||||
$el->addCss('a', 'b', 'c', 'd')->removeCss('b', 'd');
|
||||
$this->assertEqualsCanonicalizing(
|
||||
['a', 'c'],
|
||||
$el->getCss(),
|
||||
'check chain add remove some css'
|
||||
);
|
||||
$el->resetCss();
|
||||
$this->assertEqualsCanonicalizing(
|
||||
[],
|
||||
$el->getCss(),
|
||||
'check reset css'
|
||||
);
|
||||
// remove something that does not eixst
|
||||
$el->addCss('exists');
|
||||
$el->removeCss('not');
|
||||
$this->assertEqualsCanonicalizing(
|
||||
['exists'],
|
||||
$el->getCss(),
|
||||
'check remove not exitsing'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* nested test
|
||||
*
|
||||
* @testdox nested test and loop assign detection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBuildNested(): void
|
||||
{
|
||||
Error::resetMessages();
|
||||
$el = new Element('div', 'build-test');
|
||||
$el_sub = new Element('div', 'sub-1');
|
||||
$el->addSub($el_sub);
|
||||
$this->assertEquals(
|
||||
'<div id="build-test"><div id="sub-1"></div></div>',
|
||||
$el->buildHtml(),
|
||||
'nested build failed'
|
||||
);
|
||||
// this would create a loop, throws error
|
||||
$this->expectException(HtmlBuilderExcpetion::class);
|
||||
$this->expectExceptionMessage("Cannot assign Element to itself, this would create an infinite loop");
|
||||
$el_sub->addSub($el_sub);
|
||||
$this->assertEquals(
|
||||
'<div id="sub-1"></div>',
|
||||
$el_sub->buildHtml(),
|
||||
'loop detection failed'
|
||||
);
|
||||
$this->assertTrue(
|
||||
Error::hasError(),
|
||||
'failed to throw error post loop detection'
|
||||
);
|
||||
$this->assertEquals(
|
||||
[[
|
||||
'level' => 'Error',
|
||||
'id' => '100',
|
||||
'message' => 'Cannot assign Element to itself, this would create an infinite loop',
|
||||
'context' => ['tag' => 'div', 'id' => 'sub-1']
|
||||
]],
|
||||
Error::getMessages(),
|
||||
'check error is 100 failed'
|
||||
);
|
||||
// get sub
|
||||
$this->assertEquals(
|
||||
[$el_sub],
|
||||
$el->getSub(),
|
||||
'get sub failed'
|
||||
);
|
||||
// reset sub
|
||||
$el->resetSub();
|
||||
$this->assertEquals(
|
||||
[],
|
||||
$el->getSub(),
|
||||
'reset sub failed'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox updated nested connection
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNestedChangeContent(): void
|
||||
{
|
||||
$el = new Element('div', 'build-test');
|
||||
$el_s_1 = new Element('div', 'sub-1');
|
||||
$el_s_2 = new Element('div', 'sub-2');
|
||||
$el_s_3 = new Element('div', 'sub-3');
|
||||
$el_s_4 = new Element('div', 'sub-4');
|
||||
|
||||
$el->addSub($el_s_1, $el_s_2);
|
||||
// only sub -1, -2
|
||||
$this->assertEquals(
|
||||
'<div id="build-test"><div id="sub-1"></div><div id="sub-2"></div></div>',
|
||||
$el->buildHtml(),
|
||||
'check basic nested'
|
||||
);
|
||||
|
||||
// now add -3, -4 to both -1 and -2
|
||||
$el_s_1->addSub($el_s_3, $el_s_4);
|
||||
$el_s_2->addSub($el_s_3, $el_s_4);
|
||||
$this->assertEquals(
|
||||
'<div id="build-test"><div id="sub-1"><div id="sub-3"></div><div id="sub-4">'
|
||||
. '</div></div><div id="sub-2"><div id="sub-3"></div><div id="sub-4"></div>'
|
||||
. '</div></div>',
|
||||
$el->buildHtml(),
|
||||
'check nested added'
|
||||
);
|
||||
|
||||
// now add some css to el_s_3, will update in both sets
|
||||
$el_s_3->addCss('red');
|
||||
$this->assertEquals(
|
||||
'<div id="build-test"><div id="sub-1"><div id="sub-3" class="red"></div><div id="sub-4">'
|
||||
. '</div></div><div id="sub-2"><div id="sub-3" class="red"></div><div id="sub-4"></div>'
|
||||
. '</div></div>',
|
||||
$el->buildHtml(),
|
||||
'check nested u@dated'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox test change tag/id/content
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testChangeElementData(): void
|
||||
{
|
||||
$el = new Element('div', 'id', 'Content');
|
||||
// content change
|
||||
$this->assertEquals(
|
||||
'Content',
|
||||
$el->getContent(),
|
||||
'set content'
|
||||
);
|
||||
$el->setContent('New Content');
|
||||
$this->assertEquals(
|
||||
'New Content',
|
||||
$el->getContent(),
|
||||
'changed content'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'div',
|
||||
$el->getTag(),
|
||||
'set tag'
|
||||
);
|
||||
$el->setTag('span');
|
||||
$this->assertEquals(
|
||||
'span',
|
||||
$el->getTag(),
|
||||
'changed tag'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'id',
|
||||
$el->getId(),
|
||||
'set id'
|
||||
);
|
||||
$el->setId('id-2');
|
||||
$this->assertEquals(
|
||||
'id-2',
|
||||
$el->getId(),
|
||||
'changed id'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox test change options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testChangeOptions(): void
|
||||
{
|
||||
$el = new Element('button', 'id', 'Action', ['css'], ['value' => '3']);
|
||||
$this->assertEquals(
|
||||
['value' => '3'],
|
||||
$el->getOptions(),
|
||||
'set option'
|
||||
);
|
||||
$el->setOptions([
|
||||
'value' => '2'
|
||||
]);
|
||||
$this->assertEquals(
|
||||
['value' => '2'],
|
||||
$el->getOptions(),
|
||||
'changed option'
|
||||
);
|
||||
// add a new one
|
||||
$el->setOptions([
|
||||
'Foo' => 'bar',
|
||||
'Moo' => 'cow'
|
||||
]);
|
||||
$this->assertEquals(
|
||||
[
|
||||
'value' => '2',
|
||||
'Foo' => 'bar',
|
||||
'Moo' => 'cow'
|
||||
],
|
||||
$el->getOptions(),
|
||||
'changed option'
|
||||
);
|
||||
}
|
||||
|
||||
// build output
|
||||
// build from array list
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox build element tree from object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBuildHtmlObject(): void
|
||||
{
|
||||
// build a simple block
|
||||
// div -> div -> button
|
||||
// -> div -> span
|
||||
// -> div -> input
|
||||
$el = new Element('div', 'master', '', ['master']);
|
||||
$el->addSub(
|
||||
Element::addElement(
|
||||
new Element('div', 'div-button', '', ['dv-bt']),
|
||||
new Element('button', 'button-id', 'Click me', ['bt-red'], [
|
||||
'OnClick' => 'action();',
|
||||
'value' => 'click',
|
||||
'type' => 'button'
|
||||
]),
|
||||
),
|
||||
Element::addElement(
|
||||
new Element('div', 'div-span', '', ['dv-sp']),
|
||||
new Element('span', 'span-id', 'Big important message<br>other', ['red']),
|
||||
),
|
||||
Element::addElement(
|
||||
new Element('div', 'div-input', '', ['dv-in']),
|
||||
new Element('input', 'input-id', '', ['in-blue'], [
|
||||
'OnClick' => 'otherAction();',
|
||||
'value' => 'Touch',
|
||||
'type' => 'button'
|
||||
]),
|
||||
),
|
||||
);
|
||||
$this->assertEquals(
|
||||
'<div id="master" class="master">'
|
||||
. '<div id="div-button" class="dv-bt">'
|
||||
. '<button id="button-id" name="button-id" class="bt-red" OnClick="action();" '
|
||||
. 'value="click" type="button">Click me</button>'
|
||||
. '</div>'
|
||||
. '<div id="div-span" class="dv-sp">'
|
||||
. '<span id="span-id" class="red">Big important message<br>other</span>'
|
||||
. '</div>'
|
||||
. '<div id="div-input" class="dv-in">'
|
||||
. '<input id="input-id" name="input-id" '
|
||||
. 'class="in-blue" OnClick="otherAction();" value="Touch" type="button">'
|
||||
. '</div>'
|
||||
. '</div>',
|
||||
$el->buildHtml()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox build elements from array list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testbuildHtmlArray(): void
|
||||
{
|
||||
$this->assertEquals(
|
||||
'<div id="id-1">A</div>'
|
||||
. '<div id="id-2">B</div>'
|
||||
. '<div id="id-3">C</div>',
|
||||
Element::buildHtmlFromList([
|
||||
new Element('div', 'id-1', 'A'),
|
||||
new Element('div', 'id-2', 'B'),
|
||||
new Element('div', 'id-3', 'C'),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox check for invalid tag detection, possible invalid id, possible invalid css
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvalidElement(): void
|
||||
{
|
||||
Error::resetMessages();
|
||||
$this->expectException(HtmlBuilderExcpetion::class);
|
||||
$this->expectExceptionMessage("Could not create Element");
|
||||
$el = new Element('');
|
||||
$this->assertTrue(
|
||||
Error::hasError(),
|
||||
'failed to set error invalid tag detection'
|
||||
);
|
||||
$this->assertEquals(
|
||||
[[
|
||||
'level' => 'Error',
|
||||
'id' => '201',
|
||||
'message' => 'invalid or empty tag',
|
||||
'context' => ['tag' => '']
|
||||
]],
|
||||
Error::getMessages(),
|
||||
'check error message failed'
|
||||
);
|
||||
|
||||
// if we set invalid tag
|
||||
$el = new Element('div');
|
||||
$this->expectException(HtmlBuilderExcpetion::class);
|
||||
$this->expectExceptionMessageMatches("/^Invalid or empty tag: /");
|
||||
$this->expectExceptionMessage("Invalid or empty tag: 123123");
|
||||
$el->setTag('123123');
|
||||
$this->assertTrue(
|
||||
Error::hasError(),
|
||||
'failed to set error invalid tag detection'
|
||||
);
|
||||
$this->assertEquals(
|
||||
[[
|
||||
'level' => 'Error',
|
||||
'id' => '201',
|
||||
'message' => 'invalid or empty tag',
|
||||
'context' => ['tag' => '']
|
||||
]],
|
||||
Error::getMessages(),
|
||||
'check error message failed'
|
||||
);
|
||||
|
||||
|
||||
// invalid id (warning)
|
||||
Error::resetMessages();
|
||||
$el = new Element('div', '-$a15');
|
||||
$this->assertTrue(
|
||||
Error::hasWarning(),
|
||||
'failed to set warning invalid id detection'
|
||||
);
|
||||
$this->assertEquals(
|
||||
[[
|
||||
'level' => 'Warning',
|
||||
'id' => '202',
|
||||
'message' => 'possible invalid id',
|
||||
'context' => ['id' => '-$a15', 'tag' => 'div']
|
||||
]],
|
||||
Error::getMessages(),
|
||||
'check error message failed'
|
||||
);
|
||||
|
||||
// invalid name
|
||||
Error::resetMessages();
|
||||
$el = new Element('div', 'valid', '', [], ['name' => '-$asdf&']);
|
||||
$this->assertTrue(
|
||||
Error::hasWarning(),
|
||||
'failed to set warning invalid name detection'
|
||||
);
|
||||
$this->assertEquals(
|
||||
[[
|
||||
'level' => 'Warning',
|
||||
'id' => '203',
|
||||
'message' => 'possible invalid name',
|
||||
'context' => ['name' => '-$asdf&', 'id' => 'valid', 'tag' => 'div']
|
||||
]],
|
||||
Error::getMessages(),
|
||||
'check error message failed'
|
||||
);
|
||||
}
|
||||
|
||||
// static add element
|
||||
// print object/array
|
||||
}
|
||||
|
||||
// __END__
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use CoreLibs\Template\HtmlBuilder\StringReplace;
|
||||
|
||||
/**
|
||||
* Test class for Template\HtmlBuilder\StringReplace
|
||||
* @coversDefaultClass \CoreLibs\Template\HtmlBuilder\StringReplace
|
||||
* @testdox \CoreLibs\Template\HtmlBuilder\StringReplace method tests
|
||||
*/
|
||||
final class CoreLibsTemplateHtmlBuilderStringReplaceTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::replaceData
|
||||
* @testdox test basic replaceData
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testReplaceData(): void
|
||||
{
|
||||
$html_block = <<<HTML
|
||||
<div id="{ID}" class="{CSS}">
|
||||
{CONTENT}
|
||||
</div>
|
||||
HTML;
|
||||
|
||||
$this->assertEquals(
|
||||
<<<HTML
|
||||
<div id="block-id" class="blue,red">
|
||||
Some content here<br>with bla bla inside
|
||||
</div>
|
||||
HTML,
|
||||
StringReplace::replaceData(
|
||||
$html_block,
|
||||
[
|
||||
'ID' => 'block-id',
|
||||
'CSS' => join(',', ['blue', 'red']),
|
||||
'{CONTENT}' => 'Some content here<br>with bla bla inside',
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @testdox replaceData error
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
/* public function testReplaceDataErrors(): void
|
||||
{
|
||||
$this->expectException(HtmlBuilderExcpetion::class);
|
||||
$this->expectExceptionMessage("Replace and content array count differ");
|
||||
StringReplace::replaceData('<span>{FOO}</span>', ['{FOO}', '{BAR}'], ['foo']);
|
||||
} */
|
||||
}
|
||||
|
||||
// __END__
|
||||
Reference in New Issue
Block a user