Compare commits

...

2 Commits

Author SHA1 Message Date
Clemens Schwaighofer
4bbbd653cd DB\IO fix for regex query detection
Fix for basic query detection:
Simeple starts with
SELECT/WITH/SHOW
INSERT INTO/UPDATE/DELETE FROM
UPDATE

Above does no complex query detection, just if the string starts with this

Fix form table detection for primary key auto set trial.
2023-01-27 11:12:46 +09:00
Clemens Schwaighofer
4c28e6d0ec Change DB\IO Returning check regex
Better regex to only get last returning in query, with proper parameter
check
2023-01-26 16:37:22 +09:00
3 changed files with 125 additions and 62 deletions

View File

@@ -1,103 +1,128 @@
# Upgrade to Version 6
* remove old `lib/CoreLibs` and copy the new over
* copy `config/config.php`
* install composer if not installed `composer init` and `composer install`
* update composer.json
```json
* remove old `lib/CoreLibs` and copy the new over
* copy `config/config.php`
* install composer if not installed `composer init` and `composer install`
* update composer.json
```json
"autoload": {
"classmap": [
"lib/"
]
},
```
Run to update autoloader list
```sh
composer dump-autoload
```
* copy `includes/edit_base.inc`
* add session start in the top header block where the `header()` calls are
* copy `includes/edit_base.inc`
* add session start in the top header block where the `header()` calls are
```php
// start session
CoreLibs\Create\Session::startSession();
```
* update all header calls if needed to add new log type call
```php
* update all header calls if needed to add new log type call
```php
// create logger
$log = new CoreLibs\Debug\Logging([
'log_folder' => BASE . LOG,
'file_id' => LOG_FILE_ID,
'print_file_date' => true,
'debug_all' => $DEBUG_ALL ?? false,
'echo_all' => $ECHO_ALL ?? false,
'print_all' => $PRINT_ALL ?? false,
'log_folder' => BASE . LOG,
'file_id' => LOG_FILE_ID,
'print_file_date' => true,
'debug_all' => $DEBUG_ALL ?? false,
'echo_all' => $ECHO_ALL ?? false,
'print_all' => $PRINT_ALL ?? false,
]);
```
* add a db class
* add a db class
```php
// db config with logger
$db = new CoreLibs\DB\IO(DB_CONFIG, $log);
```
* login class needs to have db and logger added
* login class needs to have db and logger added
```php
// login & page access check
$login = new CoreLibs\ACL\Login($db, $log);
```
* update language class
```php
// pre auto detect language after login
$locale = \CoreLibs\Language\GetLocale::setLocale();
// set lang and pass to smarty/backend
$l10n = new \CoreLibs\Language\L10n(
$locale['locale'],
$locale['domain'],
$locale['path'],
$locale['locale'],
$locale['domain'],
$locale['path'],
);
```
* smarty needs language
```php
$smarty = new CoreLibs\Template\SmartyExtend($l10n, $locale);
```
* admin backend also needs logger
```php
$cms = new CoreLibs\Admin\Backend($db, $log, $l10n, $locale);
```
* update and `$cms` or similar calls so db is in `$cms->db->...` and log are in `$cms->log->...`
* update all `config.*.php` files where needed
* check config.master.php for `BASE_NAME` and `G_TITLE` and set them in the `.env` file so the `config.master.php` can be copied as os
* If not doable, see changed below in `config.master.php` must remove old auto loder and `FLASH` constant at least
**REMOVE:**
```php
/************* AUTO LOADER *******************/
// read auto loader
require BASE . LIB . 'autoloader.php';
```
**UPDATE:**
```php
// po langs [DEPRECAED: use LOCALE]
define('LANG', 'lang' . DIRECTORY_SEPARATOR);
// po locale file
define('LOCALE', 'locale' . DIRECTORY_SEPARATOR);
```
```php
// SSL host name
// define('SSL_HOST', $_ENV['SSL_HOST'] ?? '');
```
```php
// define full regex
define('PASSWORD_REGEX', "/^"
. (defined('PASSWORD_LOWER') ? PASSWORD_LOWER : '')
. (defined('PASSWORD_UPPER') ? PASSWORD_UPPER : '')
. (defined('PASSWORD_NUMBER') ? PASSWORD_NUMBER : '')
. (defined('PASSWORD_SPECIAL') ? PASSWORD_SPECIAL : '')
. "[A-Za-z\d" . PASSWORD_SPECIAL_RANGE . "]{" . PASSWORD_MIN_LENGTH . "," . PASSWORD_MAX_LENGTH . "}$/");
. (defined('PASSWORD_LOWER') ? PASSWORD_LOWER : '')
. (defined('PASSWORD_UPPER') ? PASSWORD_UPPER : '')
. (defined('PASSWORD_NUMBER') ? PASSWORD_NUMBER : '')
. (defined('PASSWORD_SPECIAL') ? PASSWORD_SPECIAL : '')
. "[A-Za-z\d" . PASSWORD_SPECIAL_RANGE . "]{" . PASSWORD_MIN_LENGTH . "," . PASSWORD_MAX_LENGTH . "}$/");
```
```php
/************* LAYOUT WIDTHS *************/
define('PAGE_WIDTH', '100%');
define('CONTENT_WIDTH', '100%');
```
```php
/************* OVERALL CONTROL NAMES *************/
// BELOW has HAS to be changed
@@ -105,6 +130,7 @@ define('CONTENT_WIDTH', '100%');
// only alphanumeric characters, strip all others
define('BASE_NAME', preg_replace('/[^A-Za-z0-9]/', '', $_ENV['BASE_NAME'] ?? ''));
```
```php
/************* LANGUAGE / ENCODING *******/
// default lang + encoding
@@ -112,53 +138,63 @@ define('DEFAULT_LOCALE', 'en_US.UTF-8');
// default web page encoding setting
define('DEFAULT_ENCODING', 'UTF-8');
```
```php
// BAIL ON MISSING DB CONFIG:
// we have either no db selction for this host but have db config entries
// or we have a db selection but no db config as array or empty
// or we have a selection but no matching db config entry
if (
(!isset($SITE_CONFIG[HOST_NAME]['db_host']) && count($DB_CONFIG)) ||
(isset($SITE_CONFIG[HOST_NAME]['db_host']) &&
// missing DB CONFIG
((is_array($DB_CONFIG) && !count($DB_CONFIG)) ||
!is_array($DB_CONFIG) ||
// has DB CONFIG but no match
empty($DB_CONFIG[$SITE_CONFIG[HOST_NAME]['db_host']]))
)
(!isset($SITE_CONFIG[HOST_NAME]['db_host']) && count($DB_CONFIG)) ||
(isset($SITE_CONFIG[HOST_NAME]['db_host']) &&
// missing DB CONFIG
((is_array($DB_CONFIG) && !count($DB_CONFIG)) ||
!is_array($DB_CONFIG) ||
// has DB CONFIG but no match
empty($DB_CONFIG[$SITE_CONFIG[HOST_NAME]['db_host']]))
)
) {
echo 'No matching DB config found for: "' . HOST_NAME . '". Contact Administrator';
exit;
echo 'No matching DB config found for: "' . HOST_NAME . '". Contact Administrator';
exit;
}
```
```php
// remove SITE_LANG
define('SITE_LOCALE', $SITE_CONFIG[HOST_NAME]['site_locale'] ?? DEFAULT_LOCALE);
define('SITE_ENCODING', $SITE_CONFIG[HOST_NAME]['site_encoding'] ?? DEFAULT_ENCODING);
```
```php
/************* GENERAL PAGE TITLE ********/
define('G_TITLE', $_ENV['G_TITLE'] ?? '');
```
* move all login passweords into the `.env` file in the `configs/` folder
in the `.env` file
```
```sql
DB_NAME.TEST=some_database
...
```
In the config then
```php
'db_name' => $_ENV['DB_NAME.TEST'] ?? '',
```
* config.host.php update
must add site_locale (site_lang + site_encoding)
remove site_lang
```php
// lang + encoding
'site_locale' => 'en_US.UTF-8',
// site language
'site_encoding' => 'UTF-8',
// lang + encoding
'site_locale' => 'en_US.UTF-8',
// site language
'site_encoding' => 'UTF-8',
```
* copy `layout/admin/javascript/edit.jq.js`
* check other javacsript files if needed (`edit.jq.js`)

View File

@@ -161,7 +161,7 @@ print "DIRECT INSERT PREVIOUS INSERTED: "
$db->dbPrepare("ins_test_foo", "INSERT INTO test_foo (test) VALUES ($1) RETURNING test");
$status = $db->dbExecute("ins_test_foo", ['BAR TEST ' . time()]);
print "PREPARE INSERT[ins_test_foo] STATUS: " . Support::printToString($status) . " |<br>"
. "QUERY: " . $db->dbGetQuery() . " |<br>"
. "QUERY: " . $db->dbGetPrepareCursorValue('ins_test_foo', 'query') . " |<br>"
. "PRIMARY KEY: " . $db->dbGetInsertPK() . " | "
. "RETURNING EXT: " . print_r($db->dbGetReturningExt(), true) . " | "
. "RETURNING RETURN: " . print_r($db->dbGetReturningArray(), true) . "<br>";
@@ -186,7 +186,7 @@ EOM;
$db->dbPrepare("ins_test_foo_eom", $query);
$status = $db->dbExecute("ins_test_foo_eom", ['EOM BAR TEST ' . time()]);
print "EOM STRING PREPARE INSERT[ins_test_foo_eom] STATUS: " . Support::printToString($status) . " |<br>"
. "QUERY: " . $db->dbGetQuery() . " |<br>"
. "QUERY: " . $db->dbGetPrepareCursorValue('ins_test_foo_eom', 'query') . " |<br>"
. "PRIMARY KEY: " . $db->dbGetInsertPK() . " | "
. "RETURNING EXT: " . print_r($db->dbGetReturningExt(), true) . " | "
. "RETURNING RETURN: " . print_r($db->dbGetReturningArray(), true) . "<br>";

View File

@@ -266,16 +266,18 @@ class IO
// 1: read new, keep at end, clean before new run
// 2: read new, clean at the end (temporary cache)
// 3: never cache
/** @var int */
/** @var int use cache (default) in dbReturn */
public const USE_CACHE = 0;
/** @var int */
/** @var int reset cache and read new in dbReturn */
public const READ_NEW = 1;
/** @var int */
/** @var int clear cache after read in dbeEturn */
public const CLEAR_CACHE = 2;
/** @var int */
/** @var int do not use any cache in dbReturn */
public const NO_CACHE = 3;
/** @var string */
/** @var string default hash type */
public const ERROR_HASH_TYPE = 'adler32';
/** @var string regex to get returning with matches at position 1 */
public const REGEX_RETURNING = '/\s?returning(?: (.+?));?$/i';
// recommend to set private/protected and only allow setting via method
// can bet set from outside
@@ -573,14 +575,14 @@ class IO
/**
* checks if query is a SELECT, SHOW or WITH, if not error, 0 return
* NOTE:
* Query needs to start with SELECT, SHOW or WITH. if starts with "with" it is ignored
* Query needs to start with SELECT, SHOW or WITH
* @param string $query query to check
* @return bool true if matching, false if not
*/
private function __checkQueryForSelect(string $query): bool
{
// perhaps allow spaces before select ?!?
if (preg_match("/^(select|show|with) /i", $query)) {
// change to string starts with?
if (preg_match("/^(?:SELECT|SHOW|WITH)\s/i", $query)) {
return true;
}
return false;
@@ -597,10 +599,10 @@ class IO
*/
private function __checkQueryForInsert(string $query, bool $pure = false): bool
{
if ($pure && preg_match("/^insert /i", $query)) {
if ($pure && preg_match("/^INSERT\s+?INTO\s/i", $query)) {
return true;
}
if (!$pure && preg_match("/^(insert|update|delete) /i", $query)) {
if (!$pure && preg_match("/^(?:INSERT\s+?INTO|DELETE\s+?FROM|UPDATE)\s/i", $query)) {
return true;
}
return false;
@@ -614,7 +616,7 @@ class IO
*/
private function __checkQueryForUpdate(string $query): bool
{
if (preg_match("/^update /i", $query)) {
if (preg_match("/^UPDATE\s?(.+)/i", $query)) {
return true;
}
return false;
@@ -879,12 +881,32 @@ class IO
private function __dbReturnTable(string $query): array
{
$matches = [];
if (preg_match("/^SELECT /i", $query)) {
preg_match("/ (FROM) \"?(([\w_]+)\.)?([\w_]+)\"? /i", $query, $matches);
$schema_table = [];
if ($this->__checkQueryForSelect($query)) {
// only selects the first one, this is more a fallback
// MATCHES 1 (call), 3 (schema), 4 (table)
preg_match("/\s+?(FROM)\s+?([\"'])?(?:([\w_]+)\.)?([\w_]+)(?:\2)?\s?/i", $query, $matches);
$schema_table = [
$matches[3] ?? '',
$matches[4] ?? '',
];
} else {
preg_match("/(INSERT INTO|DELETE FROM|UPDATE) \"?(([\w_]+)\.)?([\w_]+)\"? /i", $query, $matches);
preg_match(
// must start with
// INSERT INTO (table)
// DELETE FROM (table)
// UPDATE (table) SET
// MATCHES 1 (call), 4 (schema), 5 (table)
"/^(INSERT\s+?INTO|DELETE\s+?FROM|(UPDATE))\s+?([\"'])?(?:([\w_]+)\.)?([\w_]+)(?:\3)?\s?(?(2)SET|)/i",
$query,
$matches
);
$schema_table = [
$matches[4] ?? '',
$matches[5] ?? ''
];
}
return [$matches[3] ?? '', $matches[4] ?? ''];
return $schema_table;
}
/**
@@ -1007,7 +1029,7 @@ class IO
$this->pk_name_table[$table] : 'NULL';
}
if (
!preg_match("/\s?returning /i", $this->query) &&
!preg_match(self::REGEX_RETURNING, $this->query) &&
$this->pk_name && $this->pk_name != 'NULL'
) {
// check if this query has a ; at the end and remove it
@@ -1016,7 +1038,9 @@ class IO
$this->query = !is_string($__query) ? $this->query : $__query;
$this->query .= " RETURNING " . $this->pk_name;
$this->returning_id = true;
} elseif (preg_match("/\s?returning (.*)/i", $this->query, $matches)) {
} elseif (
preg_match(self::REGEX_RETURNING, $this->query, $matches)
) {
if ($this->pk_name && $this->pk_name != 'NULL') {
// add the primary key if it is not in the returning set
if (!preg_match("/$this->pk_name/", $matches[1])) {
@@ -1030,7 +1054,7 @@ class IO
// if we have an UPDATE and RETURNING, flag for true, but do not add anything
if (
$this->__checkQueryForUpdate($this->query) &&
preg_match("/\s?returning (.*)/i", $this->query, $matches)
preg_match(self::REGEX_RETURNING, $this->query, $matches)
) {
$this->returning_id = true;
}
@@ -2288,11 +2312,14 @@ class IO
$this->prepare_cursor[$stm_name]['pk_name'] = $pk_name;
}
// if no returning, then add it
if (!preg_match("/\s?returning /i", $query) && $this->prepare_cursor[$stm_name]['pk_name']) {
if (
!preg_match(self::REGEX_RETURNING, $query) &&
$this->prepare_cursor[$stm_name]['pk_name']
) {
$query .= " RETURNING " . $this->prepare_cursor[$stm_name]['pk_name'];
$this->prepare_cursor[$stm_name]['returning_id'] = true;
} elseif (
preg_match("/\s?returning (.*)/i", $query, $matches) &&
preg_match(self::REGEX_RETURNING, $query, $matches) &&
$this->prepare_cursor[$stm_name]['pk_name']
) {
// if returning exists but not pk_name, add it