Compare commits

...

28 Commits

Author SHA1 Message Date
Clemens Schwaighofer
0c68ebe652 Login\ACL revalidate flow fixes
- DB function had wrong column name
- Queries in ACL\Login had wrong column name
- Renamed from login_user_id_last_login to login_user_id_last_revalidate
  to make it more clear what this column is
- add edit_user admin page output for this column
- add phpUnit test case for revalidate is needed and login with next
  loginUserId is ok again
2022-06-23 06:50:07 +09:00
Clemens Schwaighofer
31d0cdb8ad Fix revalidate after flow in ACL\Login
After revalidate time was reached, it was never reset because it used
the original loginUserId set date.
A new column has been added that gets reset every time the user logs in
with username and password if a loginUserId is set in the database
2022-06-22 19:38:03 +09:00
Clemens Schwaighofer
0f823bd283 Just minor line length fixes in ArrayIO class 2022-06-22 18:10:23 +09:00
Clemens Schwaighofer
6385a48824 add back unique constraint because null login_user_id are allowed 2022-06-22 16:56:51 +09:00
Clemens Schwaighofer
a754d897cf Bug fixes for emptynull type in ArrayIO, Form\Generate interval
Form\Generate for intervals also allows day(s), month(s), year(s), call
case insensitive

ArrayIO fix for missing escale literal for
date/datetime/interval/emptynull text type
2022-06-22 16:17:16 +09:00
Clemens Schwaighofer
4600f8f7bf Update edit_user form page and also minor updates to Form and ArraIO
login_user_id is unique if not null (as index, constraint only with
PostgreSQL 15)
login_user_id_revalidate_after is not longer not null and default set,
no need for this

DB\Extended\ArrayIO:
add sql_read for datetime fields to change amount of data (eg only up
to minute) with to_char() method. sample: YYYY-MM-DD HH24:MI
Add date/datetime/emptynull for setting empty fields to null and not
empty string

Output\From\Generate:
Remove all fill for spacer and change them to placeholder html types.
Add datetime check next to date, time only checks

edit_user Admin Form:
add all new columns there
2022-06-22 15:50:07 +09:00
Clemens Schwaighofer
04e4fe46f2 Update ACL\Login class with _GET/_POST login parameter
loginUserId parameter in _GET or _POST for direct login without username
and password.

This can be secured by:
- must login after x days from set loginUserId on
- can only login with loginUserId in given time range
- flag lock loginUserId
2022-06-22 13:52:47 +09:00
Clemens Schwaighofer
c35d3c9324 Remove constant from deprecated ReadEnvFile class (now dotEnv) 2022-06-14 16:27:00 +09:00
Clemens Schwaighofer
e92a682a8c ACL\Login phpUnit tets update for ajax page tests 2022-06-14 16:24:17 +09:00
Clemens Schwaighofer
ea07e4b95b Update ACL\Login with internal ajax_page flag override
Also ajax flag return method
2022-06-14 16:23:24 +09:00
Clemens Schwaighofer
88178cb08d Rename class ReadEnvFile to DotEnv and add test cases
previous named Get\ReadEnvFile is no Get\DotEnv, static method is the
same.
Update for not parsing comments at the end of a line if the line was not
in quotes. Strips everything after comment mark and also right trims any
trailing spaces

Old:
FOO=Test # Comment -> $_ENV['FOO'] = "Test # Comment"

New:
FOO=Test # Comment -> $_ENV['FOO'] = "Test"

Add phpUnit tests for DotEnv class.
Update config.php with new class name

The old class name exists and is markted as deprecated until next major
release
2022-06-09 09:05:48 +09:00
Clemens Schwaighofer
5d98be06be Code clean up for phan and phpstan 2022-06-07 18:16:23 +09:00
Clemens Schwaighofer
183cadb0fd Class ACL\Login update with phpunit testing
Move logic from constructor to separate function
Add more public access methods for internal variable access (password
min length settings, error login code, error login string error)
All error messages are declared in constructor with wrapper function to
create html error string for template creation
Add wrapper function for exit/abort and page name read for easier mocking
in testing
Fixes for multi login main function caller and cached query problem: do
not cache query for login
Add reverse default access list SESSION variable and public readers
Update logout with unset of full SESSION array to empty, use external
session class for all session calls. Also unset euid on logout
2022-06-07 18:05:50 +09:00
Clemens Schwaighofer
2067a6fe1d Config master SSL site detection update 2022-06-07 18:05:34 +09:00
Clemens Schwaighofer
f5b6c639fb Fix primary key base number after more inserts are done 2022-06-03 11:13:35 +09:00
Clemens Schwaighofer
cde29c0362 Update DB\IO dbReturn and update connected tests
Switch the code point for these below for logic reasons
CLEAR_CACHE 1 => 2 (clear cache AFTER END read)
READ_NEW 2 => 1 (clear cache BEFORE first read)

in dbReturn cursor ext array:
remove firstcall entry because it is not needed
add new:
- cache_flag: $cache method call number
- assoc_flag: the assoc read flag from the method call
- cached: if there is data cached in the cursor ext array this is true
- finished: true if the last read was false
- db_read_finished: if true the db read has fiinished (read_rows =
  num_rows)
- read_finished: if true the current read (cache or db) via pos =
  num_rows is done
- log_pos: sequential number for each call with the same query hash
- log: array with current actions done in the last read

Update DB IO class test with all cursor, cursor ext, read single step,
read in loop, read again, etc tests
2022-06-03 11:03:06 +09:00
Clemens Schwaighofer
10234000b7 ACL\Login test class add
- db create shell script for ACL\Login to reset full database to known
  good stated
- basic tests written to check core login class
2022-06-02 18:14:58 +09:00
Clemens Schwaighofer
a63a50a412 add tests for dbReturn only
dbReturn special call test file, update main db test file

Main class_test file with links update
2022-06-02 16:38:10 +09:00
Clemens Schwaighofer
59da10b649 Session class update with session destroy / start wrapper
session start wrapper as protected method

session destroy wrapper with _SESSION array unset
2022-06-02 16:35:40 +09:00
Clemens Schwaighofer
b714de498f Add print boolean stand allone support function
in the Debug\Support add printBool to print out bool as string.
Same as printAsString with bool alone but you can control prefix name,
and true/false string names

Add printArray alias to prAr
2022-06-02 16:31:35 +09:00
Clemens Schwaighofer
aa11937ab2 Update Running time for better high resolution timer
Instead of ending with the second hr timer call, we print out difference
to the last one.
Add new method to print out from start time difference and add a reset
method
2022-06-02 16:30:22 +09:00
Clemens Schwaighofer
d64d5f081c Add Class for Memory Usage tracking 2022-06-02 16:26:55 +09:00
Clemens Schwaighofer
3085b52714 Update PHPdoc parts
Add empty line between description and first @param entry.
Some other minor comment layout and text fixes
2022-06-02 16:07:38 +09:00
Clemens Schwaighofer
9949a5ef7f Update core edit_* tables with various fixes
- import script with write to file option
- fix file names for functions
- add generic (non edit tables) for only set date, set uid or combine
- fix edit table edit_language insert data
- all trigger create remove the drop on exists, as in the flow the trigger will never exists
2022-05-31 20:17:32 +09:00
Clemens Schwaighofer
74ba935e96 Comment info update in L10n class 2022-05-27 15:01:30 +09:00
Clemens Schwaighofer
39a62ed59d Update phpunit tests for Debug\Logging 2022-05-26 15:20:19 +09:00
Clemens Schwaighofer
1379cf1519 Add print bool in logging class 2022-05-26 14:31:48 +09:00
Clemens Schwaighofer
2d15b78d21 Composer update 2022-05-26 09:52:37 +09:00
124 changed files with 8208 additions and 1090 deletions

View File

