Compare commits

...

15 Commits

Author SHA1 Message Date
Clemens Schwaighofer
0c1f060759 Merge branch 'development' 2023-04-11 11:03:24 +09:00
Clemens Schwaighofer
aad46ec80a DB\IO: add missing debug query, clean up not needed code
in dbReturn with params on not matching param the system exited on fail
without printing the query making it hard to find where the error is.
Added debug output in case the params count is not matching.
Same move in the dbExecute call

removed param count check from dbReturnRow/dbReturnArray as this check
is done in the dbExecParams call anyway
2023-04-11 11:03:04 +09:00
Clemens Schwaighofer
f5e9f0610d Publish: v8.2.1 2023-04-10 17:24:47 +09:00
Clemens Schwaighofer
14a5250cd7 DB\IO: Bug fix for missing query params replacement in debug messages 2023-04-10 17:23:27 +09:00
Clemens Schwaighofer
6e6edef57d Release: v8.2.0 2023-04-10 14:38:50 +09:00
Clemens Schwaighofer
d3810db965 Add ACL\Login additional acl fields to export acl array 2023-04-10 14:37:44 +09:00
Clemens Schwaighofer
187a012284 Published v8.1.4 2023-04-10 09:05:35 +09:00
Clemens Schwaighofer
b3d2662fd2 DB\IO params detection fix 2023-04-07 14:39:00 +09:00
Clemens Schwaighofer
1189aecae9 New release v8.1.3 2023-04-03 15:08:43 +09:00
Clemens Schwaighofer
024d6d2d7a Bug fix in DB\IO returning call check 2023-04-03 15:07:29 +09:00
Clemens Schwaighofer
f2d5377347 Release v8.1.2 2023-03-29 10:07:12 +09:00
Clemens Schwaighofer
af11bd8199 DB\IO dbReturn and dbReturnParams set NO_CACHE as default 2023-03-29 10:05:09 +09:00
Clemens Schwaighofer
0e6a43a2c2 Release v8.1.1 2023-03-28 16:49:55 +09:00
Clemens Schwaighofer
94eeaaaa51 DB\IO Debug output update for parameter queries 2023-03-28 16:49:06 +09:00
Clemens Schwaighofer
4a246bec5f Release v8.1.0 2023-03-28 16:47:38 +09:00
6 changed files with 150 additions and 59 deletions

View File

@@ -1 +1 @@
8.0.7
8.2.1

View File

@@ -31,6 +31,7 @@ source .env.deploy;
cd -;
set +o allexport;
echo "[START]";
# gitea
if [ ! -z "${GITEA_USER}" ] && [ ! -z "${GITEA_TOKEN}" ]; then
curl -LJO \
@@ -56,5 +57,7 @@ if [ ! -z "${GITLAB_DEPLOY_TOKEN}" ]; then
else
echo "Missing GITLAB_DEPLOY_TOKEN environment variable";
fi;
echo "";
echo "[DONE]";
# __END__

View File

@@ -69,6 +69,7 @@ declare(strict_types=1);
namespace CoreLibs\ACL;
use CoreLibs\Check\Password;
use CoreLibs\Convert\Json;
class Login
{
@@ -753,7 +754,10 @@ class Login
// we have to get the themes in here too
$q = "SELECT eu.edit_user_id, eu.username, eu.password, "
. "eu.edit_group_id, "
. "eg.name AS edit_group_name, admin, "
. "eg.name AS edit_group_name, eu.admin, "
// additinal acl lists
. "eu.additional_acl AS user_additional_acl, "
. "eg.additional_acl AS group_additional_acl, "
// login error + locked
. "eu.login_error_count, eu.login_error_date_last, "
. "eu.login_error_date_first, eu.strict, eu.locked, "
@@ -901,8 +905,10 @@ class Login
$_SESSION['GROUP_NAME'] = $res['edit_group_name'];
$_SESSION['USER_ACL_LEVEL'] = $res['user_level'];
$_SESSION['USER_ACL_TYPE'] = $res['user_type'];
$_SESSION['USER_ADDITIONAL_ACL'] = Json::jsonConvertToArray($res['user_additional_acl']);
$_SESSION['GROUP_ACL_LEVEL'] = $res['group_level'];
$_SESSION['GROUP_ACL_TYPE'] = $res['group_type'];
$_SESSION['GROUP_ADDITIONAL_ACL'] = Json::jsonConvertToArray($res['group_additional_acl']);
// deprecated TEMPLATE setting
$_SESSION['TEMPLATE'] = $res['template'] ? $res['template'] : '';
$_SESSION['HEADER_COLOR'] = !empty($res['second_header_color']) ?
@@ -1021,7 +1027,8 @@ class Login
$_SESSION['PAGES'] = $pages;
$_SESSION['PAGES_ACL_LEVEL'] = $pages_acl;
// load the edit_access user rights
$q = "SELECT ea.edit_access_id, level, type, ea.name, ea.color, ea.uid, edit_default "
$q = "SELECT ea.edit_access_id, level, type, ea.name, "
. "ea.color, ea.uid, edit_default, ea.additional_acl "
. "FROM edit_access_user eau, edit_access_right ear, edit_access ea "
. "WHERE eau.edit_access_id = ea.edit_access_id "
. "AND eau.edit_access_right_id = ear.edit_access_right_id "
@@ -1048,6 +1055,7 @@ class Login
'uid' => $res['uid'],
'color' => $res['color'],
'default' => $res['edit_default'],
'additional_acl' => Json::jsonConvertToArray($res['additional_acl']),
'data' => $ea_data
];
// set the default unit
@@ -1122,6 +1130,11 @@ class Login
// username (login), group name
$this->acl['user_name'] = $_SESSION['USER_NAME'];
$this->acl['group_name'] = $_SESSION['GROUP_NAME'];
// set additional acl
$this->acl['additional_acl'] = [
'user' => $_SESSION['USER_ADDITIONAL_ACL'],
'group' => $_SESSION['GROUP_ADDITIONAL_ACL'],
];
// we start with the default acl
$this->acl['base'] = $this->default_acl_level;
@@ -1184,7 +1197,8 @@ class Login
'uid' => $unit['uid'],
'level' => $this->default_acl_list[$this->acl['unit'][$ea_id]]['name'] ?? -1,
'default' => $unit['default'],
'data' => $unit['data']
'data' => $unit['data'],
'additional_acl' => $unit['additional_acl']
];
// set default
if (!empty($unit['default'])) {

View File

@@ -279,8 +279,20 @@ class IO
public const NO_CACHE = 3;
/** @var string default hash type */
public const ERROR_HASH_TYPE = 'adler32';
/**
* @var string regex for params: only stand alone $number allowed
* never allowed to start with '
* must be after space/tab, =, (
*/
public const REGEX_PARAMS = '/[^\'][\s(=](\$[0-9]{1,})/';
/** @var string regex to get returning with matches at position 1 */
public const REGEX_RETURNING = '/\s+returning\s+(.+?);?$/i';
public const REGEX_RETURNING = '/\s+returning\s+(.+\s*(?:.+\s*)+);?$/i';
// REGEX_SELECT
// REGEX_UPDATE
// REGEX INSERT
// REGEX_INSERT_UPDATE_DELETE
// REGEX_FROM_TABLE
// REGEX_INSERT_UPDATE_DELETE_TABLE
// recommend to set private/protected and only allow setting via method
// can bet set from outside
@@ -892,7 +904,9 @@ class IO
for ($i = 0, $iMax = count($keys); $i < $iMax; $i++) {
$keys[$i] = '$' . ($keys[$i] + 1);
// prefix data set with parameter pos
$data[$i] = $keys[$i] . ':' . $data[$i];
$data[$i] = $keys[$i] . ':' . ($data[$i] === null ?
'"NULL"' : (string)$data[$i]
);
}
// simply replace the $1, $2, ... with the actual data and return it
return str_replace(
@@ -1015,7 +1029,7 @@ class IO
{
// search for $1, $2, in the query and push it into the control array
// skip counts for same eg $1, $1, $2 = 2 and not 3
preg_match_all('/(\$[0-9]{1,})/', $query, $match);
preg_match_all(self::REGEX_PARAMS, $query, $match);
$placeholder_count = count(array_unique($match[1]));
if ($params_count != $placeholder_count) {
$this->__dbError(
@@ -1132,7 +1146,7 @@ class IO
$this->params
),
'__dbPrepareExec',
($this->params === [] ? 'Q' : 'Qp'),
($this->params === [] ? 'Q' : 'Qp')
);
}
// import protection, hash needed
@@ -1152,7 +1166,15 @@ class IO
$this->query_called[$query_hash] > $this->MAX_QUERY_CALL
) {
$this->__dbError(30, false, $this->query);
$this->__dbDebug('db', $this->query, 'dbExec', 'Q[nc]');
$this->__dbDebug(
'db',
$this->__dbDebugPrepare(
$this->query,
$this->params
),
'dbExec',
($this->params === [] ? 'Q[nc]' : 'Qp[nc]')
);
return false;
}
$this->query_called[$query_hash] ++;
@@ -1819,7 +1841,7 @@ class IO
* Wrapper for dbReturnParams
*
* @param string $query Query string
* @param int $cache reset status: default: USE_CACHE
* @param int $cache reset status: default: NO_CACHE
* USE_CACHE/0: normal read from cache on second run
* READ_NEW/1: write to cache, clean before new run
* CLEAR_CACHE/2: write cache, clean after finished
@@ -1831,7 +1853,7 @@ class IO
*/
public function dbReturn(
string $query,
int $cache = self::USE_CACHE,
int $cache = self::NO_CACHE,
bool $assoc_only = false
): array|false {
return $this->dbReturnParams($query, [], $cache, $assoc_only);
@@ -1854,7 +1876,7 @@ class IO
*
* @param string $query Query string
* @param array<mixed> $params Query parameters
* @param int $cache reset status: default: USE_CACHE
* @param int $cache reset status: default: NO_CACHE
* USE_CACHE/0: normal read from cache on second run
* READ_NEW/1: write to cache, clean before new run
* CLEAR_CACHE/2: write cache, clean after finished
@@ -1866,7 +1888,7 @@ class IO
public function dbReturnParams(
string $query,
array $params = [],
int $cache = self::USE_CACHE,
int $cache = self::NO_CACHE,
bool $assoc_only = false
): array|false {
$this->__dbErrorReset();
@@ -1931,6 +1953,18 @@ class IO
// check if params count matches
// checks if the params count given matches the expected count
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
// in case we got an error print out query
if ($this->db_debug) {
$this->__dbDebug(
'db',
$this->__dbDebugPrepare(
$this->query,
$this->params
),
'dbReturn',
($this->params === [] ? 'Q[e]' : 'Qp[e]')
);
}
return false;
}
// set first call to false
@@ -1954,7 +1988,15 @@ class IO
$this->cursor_ext[$query_hash]['log'][] = 'No cursor';
// for DEBUG, print out each query executed
if ($this->db_debug) {
$this->__dbDebug('db', $this->cursor_ext[$query_hash]['query'], 'dbReturn', 'Q');
$this->__dbDebug(
'db',
$this->__dbDebugPrepare(
$this->cursor_ext[$query_hash]['query'],
$this->cursor_ext[$query_hash]['params']
),
'dbReturn',
($this->cursor_ext[$query_hash]['params'] === [] ? 'Q' : 'Qp'),
);
}
// if no DB Handler try to reconnect
if (!$this->dbh) {
@@ -1983,7 +2025,15 @@ class IO
// if still no cursor ...
if (!$this->cursor_ext[$query_hash]['cursor']) {
if ($this->db_debug) {
$this->__dbDebug('db', $this->cursor_ext[$query_hash]['query'], 'dbReturn', 'Q');
$this->__dbDebug(
'db',
$this->__dbDebugPrepare(
$this->cursor_ext[$query_hash]['query'],
$this->cursor_ext[$query_hash]['params']
),
'dbReturn',
($this->cursor_ext[$query_hash]['params'] === [] ? 'Q[e]' : 'Qp[e]'),
);
}
// internal error handling
$this->__dbError(13, $this->cursor_ext[$query_hash]['cursor']);
@@ -2286,10 +2336,6 @@ class IO
$this->__dbError(17, false, $query);
return false;
}
// checks if the params count given matches the expected count
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
return false;
}
$cursor = $this->dbExecParams($query, $params);
if ($cursor === false) {
return false;
@@ -2334,10 +2380,6 @@ class IO
$this->__dbError(17, false, $query);
return false;
}
// checks if the params count given matches the expected count
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
return false;
}
$cursor = $this->dbExecParams($query, $params);
if ($cursor === false) {
return false;
@@ -2586,7 +2628,7 @@ class IO
$match = [];
// search for $1, $2, in the query and push it into the control array
// skip counts for same eg $1, $1, $2 = 2 and not 3
preg_match_all('/(\$[0-9]{1,})/', $query, $match);
preg_match_all(self::REGEX_PARAMS, $query, $match);
$this->prepare_cursor[$stm_name]['count'] = count(array_unique($match[1]));
$this->prepare_cursor[$stm_name]['query'] = $query;
$result = $this->db_functions->__dbPrepare($stm_name, $query);
@@ -2647,6 +2689,17 @@ class IO
);
return false;
}
if ($this->db_debug) {
$this->__dbDebug(
'db',
$this->__dbDebugPrepare(
$this->prepare_cursor[$stm_name]['query'],
$data
),
'dbExecPrep',
'Qpe'
);
}
// if the count does not match
if ($this->prepare_cursor[$stm_name]['count'] != count($data)) {
$this->__dbError(
@@ -2659,17 +2712,6 @@ class IO
);
return false;
}
if ($this->db_debug) {
$this->__dbDebug(
'db',
$this->__dbDebugPrepare(
$this->prepare_cursor[$stm_name]['query'],
$data
),
'dbExecPrep',
'Qp'
);
}
$result = $this->db_functions->__dbExecute($stm_name, $data);
if ($result === false) {
$this->log->debug('ExecuteData', 'ERROR in STM[' . $stm_name . '|'

View File

@@ -267,6 +267,8 @@ final class CoreLibsACLLoginTest extends TestCase
'GROUP_ACL_LEVEL' => -1,
'PAGES_ACL_LEVEL' => [],
'USER_ACL_LEVEL' => -1,
'USER_ADDITIONAL_ACL' => [],
'GROUP_ADDITIONAL_ACL' => [],
'UNIT_UID' => [
'AdminAccess' => 1,
],
@@ -280,6 +282,7 @@ final class CoreLibsACLLoginTest extends TestCase
'data' => [
'test' => 'value',
],
'additional_acl' => []
],
],
// 'UNIT_DEFAULT' => '',