@@ -8,6 +8,9 @@ for file in $(ls -1 ${base_folder}../4dev/locale/*.po); do
echo "Translate language ${file}";
locale=$(echo "${file}" | cut -d "-" -f 1);
domain=$(echo "${file}" | cut -d "-" -f 2);
if [ ! -d "${base_folder}/includes/locale/${locale}/LC_MESSAGES/" ]; then
mkdir -p "${base_folder}/includes/locale/${locale}/LC_MESSAGES/";
fi;
msgfmt -o ${base_folder}/includes/locale/${locale}/LC_MESSAGES/${domain}.mo ${base_folder}../4dev/locale/${locale}-${domain}.po;
done;

View File

@@ -1,10 +1,11 @@
# this list only holds edit_* related table data
# functions
function/set_uid.sql
function/set_generic.sql
function/random_string.sql
function/set_edit_generic.sql
function/edit_set_access_uid.sql
function/edit_access_set_uid.sql
function/edit_group_set_uid.sql
function/edit_log_partition_insert.sql
function/edit_user_set_login_user_id_set_date.sql
# generic tables
table/edit_temp_files.sql
table/edit_generic.sql

View File

@@ -6,20 +6,25 @@
#exit;
# if flagged 'y' then it will ask after each import to continue
development='y';
development='n';
# do not import anything, just order flow output
test='n';
input='';
# write to file do not write to DB directly
write='y';
# database connection info
db='<db name>';
host='<db host>';
user='<db user>';
schema="public";
schemas='public';
export PGPASSWORD='';
# log files
error_file="log/error";
output_file="log/output";
error_file='log/error';
output_file='log/output';
data_file='database_create_data.sql';
if [ "$write" = 'y' ]; then
rm -f "${data_file}";
fi;
if [ ! -f ORDER ]; then
echo "Could not find ORDER file";
exit;
@@ -40,26 +45,37 @@ while read file <&3; do
if [ -f "$file" ]; then
for path in "$schemas"; do
echo "[+] WORK ON '${file}' @ '${path}'";
# skip all on test
if [ "$test" = 'n' ]; then
echo "=== START [$file] ===>" >> ${error_file};
psql -U ${user} -h ${host} -f "${file}" ${db} 1>> ${output_file} 2>> ${error_file}
echo "=== END [$file] ===>" >> ${error_file};
fi;
if [ "$development" = "y" ]; then
echo "Press 'y' to move to next. Press 'r' to reload last file. ^c to abort";
fi;
while [ "$development" = "y" ] && [ "$input" != "y" ]; do
read -ep "Continue (y|r|^c): " input;
if [ "$input" = "r" ]; then
echo "Reload File '${file}' ...";
if [ "$test" = 'n' ]; then
echo "=== START RELOAD [$file] ===>" >> ${error_file};
psql -U ${user} -h ${host} -f "${file}" ${db} 1>> ${output_file} 2>> ${error_file}
echo "=== END RELOAD [$file] ===>" >> ${error_file};
# write to file
if [ "$write" = 'y' ]; then
echo "-- START: ${file}" >> ${data_file};
cat "${file}" >> ${data_file};
echo "-- END: ${file}" >> ${data_file};
else
# write to DB
echo "=== START [$file] ===>" >> ${error_file};
psql -U ${user} -h ${host} -f "${file}" ${db} 1>> ${output_file} 2>> ${error_file}
echo "=== END [$file] ===>" >> ${error_file};
# next wait for dev
if [ "$development" = "y" ]; then
echo "Press 'y' to move to next. Press 'r' to reload last file. ^c to abort";
fi;
# loop run for reload on failed
while [ "$development" = "y" ] && [ "$input" != "y" ]; do
read -ep "Continue (y|r|^c): " input;
if [ "$input" = "r" ]; then
echo "Reload File '${file}' ...";
if [ "$test" = 'n' ]; then
echo "=== START RELOAD [$file] ===>" >> ${error_file};
psql -U ${user} -h ${host} -f "${file}" ${db} 1>> ${output_file} 2>> ${error_file}
echo "=== END RELOAD [$file] ===>" >> ${error_file};
fi;
fi;
done;
input='';
fi;
done;
input='';
fi;
done;
elif [[ ${file::1} != "#" ]]; then
echo "[!] COULD NOT FIND FILE: '${file}'";

View File

@@ -68,10 +68,11 @@ INSERT INTO edit_scheme (name, header_color, enabled) VALUES ('Visitor', 'B0C4B3
INSERT INTO edit_scheme (name, header_color, enabled) VALUES ('User', '1E789E', 1);
-- edit language
-- short_name = locale without encoding
-- iso_name = encoding
DELETE FROM edit_language;
INSERT INTO edit_language (long_name, short_name, iso_name, order_number, enabled, lang_default) VALUES ('English', 'en_US', 'UTF-8', 1, 1, 1);
INSERT INTO edit_language (long_name, short_name, long_name, iso_name, order_number, enabled, lang_default) VALUES ('Japanese', 'ja_JP', 'UTF-8', 2, 1, 0);
INSERT INTO edit_language (long_name, short_name, iso_name, order_number, enabled, lang_default) VALUES ('Japanese', 'ja_JP', 'UTF-8', 2, 1, 0);
-- edit group
DELETE FROM edit_group;
@@ -130,7 +131,7 @@ INSERT INTO edit_page_access (enabled, edit_group_id, edit_page_id, edit_access_
-- inserts admin user so basic users can be created
DELETE FROM edit_user;
INSERT INTO edit_user (username, password, enabled, debug, db_debug, email, protected, admin, edit_language_id, edit_group_id, edit_scheme_id, edit_access_right_id) VALUES ('admin', 'admin', 1, 1, 1, '', 1, 1,
(SELECT edit_language_id FROM edit_language WHERE short_name = 'en'),
(SELECT edit_language_id FROM edit_language WHERE short_name = 'en_US'),
(SELECT edit_group_id FROM edit_group WHERE name = 'Admin'),
(SELECT edit_scheme_id FROM edit_scheme WHERE name = 'Admin'),
(SELECT edit_access_right_id FROM edit_access_right WHERE type = 'admin')

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
-- add uid add for edit_access table
CREATE OR REPLACE FUNCTION set_edit_access_uid() RETURNS TRIGGER AS
$$
DECLARE
myrec RECORD;
v_uid VARCHAR;
BEGIN
-- skip if NEW.name is not set
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
-- use NEW.name as base, remove all spaces
-- name data is already unique, so we do not need to worry about this here
v_uid := REPLACE(NEW.name, ' ', '');
IF TG_OP = 'INSERT' THEN
-- always set
NEW.uid := v_uid;
ELSIF TG_OP = 'UPDATE' THEN
-- check if not set, then set
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
IF FOUND THEN
NEW.uid := v_uid;
END IF;
END IF;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -0,0 +1,28 @@
-- add uid add for edit_group table
CREATE OR REPLACE FUNCTION set_edit_group_uid() RETURNS TRIGGER AS
$$
DECLARE
myrec RECORD;
v_uid VARCHAR;
BEGIN
-- skip if NEW.name is not set
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
-- use NEW.name as base, remove all spaces
-- name data is already unique, so we do not need to worry about this here
v_uid := REPLACE(NEW.name, ' ', '');
IF TG_OP = 'INSERT' THEN
-- always set
NEW.uid := v_uid;
ELSIF TG_OP = 'UPDATE' THEN
-- check if not set, then set
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
IF FOUND THEN
NEW.uid := v_uid;
END IF;
END IF;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -1,28 +0,0 @@
-- add uid add for edit_access table
CREATE OR REPLACE FUNCTION set_edit_access_uid() RETURNS TRIGGER AS
$$
DECLARE
myrec RECORD;
v_uid VARCHAR;
BEGIN
-- skip if NEW.name is not set
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
-- use NEW.name as base, remove all spaces
-- name data is already unique, so we do not need to worry about this here
v_uid := REPLACE(NEW.name, ' ', '');
IF TG_OP = 'INSERT' THEN
-- always set
NEW.uid := v_uid;
ELSIF TG_OP = 'UPDATE' THEN
-- check if not set, then set
SELECT INTO myrec t.* FROM edit_access t WHERE edit_access_id = NEW.edit_access_id;
IF FOUND THEN
NEW.uid := v_uid;
END IF;
END IF;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -1,28 +0,0 @@
-- add uid add for edit_group table
CREATE OR REPLACE FUNCTION set_edit_group_uid() RETURNS TRIGGER AS
$$
DECLARE
myrec RECORD;
v_uid VARCHAR;
BEGIN
-- skip if NEW.name is not set
IF NEW.name IS NOT NULL AND NEW.name <> '' THEN
-- use NEW.name as base, remove all spaces
-- name data is already unique, so we do not need to worry about this here
v_uid := REPLACE(NEW.name, ' ', '');
IF TG_OP = 'INSERT' THEN
-- always set
NEW.uid := v_uid;
ELSIF TG_OP = 'UPDATE' THEN
-- check if not set, then set
SELECT INTO myrec t.* FROM edit_group t WHERE edit_group_id = NEW.edit_group_id;
IF FOUND THEN
NEW.uid := v_uid;
END IF;
END IF;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -0,0 +1,26 @@
-- set edit user login_user_id_set_date if login_user_id is set
-- NOW() if not empty
CREATE OR REPLACE FUNCTION set_login_user_id_set_date()
RETURNS TRIGGER AS
$$
BEGIN
-- if new is not null/empty
-- and old one is null or old one different new one
-- set NOW()
-- if new one is NULL
-- set NULL
IF
NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND
(OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id)
THEN
NEW.login_user_id_set_date = NOW();
NEW.login_user_id_last_revalidate = NOW();
ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN
NEW.login_user_id_set_date = NULL;
NEW.login_user_id_last_revalidate = NULL;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -1,7 +1,8 @@
-- create random string with length X
CREATE FUNCTION random_string(randomLength int)
RETURNS text AS $$
RETURNS text AS
$$
SELECT array_to_string(
ARRAY(
SELECT substring(
@@ -13,6 +14,7 @@ SELECT array_to_string(
),
''
)
$$ LANGUAGE SQL
$$
LANGUAGE SQL
RETURNS NULL ON NULL INPUT
VOLATILE; -- LEAKPROOF;
VOLATILE; -- LEAKPROOF;

View File

@@ -0,0 +1,15 @@
-- adds the created or updated date tags
CREATE OR REPLACE FUNCTION set_date()
RETURNS TRIGGER AS
$$
BEGIN
IF TG_OP = 'INSERT' THEN
NEW.date_created := 'now';
ELSIF TG_OP = 'UPDATE' THEN
NEW.date_updated := 'now';
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -1,15 +1,18 @@
-- adds the created or updated date tags
CREATE OR REPLACE FUNCTION set_edit_generic() RETURNS TRIGGER AS '
DECLARE
random_length INT = 12; -- that should be long enough
BEGIN
IF TG_OP = ''INSERT'' THEN
NEW.date_created := ''now'';
NEW.cuid := random_string(random_length);
ELSIF TG_OP = ''UPDATE'' THEN
NEW.date_updated := ''now'';
END IF;
RETURN NEW;
END;
' LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION set_edit_generic()
RETURNS TRIGGER AS
$$
DECLARE
random_length INT = 12; -- that should be long enough
BEGIN
IF TG_OP = 'INSERT' THEN
NEW.date_created := 'now';
NEW.cuid := random_string(random_length);
ELSIF TG_OP = 'UPDATE' THEN
NEW.date_updated := 'now';
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -1,12 +0,0 @@
-- adds the created or updated date tags
CREATE OR REPLACE FUNCTION set_generic() RETURNS TRIGGER AS '
BEGIN
IF TG_OP = ''INSERT'' THEN
NEW.date_created := ''now'';
ELSIF TG_OP = ''UPDATE'' THEN
NEW.date_updated := ''now'';
END IF;
RETURN NEW;
END;
' LANGUAGE 'plpgsql';

View File

@@ -0,0 +1,21 @@
-- set generic with date and uid combined
-- don't use with set_generic/set_uid together
CREATE OR REPLACE FUNCTION set_generic()
RETURNS TRIGGER AS
$$
DECLARE
random_length INT = 32; -- long for massive data
BEGIN
IF TG_OP = 'INSERT' THEN
NEW.date_created := 'now';
IF NEW.uid IS NULL THEN
NEW.uid := random_string(random_length);
END IF;
ELSIF TG_OP = 'UPDATE' THEN
NEW.date_updated := 'now';
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -1,12 +1,15 @@
-- adds the created or updated date tags
CREATE OR REPLACE FUNCTION set_uid() RETURNS TRIGGER AS '
DECLARE
random_length INT = 32; -- that should be long enough
BEGIN
IF TG_OP = ''INSERT'' THEN
NEW.uid := random_string(random_length);
END IF;
RETURN NEW;
END;
' LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION set_uid()
RETURNS TRIGGER AS
$$
DECLARE
random_length INT = 32; -- that should be long enough
BEGIN
IF TG_OP = 'INSERT' THEN
NEW.uid := random_string(random_length);
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';

View File

@@ -2,15 +2,18 @@
-- OLD, DEPRECATED, use set_generic.sql
-- CREATE OR REPLACE FUNCTION set_generic() RETURNS TRIGGER AS '
-- BEGIN
-- IF TG_OP = ''INSERT'' THEN
-- NEW.date_created := clock_timestamp();
-- NEW.user_created := current_user;
-- ELSIF TG_OP = ''UPDATE'' THEN
-- NEW.date_updated := clock_timestamp();
-- NEW.user_updated := current_user;
-- END IF;
-- RETURN NEW;
-- END;
-- ' LANGUAGE 'plpgsql';
-- CREATE OR REPLACE FUNCTION set_generic()
-- RETURNS TRIGGER AS
-- $$
-- BEGIN
-- IF TG_OP = 'INSERT' THEN
-- NEW.date_created := clock_timestamp();
-- NEW.user_created := current_user;
-- ELSIF TG_OP = 'UPDATE' THEN
-- NEW.date_updated := clock_timestamp();
-- NEW.user_updated := current_user;
-- END IF;
-- RETURN NEW;
-- END;
-- $$
-- LANGUAGE 'plpgsql';

View File

@@ -18,31 +18,82 @@ CREATE TABLE edit_user (
FOREIGN KEY (edit_scheme_id) REFERENCES edit_scheme (edit_scheme_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
edit_access_right_id INT NOT NULL,
FOREIGN KEY (edit_access_right_id) REFERENCES edit_access_right (edit_access_right_id) MATCH FULL ON DELETE CASCADE ON UPDATE CASCADE,
enabled SMALLINT NOT NULL DEFAULT 0,
deleted SMALLINT NOT NULL DEFAULT 0,
-- username/password
username VARCHAR UNIQUE,
password VARCHAR,
-- name block
first_name VARCHAR,
last_name VARCHAR,
first_name_furigana VARCHAR,
last_name_furigana VARCHAR,
-- email
email VARCHAR,
-- eanbled/deleted flag
enabled SMALLINT NOT NULL DEFAULT 0,
deleted SMALLINT NOT NULL DEFAULT 0,
-- general flags
strict SMALLINT DEFAULT 0,
locked SMALLINT DEFAULT 0,
protected SMALLINT NOT NULL DEFAULT 0,
-- legacy, debug flags
debug SMALLINT NOT NULL DEFAULT 0,
db_debug SMALLINT NOT NULL DEFAULT 0,
email VARCHAR,
protected SMALLINT NOT NULL DEFAULT 0,
-- is admin user
admin SMALLINT NOT NULL DEFAULT 0,
-- last login log
last_login TIMESTAMP WITHOUT TIME ZONE,
-- login error
login_error_count INT DEFAULT 0,
login_error_date_last TIMESTAMP WITHOUT TIME ZONE,
login_error_date_first TIMESTAMP WITHOUT TIME ZONE,
strict SMALLINT DEFAULT 0,
locked SMALLINT DEFAULT 0,
-- time locked
lock_until TIMESTAMP WITHOUT TIME ZONE,
lock_after TIMESTAMP WITHOUT TIME ZONE,
-- password change
password_change_date TIMESTAMP WITHOUT TIME ZONE, -- only when password is first set or changed
password_change_interval INTERVAL, -- null if no change is needed, or d/m/y time interval
password_reset_time TIMESTAMP WITHOUT TIME ZONE, -- when the password reset was requested
password_reset_uid VARCHAR, -- the uid to access the password reset page
-- _GET login id for direct login
login_user_id VARCHAR UNIQUE, -- the loginUserId, at least 32 chars
login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE, -- when above uid was set
login_user_id_last_revalidate TIMESTAMP WITHOUT TIME ZONE, -- when the last login was done with user name and password
login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE, -- if set, from when the above uid is valid
login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE, -- if set, until when the above uid is valid
login_user_id_revalidate_after INTERVAL, -- user must login to revalidated loginUserId after set days, 0 for forever
login_user_id_locked SMALLINT DEFAULT 0, -- lock for loginUserId, but still allow normal login
-- additional ACL json block
additional_acl JSONB -- additional ACL as JSON string (can be set by other pages)
) INHERITS (edit_generic) WITHOUT OIDS;
-- create unique index
-- CREATE UNIQUE INDEX edit_user_login_user_id_key ON edit_user (login_user_id) WHERE login_user_id IS NOT NULL;
COMMENT ON COLUMN edit_user.username IS 'Login username, must set';
COMMENT ON COLUMN edit_user.password IS 'Login password, must set';
COMMENT ON COLUMN edit_user.enabled IS 'Login is enabled (master switch)';
COMMENT ON COLUMN edit_user.deleted IS 'Login is deleted (master switch), overrides all other';
COMMENT ON COLUMN edit_user.strict IS 'If too many failed logins user will be locked, default off';
COMMENT ON COLUMN edit_user.locked IS 'Locked from too many wrong password logins';
COMMENT ON COLUMN edit_user.protected IS 'User can only be chnaged by admin user';
COMMENT ON COLUMN edit_user.debug IS 'Turn debug flag on (legacy)';
COMMENT ON COLUMN edit_user.db_debug IS 'Turn DB debug flag on (legacy)';
COMMENT ON COLUMN edit_user.admin IS 'If set, this user is SUPER admin';
COMMENT ON COLUMN edit_user.last_login IS 'Last succesfull login tiemstamp';
COMMENT ON COLUMN edit_user.login_error_count IS 'Number of failed logins, reset on successful login';
COMMENT ON COLUMN edit_user.login_error_date_last IS 'Last login error date';
COMMENT ON COLUMN edit_user.login_error_date_first IS 'First login error date, reset on successfull login';
COMMENT ON COLUMN edit_user.lock_until IS 'Account is locked until this date, <';
COMMENT ON COLUMN edit_user.lock_after IS 'Account is locked after this date, >';
COMMENT ON COLUMN edit_user.password_change_date IS 'Password was changed on';
COMMENT ON COLUMN edit_user.password_change_interval IS 'After how many days the password has to be changed';
COMMENT ON COLUMN edit_user.password_reset_time IS 'When the password reset was requested. For reset page uid valid check';
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid';
COMMENT ON COLUMN edit_user.password_reset_uid IS 'Password reset page uid, one time, invalid after reset successful or time out';
COMMENT ON COLUMN edit_user.login_user_id IS 'Min 32 character UID to be used to login without password. Via GET/POST parameter';
COMMENT ON COLUMN edit_user.login_user_id_set_date IS 'loginUserId was set at what date';
COMMENT ON COLUMN edit_user.login_user_id_last_revalidate IS 'set when username/password login is done and loginUserId is set';
COMMENT ON COLUMN edit_user.login_user_id_valid_from IS 'loginUserId is valid from this date, >=';
COMMENT ON COLUMN edit_user.login_user_id_valid_until IS 'loginUserId is valid until this date, <=';
COMMENT ON COLUMN edit_user.login_user_id_revalidate_after IS 'If set to a number greater 0 then user must login after given amount of days to revalidate the loginUserId, set to 0 for valid forver';
COMMENT ON COLUMN edit_user.login_user_id_locked IS 'A separte lock flag for loginUserId, user can still login normal';
COMMENT ON COLUMN edit_user.additional_acl IS 'Additional Access Control List stored in JSON format';

View File

@@ -1,12 +1,13 @@
-- AUTHOR: Clemens Schwaighofer
-- DATE: 2005/07/05
-- DESCRIPTION:
-- cms tables; generic basic table
-- generic basic table with date and uid column
-- TABLE: generic
-- HISTORY:
-- DROP TABLE edit_generic;
-- DROP TABLE generic;
CREATE TABLE generic (
date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT clock_timestamp(),
date_updated TIMESTAMP WITHOUT TIME ZONE
date_updated TIMESTAMP WITHOUT TIME ZONE,
uid VARCHAR
);

View File

@@ -1,9 +1,9 @@
DROP TRIGGER IF EXISTS trg_edit_access ON edit_access;
-- DROP TRIGGER IF EXISTS trg_edit_access ON edit_access;
CREATE TRIGGER trg_edit_access
BEFORE INSERT OR UPDATE ON edit_access
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
DROP TRIGGER IF EXISTS trg_set_edit_access_uid ON edit_access;
-- DROP TRIGGER IF EXISTS trg_set_edit_access_uid ON edit_access;
CREATE TRIGGER trg_set_edit_access_uid
BEFORE INSERT OR UPDATE ON edit_access
FOR EACH ROW EXECUTE PROCEDURE set_edit_access_uid();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_access_data ON edit_access_data;
-- DROP TRIGGER IF EXISTS trg_edit_access_data ON edit_access_data;
CREATE TRIGGER trg_edit_access_data
BEFORE INSERT OR UPDATE ON edit_access_data
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_access_right ON edit_access_right;
-- DROP TRIGGER IF EXISTS trg_edit_access_right ON edit_access_right;
CREATE TRIGGER trg_edit_access_right
BEFORE INSERT OR UPDATE ON edit_access_right
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_access_user ON edit_access_user;
-- DROP TRIGGER IF EXISTS trg_edit_access_user ON edit_access_user;
CREATE TRIGGER trg_edit_access_user
BEFORE INSERT OR UPDATE ON edit_access_user
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,9 +1,9 @@
DROP TRIGGER IF EXISTS trg_edit_group ON edit_group;
-- DROP TRIGGER IF EXISTS trg_edit_group ON edit_group;
CREATE TRIGGER trg_edit_group
BEFORE INSERT OR UPDATE ON edit_group
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
DROP TRIGGER IF EXISTS trg_set_edit_group_uid ON edit_group;
-- DROP TRIGGER IF EXISTS trg_set_edit_group_uid ON edit_group;
CREATE TRIGGER trg_set_edit_group_uid
BEFORE INSERT OR UPDATE ON edit_group
FOR EACH ROW EXECUTE PROCEDURE set_edit_group_uid();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_language ON edit_language;
-- DROP TRIGGER IF EXISTS trg_edit_language ON edit_language;
CREATE TRIGGER trg_edit_language
BEFORE INSERT OR UPDATE ON edit_language
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,9 +1,9 @@
DROP TRIGGER IF EXISTS trg_edit_log ON edit_log;
-- DROP TRIGGER IF EXISTS trg_edit_log ON edit_log;
CREATE TRIGGER trg_edit_log
BEFORE INSERT OR UPDATE ON edit_log
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
DROP TRIGGER IF EXISTS trg_edit_log_insert_partition ON edit_log;
-- DROP TRIGGER IF EXISTS trg_edit_log_insert_partition ON edit_log;
CREATE TRIGGER trg_edit_log_insert_partition
BEFORE INSERT OR UPDATE ON edit_log
FOR EACH ROW EXECUTE PROCEDURE edit_log_insert_trigger();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_log_overflow ON edit_log_overflow;
-- DROP TRIGGER IF EXISTS trg_edit_log_overflow ON edit_log_overflow;
CREATE TRIGGER trg_edit_log_overflow
BEFORE INSERT OR UPDATE ON edit_log_overflow
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_menu_group ON edit_menu_group;
-- DROP TRIGGER IF EXISTS trg_edit_menu_group ON edit_menu_group;
CREATE TRIGGER trg_edit_menu_group
BEFORE INSERT OR UPDATE ON edit_menu_group
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_page ON edit_page;
-- DROP TRIGGER IF EXISTS trg_edit_page ON edit_page;
CREATE TRIGGER trg_edit_page
BEFORE INSERT OR UPDATE ON edit_page
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_page_access ON edit_page_access;
-- DROP TRIGGER IF EXISTS trg_edit_page_access ON edit_page_access;
CREATE TRIGGER trg_edit_page_access
BEFORE INSERT OR UPDATE ON edit_page_access
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_page_content ON edit_page_content;
-- DROP TRIGGER IF EXISTS trg_edit_page_content ON edit_page_content;
CREATE TRIGGER trg_edit_page_content
BEFORE INSERT OR UPDATE ON edit_page_content
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_query_string ON edit_query_string;
-- DROP TRIGGER IF EXISTS trg_edit_query_string ON edit_query_string;
CREATE TRIGGER trg_edit_query_string
BEFORE INSERT OR UPDATE ON edit_query_string
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_scheme ON edit_scheme;
-- DROP TRIGGER IF EXISTS trg_edit_scheme ON edit_scheme;
CREATE TRIGGER trg_edit_scheme
BEFORE INSERT OR UPDATE ON edit_scheme
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,9 @@
DROP TRIGGER IF EXISTS trg_edit_user ON edit_user;
-- DROP TRIGGER IF EXISTS trg_edit_user ON edit_user;
CREATE TRIGGER trg_edit_user
BEFORE INSERT OR UPDATE ON edit_user
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();
-- DROP TRIGGER IF EXISTS trg_edit_user_set_login_user_id_set_date ON edit_user;
CREATE TRIGGER trg_edit_user_set_login_user_id_set_date
BEFORE INSERT OR UPDATE ON edit_user
FOR EACH ROW EXECUTE PROCEDURE set_login_user_id_set_date();

View File

@@ -1,4 +1,4 @@
DROP TRIGGER IF EXISTS trg_edit_visible_group ON edit_visible_group;
-- DROP TRIGGER IF EXISTS trg_edit_visible_group ON edit_visible_group;
CREATE TRIGGER trg_edit_visible_group
BEFORE INSERT OR UPDATE ON edit_visible_group
FOR EACH ROW EXECUTE PROCEDURE set_edit_generic();

View File

@@ -1,4 +1,4 @@
-- update missing edit_* table data
-- 2019/12/11 update missing edit_* table data
ALTER TABLE edit_generic ADD cuid VARCHAR;

View File

@@ -0,0 +1,51 @@
-- 2022/6/17 update edit_user with login uid
-- the login uid, at least 32 chars
ALTER TABLE edit_user ADD login_user_id VARCHAR UNIQUE;
-- CREATE UNIQUE INDEX edit_user_login_user_id_key ON edit_user (login_user_id) WHERE login_user_id IS NOT NULL;
-- ALTER TABLE edit_user ADD CONSTRAINT edit_user_login_user_id_key UNIQUE (login_user_id);
-- when above uid was set
ALTER TABLE edit_user ADD login_user_id_set_date TIMESTAMP WITHOUT TIME ZONE;
ALTER TABLE edit_user ADD login_user_id_last_revalidate TIMESTAMP WITHOUT TIME ZONE;
-- if set, from/until when the above uid is valid
ALTER TABLE edit_user ADD login_user_id_valid_from TIMESTAMP WITHOUT TIME ZONE;
ALTER TABLE edit_user ADD login_user_id_valid_until TIMESTAMP WITHOUT TIME ZONE;
-- user must login to revalidated login id after set days, 0 for forever
ALTER TABLE edit_user ADD login_user_id_revalidate_after INTERVAL;
-- lock for login user id, but still allow normal login
ALTER TABLE edit_user ADD login_user_id_locked SMALLINT NOT NULL DEFAULT 0;
-- disable login before date
ALTER TABLE edit_user ADD lock_until TIMESTAMP WITHOUT TIME ZONE;
-- disable login after date
ALTER TABLE edit_user ADD lock_after TIMESTAMP WITHOUT TIME ZONE;
CREATE OR REPLACE FUNCTION set_login_user_id_set_date()
RETURNS TRIGGER AS
$$
BEGIN
-- if new is not null/empty
-- and old one is null or old one different new one
-- set NOW()
-- if new one is NULL
-- set NULL
IF
NEW.login_user_id IS NOT NULL AND NEW.login_user_id <> '' AND
(OLD.login_user_id IS NULL OR NEW.login_user_id <> OLD.login_user_id)
THEN
NEW.login_user_id_set_date = NOW();
NEW.login_user_id_last_revalidate = NOW();
ELSIF NEW.login_user_id IS NULL OR NEW.login_user_id = '' THEN
NEW.login_user_id_set_date = NULL;
NEW.login_user_id_last_revalidate = NULL;
END IF;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
CREATE TRIGGER trg_edit_user_set_login_user_id_set_date
BEFORE INSERT OR UPDATE ON edit_user
FOR EACH ROW EXECUTE PROCEDURE set_login_user_id_set_date();
-- __END__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# note: there is currently no port selection, standard 5432 port is assumed
# note: we use the default in path postgresql commands and connect to whatever default DB is set
# PARAMETER 1: database data file to load
# PARAMETER 2: db user WHO MUST BE ABLE TO CREATE A DATABASE
# PARAMETER 3: db name
# PARAMETER 4: db host
# PARAMETER 5: print out for testing
load_sql="${1}";
# abort with 1 if we cannot find the file
if [ ! -f "${load_sql}" ]; then
echo 1;
exit 1;
fi;
db_user="${2}";
db_name="${3}";
db_host="${4}";
# empty db name or db user -> exit with 2
if [ -z "${db_user}" ] || [ -z "${db_name}" ] || [ -z "${db_host}" ]; then
echo 2;
exit 2;
fi;
# drop database, on error exit with 3
dropdb -U ${db_user} -h ${db_host} ${db_name} 2>&1;
if [ $? -ne 0 ]; then
echo 3;
exit 3;
fi;
# create database, on error exit with 4
createdb -U ${db_user} -O ${db_user} -h ${db_host} -E utf8 ${db_name} 2>&1;
if [ $? -ne 0 ]; then
echo 4;
exit 4;
fi;
# if error 5 thrown, test with enabled below
if [ ! -z "${5}" ]; then
psql -U ${db_user} -h ${db_host} -f ${load_sql} ${db_name};
else
# load data (redirect ALL error to null), on error exit with 5
psql -U ${db_user} -h ${db_host} -f ${load_sql} ${db_name} 2>&1 1>/dev/null 2>/dev/null;
fi;
if [ $? -ne 0 ]; then
echo 5;
exit 5;
fi;
echo 0;
exit 0;
# __END__

File diff suppressed because it is too large Load Diff

View File

@@ -709,6 +709,64 @@ final class CoreLibsDebugLoggingTest extends TestCase
);
}
public function prBlProvider(): array
{
return [
'true bool default' => [
true,
null,
null,
'true'
],
'false bool default' => [
false,
null,
null,
'false'
],
'true bool override' => [
true,
'ok',
'not ok',
'ok'
],
'false bool override' => [
false,
'ok',
'not ok',
'not ok'
],
];
}
/**
* check bool to string converter
*
* @covers ::prBl
* @dataProvider prBlProvider
* @textdox check prBl $input ($true/$false) is expected $false [$_dataName]
*
* @param bool $input
* @param string|null $true
* @param string|null $false
* @param string $expected
* @return void
*/
public function testPrBl(bool $input, ?string $true, ?string $false, string $expected): void
{
$this->log = new \CoreLibs\Debug\Logging();
$return = '';
if ($true === null && $false === null) {
$return = $this->log->prBl($input);
} elseif ($true !== null || $false !== null) {
$return = $this->log->prBl($input, $true ?? '', $false ?? '');
}
$this->assertEquals(
$expected,
$return
);
}
// from here are complex debug tests
/**

View File

@@ -0,0 +1,119 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Debug\MemoryUsage;
/**
* Test class for Debug\MemoryUsage
* @coversDefaultClass \CoreLibs\Debug\MemoryUsage
* @testdox \CoreLibs\Debug\MemoryUsage method tests
*/
final class CoreLibsDebugMemoryUsageTest extends TestCase
{
/**
* Undocumented function
*
* @return array
*/
public function memoryUsageProvider(): array
{
$regex_raw_off = '/^\[[\w\s_-]+\] Peak\/Curr\/Change: \d+(\.\d+)? ?\w{1,2}\/'
. '\d+(\.\d+)? ?\w{1,2}\/'
. 'Since Start: \d+(\.\d+)? ?\w{1,2} \| '
. 'Since Last: \d+(\.\d+)? ?\w{1,2} \| '
. 'Since Set: \d+(\.\d+)? ?\w{1,2}$/';
$regex_raw_on = '/^\[[\w\s_-]+\] Peak\/Curr\/'
// . 'Change: \d+(\.\d+)? ?\w{1,2}\/\d+(\.\d+)? ?\w{1,2} \[\d+\]\/'
. 'Change: \d+(\.\d+)? ?\w{1,2}\/\d+(\.\d+)? ?\w{1,2}/'
. 'Since Start: \d+(\.\d+)? ?\w{1,2} \[\d+\] \| '
. 'Since Last: \d+(\.\d+)? ?\w{1,2} \[\d+\] \| '
. 'Since Set: \d+(\.\d+)? ?\w{1,2} \[\d+\]$/';
$regex_array = [
'prefix' => '/^[\w\s_-]+$/',
'peak' => '/^\d+$/',
'usage' => '/^\d+$/',
'start' => '/^\d+$/',
'last' => '/^\d+$/',
'set' => '/^\d+$/',
];
// 0: prefix
// 1: raw flag
// 2: set flags array
// 3: array output expected (as regex)
// 4: string output expected (as regex)
return [
'test normal' => [
'test',
null,
[],
$regex_array,
$regex_raw_off,
]
];
}
/**
* Undocumented function
*
* @cover ::resetMemory
* @cover ::debugMemoryFlag
* @cover ::setStartMemory
* @cover ::setMemory
* @cover ::memoryUsage
* @cover ::printMemoryUsage
* @dataProvider memoryUsageProvider
* @testdox memoryUsage with $prefix, raw memory $raw [$_dataName]
*
* @param string $prefix
* @param bool|null $raw
* @param array $set_flags
* @param array $expected_array
* @param string $expected_string
* @return void
*/
public function testMemoryUsage(
string $prefix,
?bool $raw,
array $settings,
array $expected_array,
string $expected_string
): void {
// always reeset to null
MemoryUsage::resetMemory();
MemoryUsage::debugMemoryFlag(true);
MemoryUsage::setStartMemory();
MemoryUsage::setMemory();
// run collector
$memory = MemoryUsage::memoryUsage($prefix);
if ($raw === null) {
$string = MemoryUsage::printMemoryUsage($memory);
} else {
$string = MemoryUsage::printMemoryUsage($memory, $raw);
}
// expected_array for each
foreach ($expected_array as $name => $regex) {
$this->assertMatchesRegularExpression(
$regex,
(string)$memory[$name],
'assert memory usage array ' . $name
);
}
// regex match string
$this->assertMatchesRegularExpression(
$expected_string,
$string,
'assert memory usage string as regex'
);
// TODO additional tests with use more memory and check diff matching
// TODO reset memory usage test
}
}
// __END__

View File

@@ -15,6 +15,8 @@ final class CoreLibsDebugRunningTimeTest extends TestCase
{
public function hrRunningTimeProvider(): array
{
// 0: return time difference
// 1: return time on first run in regex
return [
'default time' => [
0 => null,
@@ -69,21 +71,73 @@ final class CoreLibsDebugRunningTimeTest extends TestCase
*/
public function testHrRunningTime(?string $out_time, string $expected): void
{
// reset for each run
\CoreLibs\Debug\RunningTime::hrRunningTimeReset();
$start = \CoreLibs\Debug\RunningTime::hrRunningTime();
$this->assertEquals(
0,
$start
$start,
'assert first run 0'
);
time_nanosleep(1, 500);
if ($out_time === null) {
$end = \CoreLibs\Debug\RunningTime::hrRunningTime();
$second = \CoreLibs\Debug\RunningTime::hrRunningTime();
} else {
$end = \CoreLibs\Debug\RunningTime::hrRunningTime($out_time);
$second = \CoreLibs\Debug\RunningTime::hrRunningTime($out_time);
}
// print "E: " . $end . "\n";
$this->assertMatchesRegularExpression(
$expected,
(string)$end
(string)$second,
'assert second run regex'
);
if ($out_time === null) {
$end_second = \CoreLibs\Debug\RunningTime::hrRunningTimeFromStart();
} else {
$end_second = \CoreLibs\Debug\RunningTime::hrRunningTimeFromStart($out_time);
}
$this->assertEquals(
$end_second,
$second,
'assert end is equal second'
);
// sleep again, second messurement
time_nanosleep(1, 500);
if ($out_time === null) {
$third = \CoreLibs\Debug\RunningTime::hrRunningTime();
} else {
$third = \CoreLibs\Debug\RunningTime::hrRunningTime($out_time);
}
// third call is not null
$this->assertNotEquals(
0,
$third,
'assert third call not null'
);
// third call is bigger than end
$this->assertNotEquals(
$second,
$third,
'assert third different second'
);
// last messurement, must match start - end + last
if ($out_time === null) {
$end = \CoreLibs\Debug\RunningTime::hrRunningTimeFromStart();
} else {
$end = \CoreLibs\Debug\RunningTime::hrRunningTimeFromStart($out_time);
}
$this->assertGreaterThan(
$third,
$end,
'assert end greater third'
);
// new start
\CoreLibs\Debug\RunningTime::hrRunningTimeReset();
$new_start = \CoreLibs\Debug\RunningTime::hrRunningTime();
$this->assertEquals(
0,
$new_start,
'assert new run 0'
);
}

View File

@@ -45,7 +45,7 @@ final class CoreLibsDebugSupportTest extends TestCase
*
* @return array
*/
public function printArProvider(): array
public function printArrayProvider(): array
{
return [
'empty array' => [
@@ -62,6 +62,51 @@ final class CoreLibsDebugSupportTest extends TestCase
];
}
/**
* Undocumented function
*
* @return array
*/
public function printBoolProvider(): array
{
return [
'true input default' => [
0 => true,
1 => [],
2 => 'true'
],
'false input default' => [
0 => false,
1 => [],
2 => 'false'
],
'false input param name' => [
0 => false,
1 => [
'name' => 'param test'
],
2 => '<b>param test</b>: false'
],
'true input param name, true override' => [
0 => true,
1 => [
'name' => 'param test',
'true' => 'ok'
],
2 => '<b>param test</b>: ok'
],
'false input param name, true override, false override' => [
0 => false,
1 => [
'name' => 'param test',
'true' => 'ok',
'false' => 'not',
],
2 => '<b>param test</b>: not'
],
];
}
/**
* Undocumented function
*
@@ -184,8 +229,9 @@ final class CoreLibsDebugSupportTest extends TestCase
* Undocumented function
*
* @cover ::printAr
* @dataProvider printArProvider
* @testdox printAr $input will be $expected [$_dataName]
* @cover ::printArray
* @dataProvider printArrayProvider
* @testdox printAr/printArray $input will be $expected [$_dataName]
*
* @param array $input
* @param string $expected
@@ -195,7 +241,59 @@ final class CoreLibsDebugSupportTest extends TestCase
{
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::printAr($input)
\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'
);
}

View File

@@ -0,0 +1,162 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Get\DotEnv;
/**
* Test class for ACL\Login
* @coversDefaultClass \CoreLibs\Get\DotEnv
* @testdox \CoreLibs\Get\DotEnv method tests
*/
final class CoreLibsGetDotEnvTest extends TestCase
{
/**
* Undocumented function
*
* @return array
*/
public function envFileProvider(): array
{
$dot_env_content = [
'SOMETHING' => 'A',
'OTHER' => 'B IS B',
'Complex' => 'A B \"D is F',
'HAS_SPACE' => 'ABC',
'HAS_COMMENT_QUOTES_SPACE' => 'Comment at end with quotes and space',
'HAS_COMMENT_QUOTES_NO_SPACE' => 'Comment at end with quotes no space',
'HAS_COMMENT_NO_QUOTES_SPACE' => 'Comment at end no quotes and space',
'HAS_COMMENT_NO_QUOTES_NO_SPACE' => 'Comment at end no quotes no space',
'COMMENT_IN_TEXT_QUOTES' => 'Foo bar # comment in here',
'FAILURE' => 'ABC',
'SIMPLEBOX' => 'A B C',
'TITLE' => '1',
'FOO' => '1.2',
'SOME.TEST' => 'Test Var',
'SOME.LIVE' => 'Live Var',
'A_TEST1' => 'foo',
'A_TEST2' => '${TEST1:-bar}',
'A_TEST3' => '${TEST4:-bar}',
'A_TEST5' => 'null',
'A_TEST6' => '${TEST5-bar}',
'A_TEST7' => '${TEST6:-bar}',
'B_TEST1' => 'foo',
'B_TEST2' => '${TEST1:=bar}',
'B_TEST3' => '${TEST4:=bar}',
'B_TEST5' => 'null',
'B_TEST6' => '${TEST5=bar}',
'B_TEST7' => '${TEST6=bar}',
'Test' => 'A',
'TEST' => 'B',
'LINE' => "ABC\nDEF",
'OTHERLINE' => "ABC\nAF\"ASFASDF\nMORESHIT",
'SUPERLINE' => '',
'__FOO_BAR_1' => 'b',
'__FOOFOO' => 'f ',
123123 => 'number',
'EMPTY' => '',
];
// 0: folder relative to test folder, if unset __DIR__
// 1: file, if unset .env
// 2: status to be returned
// 3: _ENV file content to be set
// 4: override chmod as octect in string
return [
'default' => [
'folder' => null,
'file' => null,
'status' => 3,
'content' => [],
'chmod' => null,
],
'cannot open file' => [
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
'file' => 'cannot_read.env',
'status' => 2,
'content' => [],
'chmod' => '000',
],
'empty file' => [
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
'file' => 'empty.env',
'status' => 1,
'content' => [],
'chmod' => null,
],
'override all' => [
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
'file' => 'test.env',
'status' => 0,
'content' => $dot_env_content,
'chmod' => null,
],
'override directory' => [
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
'file' => null,
'status' => 0,
'content' => $dot_env_content,
'chmod' => null,
],
];
}
/**
* test read .env file
*
* @covers ::readEnvFile
* @dataProvider envFileProvider
* @testdox Read _ENV file from $folder / $file with expected status: $expected_status and chmod $chmod [$_dataName]
*
* @param string|null $folder
* @param string|null $file
* @param int $expected_status
* @param array $expected_env
* @param string|null $chmod
* @return void
*/
public function testReadEnvFile(
?string $folder,
?string $file,
int $expected_status,
array $expected_env,
?string $chmod
): void {
// if we have file + chmod set
$old_chmod = null;
if (
is_file($folder . DIRECTORY_SEPARATOR . $file) &&
!empty($chmod)
) {
// get the old permissions
$old_chmod = fileperms($folder . DIRECTORY_SEPARATOR . $file);
chmod($folder . DIRECTORY_SEPARATOR . $file, octdec($chmod));
}
if ($folder !== null && $file !== null) {
$status = DotEnv::readEnvFile($folder, $file);
} elseif ($folder !== null) {
$status = DotEnv::readEnvFile($folder);
} else {
$status = DotEnv::readEnvFile();
}
$this->assertEquals(
$status,
$expected_status,
'Assert returned status equal'
);
// now assert read data
$this->assertEquals(
$_ENV,
$expected_env,
'Assert _ENV correct'
);
// if we have file and chmod unset
if ($old_chmod !== null) {
chmod($folder . DIRECTORY_SEPARATOR . $file, $old_chmod);
}
}
}
// __END__

File diff suppressed because it is too large Load Diff

1
4dev/tests/dotenv/.env Symbolic link
View File

@@ -0,0 +1 @@
test.env

View File

View File

View File

@@ -0,0 +1,49 @@
# enviroment file
SOMETHING=A
OTHER="B IS B"
Complex="A B \"D is F"
# COMMENT
HAS_SPACE= "ABC";
# COMMENT AT END
HAS_COMMENT_QUOTES_SPACE="Comment at end with quotes and space" # Comment QE
HAS_COMMENT_QUOTES_NO_SPACE="Comment at end with quotes no space"# Comment QES
HAS_COMMENT_NO_QUOTES_SPACE=Comment at end no quotes and space # Comment NQE
HAS_COMMENT_NO_QUOTES_NO_SPACE=Comment at end no quotes no space# Comment NQES
COMMENT_IN_TEXT_QUOTES="Foo bar # comment in here"
FAILURE = ABC
SIMPLEBOX= A B C
TITLE=1
FOO=1.2
SOME.TEST=Test Var
SOME.LIVE=Live Var
# VAR TESTS -
A_TEST1 = foo
A_TEST2 = ${TEST1:-bar} # TEST1 is set so the value of TEST2 = foo
A_TEST3 = ${TEST4:-bar} # TEST4 is not set so the value of TEST3 = bar
A_TEST5 = null
A_TEST6 = ${TEST5-bar} # TEST5 is set but empty so the value of TEST6 = null
A_TEST7 = ${TEST6:-bar} # TEST5 is set and empty so the value of TEST7 = bar
# VAR TESTS =
B_TEST1 = foo
B_TEST2 = ${TEST1:=bar} # TEST1 is set so the value of TEST2 = foo
B_TEST3 = ${TEST4:=bar} # TEST4 is not set so the value of TEST3 = bar and TEST4 = bar
B_TEST5 = null
B_TEST6 = ${TEST5=bar} # TEST5 is set but emtpy so the value of TEST6 = null
B_TEST7 = ${TEST6=bar} # TEST5 is set and empty so the value of TEST7 = bar and TEST5 = bar
# VAR TEST END
Test="A"
TEST="B"
TEST="D"
LINE="ABC
DEF"
OTHERLINE="ABC
AF\"ASFASDF
MORESHIT"
SUPERLINE=
"asfasfasf"
__FOO_BAR_1 = b
__FOOFOO = f
123123=number
EMPTY=
= flase
asfasdf

View File

@@ -0,0 +1,140 @@
<?php // phpcs:ignore warning
/**
* @phan-file-suppress PhanTypeSuspiciousStringExpression
*/
declare(strict_types=1);
// turn on all error reporting
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
ob_start();
// basic class test file
define('USE_DATABASE', true);
// sample config
require 'config.php';
// override ECHO ALL FALSE
$ECHO_ALL = true;
// define log file id
$LOG_FILE_ID = 'classTest-db';
ob_end_flush();
use CoreLibs\Debug\Support;
use CoreLibs\Debug\RunningTime;
$log = new CoreLibs\Debug\Logging([
'log_folder' => BASE . LOG,
'file_id' => $LOG_FILE_ID,
// add file date
'print_file_date' => true,
// set debug and print flags
'debug_all' => $DEBUG_ALL ?? false,
'echo_all' => $ECHO_ALL ?? false,
'print_all' => $PRINT_ALL ?? false,
]);
// db connection and attach logger
$db = new CoreLibs\DB\IO(DB_CONFIG, $log);
$db->log->debug('START', '=============================>');
$PAGE_NAME = 'TEST CLASS: DB dbReturn';
print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title><head>";
print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><a href="class_test.db.php">Class Test DB</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>';
print "LOGFILE NAME: " . $db->log->getSetting('log_file_name') . "<br>";
print "LOGFILE ID: " . $db->log->getSetting('log_file_id') . "<br>";
print "DBINFO: " . $db->dbInfo() . "<br>";
// DB client encoding
print "DB client encoding: " . $db->dbGetEncoding() . "<br>";
print "DB search path: " . $db->dbGetSchema() . "<br>";
// SELECT read tests with dbReturn and cache values
print "<br>";
print "<b>dbReturn CACHE tests</b><br>";
// DATA has two rows for reading
// delete and repare base data
$db->dbExec("DELETE FROM test_db_return");
$db->dbExec("INSERT INTO test_db_return (uid, data) VALUES ('A1', 'Test A'), ('B1', 'Test B')");
// read query to use
$q_db_ret = "SELECT * FROM test_db_return ORDER BY uid";
RunningTime::hrRunningTime();
$cache_flag = 'USE_CACHE (0)';
print "dbReturn '" . $cache_flag . "'/Default: " . $q_db_ret . "<br>";
// SINGLE read on multi row return
// Do twice
for ($i = 1; $i <= 6; $i++) {
$res = $db->dbReturn($q_db_ret);
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . $db->log->prBl($res) :
(is_array($res) ?
"Array: " . $db->log->prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr($db->dbGetCursorExt($q_db_ret)) . "</pre>";
print "Run time: " . RunningTime::hrRunningTime() . "<br>";
}
// reset all read data
$db->dbCacheReset($q_db_ret);
echo "<hr>";
$cache_flag = 'READ_NEW (1)';
print "dbReturn '" . $cache_flag . "': " . $q_db_ret . "<br>";
// NO CACHE
for ($i = 1; $i <= 6; $i++) {
$res = $db->dbReturn($q_db_ret, $db::READ_NEW);
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . $db->log->prBl($res) :
(is_array($res) ?
"Array: " . $db->log->prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr($db->dbGetCursorExt($q_db_ret)) . "</pre>";
print "Run time: " . RunningTime::hrRunningTime() . "<br>";
}
// reset all read data
$db->dbCacheReset($q_db_ret);
echo "<hr>";
$cache_flag = 'CLEAR_CACHE (2)';
print "dbReturn '" . $cache_flag . "': " . $q_db_ret . "<br>";
// NO CACHE
for ($i = 1; $i <= 6; $i++) {
$res = $db->dbReturn($q_db_ret, $db::CLEAR_CACHE);
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . $db->log->prBl($res) :
(is_array($res) ?
"Array: " . $db->log->prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr($db->dbGetCursorExt($q_db_ret)) . "</pre>";
print "Run time: " . RunningTime::hrRunningTime() . "<br>";
}
// reset all read data
$db->dbCacheReset($q_db_ret);
echo "<hr>";
$cache_flag = 'NO_CACHE (3)';
print "dbReturn '" . $cache_flag . "': " . $q_db_ret . "<br>";
// NO CACHE
for ($i = 1; $i <= 6; $i++) {
$res = $db->dbReturn($q_db_ret, $db::NO_CACHE);
print $i . ") " . $cache_flag . ": "
. "res: " . (is_bool($res) ?
"<b>Bool:</b> " . $db->log->prBl($res) :
(is_array($res) ?
"Array: " . $db->log->prBl(is_array($res)) : '{-}')
) . ", "
. "cursor_ext: <pre>" . Support::printAr($db->dbGetCursorExt($q_db_ret)) . "</pre>";
print "Run time: " . RunningTime::hrRunningTime() . "<br>";
}
// reset all data
$db->dbCacheReset($q_db_ret);
print "<br>";
print "Overall Run time: " . RunningTime::hrRunningTimeFromStart() . "<br>";
// __END__

View File

@@ -44,6 +44,7 @@ print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title><head>";
print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><a href="class_test.db.dbReturn.php">Class Test DB dbReturn</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>';
print "LOGFILE NAME: " . $db->log->getSetting('log_file_name') . "<br>";
@@ -72,6 +73,8 @@ $db->dbSetEncoding('SJIS');
print "ENCODING TEST: " . $db->dbVersionInfo('client_encoding') . "/" . $db->dbGetEncoding() . "<br>";
$db->dbResetEncoding();
// TEST CACHE READS
$res = $db->dbReturn("SELECT * FROM max_test");
print "DB RETURN ROWS: " . $db->dbGetNumRows() . "<br>";
@@ -97,6 +100,12 @@ print "NO CACHED DATA: <pre>" . print_r($db->dbGetCursorExt(), true) . "</pre><b
// print "UUD/TIME: " . $res['uid'] . "/" . $res['time'] . "<br>";
// }
// dbReturn tests on separate page
print "<br>";
print "<b>dbReturn CACHE tests</b><br>";
print '<a href="class_test.db.dbReturn.php">Class Test DB dbReturn</a><br>';
print "<br>";
print "<pre>";
print "SOCKET: " . pg_socket($db->dbGetDbh()) . "<br>";
@@ -182,7 +191,6 @@ print "UPDATE WITH PK " . $last_insert_pk
. "RETURNING EXT: " . print_r($db->dbGetReturningExt(), true) . " | "
. "RETURNING ARRAY: " . print_r($db->dbGetReturningArray(), true) . "<br>";
// INSERT WITH NO RETURNING
$status = $db->dbExec("INSERT INTO test_foobar (type, integer) VALUES ('WITHOUT DATA', 456)");
print "INSERT WITH NO PRIMARY KEY NO RETURNING STATUS: " . Support::printToString($status) . " |<br>"
@@ -222,7 +230,6 @@ if (
}
}
# db write class test
$table = 'test_foo';
print "TABLE META DATA: " . DgS::printAr($db->dbShowTableMetaData($table)) . "<br>";

View File

@@ -66,6 +66,10 @@ print "S::GETCALLERMETHOD: " . test() . "<br>";
print "S::GETCALLERMETHODLIST: <pre>" . print_r(test2(), true) . "</pre><br>";
print "S::PRINTAR: " . DebugSupport::printAr(['Foo', 'Bar']) . "<br>";
print "V-S::PRINTAR: " . $debug_support_class::printAr(['Foo', 'Bar']) . "<br>";
print "S::PRINTBOOL(default): " . DebugSupport::printBool(true) . "<br>";
print "S::PRINTBOOL(name): " . DebugSupport::printBool(true, 'Name') . "<br>";
print "S::PRINTBOOL(name, ok): " . DebugSupport::printBool(true, 'Name', 'ok') . "<br>";
print "S::PRINTBOOL(name, ok, not): " . DebugSupport::printBool(false, 'Name', 'ok', 'not') . "<br>";
print "S::DEBUSTRING(s): " . DebugSupport::debugString('SET') . "<br>";
print "S::DEBUSTRING(''): " . DebugSupport::debugString('') . "<br>";
print "S::DEBUSTRING(,s): " . DebugSupport::debugString(null, '{-}') . "<br>";
@@ -181,6 +185,10 @@ $debug->debug('TEST PER LEVEL', 'Per level test');
$debug->debug('()', 'Per level test: invalid chars');
$debug->setLogPer('level', false);
$ar = ['A', 1, ['B' => 'D']];
$debug->debug('ARRAY', 'Array: ' . $debug->prAr($ar));
$debug->debug('BOOL', 'True: ' . $debug->prBl(true) . ', False: ' . $debug->prBl(false));
// error message
// future DEPRECATED
// $debug->debug('BASIC CLASS', 'Debug test');

View File

@@ -0,0 +1,91 @@
<?php // phpcs:ignore warning
/**
* @phan-file-suppress PhanTypeSuspiciousStringExpression
*/
declare(strict_types=1);
$DEBUG_ALL_OVERRIDE = 0; // set to 1 to debug on live/remote server locations
$DEBUG_ALL = 1;
$PRINT_ALL = 1;
$DB_DEBUG = 1;
if ($DEBUG_ALL) {
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
}
ob_start();
// basic class test file
define('USE_DATABASE', false);
// sample config
require 'config.php';
// define log file id
$LOG_FILE_ID = 'classTest-memoryusage';
ob_end_flush();
use CoreLibs\Debug\MemoryUsage;
use CoreLibs\Debug\Support;
$log = new CoreLibs\Debug\Logging([
'log_folder' => BASE . LOG,
'file_id' => $LOG_FILE_ID,
// add file date
'print_file_date' => true,
// set debug and print flags
'debug_all' => $DEBUG_ALL ?? false,
'echo_all' => $ECHO_ALL ?? false,
'print_all' => $PRINT_ALL ?? false,
]);
$PAGE_NAME = 'TEST CLASS: MEMORY USAGE';
print "<!DOCTYPE html>";
print "<html><head><title>" . $PAGE_NAME . "</title><head>";
print "<body>";
print '<div><a href="class_test.php">Class Test Master</a></div>';
print '<div><h1>' . $PAGE_NAME . '</h1></div>';
MemoryUsage::debugMemoryFlag(true);
print "Debug Flag: " . Support::printBool(MemoryUsage::debugMemoryFlag()) . "<br>";
MemoryUsage::setStartMemory();
MemoryUsage::setMemory();
$data = MemoryUsage::memoryUsage('first run');
print "Memory usage 1 array: " . Support::printAr($data) . "<br>";
print "Memory usage 1 string: " . MemoryUsage::printMemoryUsage($data) . "<br>";
print "Memory usage 1 string raw: " . MemoryUsage::printMemoryUsage($data, true) . "<br>";
$var = 'foo';
$out = '';
for ($i = 1; $i <= 100; $i++) {
$out .= $var;
}
$data = MemoryUsage::memoryUsage('second run');
print "Memory usage 2 array: " . Support::printAr($data) . "<br>";
print "Memory usage 2 string: " . MemoryUsage::printMemoryUsage($data) . "<br>";
print "Memory usage 2 string raw: " . MemoryUsage::printMemoryUsage($data, true) . "<br>";
MemoryUsage::setMemory();
$var = 'foasdfasdfasdfasdfasdfo';
$out = '';
for ($i = 1; $i <= 10000; $i++) {
$out .= $var;
}
$data = MemoryUsage::memoryUsage('third run');
print "Memory usage 3 array: " . Support::printAr($data) . "<br>";
print "Memory usage 3 string: " . MemoryUsage::printMemoryUsage($data) . "<br>";
print "Memory usage 3 string raw: " . MemoryUsage::printMemoryUsage($data, true) . "<br>";
$var = 'foasdfasdfasdasdfasdfasdfadfadfasdfasdfo';
$out = '';
for ($i = 1; $i <= 100000; $i++) {
$out .= $var;
}
$data = MemoryUsage::memoryUsage('forth run');
print "Memory usage 4 array: " . Support::printAr($data) . "<br>";
print "Memory usage 4 string: " . MemoryUsage::printMemoryUsage($data) . "<br>";
print "Memory usage 4 string raw: " . MemoryUsage::printMemoryUsage($data, true) . "<br>";
// error message
print $log->printErrorMsg();
print "</body></html>";
// __END__

View File

@@ -54,6 +54,7 @@ print "<html><head><title>TEST CLASS</title><head>";
print "<body>";
print '<div><a href="class_test.db.php">Class Test: DB</a></div>';
print '<div><a href="class_test.db.DbReturn.php">Class Test: DB dbReturn</a></div>';
print '<div><a href="class_test.colors.php">Class Test: COLORS</a></div>';
print '<div><a href="class_test.mime.php">Class Test: MIME</a></div>';
print '<div><a href="class_test.json.php">Class Test: JSON</a></div>';
@@ -75,6 +76,7 @@ print '<div><a href="class_test.randomkey.php">Class Test: RANDOM KEY</a></div>'
print '<div><a href="class_test.system.php">Class Test: SYSTEM</a></div>';
print '<div><a href="class_test.readenvfile.php">Class Test: READ ENV FILE</a></div>';
print '<div><a href="class_test.runningtime.php">Class Test: RUNNING TIME</a></div>';
print '<div><a href="class_test.memoryusage.php">Class Test: MEMORY USAGE</a></div>';
print '<div><a href="class_test.debug.php">Class Test: DEBUG</a></div>';
print '<div><a href="class_test.output.form.php">Class Test: OUTPUT FORM</a></div>';
print '<div><a href="class_test.admin.backend.php">Class Test: BACKEND ADMIN CLASS</a></div>';
@@ -94,13 +96,13 @@ print "<div>READ _ENV ARRAY:</div>";
print CoreLibs\Debug\Support::printAr(array_map('htmlentities', $_ENV));
// set + check edit access id
$edit_access_id = 3;
if (is_object($login) && isset($login->acl['unit'])) {
print "ACL UNIT: " . print_r(array_keys($login->acl['unit']), true) . "<br>";
if (is_object($login) && isset($login->loginGetAcl()['unit'])) {
print "ACL UNIT: " . print_r(array_keys($login->loginGetAcl()['unit']), true) . "<br>";
print "ACCESS CHECK: " . (string)$login->loginCheckEditAccess($edit_access_id) . "<br>";
if ($login->loginCheckEditAccess($edit_access_id)) {
$backend->edit_access_id = $edit_access_id;
} else {
$backend->edit_access_id = $login->acl['unit_id'];
$backend->edit_access_id = $login->loginGetAcl()['unit_id'];
}
} else {
print "Something went wrong with the login<br>";
@@ -131,8 +133,8 @@ $log->debug('SOME MARK', 'Some error output');
// INTERNAL SET
print "EDIT ACCESS ID: " . $backend->edit_access_id . "<br>";
if (is_object($login)) {
// print "ACL: <br>".$backend->print_ar($login->acl)."<br>";
$log->debug('ACL', "ACL: " . \CoreLibs\Debug\Support::printAr($login->acl));
// print "ACL: <br>".$backend->print_ar($login->loginGetAcl())."<br>";
$log->debug('ACL', "ACL: " . \CoreLibs\Debug\Support::printAr($login->loginGetAcl()));
// print "DEFAULT ACL: <br>".$backend->print_ar($login->default_acl_list)."<br>";
// print "DEFAULT ACL: <br>".$backend->print_ar($login->default_acl_list)."<br>";
// $result = array_flip(
@@ -147,7 +149,7 @@ if (is_object($login)) {
// );
// print "DEFAULT ACL: <br>".$backend->print_ar($result)."<br>";
// DEPRICATED CALL
// $backend->adbSetACL($login->acl);
// $backend->adbSetACL($login->loginGetAcl());
}
print "THIS HOST: " . HOST_NAME . ", with PROTOCOL: " . HOST_PROTOCOL . " is running SSL: " . HOST_SSL . "<br>";

View File

@@ -40,6 +40,9 @@ print '<div><h1>' . $PAGE_NAME . '</h1></div>';
print "ALREADY from config.php: " . \CoreLibs\Debug\Support::printAr($_ENV) . "<br>";
// test .env in local
$status = \CoreLibs\Get\DotEnv::readEnvFile('.', 'test.env');
print "test.env: STATUS: " . $status . "<br>";
print "AFTER reading test.env file: " . \CoreLibs\Debug\Support::printAr($_ENV) . "<br>";
// error message
print $log->printErrorMsg();

View File

@@ -52,8 +52,17 @@ echo "TIMED [hr]: " . RunningTime::hrRunningTime() . "<br>";
echo "TIMED [def]: " . RunningTime::runningTime() . "<br>";
echo "TIMED [string]: " . RunningTime::runningTimeString() . "<br>";
RunningTime::hrRunningTime();
echo "TIMED [hr-end] " . RunningTime::hrRunningTimeFromStart() . "<br>";
echo "<br>";
echo "RANDOM KEY [default]: " . \CoreLibs\Create\RandomKey::randomKeyGen() . "<br>";
echo "TIMED [hr]: " . RunningTime::hrRunningTime() . "<br>";
echo "TIMED 1 [hr]: " . RunningTime::hrRunningTime() . "<br>";
echo "TIMED 1 [hr-n]: " . RunningTime::hrRunningTime() . "<br>";
echo "TIMED 1 [hr-b]: " . RunningTime::hrRunningTime() . "<br>";
echo "TIMED 1 [hr-end]: " . RunningTime::hrRunningTimeFromStart() . "<br>";
RunningTime::hrRunningTimeReset();
RunningTime::hrRunningTime();
echo "TIMED 2 [hr]: " . RunningTime::hrRunningTime() . "<br>";
echo "TIMED 2 [hr-end]: " . RunningTime::hrRunningTimeFromStart() . "<br>";
// error message
print $log->printErrorMsg();

View File

@@ -0,0 +1,61 @@
<?php // phpcs:ignore PSR1.Files.SideEffects
// this is an empty test page for login tests only
declare(strict_types=1);
$DEBUG_ALL_OVERRIDE = false; // set to 1 to debug on live/remote server locations
$DEBUG_ALL = true;
$PRINT_ALL = true;
$DB_DEBUG = true;
if ($DEBUG_ALL) {
error_reporting(E_ALL | E_STRICT | E_ERROR | E_WARNING | E_PARSE | E_COMPILE_ERROR);
}
ob_start();
// basic class test file
define('USE_DATABASE', true);
// sample config
require 'config.php';
// define log file id
$LOG_FILE_ID = 'classTest';
$SET_SESSION_NAME = EDIT_SESSION_NAME;
// init login & backend class
$session = new CoreLibs\Create\Session($SET_SESSION_NAME);
$log = new CoreLibs\Debug\Logging([
'log_folder' => BASE . LOG,
'file_id' => $LOG_FILE_ID,
// add file date
'print_file_date' => true,
// set debug and print flags
'debug_all' => $DEBUG_ALL ?? false,
'echo_all' => $ECHO_ALL ?? false,
'print_all' => $PRINT_ALL ?? false,
]);
$db = new CoreLibs\DB\IO(DB_CONFIG, $log);
$login = new CoreLibs\ACL\Login($db, $log, $session);
$locale = \CoreLibs\Language\GetLocale::setLocale();
$l10n = new \CoreLibs\Language\L10n(
$locale['locale'],
$locale['domain'],
$locale['path'],
);
print "<!DOCTYPE html>";
print "<html><head><title>GROUP TESTER</title><head>";
print "<body>";
print '<form method="post" name="loginlogout">';
print '<a href="javascript:document.loginlogout.login_logout.value=\'Logou\';'
. 'document.loginlogout.submit();">Logout</a>';
print '<input type="hidden" name="login_logout" value="">';
print '</form>';
print "<h1>TEST Login</h1>";
print "</body></html>";
// __END__

1
www/admin/test.env Symbolic link
View File

@@ -0,0 +1 @@
../../4dev/tests/dotenv/test.env

38
www/composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fb2235a66a37d89e7941a863843d2e15",
"content-hash": "a71e6f4fbc06f0efb6ad34538b515c53",
"packages": [],
"packages-dev": [
{
@@ -415,16 +415,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.6.0",
"version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706"
"reference": "77a32518733312af16a44300404e945338981de3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"reference": "93ebd0014cab80c4ea9f5e297ea48672f1b87706",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3",
"reference": "77a32518733312af16a44300404e945338981de3",
"shasum": ""
},
"require": {
@@ -459,9 +459,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.0"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1"
},
"time": "2022-01-04T19:58:01+00:00"
"time": "2022-03-15T21:29:03+00:00"
},
{
"name": "phpspec/prophecy",
@@ -850,16 +850,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.19",
"version": "9.5.20",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807"
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/35ea4b7f3acabb26f4bb640f8c30866c401da807",
"reference": "35ea4b7f3acabb26f4bb640f8c30866c401da807",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/12bc8879fb65aef2138b26fc633cb1e3620cffba",
"reference": "12bc8879fb65aef2138b26fc633cb1e3620cffba",
"shasum": ""
},
"require": {
@@ -937,7 +937,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.19"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.20"
},
"funding": [
{
@@ -949,7 +949,7 @@
"type": "github"
}
],
"time": "2022-03-15T09:57:31+00:00"
"time": "2022-04-01T12:37:26+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -1317,16 +1317,16 @@
},
{
"name": "sebastian/environment",
"version": "5.1.3",
"version": "5.1.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "388b6ced16caa751030f6a69e588299fa09200ac"
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac",
"reference": "388b6ced16caa751030f6a69e588299fa09200ac",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7",
"reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7",
"shasum": ""
},
"require": {
@@ -1368,7 +1368,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.3"
"source": "https://github.com/sebastianbergmann/environment/tree/5.1.4"
},
"funding": [
{
@@ -1376,7 +1376,7 @@
"type": "github"
}
],
"time": "2020-09-28T05:52:38+00:00"
"time": "2022-04-03T09:37:03+00:00"
},
{
"name": "sebastian/exporter",

View File

@@ -232,10 +232,16 @@ if (
exit;
}
// set SSL on
if (
(array_key_exists('HTTPS', $_SERVER) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
$_SERVER['SERVER_PORT'] == 443
$is_secure = false;
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$is_secure = true;
} elseif (
!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' ||
!empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on'
) {
$is_secure = true;
}
if ($is_secure) {
define('HOST_SSL', true);
define('HOST_PROTOCOL', 'https://');
} else {

View File

@@ -50,7 +50,7 @@ for (
is_file($__DIR__PATH . $CONFIG_PATH_PREFIX . CONFIG_PATH . 'config.master.php')
) {
// load enviorment file if it exists
\CoreLibs\Get\ReadEnvFile::readEnvFile(
\CoreLibs\Get\DotEnv::readEnvFile(
$__DIR__PATH . $CONFIG_PATH_PREFIX . CONFIG_PATH
);
// load master config file that loads all other config files

View File

@@ -19,15 +19,17 @@ if (!empty($DEBUG_ALL) && !empty($ENABLE_ERROR_HANDLING)) {
//------------------------------ library include start
// set output to quiet for load of classes & session settings
ob_start();
// set the session name
$SET_SESSION_NAME = EDIT_SESSION_NAME;
$LOG_FILE_ID = BASE_NAME . 'Admin';
//------------------------------ library include end
//------------------------------ basic variable settings start
// set the session name
$SET_SESSION_NAME = EDIT_SESSION_NAME;
$LOG_FILE_ID = BASE_NAME . 'Admin';
// ajax page flag
if (!isset($AJAX_PAGE)) {
$AJAX_PAGE = false;
}
// zip download flag
if (!isset($ZIP_STREAM)) {
$ZIP_STREAM = false;
}
@@ -48,7 +50,7 @@ if ($AJAX_PAGE && !$ZIP_STREAM) {
// start session
$session = new \CoreLibs\Create\Session($SET_SESSION_NAME);
// create logger
$log = new CoreLibs\Debug\Logging([
$log = new \CoreLibs\Debug\Logging([
'log_folder' => BASE . LOG,
'file_id' => $LOG_FILE_ID,
'print_file_date' => true,
@@ -69,9 +71,9 @@ if (
}
}
// db config with logger
$db = new CoreLibs\DB\IO(DB_CONFIG, $log);
$db = new \CoreLibs\DB\IO(DB_CONFIG, $log);
// login & page access check
$login = new CoreLibs\ACL\Login($db, $log, $session);
$login = new \CoreLibs\ACL\Login($db, $log, $session);
// lang, path, domain
// pre auto detect language after login
$locale = \CoreLibs\Language\GetLocale::setLocale();
@@ -82,15 +84,15 @@ $l10n = new \CoreLibs\Language\L10n(
$locale['path'],
);
// create smarty object
$smarty = new CoreLibs\Template\SmartyExtend($l10n, $locale);
$smarty = new \CoreLibs\Template\SmartyExtend($l10n, $locale);
// create new Backend class with db and loger attached
$cms = new CoreLibs\Admin\Backend($db, $log, $session, $l10n, $locale);
$cms = new \CoreLibs\Admin\Backend($db, $log, $session, $l10n, $locale);
// the menu show flag (what menu to show)
$cms->menu_show_flag = 'main';
// db info
$cms->db->dbInfo();
// set acl
$cms->setACL($login->acl);
$cms->setACL($login->loginGetAcl());
// flush (can we move that to header block above)
ob_end_flush();
//------------------------------ class init end

View File

@@ -397,10 +397,18 @@ if ($form->my_page_name == 'edit_order') {
$elements[] = $form->formCreateElement('login_error_date_last');
$elements[] = $form->formCreateElement('login_error_date_first');
$elements[] = $form->formCreateElement('enabled');
$elements[] = $form->formCreateElement('deleted');
$elements[] = $form->formCreateElement('protected');
$elements[] = $form->formCreateElement('username');
$elements[] = $form->formCreateElement('password');
$elements[] = $form->formCreateElement('password_change_interval');
$elements[] = $form->formCreateElement('login_user_id');
$elements[] = $form->formCreateElement('login_user_id_set_date');
$elements[] = $form->formCreateElement('login_user_id_last_revalidate');
$elements[] = $form->formCreateElement('login_user_id_locked');
$elements[] = $form->formCreateElement('login_user_id_revalidate_after');
$elements[] = $form->formCreateElement('login_user_id_valid_from');
$elements[] = $form->formCreateElement('login_user_id_valid_until');
$elements[] = $form->formCreateElement('email');
$elements[] = $form->formCreateElement('last_name');
$elements[] = $form->formCreateElement('first_name');
@@ -408,6 +416,8 @@ if ($form->my_page_name == 'edit_order') {
$elements[] = $form->formCreateElement('edit_access_right_id');
$elements[] = $form->formCreateElement('strict');
$elements[] = $form->formCreateElement('locked');
$elements[] = $form->formCreateElement('lock_until');
$elements[] = $form->formCreateElement('lock_after');
$elements[] = $form->formCreateElement('admin');
$elements[] = $form->formCreateElement('debug');
$elements[] = $form->formCreateElement('db_debug');

View File

@@ -53,6 +53,16 @@ $edit_users = [
'0' => 'No'
],
],
'deleted' => [
'value' => $GLOBALS['deleted'] ?? '',
'output_name' => 'Deleted',
'type' => 'binary',
'int' => 1,
'element_list' => [
'1' => 'Yes',
'0' => 'No'
],
],
'strict' => [
'value' => $GLOBALS['strict'] ?? '',
'output_name' => 'Strict (Lock after errors)',
@@ -119,6 +129,77 @@ $edit_users = [
'output_name' => 'First Name',
'type' => 'text'
],
'lock_until' => [
'value' => $GLOBALS['lock_until'] ?? '',
'output_name' => 'Lock account until',
'type' => 'datetime',
'error_check' => 'datetime',
'sql_read' => 'YYYY-MM-DD HH24:MI',
'datetime' => 1,
],
'lock_after' => [
'value' => $GLOBALS['lock_after'] ?? '',
'output_name' => 'Lock account after',
'type' => 'datetime',
'error_check' => 'datetime',
'sql_read' => 'YYYY-MM-DD HH24:MI',
'datetime' => 1,
],
'login_user_id' => [
'value' => $GLOBALS['login_user_id'] ?? '',
'output_name' => '_GET/_POST loginUserId direct login ID',
'type' => 'text',
'error_check' => 'unique|custom',
'error_regex' => "/^[A-Za-z0-9]+$/",
'emptynull' => 1,
],
'login_user_id_set_date' => [
'output_name' => 'loginUserId set date',
'value' => $GLOBALS['login_user_id_set_date'] ?? '',
'type' => 'view',
'empty' => '-'
],
'login_user_id_last_revalidate' => [
'output_name' => 'loginUserId last revalidate date',
'value' => $GLOBALS['login_user_id_last_revalidate'] ?? '',
'type' => 'view',
'empty' => '-'
],
'login_user_id_locked' => [
'value' => $GLOBALS['login_user_id_locked'] ?? '',
'output_name' => 'loginUserId usage locked',
'type' => 'binary',
'int' => 1,
'element_list' => [
'1' => 'Yes',
'0' => 'No'
],
],
'login_user_id_revalidate_after' => [
'value' => $GLOBALS['login_user_id_revalidate_after'] ?? '',
'output_name' => 'loginUserId, User must login after n days',
'type' => 'text',
'error_check' => 'intervalshort',
'interval' => 1, // interval needs NULL write for empty
'size' => 5, // make it 5 chars long
'length' => 5
],
'login_user_id_valid_from' => [
'value' => $GLOBALS['login_user_id_valid_from'] ?? '',
'output_name' => 'loginUserId valid from',
'type' => 'datetime',
'error_check' => 'datetime',
'sql_read' => 'YYYY-MM-DD HH24:MI',
'datetime' => 1,
],
'login_user_id_valid_until' => [
'value' => $GLOBALS['login_user_id_valid_until'] ?? '',
'output_name' => 'loginUserId valid until',
'type' => 'datetime',
'error_check' => 'datetime',
'sql_read' => 'YYYY-MM-DD HH24:MI',
'datetime' => 1,
],
'edit_language_id' => [
'value' => $GLOBALS['edit_language_id'] ?? '',
'output_name' => 'Language',
@@ -187,7 +268,8 @@ $edit_users = [
'cols' => 60
],
],
'load_query' => "SELECT edit_user_id, username, enabled, debug, db_debug, strict, locked, login_error_count "
'load_query' => "SELECT edit_user_id, username, enabled, deleted, "
. "strict, locked, login_error_count "
. "FROM edit_user ORDER BY username",
'table_name' => 'edit_user',
'show_fields' => [
@@ -197,31 +279,26 @@ $edit_users = [
[
'name' => 'enabled',
'binary' => ['Yes', 'No'],
'before_value' => 'Enabled: '
'before_value' => 'ENBL: '
],
[
'name' => 'debug',
'name' => 'deleted',
'binary' => ['Yes', 'No'],
'before_value' => 'Debug: '
],
[
'name' => 'db_debug',
'binary' => ['Yes', 'No'],
'before_value' => 'DB Debug: '
'before_value' => 'DEL: '
],
[
'name' => 'strict',
'binary' => ['Yes', 'No'],
'before_value' => 'Strict: '
'before_value' => 'STRC: '
],
[
'name' => 'locked',
'binary' => ['Yes', 'No'],
'before_value' => 'Locked: '
'before_value' => 'LCK: '
],
[
'name' => 'login_error_count',
'before_value' => 'Errors: '
'before_value' => 'ERR: '
],
],
'element_list' => [

View File

@@ -32,7 +32,10 @@
<input type="hidden" name="HIDDEN_{$element.data.name}" value="{$element.data.HIDDEN_value}">
{/if}
{if $element.type == 'date'}
<input type="text" name="{$element.data.name}" value="{$element.data.value}" size="10" maxlength="10">
<input type="text" name="{$element.data.name}" value="{$element.data.value}" size="10" maxlength="10" placeholder="YYYY-MM-DD">
{/if}
{if $element.type == 'datetime'}
<input type="text" name="{$element.data.name}" value="{$element.data.value}" size="16" maxlength="16" placeholder="YYYY-MM-DD HH:mm">
{/if}
{if $element.type == 'textarea'}
<textarea name="{$element.data.name}"{if $element.data.rows} rows="{$element.data.rows}"{/if}{if $element.data.cols} cols="{$element.data.cols}"{/if}>{$element.data.value}</textarea>

File diff suppressed because it is too large Load Diff

View File

@@ -116,6 +116,7 @@ class Backend
// CONSTRUCTOR / DECONSTRUCTOR |====================================>
/**
* main class constructor
*
* @param \CoreLibs\DB\IO $db Database connection class
* @param \CoreLibs\Debug\Logging $log Logging class
* @param \CoreLibs\Create\Session $session Session interface class
@@ -175,6 +176,7 @@ class Backend
/**
* set internal ACL from login ACL
*
* @param array<mixed> $acl login acl array
*/
public function setACL(array $acl): void
@@ -183,7 +185,8 @@ class Backend
}
/**
* writes all action vars plus other info into edit_log tabl
* writes all action vars plus other info into edit_log table
*
* @param string $event any kind of event description,
* @param string|array<mixed> $data any kind of data related to that event
* @param string $write_type write type can bei STRING or BINARY
@@ -255,6 +258,7 @@ class Backend
/**
* Set the menu show flag
*
* @param string|int $menu_show_flag
* @return string|int
*/
@@ -267,6 +271,7 @@ class Backend
/**
* Return the menu show flag
*
* @return string|int
*/
public function adbGetMenuShowFlag()
@@ -276,6 +281,7 @@ class Backend
/**
* menu creater (from login menu session pages)
*
* @param int $flag visible flag trigger
* @return array<mixed> menu array for output on page (smarty)
*/
@@ -403,6 +409,7 @@ class Backend
/**
* ONLY USED IN adbTopMenu
* checks if this filename is in the current situation (user id, etc) available
*
* @param string|null $filename filename
* @return bool true for visible/accessable menu point, false for not
*/
@@ -422,8 +429,8 @@ class Backend
}
/**
* @deprecated
* creates out of a normal db_return array an assoc array
*
* @param array<mixed> $db_array input array
* @param string|int|bool $key key
* @param string|int|bool $value value
@@ -440,8 +447,8 @@ class Backend
}
/**
* @deprecated
* converts bytes into formated string with KB, MB, etc
*
* @param string|int|float $number string or int or number
* @return string formatted string
* @deprecated \CoreLibs\Convert\Byte::humanReadableByteFormat()
@@ -456,8 +463,8 @@ class Backend
}
/**
* @deprecated
* converts picture to a thumbnail with max x and max y size
*
* @param string $pic source image file with or without path
* @param int $size_x maximum size width
* @param int $size_y maximum size height
@@ -485,6 +492,7 @@ class Backend
/**
* wrapper function to fill up the mssages array
*
* @param string $level info/warning/error
* @param string $msg string, can be printf formated
* @param array<mixed> $vars optional data for a possible printf formated msg
@@ -514,6 +522,7 @@ class Backend
/**
* writes live queue
*
* @param string $queue_key string to identfy the queue
* @param string $type [description]
* @param string $target [description]
@@ -559,17 +568,22 @@ class Backend
/**
* Basic class holds exact the same, except the Year/Month/Day/etc strings
* are translated in this call
*
* @param int $year year YYYY
* @param int $month month m
* @param int $day day d
* @param int $hour hour H
* @param int $min min i
* @param string $suffix additional info printed after the date time variable in the drop down
* @param string $suffix additional info printed after the date time
* variable in the drop down
* also used for ID in the on change JS call
* @param int $min_steps default is 1 (minute), can set to anything, is used as sum up from 0
* @param bool $name_pos_back default false, if set to true, the name will be printend
* @param int $min_steps default is 1 (minute), can set to anything,
* is used as sum up from 0
* @param bool $name_pos_back default false, if set to true,
* the name will be printend
* after the drop down and not before the drop down
* @return string HTML formated strings for drop down lists of date and time
* @return string HTML formated strings for drop down lists
* of date and time
*/
public function adbPrintDateTime(
$year,

View File

@@ -165,6 +165,7 @@ class Email
/**
* guesses the email type (mostly for mobile) from the domain
* if second is set to true, it will return short naming scheme (only provider)
*
* @param string $email email string
* @param bool $short default false, if true,
* returns only short type (pc instead of pc_html)
@@ -197,6 +198,7 @@ class Email
/**
* gets the short email type from a long email type
*
* @param string $email_type email string
* @return string|bool short string or false for invalid
*/
@@ -227,7 +229,7 @@ class Email
}
/**
* Undocumented function
* check email with all regex checks possible and return errors as array
*
* @param string $email Email address, will be checkd as lower
* @param bool $error_code_only If this is set to true it will only return

View File

@@ -12,6 +12,7 @@ class File
{
/**
* quick return the extension of the given file name
*
* @param string $filename file name
* @return string extension of the file name
*/
@@ -23,6 +24,7 @@ class File
/**
* get lines in a file
*
* @param string $file file for line count read
* @return int number of lines or -1 for non readable file
*/

View File

@@ -12,7 +12,6 @@ use CoreLibs\Convert\Json;
class Jason
{
/**
* @param string|null $json a json string, or null data
* @param bool $override if set to true, then on json error

View File

@@ -12,6 +12,7 @@ class Password
{
/**
* creates the password hash
*
* @param string $password password
* @return string hashed password
*/
@@ -25,6 +26,7 @@ class Password
/**
* checks if the entered password matches the hash
*
* @param string $password password
* @param string $hash password hash
* @return bool true or false
@@ -40,6 +42,7 @@ class Password
/**
* checks if the password needs to be rehashed
*
* @param string $hash password hash
* @return bool true or false
*/

View File

@@ -10,6 +10,7 @@ class PhpVersion
* checks if running PHP version matches given PHP version (min or max)
* if either is empty or null it will be ignored
* if no min version (null or empty)
*
* @param string|null $min_version minimum version as string (x, x.y, x.y.x)
* @param string|null $max_version optional maximum version as string (x, x.y, x.y.x)
* @return bool true if ok, false if not matching version

View File

@@ -13,6 +13,7 @@ class ArrayHandler
/**
* searches key = value in an array / array
* only returns the first one found
*
* @param string|int $needle needle (search for)
* @param array<mixed> $haystack haystack (search in)
* @param string|null $key_search_for the key to look out for, default empty
@@ -68,10 +69,12 @@ class ArrayHandler
/**
* recursive array search function, which returns all found not only the first one
*
* @param string|int $needle needle (search for)
* @param array<mixed> $haystack haystack (search in)
* @param string|int $key_search_for the key to look for in
* @param bool $old [true], if set to false will return new flat layout
* @param bool $old [true], if set to false will
* return new flat layout
* @param array<mixed>|null $path recursive call for previous path
* @return array<mixed>|null all array elements paths where
* the element was found
@@ -148,6 +151,7 @@ class ArrayHandler
/**
* array search simple. looks for key, value combination, if found, returns true
* on default does not strict check, so string '4' will match int 4 and vica versa
*
* @param array<mixed> $array search in as array
* @param string|int $key key (key to search in)
* @param string|int $value value (what to find)
@@ -184,6 +188,7 @@ class ArrayHandler
* ... etc
* bool key flag: true: handle keys as string or int
* default false: all keys are string
*
* @return array<mixed>|bool merged array
*/
public static function arrayMergeRecursive()
@@ -240,6 +245,7 @@ class ArrayHandler
* array_diff only checks elements from A that are not in B, but not the
* other way around.
* Note that like array_diff this only checks first level values not keys
*
* @param array<mixed> $a array to compare a
* @param array<mixed> $b array to compare b
* @return array<mixed> array with missing elements from a & b
@@ -254,9 +260,12 @@ class ArrayHandler
* search for the needle array elements in haystack and
* return the ones found as an array,
* is there nothing found, it returns FALSE (boolean)
*
* @param array<mixed> $needle elements to search for
* @param array<mixed> $haystack array where the $needle elements should be searched int
* @return array<mixed>|bool either the found elements or false for nothing found or error
* @param array<mixed> $haystack array where the $needle elements should
* be searched int
* @return array<mixed>|bool either the found elements or
* false for nothing found or error
*/
public static function inArrayAny(array $needle, array $haystack)
{
@@ -275,6 +284,7 @@ class ArrayHandler
/**
* creates out of a normal db_return array an assoc array
*
* @param array<mixed> $db_array return array from the database
* @param string|int|bool $key key set, false for not set
* @param string|int|bool $value value set, false for not set
@@ -313,6 +323,7 @@ class ArrayHandler
/**
* converts multi dimensional array to a flat array
* does NOT preserve keys
*
* @param array<mixed> $array multi dimensionial array
* @return array<mixed> flattened array
*/
@@ -330,6 +341,7 @@ class ArrayHandler
/**
* will loop through an array recursivly and write the array keys back
*
* @param array<mixed> $array multidemnsional array to flatten
* @param array<mixed> $return recoursive pass on array of keys
* @return array<mixed> flattened keys array
@@ -348,6 +360,7 @@ class ArrayHandler
/**
* as above will flatten an array, but in this case only the outmost
* leave nodes, all other keyswill be skipped
*
* @param array<mixed> $array multidemnsional array to flatten
* @return array<mixed> flattened keys array
*/
@@ -366,6 +379,7 @@ class ArrayHandler
/**
* searches for key -> value in an array tree and writes the value one level up
* this will remove this leaf will all other values
*
* @param array<mixed> $array nested array
* @param string|int $search key to find that has no sub leaf
* and will be pushed up

View File

@@ -66,9 +66,11 @@ class DateTime
/**
* a simple wrapper for the date format
* if an invalid timestamp is give zero timestamp unix time is used
*
* @param int|float $timestamp unix timestamp
* @param bool $show_micro show the micro time (default false)
* @param bool $micro_as_float Add the micro time with . instead of ms (default false)
* @param bool $micro_as_float Add the micro time with . instead
* of ms (default false)
* @return string formated date+time in Y-M-D h:m:s ms
*/
public static function dateStringFormat(
@@ -92,7 +94,9 @@ class DateTime
/**
* formats a timestamp into interval, not into a date
* @param string|int|float $timestamp interval in seconds and optional float micro seconds
*
* @param string|int|float $timestamp interval in seconds and optional
* float micro seconds
* @param bool $show_micro show micro seconds, default true
* @return string interval formatted string or string as is
*/
@@ -149,6 +153,7 @@ class DateTime
/**
* does a reverse of the timeStringFormat and converts the string from
* xd xh xm xs xms to a timestamp.microtime format
*
* @param string|int|float $timestring formatted interval
* @return string|int|float converted float interval, or string as is
*/
@@ -190,6 +195,7 @@ class DateTime
/**
* splits & checks date, wrap around for check_date function
*
* @param string $date a date string in the format YYYY-MM-DD
* @return bool true if valid date, false if date not valid
*/
@@ -214,6 +220,7 @@ class DateTime
/**
* splits & checks date, wrap around for check_date function
*
* @param string $datetime date (YYYY-MM-DD) + time (HH:MM:SS), SS can be dropped
* @return bool true if valid date, false if date not valid
*/
@@ -263,6 +270,7 @@ class DateTime
* 0 if both are equal
* 1 if the first date is bigger than the last
* false (bool): error
*
* @param string $start_date start date string in YYYY-MM-DD
* @param string $end_date end date string in YYYY-MM-DD
* @return int|bool false on error, or int -1/0/1 as difference
@@ -297,12 +305,14 @@ class DateTime
}
/**
* compares the two dates + times. if seconds missing in one set, add :00, converts / to -
* compares the two dates + times. if seconds missing in one set,
* add :00, converts / to -
* returns int/bool in:
* -1 if the first date is smaller the last
* 0 if both are equal
* 1 if the first date is bigger than the last
* false if no valid date/times chould be found
*
* @param string $start_datetime start date/time in YYYY-MM-DD HH:mm:ss
* @param string $end_datetime end date/time in YYYY-MM-DD HH:mm:ss
* @return int|bool false for error or -1/0/1 as difference
@@ -336,6 +346,7 @@ class DateTime
* calculates the days between two dates
* return: overall days, week days, weekend days as array 0...2 or named
* as overall, weekday and weekend
*
* @param string $start_date valid start date (y/m/d)
* @param string $end_date valid end date (y/m/d)
* @param bool $return_named return array type, false (default), true for named

View File

@@ -30,6 +30,7 @@ class Byte
* BYTE_FORMAT_ADJUST [2] use sprintf to always print two decimals
* BYTE_FORMAT_SI [3] use si standard 1000 instead of bytes 1024
* To use the constant from outside use class::CONSTANT
*
* @param string|int|float $bytes bytes as string int or pure int
* @param int $flags bitwise flag with use space turned on
* @return string converted byte number (float) with suffix
@@ -106,6 +107,7 @@ class Byte
* NOTE: large exabyte numbers will overflow
* flag allowed:
* BYTE_FORMAT_SI [3] use si standard 1000 instead of bytes 1024
*
* @param string|int|float $number any string or number to convert
* @param int $flags bitwise flag with use space turned on
* @return string|int|float converted value or original value

View File

@@ -23,6 +23,7 @@ class Colors
* converts the rgb values from int data to the valid rgb html hex string
* optional can turn of leading #
* if one value is invalid, will return false
*
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
@@ -49,6 +50,7 @@ class Colors
/**
* converts a hex RGB color to the int numbers
*
* @param string $hexStr RGB hexstring
* @param bool $return_as_string flag to return as string
* @param string $seperator string seperator: default: ","
@@ -90,6 +92,7 @@ class Colors
* converts RGB to HSB/V values
* returns:
* array with hue (0-360), sat (0-100%), brightness/value (0-100%)
*
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
@@ -136,6 +139,7 @@ class Colors
* hsb2rgb does not clean convert back to hsb in a round trip
* converts HSB/V to RGB values RGB is full INT
* if HSB/V value is invalid, sets this value to 0
*
* @param float $H hue 0-360 (int)
* @param float $S saturation 0-100 (int)
* @param float $V brightness/value 0-100 (int)
@@ -218,6 +222,7 @@ class Colors
* converts a RGB (0-255) to HSL
* return:
* array with hue (0-360), saturation (0-100%) and luminance (0-100%)
*
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
@@ -271,6 +276,7 @@ class Colors
/**
* converts an HSL to RGB
* if HSL value is invalid, set this value to 0
*
* @param float $hue hue: 0-360 (degrees)
* @param float $sat saturation: 0-100
* @param float $lum luminance: 0-100

View File

@@ -15,6 +15,7 @@ class Html
/**
* full wrapper for html entities
*
* @param mixed $string string to html encode
* @return mixed if string, encoded, else as is (eg null)
*/
@@ -42,10 +43,14 @@ class Html
* returns 'checked' or 'selected' if okay
* $needle is a var, $haystack an array or a string
* **** THE RETURN: VALUE WILL CHANGE TO A DEFAULT NULL IF NOT FOUND ****
* @param array<mixed>|string $haystack (search in) haystack can be an array or a string
*
* @param array<mixed>|string $haystack (search in) haystack can be
* an array or a string
* @param string $needle needle (search for)
* @param int $type type: 0: returns selected, 1, returns checked
* @return ?string returns checked or selected, else returns null
* @param int $type type: 0: returns selected, 1,
* returns checked
* @return ?string returns checked or selected,
* else returns null
*/
public static function checked($haystack, string $needle, int $type = 0): ?string
{

View File

@@ -21,6 +21,7 @@ class Json
* or failed convert to array
* In ANY case it will ALWAYS return array.
* Does not throw errors
*
* @param string|null $json a json string, or null data
* @param bool $override if set to true, then on json error
* set original value as array
@@ -49,6 +50,7 @@ class Json
/**
* returns human readable string for json errors thrown in jsonConvertToArray
*
* @param bool|boolean $return_string [default=false] if set to true
* it will return the message string and not
* the error number

View File

@@ -13,6 +13,7 @@ class Math
/**
* some float numbers will be rounded up even if they have no decimal entries
* this function fixes this by pre-rounding before calling ceil
*
* @param float $number number to round
* @param int|integer $precision intermediat round up decimals (default 10)
* @return float correct ceil number
@@ -25,6 +26,7 @@ class Math
/**
* round inside an a number, not the decimal part only
* eg 48767 with -2 -> 48700
*
* @param float $number number to round
* @param int $precision negative number for position in number (default -2)
* @return float rounded number
@@ -42,6 +44,7 @@ class Math
/**
* inits input to 0, if value is not numeric
*
* @param string|int|float $number string or number to check
* @return float if not number, then returns 0, else original input
*/

View File

@@ -55,6 +55,7 @@ class MimeAppName
/**
* Sets or updates a mime type
*
* @param string $mime MIME Name, no validiation
* @param string $app Applicaiton name
* @return void
@@ -71,6 +72,7 @@ class MimeAppName
/**
* get the application name from mime type
* if not set returns "Other file"
*
* @param string $mime MIME Name
* @return string Application name matching
*/

View File

@@ -19,6 +19,7 @@ class Hash
* hash returns false
* preg_replace fails for older php version
* Use __hash with crc32b or hash('crc32b', ...) for correct output
*
* @param string $string string to crc
* @return string crc32b hash (old type)
*/
@@ -39,6 +40,7 @@ class Hash
/**
* replacement for __crc32b call
*
* @param string $string string to hash
* @param bool $use_sha use sha instead of crc32b (default false)
* @return string hash of the string
@@ -58,6 +60,7 @@ class Hash
* defaults to adler 32
* allowed crc32b, adler32, fnv132, fnv1a32, joaat
* all that create 8 char long hashes
*
* @param string $string string to hash
* @param string $hash_type hash type (default adler32)
* @return string hash of the string
@@ -79,6 +82,7 @@ class Hash
/**
* Wrapper function for standard long hashd
*
* @param string $string String to be hashed
* @return string Hashed string
*/

View File

@@ -29,6 +29,7 @@ class RandomKey
}
/**
* sets the random key range with the default values
*
* @return void has no return
*/
private static function initRandomKeyData()
@@ -44,6 +45,7 @@ class RandomKey
/**
* validates they key length for random string generation
*
* @param int $key_length key length
* @return bool true for valid, false for invalid length
*/
@@ -63,6 +65,7 @@ class RandomKey
/**
* sets the key length and checks that they key given is valid
* if failed it will not change the default key length and return false
*
* @param int $key_length key length
* @return bool true/false for set status
*/
@@ -91,6 +94,7 @@ class RandomKey
* creates a random key based on the key_range with key_length
* if override key length is set, it will check on valid key and use this
* this will not set the class key length variable
*
* @param int $key_length key length override, -1 for use default
* @return string random key
*/

View File

@@ -18,6 +18,19 @@ class Session
/** @var string list for errors */
private $session_intern_error_str = '';
/**
* Start session
* startSession should be called for complete check
* If this is called without any name set before the php.ini name is
* used.
*
* @return void
*/
protected function startSessionCall(): void
{
session_start();
}
/**
* init a session, if array is empty or array does not have session_name set
* then no auto init is run
@@ -58,19 +71,6 @@ class Session
return true;
}
/**
* Start session
* startSession should be called for complete check
* If this is called without any name set before the php.ini name is
* used.
*
* @return void
*/
public function startSessionCall(): void
{
session_start();
}
/**
* Return set error string, empty if none set
* Error strings are only set in the startSession method
@@ -206,6 +206,39 @@ class Session
return session_write_close();
}
/**
* Proper destroy a session
* - unset the _SESSION array
* - unset cookie if cookie on and we have not strict mode
* - destroy session
*
* @return bool
*/
public function sessionDestroy(): bool
{
$_SESSION = [];
if (
ini_get('session.use_cookies') &&
!ini_get('session.use_strict_mode')
) {
$session_name = $this->getSessionName();
if ($session_name === false) {
$session_name = '';
}
$params = session_get_cookie_params();
setcookie(
(string)$session_name,
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}
return session_destroy();
}
/**
* get session status
* PHP_SESSION_DISABLED if sessions are disabled.

View File

@@ -15,6 +15,7 @@ class Uids
* creates psuedo random uuid v4
* Code take from class here:
* https://www.php.net/manual/en/function.uniqid.php#94959
*
* @return string pseudo random uuid v4
*/
public static function uuidv4(): string
@@ -44,6 +45,7 @@ class Uids
* TODO: make this a proper uniq ID creation
* add uuidv4 subcall to the uuid function too
* creates a uniq id
*
* @param string $type uniq id type, currently md5 or sha256 allowed
* if not set will use DEFAULT_HASH if set
* @return string uniq id
@@ -81,7 +83,7 @@ class Uids
return $uniq_id;
}
/**
/**
* create a unique id with the standard hash type defined in __hash
*
* @return string Unique ID with fixed length of 8 characters

View File

@@ -50,6 +50,7 @@ class ArrayIO extends \CoreLibs\DB\IO
/**
* constructor for the array io class, set the
* primary key name automatically (from array)
*
* @param array<mixed> $db_config db connection config
* @param array<mixed> $table_array table array config
* @param string $table_name table name string
@@ -93,6 +94,7 @@ class ArrayIO extends \CoreLibs\DB\IO
* works for <b>,<i>, and <a> (thought <a> can be / or should
* be handled with the magic links functions
* used with the read function
*
* @param string $text any html encoded string
* @return string decoded html string
*/
@@ -111,6 +113,7 @@ class ArrayIO extends \CoreLibs\DB\IO
/**
* changeds all HTML entities into non HTML ones
*
* @param string $text encoded html string
* @return string decoded html string
*/
@@ -126,6 +129,7 @@ class ArrayIO extends \CoreLibs\DB\IO
/**
* dumps the current data
*
* @param bool $write write to error message, default false
* @return string the array data as html string entry
*/
@@ -144,7 +148,9 @@ class ArrayIO extends \CoreLibs\DB\IO
}
/**
* checks if pk is set and if not, set from pk_id and if this also not set return 0
* checks if pk is set and if not, set from pk_id and
* if this also not set return 0
*
* @return bool true if pk value is set, else false
*/
public function dbCheckPkSet()
@@ -171,7 +177,7 @@ class ArrayIO extends \CoreLibs\DB\IO
public function dbResetArray($reset_pk = false): void
{
reset($this->table_array);
foreach ($this->table_array as $column => $data_array) {
foreach (array_keys($this->table_array) as $column) {
if (!$this->table_array[$column]['pk']) {
unset($this->table_array[$column]['value']);
} elseif ($reset_pk) {
@@ -182,6 +188,7 @@ class ArrayIO extends \CoreLibs\DB\IO
/**
* deletes one dataset
*
* @param array<mixed> $table_array optional override for table array set
* set this as new table array too
* @return array<mixed> returns the table array that was deleted
@@ -201,7 +208,7 @@ class ArrayIO extends \CoreLibs\DB\IO
// delete files and build FK query
reset($this->table_array);
$q_where = '';
foreach ($this->table_array as $column => $data_array) {
foreach (array_keys($this->table_array) as $column) {
// suchen nach bildern und lschen ...
if (
!empty($this->table_array[$column]['file']) &&
@@ -241,8 +248,10 @@ class ArrayIO extends \CoreLibs\DB\IO
/**
* reads one row into the array
*
* @param boolean $edit on true convert data, else as is
* @param array<mixed> $table_array optional table array, overwrites internal set array
* @param array<mixed> $table_array optional table array, overwrites
* internal set array
* @return array<mixed> set table array with values
*/
public function dbRead($edit = false, $table_array = [])
@@ -262,11 +271,22 @@ class ArrayIO extends \CoreLibs\DB\IO
if ($q_select) {
$q_select .= ', ';
}
$q_select .= $column;
if (
!empty($data_array['type']) && $data_array['type'] == 'datetime' &&
!empty($data_array['sql_read'])
) {
// convert tom different timestamp type
$q_select .= "TO_CHAR($column, '" . $data_array['sql_read'] . "') AS $column";
} else {
$q_select .= $column;
}
// check FK ...
if (isset($this->table_array[$column]['fk']) && isset($this->table_array[$column]['value'])) {
if ($q_where) {
if (
isset($this->table_array[$column]['fk']) &&
isset($this->table_array[$column]['value'])
) {
if (!empty($q_where)) {
$q_where .= ' AND ';
}
$q_where .= $column .= ' = ' . $this->table_array[$column]['value'];
@@ -315,6 +335,7 @@ class ArrayIO extends \CoreLibs\DB\IO
/**
* writes one set into DB or updates one set (if PK exists)
*
* @param boolean $addslashes old convert entities and set set escape
* @param array<mixed> $table_array optional table array, overwrites internal one
* @return array<mixed> table array or null
@@ -440,7 +461,12 @@ class ArrayIO extends \CoreLibs\DB\IO
} elseif (isset($this->table_array[$column]['bool'])) {
// boolean storeage (reverse check on ifset)
$q_data .= "'" . $this->dbBoolean($this->table_array[$column]['value'], true) . "'";
} elseif (isset($this->table_array[$column]['interval'])) {
} elseif (
isset($this->table_array[$column]['interval']) ||
isset($this->table_array[$column]['date']) ||
isset($this->table_array[$column]['datetime']) ||
isset($this->table_array[$column]['emptynull'])
) {
// for interval we check if no value, then we set null
if (
!isset($this->table_array[$column]['value']) ||
@@ -448,7 +474,7 @@ class ArrayIO extends \CoreLibs\DB\IO
) {
$_value = 'NULL';
} elseif (isset($this->table_array[$column]['value'])) {
$_value = $this->table_array[$column]['value'];
$_value = $this->dbEscapeLiteral($this->table_array[$column]['value']);
} else {
// fallback
$_value = 'NULL';
@@ -490,7 +516,10 @@ class ArrayIO extends \CoreLibs\DB\IO
// create select part & addition FK part
foreach ($this->table_array as $column => $data_array) {
// check FK ...
if (isset($this->table_array[$column]['fk']) && isset($this->table_array[$column]['value'])) {
if (
isset($this->table_array[$column]['fk']) &&
isset($this->table_array[$column]['value'])
) {
if (!empty($q_where)) {
$q_where .= ' AND ';
}
@@ -536,7 +565,6 @@ class ArrayIO extends \CoreLibs\DB\IO
}
// set primary key
if ($insert) {
// FIXME: this has to be fixes by fixing DB::IO clas
$insert_id = $this->dbGetInsertPK();
if (is_array($insert_id)) {
$insert_id = 0;

View File

@@ -263,15 +263,15 @@ use CoreLibs\Create\Uids;
class IO
{
// 0: normal read, store in cache
// 1: read cache, clean at the end
// 2: read new, clean at end
// 1: read new, keep at end, clean before new run
// 2: read new, clean at the end (temporary cache)
// 3: never cache
/** @var int */
public const USE_CACHE = 0;
/** @var int */
public const CLEAR_CACHE = 1;
public const READ_NEW = 1;
/** @var int */
public const READ_NEW = 2;
public const CLEAR_CACHE = 2;
/** @var int */
public const NO_CACHE = 3;
/** @var string */
@@ -1682,18 +1682,18 @@ class IO
* data, or with reset flag set calls data from DB again
* NOTE on $cache param:
* - if set to 0, if same query run again, will read from cache
* - if set to 1, at the end of the query (last row returned),
* the stored array will be deleted ...
* - if set to 2, the data will be read new and cached
* - if set to 1, the data will be read new and cached, cache reset a new run
* (wheres 1 reads cache AND destroys at end of read)
* - if set to 2, at the end of the query (last row returned),
* the stored array will be deleted ...
* - if set to 3, after EACH row, the data will be reset,
* no caching is done except for basic (count, etc)
* @param string $query Query string
* @param int $cache reset status: default: USE_CACHE
* USE_CACHE/0: normal read from cache on second run
* CLEAR_CACHE/1: read cache, clean at the end
* READ_NEW/2: read new, clean at end
* NO_CACHE/3: never cache [default]
* READ_NEW/1: write to cache, clean before new run
* CLEAR_CACHE/2: write cache, clean after finished
* NO_CACHE/3: don't write cache
* @param bool $assoc_only True to only returned the named and not
* index position ones
* @return array<mixed>|bool return array data or false on error/end
@@ -1714,17 +1714,44 @@ class IO
// pre declare array
if (!isset($this->cursor_ext[$query_hash])) {
$this->cursor_ext[$query_hash] = [
// cursor, null: unset, 1: finished read/cache, 2: object/resource reading
'cursor' => null,
// cached data
'data' => [],
// field names as array
'field_names' => [],
'firstcall' => 0,
// number of fields (field names)
'num_fields' => 0,
// number of rows that will be maximum returned
'num_rows' => 0,
'pos' => 0,
'query' => '',
// how many rows have been read from db
'read_rows' => 0,
// current read pos (db/cache), 0 on last read (finished)
'pos' => 0,
// the query used in this call
'query' => '',
// cache flag from method call
'cache_flag' => $cache,
// flag if we only have assoc data
'assoc_flag' => $assoc_only,
// flag if we have cache data stored at the moment
'cached' => false,
// when fetch array or cache read returns false
// in loop read that means dbReturn retuns false without erro
'finished' => false,
// read from cache/db (pos == rows)
'read_finished' => false,
// read from db only (read == rows)
'db_read_finished' => false,
// for debug
'log_pos' => 1, // how many times called overall
'log' => [], // current run log
];
} else {
$this->cursor_ext[$query_hash]['log_pos'] ++;
}
// reset log for each read
$this->cursor_ext[$query_hash]['log'] = [];
// set the query
$this->cursor_ext[$query_hash]['query'] = $query;
// before doing ANYTHING check if query is "SELECT ..." everything else does not work
@@ -1732,20 +1759,25 @@ class IO
$this->__dbError(17, false, $this->cursor_ext[$query_hash]['query']);
return false;
}
// set first call to false
$first_call = false;
// init return als false
$return = false;
// if it is a call with reset in it we reset the cursor,
// so we get an uncached return
// but only for the FIRST call (pos == 0)
if ($cache > self::USE_CACHE && !$this->cursor_ext[$query_hash]['pos']) {
$this->cursor_ext[$query_hash]['log'][] = 'Reset cursor';
$this->cursor_ext[$query_hash]['cursor'] = null;
if ($cache == self::READ_NEW) {
$this->cursor_ext[$query_hash]['log'][] = 'Cache reset';
$this->cursor_ext[$query_hash]['data'] = [];
}
}
// $this->debug('MENU', 'Reset: '.$reset.', Cursor: '
// .$this->cursor_ext[$query_hash]['cursor'].', Pos: '.$this->cursor_ext[$query_hash]['pos']
// .', Query: '.$query);
// if no cursor yet, execute
if (!$this->cursor_ext[$query_hash]['cursor']) {
$this->cursor_ext[$query_hash]['log'][] = 'No cursor';
// for DEBUG, print out each query executed
if ($this->db_debug) {
$this->__dbDebug('db', $this->cursor_ext[$query_hash]['query'], 'dbReturn', 'Q');
@@ -1773,13 +1805,14 @@ class IO
$this->__dbError(13, $this->cursor_ext[$query_hash]['cursor']);
return false;
} else {
$this->cursor_ext[$query_hash]['firstcall'] = 1;
$first_call = true;
}
} // only go if NO cursor exists
// if cursor exists ...
if ($this->cursor_ext[$query_hash]['cursor']) {
if ($this->cursor_ext[$query_hash]['firstcall'] == 1) {
if ($first_call === true) {
$this->cursor_ext[$query_hash]['log'][] = 'First call';
// count the rows returned (if select)
$this->cursor_ext[$query_hash]['num_rows'] =
$this->db_functions->__dbNumRows($this->cursor_ext[$query_hash]['cursor']);
@@ -1799,35 +1832,51 @@ class IO
);
}
$this->field_names = $this->cursor_ext[$query_hash]['field_names'];
// reset first call vars
$this->cursor_ext[$query_hash]['firstcall'] = 0;
// reset first call var
$first_call = false;
// reset the internal pos counter
$this->cursor_ext[$query_hash]['pos'] = 0;
// reset the global (for cache) read counter
$this->cursor_ext[$query_hash]['read_rows'] = 0;
// reset read finished flag
$this->cursor_ext[$query_hash]['finished'] = false;
$this->cursor_ext[$query_hash]['read_finished'] = false;
$this->cursor_ext[$query_hash]['db_read_finished'] = false;
// set cursor ccached flag based on cache flag
if ($cache < self::NO_CACHE) {
$this->cursor_ext[$query_hash]['cached'] = true;
}
}
// read data for further work ... but only if necessarry
// main database read if not all read and we have an active cursor
if (
$this->cursor_ext[$query_hash]['read_rows'] ==
$this->cursor_ext[$query_hash]['num_rows']
$this->cursor_ext[$query_hash]['read_rows'] !=
$this->cursor_ext[$query_hash]['num_rows'] &&
!is_int($this->cursor_ext[$query_hash]['cursor'])
) {
$return = false;
} else {
$return = $this->__dbConvertEncoding(
$this->db_functions->__dbFetchArray(
$this->cursor_ext[$query_hash]['cursor'],
$this->db_functions->__dbResultType($assoc_only)
)
);
$this->cursor_ext[$query_hash]['log'][] = 'DB Reading data: '
. (is_bool($return) ? 'EOF' : 'DATA');
// if returned is NOT an array, abort to false
if (!is_array($return)) {
$return = false;
}
}
// check if cached call or reset call ...
// read from cache, or do partial cache set and caching
if (!$return && $cache == self::USE_CACHE) {
// check if end of output ...
if ($this->cursor_ext[$query_hash]['pos'] >= $this->cursor_ext[$query_hash]['num_rows']) {
if (
$this->cursor_ext[$query_hash]['pos'] >=
$this->cursor_ext[$query_hash]['num_rows']
) {
$this->cursor_ext[$query_hash]['log'][] = 'USE CACHE, end';
// finish read
$this->cursor_ext[$query_hash]['finished'] = true;
// reset pos for next read
$this->cursor_ext[$query_hash]['pos'] = 0;
// if not reset given, set the cursor to true, so in a cached
// call on a different page we don't get problems from
@@ -1835,36 +1884,55 @@ class IO
$this->cursor_ext[$query_hash]['cursor'] = 1;
$return = false;
} else {
$this->cursor_ext[$query_hash]['log'][] = 'USE CACHE, read data';
$this->cursor_ext[$query_hash]['read_finished'] = false;
$this->cursor_ext[$query_hash]['finished'] = false;
// cached data read
$return = $this->__dbReturnCacheRead($query_hash, $assoc_only);
if (
$this->cursor_ext[$query_hash]['pos'] ==
$this->cursor_ext[$query_hash]['num_rows']
) {
$this->cursor_ext[$query_hash]['log'][] = 'USE CACHE, all cache rows read';
$this->cursor_ext[$query_hash]['read_finished'] = true;
}
}
} else {
// return row, if last && reset, then unset the hole hash array
if (
!$return &&
($cache == self::CLEAR_CACHE || $cache == self::NO_CACHE) &&
$this->cursor_ext[$query_hash]['pos']
) {
// unset data block only
$this->cursor_ext[$query_hash]['data'] = [];
$this->cursor_ext[$query_hash]['pos'] = 0;
} elseif (
!$return && $cache == self::READ_NEW &&
$this->cursor_ext[$query_hash]['pos']
) {
// at end of read reset pos & set cursor to 1
// (so it does not get lost in session transfer)
// return row, if last && reset, then unset the whole hash array
if (!$return && $this->cursor_ext[$query_hash]['pos']) {
$this->cursor_ext[$query_hash]['pos'] = 0;
$this->cursor_ext[$query_hash]['cursor'] = 1;
$return = false;
$this->cursor_ext[$query_hash]['finished'] = true;
// for clear cache, clear cache, else only write log info
if ($cache == self::CLEAR_CACHE) {
$this->cursor_ext[$query_hash]['log'][] = 'CLEAR CACHE, end';
// unset data block only
$this->cursor_ext[$query_hash]['data'] = [];
$this->cursor_ext[$query_hash]['cached'] = false;
} elseif ($cache == self::READ_NEW) {
$this->cursor_ext[$query_hash]['log'][] = 'READ NEW, end';
} elseif ($cache == self::NO_CACHE) {
$this->cursor_ext[$query_hash]['log'][] = 'NO CACHE, end';
}
}
// if something found, write data into hash array
if ($return) {
$this->cursor_ext[$query_hash]['log'][] = 'Return Data';
// internal position counter
$this->cursor_ext[$query_hash]['pos'] ++;
$this->cursor_ext[$query_hash]['read_rows'] ++;
// read is finished
if (
$this->cursor_ext[$query_hash]['read_rows'] ==
$this->cursor_ext[$query_hash]['num_rows']
) {
$this->cursor_ext[$query_hash]['log'][] = 'Return data all db rows read';
$this->cursor_ext[$query_hash]['db_read_finished'] = true;
$this->cursor_ext[$query_hash]['read_finished'] = true;
}
// if reset is < NO_CACHE level caching is done, else no
if ($cache < self::NO_CACHE) {
$this->cursor_ext[$query_hash]['log'][] = 'Cache Data';
// why was this here?
// $temp = [];
// foreach ($return as $field_name => $data) {

View File

@@ -59,15 +59,9 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/** @var object|resource|bool */ // replace object with PgSql\Connection
private $dbh;
/**
* class constructor, empty does nothing
*/
// public function __construct()
// {
// }
/**
* queries last error query and returns true or false if error was set
*
* @return bool true/false if last error is set
*/
public function __dbLastErrorQuery(): bool
@@ -81,6 +75,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_query, catches error and stores it in class var
*
* @param string $query Query string
* @return object|resource|bool query result (PgSql\Result)
*/
@@ -102,6 +97,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
* Proposed
* wrapperf or pg_query_params for queries in the style of
* SELECT foo FROM bar WHERE foobar = $1
*
* @param string $query Query string with placeholders $1, ..
* @param array<mixed> $params Matching parameters for each placerhold
* @return object|resource|bool Query result (PgSql\Result)
@@ -124,6 +120,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* sends an async query to the server
*
* @param string $query query string
* @return bool true/false if query was sent successful
*/
@@ -138,6 +135,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_get_result
*
* @return object|resource|bool resource handler or false for error (PgSql\Result)
*/
public function __dbGetResult()
@@ -158,6 +156,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_close
*
* @return void has no return
*/
public function __dbClose(): void
@@ -173,9 +172,11 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_prepare
*
* @param string $name statement name
* @param string $query query string
* @return object|resource|bool prepare statement handler or false for error (PgSql\Result)
* @return object|resource|bool prepare statement handler or
* false for error (PgSql\Result)
*/
public function __dbPrepare(string $name, string $query)
{
@@ -191,6 +192,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_execute for running a prepared statement
*
* @param string $name statement name
* @param array<mixed> $data data array
* @return object|resource|bool returns status or false for error (PgSql\Result)
@@ -209,6 +211,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_num_rows
*
* @param object|resource|bool $cursor cursor PgSql\Result (former resource)
* @return int number of rows, -1 on error
*/
@@ -222,6 +225,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_num_fields
*
* @param object|resource|bool $cursor cursor PgSql\Result (former resource)
* @return int number for fields in result, -1 on error
*/
@@ -235,6 +239,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_field_name
*
* @param object|resource|bool $cursor cursor PgSql\Result (former resource)
* @param int $i field position
* @return string|bool name or false on error
@@ -250,6 +255,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_fetch_array
* if through/true false, use __dbResultType(true)
*
* @param object|resource|bool $cursor cursor PgSql\Result (former resource)
* @param int $result_type result type as int number
* @return array<mixed>|bool array result data or false on end/error
@@ -265,6 +271,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* simple match up between assoc true/false
*
* @param bool $assoc_type true (default) for PGSQL_ASSOC, false for PGSQL_BOTH
* @return int valid result type for fetch array
*/
@@ -279,6 +286,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_fetch_all
*
* @param object|resource|bool $cursor cursor PgSql\Result (former resource)
* @return array<mixed>|bool data array or false for end/error
*/
@@ -292,6 +300,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_affected_rows
*
* @param object|resource|bool $cursor cursor PgSql\Result (former resource)
* @return int affected rows, 0 for none, -1 for error
*/
@@ -306,7 +315,9 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* reads the last inserted primary key for the query
* if there is no pk_name tries to auto built it from the table name
* this only works if db schema is after "no plural names. and pk name is table name + _id
* this only works if db schema is after no plural names
* and pk name is table name + _id
*
* detects schema prefix in table name
* @param string $query query string
* @param string|null $pk_name primary key name, if '' then auto detect
@@ -355,6 +366,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* queries database for the primary key name to this table in the selected schema
*
* @param string $table table name
* @param string $schema optional schema name, '' for default
* @return string|bool primary key name or false if not found
@@ -407,6 +419,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_connect, writes out failure to screen if error occurs (hidden var)
*
* @param string $db_host host name
* @param string $db_user user name
* @param string $db_pass password
@@ -456,6 +469,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* reads the last error for this cursor and returns
* html formatted string with error name
*
* @param bool|object|resource $cursor cursor PgSql\Result (former resource)
* or null
* @return string error string
@@ -481,6 +495,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_meta_data
*
* @param string $table table name
* @param bool $extended show extended info (default true)
* @return array<mixed>|bool array data for the table info or false on error
@@ -496,6 +511,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_escape_string
*
* @param string|int|float|bool $string any string/int/float/bool
* @return string excaped string
*/
@@ -511,6 +527,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
* wrapper for pg_escape_literal
* difference to escape string is that this one adds quotes ('') around
* the string too
*
* @param string|int|float|bool $string any string/int/float/bool
* @return string excaped string including quites
*/
@@ -526,6 +543,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_escape_identifier
* Only used for table names, column names
*
* @param string $string any string
* @return string escaped string
*/
@@ -540,6 +558,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_escape_byte
*
* @param string $bytea bytea data stream
* @return string escaped bytea string
*/
@@ -553,6 +572,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for pg_connection_busy
*
* @return bool True if connection is busy, False if not or no db connection at all
*/
public function __dbConnectionBusy(): bool
@@ -565,6 +585,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* Experimental wrapper with scoket timetout
*
* @param integer $timeout_seconds Wait how many seconds on timeout
* @return boolean True if connection is busy, or false on
* not busy or no db connection at all
@@ -593,6 +614,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
* if not in array return empty string
* On default 'version' will be stripped of any space attached info
* eg 13.5 (other info) will return only 13.5
*
* @param string $parameter Parameter string to extract from array
* @param boolean $strip If parameter is server strip out on default
* Set to false to get original string AS is
@@ -617,6 +639,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* Returns all parameters that are possible from the db_version
*
* @return array<mixed> Parameter key names from pg_version
*/
public function __dbVersionInfoParameterList(): array
@@ -631,6 +654,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
* wrapper for pg_version
* Note: this only returns server version
* not connection version OR client version
*
* @return string version string
*/
public function __dbVersion(): string
@@ -649,6 +673,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
* Old version is 9.5.6 where 9.5 is the major version
* Newer Postgresql (10 on) have only one major version so eg 13.5
* is returned as 130005
*
* @return integer Server version
*/
public function __dbVersionNumeric(): int
@@ -662,6 +687,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
* This is a fallback for old PostgreSQL versions
* postgresql array to php array
* https://stackoverflow.com/a/27964420
*
* @param string $array_text Array text from PostgreSQL
* @param int $start Start string position
* @param int|null $end End string position from recursive call
@@ -721,6 +747,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
* Returns any server setting
* if no connection or empty parameter or other error returns false
* else returns a string
*
* @param string $parameter Parameter to query
* @return string|bool Settings value as string
*/
@@ -738,6 +765,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* wrapper for any SHOW data blocks
* eg search_path or client_encoding
*
* @param string $show_string Part to show, if invalid will return empty string
* @return string Found part as is
*/
@@ -758,6 +786,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* Sets a new database schema/search_path
* Checks if schema exits and if not aborts with error code 2
*
* @param string $db_schema Schema to set
* @return int Returns 0 if no error
* 1 for check query failed
@@ -788,6 +817,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* Returns current set schema/search_path
*
* @return string Search Path as currently set in DB
*/
public function __dbGetSchema(): string
@@ -798,6 +828,7 @@ class PgSQL implements \CoreLibs\DB\SQL\SqlInterface\SqlFunctions
/**
* set the client encoding
* Returns 0 on set ok, or 3 if the client encoding could not be set
*
* @param string $db_encoding
* @return int Returns 0 for no error
* [not used] 1 for check query failed

View File

@@ -16,7 +16,7 @@ class FileWriter
/** @var string */
private static $debug_folder;
/**
/**
* Set a debug log folder, if not set BASE+LOG folders are set
* if they are defined
* This folder name must exist and must be writeable
@@ -60,6 +60,7 @@ class FileWriter
/**
* writes a string to a file immediatly, for fast debug output
*
* @param string $string string to write to the file
* @param boolean $enter default true, if set adds a linebreak \n at the end
* @return bool True for log written, false for not wirrten

View File

@@ -310,6 +310,7 @@ class Logging
* 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
@@ -332,6 +333,7 @@ class Logging
/**
* 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
@@ -412,6 +414,7 @@ class Logging
/**
* 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
*/
@@ -425,6 +428,7 @@ class Logging
* 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()
@@ -438,6 +442,7 @@ class Logging
* 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
*/
@@ -460,6 +465,7 @@ class Logging
/**
* old name for setLogLevel
*
* @param string $type debug, echo, print
* @param string $flag on/off
* array $array of levels to turn on/off debug
@@ -475,6 +481,7 @@ class Logging
/**
* 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
@@ -491,6 +498,7 @@ class Logging
/**
* 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
*/
@@ -506,6 +514,7 @@ class Logging
/**
* 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
@@ -541,6 +550,7 @@ class Logging
/**
* 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
@@ -572,6 +582,7 @@ class Logging
* - 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
@@ -587,6 +598,7 @@ class Logging
/**
* 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
*/
@@ -601,6 +613,7 @@ class Logging
/**
* 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
@@ -615,6 +628,7 @@ class Logging
/**
* Return current set log file name
*
* @return string Filename set set after the last time debug was called
*/
public function getLogFileName(): string
@@ -628,6 +642,7 @@ class Logging
* 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
*/
@@ -636,14 +651,32 @@ class Logging
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
* @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
@@ -729,6 +762,7 @@ class Logging
/**
* 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
*/
@@ -780,6 +814,7 @@ class Logging
* 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
*/
@@ -795,6 +830,7 @@ class Logging
/**
* for ECHO ON only
* Get current error message array
*
* @return array<mixed> error messages collected
*/
public function getErrorMsg(): array
@@ -806,6 +842,7 @@ class Logging
* 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
*/

View File

@@ -0,0 +1,129 @@
<?php
/*
* dump memory usage
*/
declare(strict_types=1);
namespace CoreLibs\Debug;
use CoreLibs\Convert\Byte;
class MemoryUsage
{
/** @var int */
private static $start_memory = 0;
/** @var int */
private static $set_memory = 0;
/** @var int */
private static $previous_memory = 0;
/** @var bool */
private static $debug_memory = false;
/**
* set memory flag, or return set memory flag
*
* @param bool|null $set_debug
* @return bool
*/
public static function debugMemoryFlag(?bool $set_debug = null): bool
{
if ($set_debug === null) {
return self::$debug_memory;
}
self::$debug_memory = $set_debug;
return self::$debug_memory;
}
/**
* Reset all memory variables to 0
*
* @return void
*/
public static function resetMemory(): void
{
self::$start_memory = 0;
self::$set_memory = 0;
self::$previous_memory = 0;
}
/**
* set the start memory velue, or reset to a new start value
*
* @return void
*/
public static function setStartMemory(): void
{
self::$start_memory = memory_get_usage();
}
/**
* set the and independent memory set for a sub tracking outside main
*
* @return void
*/
public static function setMemory(): void
{
self::$set_memory = memory_get_usage();
}
/**
* calculate and set memory usage values
* this will return an array with all the data that can be used in
* printMemoryUsage for human readable output
*
* @param string $prefix A prefix tag
* @return array<string,int|string> return array
*/
public static function memoryUsage(string $prefix): array
{
// skip if DEBUG is off
if (self::$debug_memory === false) {
return [];
}
if (empty(self::$start_memory)) {
self::$start_memory = memory_get_usage();
}
$memory_usage = memory_get_usage();
$data = [
'prefix' => $prefix,
'peak' => memory_get_peak_usage(),
'usage' => $memory_usage,
'start' => $memory_usage - self::$start_memory,
'last' => $memory_usage - self::$previous_memory,
'set' => $memory_usage - self::$set_memory
];
self::$previous_memory = $memory_usage;
return $data;
}
/**
* returns a human readable output from the memoryUsage function
* can be used for logging purpose
*
* @param array<string,int|string> $data Data array from memoryUsage
* @param bool $raw Flag to shaw unconverted memory numbers
* @return string Return debug string with memory usage
*/
public static function printMemoryUsage(array $data, bool $raw = false): string
{
return
'[' . $data['prefix'] . '] Peak/Curr/Change: '
. Byte::humanReadableByteFormat($data['peak'])
. '/'
. Byte::humanReadableByteFormat($data['usage'])
// . ($raw === true ? ' [' . $data['usage'] . ']' : '')
. '/Since Start: '
. Byte::humanReadableByteFormat($data['start'])
. ($raw === true ? ' [' . $data['start'] . ']' : '')
. ' | Since Last: '
. Byte::humanReadableByteFormat($data['last'])
. ($raw === true ? ' [' . $data['last'] . ']' : '')
. ' | Since Set: '
. Byte::humanReadableByteFormat($data['set'])
. ($raw === true ? ' [' . $data['set'] . ']' : '');
}
}
// __END__

View File

@@ -12,43 +12,30 @@ class RunningTime
{
// hr
/** @var float */
private static $hr_starttime;
private static $hr_start_time;
/** @var float */
private static $hr_runtime;
private static $hr_end_time;
/** @var float */
private static $hr_endtime;
private static $hr_last_time;
// normal
/** @var float */
private static $starttime;
private static $start_time;
/** @var float */
private static $endtime;
private static $end_time;
/** @var string */
private static $runningtime_string;
private static $running_time_string;
/**
* for messure run time between two calls for this method
* uses the hrtime() for running time
* first call sets start time and returns 0,
* second call sets end time and returns the run time
* the out_time parameter can be:
* n/ns (nano), y/ys (micro), m/ms (milli), s (seconds)
* default is milliseconds
* @param string $out_time set return time adjustment calculation
* @return float running time without out_time suffix
* sub calculation for running time based on out time.
* If no running time set, return 0
*
* @param string $out_time
* @return float
*/
public static function hrRunningTime(string $out_time = 'ms'): float
{
// if start time not set, set start time
if (!self::$hr_starttime) {
self::$hr_starttime = hrtime(true);
self::$hr_runtime = 0;
} else {
self::$hr_endtime = hrtime(true);
self::$hr_runtime = self::$hr_endtime - self::$hr_starttime;
// reset start and end time past run
self::$hr_starttime = 0;
self::$hr_endtime = 0;
}
private static function hrRunningTimeCalc(
float $run_time,
string $out_time = 'ms'
): float {
// init divisor, just in case
$divisor = 1;
// check through valid out time, if nothing matches default to ms
@@ -74,8 +61,67 @@ class RunningTime
break;
}
// return the run time in converted format
self::$hr_runtime /= $divisor;
return self::$hr_runtime;
return $run_time /= $divisor;
}
/**
* for messure run time between two calls for this method
* uses the hrtime() for running time
* first call sets start time and returns 0,
* every other call sets end time and returns the run time since start
* the out_time parameter can be:
* n/ns (nano), y/ys (micro), m/ms (milli), s (seconds)
* default is milliseconds
*
* @param string $out_time set return time adjustment calculation
* @return float running time without out_time suffix
*/
public static function hrRunningTime(string $out_time = 'ms'): float
{
// if start time not set, set start time
if (!self::$hr_start_time) {
self::$hr_start_time = hrtime(true);
self::$hr_last_time = self::$hr_start_time;
$run_time = 0;
} else {
self::$hr_end_time = hrtime(true);
$run_time = self::$hr_end_time - self::$hr_last_time;
self::$hr_last_time = self::$hr_end_time;
}
return self::hrRunningTimeCalc($run_time, $out_time);
}
/**
* print overall end time , can only be called after hrRunningtime
* see $out_time parameter description in hrRunningtime.
* Does not record a new timestamp, only prints different between start and
* last recoreded timestamp
*
* @param string $out_time set return time adjustment calculation
* @return float overall running time without out_time suffix
*/
public static function hrRunningTimeFromStart(string $out_time = 'ms'): float
{
if (!self::$hr_start_time) {
return (float)0;
}
$time = self::hrRunningTimeCalc(
self::$hr_end_time - self::$hr_start_time,
$out_time
);
return $time;
}
/**
* reset hr running time internal variables (start, end, last)
*
* @return void
*/
public static function hrRunningTimeReset(): void
{
self::$hr_start_time = 0;
self::$hr_end_time = 0;
self::$hr_last_time = 0;
}
/**
@@ -91,24 +137,24 @@ class RunningTime
list($micro, $timestamp) = explode(' ', microtime());
$running_time = 0;
// set start & end time
if (!self::$starttime) {
if (!self::$start_time) {
// always reset running time string on first call
self::$runningtime_string = '';
self::$starttime = ((float)$micro + (float)$timestamp);
self::$runningtime_string .= $simple ? 'Start: ' : "<b>Started at</b>: ";
self::$running_time_string = '';
self::$start_time = ((float)$micro + (float)$timestamp);
self::$running_time_string .= $simple ? 'Start: ' : "<b>Started at</b>: ";
} else {
self::$endtime = ((float)$micro + (float)$timestamp);
self::$runningtime_string .= $simple ? 'End: ' : "<b>Stopped at</b>: ";
self::$end_time = ((float)$micro + (float)$timestamp);
self::$running_time_string .= $simple ? 'End: ' : "<b>Stopped at</b>: ";
}
self::$runningtime_string .= date('Y-m-d H:i:s', (int)$timestamp);
self::$runningtime_string .= ' ' . $micro . ($simple ? ', ' : '<br>');
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::$starttime && self::$endtime) {
$running_time = self::$endtime - self::$starttime;
self::$runningtime_string .= ($simple ? 'Run: ' : "<b>Script running time</b>: ") . $running_time . " s";
if (self::$start_time && 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
self::$starttime = 0;
self::$endtime = 0;
self::$start_time = 0;
self::$end_time = 0;
}
return $running_time;
}
@@ -120,7 +166,7 @@ class RunningTime
*/
public static function runningTimeString(): string
{
return self::$runningtime_string;
return self::$running_time_string;
}
}

View File

@@ -12,7 +12,9 @@ class Support
{
/**
* wrapper around microtime function to print out y-m-d h:i:s.ms
* @param int $set_microtime -1 to set micro time, 0 for none, positive for rounding
*
* @param int $set_microtime -1 to set micro time, 0 for none,
* positive for rounding
* @return string formated datetime string with microtime
*/
public static function printTime(int $set_microtime = -1): string
@@ -31,6 +33,7 @@ class Support
/**
* prints a html formatted (pre) array
*
* @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
@@ -44,12 +47,47 @@ class Support
}
}
/**
* 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
*/
public static function printArray(array $array, bool $no_html = false): string
{
return self::printAr($array, $no_html);
}
/**
* convert bool value to string
* if $name is set prefix with nae
* default true: true, false: false
*
* @param bool $bool Variable to convert
* @param string $name [default: ''] Prefix name
* @param string $true [default: true] True string
* @param string $false [default: false] False string
* @return string String with converted bool text for debug
*/
public static function printBool(
bool $bool,
string $name = '',
string $true = 'true',
string $false = 'false'
): string {
$string = (!empty($name) ? '<b>' . $name . '</b>: ' : '')
. ($bool ? $true : $false);
return $string;
}
/**
* print out any data as string
* will convert boolean to TRUE/FALSE
* if object return get_class
* for array use printAr function, can be controlled with no_html for
* Debug\Logging compatible output
*
* @param mixed $mixed
* @param bool $no_html set to true to use ##HTMLPRE##
* @return string
@@ -57,7 +95,7 @@ class Support
public static function printToString($mixed, bool $no_html = false): string
{
if (is_bool($mixed)) {
return $mixed ? 'TRUE' : 'FALSE';
return self::printBool($mixed, '', 'TRUE', 'FALSE');
} elseif (is_resource($mixed)) {
return (string)$mixed;
} elseif (is_object($mixed)) {
@@ -74,9 +112,11 @@ class Support
/**
* 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
* @return ?string null or the function that called the function where this method is called
* @return ?string null or the function that called the function
* where this method is called
*/
public static function getCallerMethod(int $level = 1): ?string
{
@@ -95,6 +135,7 @@ class Support
* called is last in order
* Will start with start_level to skip unwanted from stack
* Defaults to skip level 0 wich is this methid
*
* @param integer $start_level From what level on, as defaul starts with 1
* to exclude self
* @return array<mixed> All method names in list where max is last called
@@ -119,6 +160,7 @@ class Support
* was called
* gets top level class
* loops over the debug backtrace until if finds the first class (from the end)
*
* @return string Class name with namespace
*/
public static function getCallerClass(): string

View File

@@ -0,0 +1,106 @@
<?php
declare(strict_types=1);
namespace CoreLibs\Get;
class DotEnv
{
/** @var string constant comment char, set to # */
private const COMMENT_CHAR = '#';
/**
* parses .env file
*
* Rules for .env file
* variable is any alphanumeric string followed by = on the same line
* content starts with the first non space part
* strings can be contained in "
* strings MUST be contained in " if they are multiline
* if string starts with " it will match until another " is found
* anything AFTER " is ignored
* if there are two variables with the same name only the first is used
* variables are case sensitive
*
* @param string $path Folder to file, default is __DIR__
* @param string $env_file What file to load, default is .env
* @return int -1 other error
* 0 for success full load
* 1 for file loadable, no data or data already loaded
* 2 for file not readable or open failed
* 3 for file not found
*/
public static function readEnvFile(
string $path = __DIR__,
string $env_file = '.env'
): int {
// default -1;
$status = -1;
$env_file_target = $path . DIRECTORY_SEPARATOR . $env_file;
// this is not a file -> abort
if (!is_file($env_file_target)) {
$status = 3;
return $status;
}
// cannot open file -> abort
if (!is_readable($env_file_target)) {
$status = 2;
return $status;
}
// open file
if (($fp = fopen($env_file_target, 'r')) === false) {
$status = 2;
return $status;
}
// set to readable but not yet any data loaded
$status = 1;
$block = false;
$var = '';
while ($line = fgets($fp)) {
// main match for variable = value part
if (preg_match("/^\s*([\w_.]+)\s*=\s*((\"?).*)/", $line, $matches)) {
$var = $matches[1];
$value = $matches[2];
$quotes = $matches[3];
// write only if env is not set yet, and write only the first time
if (empty($_ENV[$var])) {
if (!empty($quotes)) {
// match greedy for first to last so we move any " if there are
if (preg_match('/^"(.*[^\\\])"/U', $value, $matches)) {
$value = $matches[1];
} else {
// this is a multi line
$block = true;
// first " in string remove
// add removed new line back because this is a multi line
$value = ltrim($value, '"') . PHP_EOL;
}
} else {
// strip any quotes at end for unquoted single line
// an right hand spaces are removed too
$value = false !== ($pos = strpos($value, self::COMMENT_CHAR)) ?
rtrim(substr($value, 0, $pos)) : $value;
}
// if block is set, we strip line of slashes
$_ENV[$var] = $block === true ? stripslashes($value) : $value;
// set successful load
$status = 0;
}
} elseif ($block === true) {
// read line until there is a unescaped "
// this also strips everything after the last "
if (preg_match("/(.*[^\\\])\"/", $line, $matches)) {
$block = false;
// strip ending " and EVERYTHING that follows after that
$line = $matches[1];
}
// strip line of slashes
$_ENV[$var] .= stripslashes($line);
}
}
fclose($fp);
return $status;
}
}
// __END__

View File

@@ -4,6 +4,9 @@ declare(strict_types=1);
namespace CoreLibs\Get;
/**
* @deprecated use \CoreLibs\Get\DotEnv instead
*/
class ReadEnvFile
{
/**
@@ -24,71 +27,16 @@ class ReadEnvFile
* @return int -1 other error
* 0 for success full load
* 1 for file loadable, but no data inside
* 2 for file not readable
* 2 for file not readable or open failed
* 3 for file not found
* @deprecated Use \CoreLibs\Get\DotEnv::readEnvFile() instead
*/
public static function readEnvFile(
string $path = __DIR__,
string $env_file = '.env'
): int {
// default -1;
$status = -1;
$env_file_target = $path . DIRECTORY_SEPARATOR . $env_file;
// this is not a file -> abort
if (!is_file($env_file_target)) {
$status = 3;
return $status;
}
// cannot open file -> abort
if (($fp = fopen($env_file_target, 'r')) === false) {
$status = 2;
return $status;
}
// set to readable but not yet any data loaded
$status = 1;
$block = false;
$var = '';
while ($line = fgets($fp)) {
// main match for variable = value part
if (preg_match("/^\s*([\w_.]+)\s*=\s*((\"?).*)/", $line, $matches)) {
$var = $matches[1];
$value = $matches[2];
$quotes = $matches[3];
// write only if env is not set yet, and write only the first time
if (empty($_ENV[$var])) {
if (!empty($quotes)) {
// match greedy for first to last so we move any " if there are
if (preg_match('/^"(.*[^\\\])"/U', $value, $matches)) {
$value = $matches[1];
} else {
// this is a multi line
$block = true;
// first " in string remove
// add removed new line back because this is a multi line
$value = ltrim($value, '"') . PHP_EOL;
}
}
// if block is set, we strip line of slashes
$_ENV[$var] = $block === true ? stripslashes($value) : $value;
// set successful load
$status = 0;
}
} elseif ($block === true) {
// read line until there is a unescaped "
// this also strips everything after the last "
if (preg_match("/(.*[^\\\])\"/", $line, $matches)) {
$block = false;
// strip ending " and EVERYTHING that follows after that
$line = $matches[1];
}
// strip line of slashes
$_ENV[$var] .= stripslashes($line);
}
}
fclose($fp);
return $status;
return \CoreLibs\Get\DotEnv::readEnvFile($path, $env_file);
}
}
// __END__

View File

@@ -17,6 +17,7 @@ class System
/**
* helper function for PHP file upload error messgaes to messge string
*
* @param int $error_code integer _FILE upload error code
* @return string message string, translated
*/
@@ -53,6 +54,7 @@ class System
/**
* get the host name without the port as given by the SELF var
*
* @return array<mixed> host name/port name
*/
public static function getHostName(): array
@@ -64,6 +66,7 @@ class System
/**
* get the page name of the curronte page
*
* @param int $strip_ext WITH_EXTENSION: keep filename as is (default)
* NO_EXTENSION: strip page file name extension
* FULL_PATH: keep filename as is, but add dirname too

View File

@@ -37,6 +37,7 @@ class FileReader
/**
* file read constructor
*
* @param string $filename file name to load
*/
public function __construct(string $filename)
@@ -55,6 +56,7 @@ class FileReader
/**
* read byte data length
*
* @param int $bytes how many bytes to read
* @return string read data as string
*/
@@ -83,6 +85,7 @@ class FileReader
/**
* seek to a position in the file
*
* @param int $pos position where to go to
* @return int file position after seek done
*/
@@ -98,6 +101,7 @@ class FileReader
/**
* get current position in file
*
* @return int current position in bytes
*/
public function currentpos(): int
@@ -107,6 +111,7 @@ class FileReader
/**
* file length/size
*
* @return int file size in bytes
*/
public function length(): int
@@ -116,6 +121,7 @@ class FileReader
/**
* close open file handler
*
* @return void has no return
*/
public function close(): void

View File

@@ -38,6 +38,7 @@ class StreamReader
/**
* should return a string [FIXME: perhaps return array of bytes?]
*
* @param int $bytes bytes to read
* @return bool dummy false
*/
@@ -48,6 +49,7 @@ class StreamReader
/**
* should return new position
*
* @param int $position seek to position
* @return bool dummy false
*/
@@ -58,6 +60,7 @@ class StreamReader
/**
* returns current position
*
* @return bool dummy false
*/
public function currentpos(): bool
@@ -67,6 +70,7 @@ class StreamReader
/**
* returns length of entire stream (limit for seekto()s)
*
* @return bool dummy false
*/
public function length(): bool

View File

@@ -33,6 +33,7 @@ class StringReader
/**
* constructor for string reader
*
* @param string $str basic string
*/
public function __construct(string $str = '')
@@ -43,6 +44,7 @@ class StringReader
/**
* read bytes in string
*
* @param int $bytes bytes to read in string
* @return string data read in length of bytes as string
*/
@@ -59,6 +61,7 @@ class StringReader
/**
* go to position in string
*
* @param int $pos position in string
* @return int new position in string after seek
*/
@@ -73,6 +76,7 @@ class StringReader
/**
* get current position in string
*
* @return int position in string
*/
public function currentpos(): int
@@ -82,6 +86,7 @@ class StringReader
/**
* get length of string
*
* @return int return length of assigned string
*/
public function length(): int

Some files were not shown because too many files have changed in this diff Show More