View File

@@ -2142,7 +2142,7 @@ final class CoreLibsDBIOTest extends TestCase
return [
// *** READ STEP BY STEP
// default cache: USE_CACHE
'valid select, default cache settings' => [
'valid select, default cache settings (NO_CACHE)' => [
// 0-3
$read_query,
null,
@@ -2156,9 +2156,7 @@ final class CoreLibsDBIOTest extends TestCase
// check cursor_ext
[
'cursor' => 'PgSql\Result',
'data' => [
0 => $row_a,
],
'data' => [],
'field_names' => [
'row_int',
'uid'
@@ -2173,9 +2171,9 @@ final class CoreLibsDBIOTest extends TestCase
'query' => $read_query,
'params' => [],
'read_rows' => 1,
'cache_flag' => \CoreLibs\DB\IO::USE_CACHE,
'cache_flag' => \CoreLibs\DB\IO::NO_CACHE,
'assoc_flag' => false,
'cached' => true,
'cached' => false,
'finished' => false,
'read_finished' => false,
'db_read_finished' => false,
@@ -2190,10 +2188,7 @@ final class CoreLibsDBIOTest extends TestCase
],
'cursor' => [
'cursor' => 'PgSql\Result',
'data' => [
0 => $row_a,
1 => $row_b,
],
'data' => [],
'field_names' => [
'row_int',
'uid'
@@ -2208,9 +2203,9 @@ final class CoreLibsDBIOTest extends TestCase
'query' => $read_query,
'params' => [],
'read_rows' => 2,
'cache_flag' => \CoreLibs\DB\IO::USE_CACHE,
'cache_flag' => \CoreLibs\DB\IO::NO_CACHE,
'assoc_flag' => false,
'cached' => true,
'cached' => false,
'finished' => false,
'read_finished' => true,
'db_read_finished' => true,
@@ -2221,10 +2216,7 @@ final class CoreLibsDBIOTest extends TestCase
'data' => false,
'cursor' => [
'cursor' => 1,
'data' => [
0 => $row_a,
1 => $row_b,
],
'data' => [],
'field_names' => [
'row_int',
'uid'
@@ -2239,9 +2231,9 @@ final class CoreLibsDBIOTest extends TestCase
'query' => $read_query,
'params' => [],
'read_rows' => 2,
'cache_flag' => \CoreLibs\DB\IO::USE_CACHE,
'cache_flag' => \CoreLibs\DB\IO::NO_CACHE,
'assoc_flag' => false,
'cached' => true,
'cached' => false,
'finished' => true,
'read_finished' => true,
'db_read_finished' => true,
@@ -2811,13 +2803,50 @@ final class CoreLibsDBIOTest extends TestCase
],
// *** READ AS LOOP
// from here on a complex read all full tests
'valid select, full read DEFAULT CACHE' => [
'valid select, full read, default cache settings (NO CACHE)' => [
$read_query,
null,
null,
null,
[$row_a, $row_b,],
false,
[
'cursor' => 1,
'data' => [],
'field_names' => [
'row_int',
'uid'
],
'field_types' => [
'int4',
'varchar'
],
'num_fields' => 2,
'num_rows' => 2,
'pos' => 0,
'query' => $read_query,
'params' => [],
'read_rows' => 2,
'cache_flag' => \CoreLibs\DB\IO::NO_CACHE,
'assoc_flag' => false,
'cached' => false,
'finished' => true,
'read_finished' => true,
'db_read_finished' => true,
],
[],
'',
'',
$insert_query
],
// USE CACHE
'valid select, full read, USE CACHE' => [
$read_query,
null,
\CoreLibs\DB\IO::USE_CACHE,
null,
[$row_a, $row_b,],
false,
[
'cursor' => 1,
'data' => [
@@ -2851,7 +2880,7 @@ final class CoreLibsDBIOTest extends TestCase
$insert_query
],
// READ_NEW
'valid select, full read READ NEW' => [
'valid select, full read, READ NEW' => [
$read_query,
null,
\CoreLibs\DB\IO::READ_NEW,
@@ -2891,7 +2920,7 @@ final class CoreLibsDBIOTest extends TestCase
$insert_query
],
// CLEAR_CACHE
'valid select, full read CLEAR CACHE' => [
'valid select, full read, CLEAR CACHE' => [
$read_query,
null,
\CoreLibs\DB\IO::CLEAR_CACHE,
@@ -2928,7 +2957,7 @@ final class CoreLibsDBIOTest extends TestCase
'',
$insert_query
],
'valid select, full read NO CACHE' => [
'valid select, full read, NO CACHE' => [
$read_query,
null,
\CoreLibs\DB\IO::NO_CACHE,
@@ -3070,7 +3099,7 @@ final class CoreLibsDBIOTest extends TestCase
* @covers ::dbCursorPos
* @covers ::dbCursorNumRows
* @dataProvider dbReturnProvider
* @testdox dbReturn Read Frist $read_first_only only and cache $flag_cache and assoc $flag_assoc with (Warning: $warning/Error: $error) [$_dataName]
* @testdox dbReturn Read First $read_first_only only and cache $flag_cache and assoc $flag_assoc with (Warning: $warning/Error: $error) [$_dataName]
*
* @param string $query
* @param array<mixed>|null $params
@@ -4358,7 +4387,7 @@ final class CoreLibsDBIOTest extends TestCase
// NOTE if there are different INSERTS before the primary keys
// will not match anymore. Must be updated by hand
// IMPORTANT: if this is stand alone the primary key will not match and fail
$table_with_primary_key_id = 66;
$table_with_primary_key_id = 68;
// 0: query + returning
// 1: params
// 1: pk name for db exec