Compare commits

..

12 Commits

Author SHA1 Message Date
Clemens Schwaighofer
46b2b60718 CoreLibs DB\IO dbExec*, dbReturn* params methods add 2023-03-28 15:41:02 +09:00
Clemens Schwaighofer
9616d956cb Publish v8.0.7 2023-03-13 11:35:13 +09:00
Clemens Schwaighofer
df401b9add Update SmartyExtend set vars calls with parameter changes
Frontend: drop $cms, add $smarty_data array
Backend: if $cms is set content_path options array entry must be set
2023-03-13 11:33:23 +09:00
Clemens Schwaighofer
4b9e393971 Published v8.0.6 2023-03-13 10:52:15 +09:00
Clemens Schwaighofer
6cda319ed0 Bug fix for SmartyExtend set var call 2023-03-13 10:51:09 +09:00
Clemens Schwaighofer
583edbfe0a Published v8.0.5 2023-03-13 09:29:30 +09:00
Clemens Schwaighofer
67a8e1a533 Switch from parameter list to options list for SmartyExtend var set
The SmartyExtend var set mothod calls switched to options list
2023-03-13 09:27:46 +09:00
Clemens Schwaighofer
38788dddce CoreLibs v8.0.5 release 2023-03-10 15:30:06 +09:00
Clemens Schwaighofer
cf196d56dd Bug fix in SmartyExtend set vars calls 2023-03-10 15:27:45 +09:00
Clemens Schwaighofer
0cb76c8db2 CoreLibs v8.0.3 release 2023-03-10 15:13:43 +09:00
Clemens Schwaighofer
db02bdd102 CoreLibs data update for v8.0.3 2023-03-10 15:11:58 +09:00
Clemens Schwaighofer
d9b71a64b3 Published v8.0.2 2023-03-09 16:59:18 +09:00
17 changed files with 2093 additions and 485 deletions

View File

@@ -1 +1 @@
8.0.1
8.0.7

View File

@@ -196,7 +196,12 @@ class Login
/** @var array<string,mixed> options */
private $options = [];
/** @var array<string,string> locale options: locale, domain, encoding (opt), path */
private $locale = [];
private $locale = [
'locale' => '',
'domain' => '',
'encoding' => '',
'path' => '',
];
/** @var \CoreLibs\Debug\Logging logger */
public $log;
@@ -423,7 +428,7 @@ class Login
/**
* Set options
* Current allowed
* Current allowed:
* target <string>: site target
* debug <bool>
* auto_login <bool>: self start login process
@@ -555,12 +560,12 @@ class Login
);
// set path
$options['locale_path'] = BASE . INCLUDES . LOCALE;
$_SESSION['LOCALE_PATH'] = $options['locale_path'];
}
$_SESSION['LOCALE_PATH'] = $options['locale_path'];
// LANG: LOCALE
if (empty($options['site_locale'])) {
trigger_error(
'loginMainCall: SITE_LOCALE or DEFAULT_LOCALE should not be used',
'loginMainCall: SITE_LOCALE should not be used',
E_USER_DEPRECATED
);
$options['site_locale'] = defined('SITE_LOCALE') && !empty(SITE_LOCALE) ?
@@ -580,7 +585,6 @@ class Login
);
// set domain
$options['site_domain'] = SITE_DOMAIN;
$_SESSION['DEFAULT_DOMAIN'] = $options['site_domain'];
} elseif (
defined('CONTENT_PATH')
) {
@@ -592,6 +596,16 @@ class Login
$options['set_domain'] = str_replace(DIRECTORY_SEPARATOR, '', CONTENT_PATH);
}
}
$_SESSION['DEFAULT_DOMAIN'] = $options['site_domain'];
// LANG: ENCODING
if (empty($options['site_encoding'])) {
trigger_error(
'loginMainCall: SITE_ENCODING should not be used',
E_USER_DEPRECATED
);
$options['site_encoding'] = defined('SITE_ENCODING') && !empty(SITE_ENCODING) ?
SITE_ENCODING : 'UTF-8';
}
// write array to options
$this->options = $options;
@@ -905,6 +919,7 @@ class Login
// rgb: nnn.n for each
// hsl: nnn.n for first, nnn.n% for 2nd, 3rd
// Check\Colors::validateColor()
// LANGUAGE/LOCALE/ENCODING:
$_SESSION['LANG'] = $res['locale'] ?? 'en';
$_SESSION['DEFAULT_CHARSET'] = $res['encoding'] ?? 'UTF-8';
$_SESSION['DEFAULT_LOCALE'] = $_SESSION['LANG']
@@ -1195,7 +1210,8 @@ class Login
}
/**
* set locale and load mo translator
* set locale
* if invalid, set to empty string
*
* @return void
*/
@@ -1204,22 +1220,52 @@ class Login
// ** LANGUAGE SET AFTER LOGIN **
// set the locale
if (
!empty($_SESSION['DEFAULT_LOCALE'])
!empty($_SESSION['DEFAULT_LOCALE']) &&
preg_match("/^[-A-Za-z0-9_.@]+$/", $_SESSION['DEFAULT_LOCALE'])
) {
$locale = $_SESSION['DEFAULT_LOCALE'];
} else {
} elseif (
!preg_match("/^[-A-Za-z0-9_.@]+$/", $this->options['site_locale'])
) {
$locale = $this->options['site_locale'];
} else {
$locale = '';
}
// set the charset
preg_match('/(?:\\.(?P<charset>[-A-Za-z0-9_]+))/', $locale, $matches);
$locale_encoding = $matches['charset'] ?? '';
if (!empty($locale_encoding)) {
$encoding = strtoupper($locale_encoding);
} elseif (
!empty($_SESSION['DEFAULT_CHARSET']) &&
preg_match("/^[-A-Za-z0-9_]+$/", $_SESSION['DEFAULT_CHARSET'])
) {
$encoding = $_SESSION['DEFAULT_CHARSET'];
} elseif (
!preg_match("/^[-A-Za-z0-9_]+$/", $this->options['site_encoding'])
) {
$encoding = $this->options['site_encoding'];
} else {
$encoding = '';
}
// check domain
$domain = $this->options['site_domain'];
if (
!preg_match("/^\w+$/", $this->options['site_domain'])
) {
$domain = '';
}
$path = $this->options['locale_path'];
if (!is_dir($path)) {
$path = '';
}
// domain and path are a must set from class options
$this->locale = [
'locale' => $locale,
'domain' => $this->options['site_domain'],
'path' => $this->options['locale_path'],
'domain' => $domain,
'encoding' => $encoding,
'path' => $path,
];
$this->l = new \CoreLibs\Language\L10n(
$this->locale['locale'],
$this->locale['domain'],
$this->locale['path']
);
}
/**
@@ -1824,6 +1870,12 @@ EOM;
$this->loginLogoutUser();
// ** LANGUAGE SET AFTER LOGIN **
$this->loginSetLocale();
// load translator
$this->l = new \CoreLibs\Language\L10n(
$this->locale['locale'],
$this->locale['domain'],
$this->locale['path']
);
// if the password change flag is okay, run the password change method
if ($this->password_change) {
$this->loginPasswordChange();
@@ -2396,6 +2448,53 @@ EOM;
): bool|string {
return $this->loginGetEditAccessData($edit_access_id, $data_key);
}
/**
* Return locale settings with
* locale
* domain
* encoding
* path
*
* empty string if not set
*
* @return array<string,string> Locale settings
*/
public function loginGetLocale(): array
{
return $this->locale;
}
/**
* return header color or null for not set
*
* @return string|null Header color in RGB hex with leading sharp
*/
public function loginGetHeaderColor(): ?string
{
return $_SESSION['HEADER_COLOR'] ?? null;
}
/**
* Return the current loaded list of pages the user can access
*
* @return array<mixed>
*/
public function loginGetPages(): array
{
return $_SESSION['PAGES'] ?? [];
}
/**
* Get the current set EUID (edit user id)
*
* @return string EUID as string
*/
public function loginGetEuid(): string
{
return $this->euid;
}
}
// __END__

View File

@@ -121,14 +121,13 @@ class Backend
* @param \CoreLibs\Debug\Logging $log Logging class
* @param \CoreLibs\Create\Session $session Session interface class
* @param \CoreLibs\Language\L10n $l10n l10n language class
* @param array<string,string> $locale locale data read from setLocale
* @param int|null $set_default_acl_level Default ACL level
*/
public function __construct(
\CoreLibs\DB\IO $db,
\CoreLibs\Debug\Logging $log,
\CoreLibs\Create\Session $session,
\CoreLibs\Language\L10n $l10n,
array $locale,
?int $set_default_acl_level = null
) {
// attach db class
@@ -142,12 +141,12 @@ class Backend
// get the language sub class & init it
$this->l = $l10n;
// parse and read, legacy stuff
$locale = $this->l->getLocaleAsArray();
$this->encoding = $locale['encoding'];
$this->lang = $locale['lang'];
// get first part from lang
$this->lang_short = explode('_', $locale['lang'])[0];
$this->domain = $this->l->getDomain();
$this->lang_dir = $this->l->getBaseLocalePath();
$this->lang_short = $locale['lang_short'];
$this->domain = $locale['domain'];
$this->lang_dir = $locale['path'];
// set the page name
$this->page_name = \CoreLibs\Get\System::getPageName();

View File

@@ -35,6 +35,8 @@ class EditBase
private $form;
/** @var \CoreLibs\Debug\Logging */
public $log;
/** @var \CoreLibs\ACL\Login */
public $login;
/**
* construct form generator
@@ -42,18 +44,24 @@ class EditBase
* @param array<mixed> $db_config db config array, mandatory
* @param \CoreLibs\Debug\Logging $log Logging class, null auto set
* @param \CoreLibs\Language\L10n $l10n l10n language class, null auto set
* @param array<string,string> $locale locale array from ::setLocale,
* null auto set
* @param \CoreLibs\ACL\Login $login login class for ACL settings
* @param array<string,mixed> $options Various settings options
*/
public function __construct(
array $db_config,
\CoreLibs\Debug\Logging $log,
\CoreLibs\Language\L10n $l10n,
array $locale
\CoreLibs\ACL\Login $login,
array $options
) {
$this->log = $log;
$this->login = $login;
// smarty template engine (extended Translation version)
$this->smarty = new \CoreLibs\Template\SmartyExtend($l10n, $locale);
$this->smarty = new \CoreLibs\Template\SmartyExtend(
$l10n,
$options['cache_id'] ?? '',
$options['compile_id'] ?? '',
);
// turn off set log per class
$log->setLogPer('class', false);
@@ -62,7 +70,7 @@ class EditBase
$db_config,
$log,
$l10n,
$locale
$this->login->loginGetAcl()
);
if ($this->form->mobile_phone) {
echo "I am sorry, but this page cannot be viewed by a mobile phone";
@@ -272,23 +280,16 @@ class EditBase
// MENU START
// request some session vars
if (empty($_SESSION['HEADER_COLOR'])) {
$this->DATA['HEADER_COLOR'] = '#E0E2FF';
} else {
$this->DATA['HEADER_COLOR'] = $_SESSION['HEADER_COLOR'];
}
$this->DATA['USER_NAME'] = $_SESSION['USER_NAME'];
$this->DATA['EUID'] = $_SESSION['EUID'];
$this->DATA['GROUP_NAME'] = $_SESSION['GROUP_NAME'];
$this->DATA['GROUP_LEVEL'] = $_SESSION['GROUP_ACL_LEVEL'];
$PAGES = $_SESSION['PAGES'];
$this->DATA['HEADER_COLOR'] = $this->login->loginGetHeaderColor() ?? '#E0E2FF';
$this->DATA['USER_NAME'] = $this->login->loginGetAcl()['user_name'] ?? '';
$this->DATA['EUID'] = $this->login->loginGetEuid();
$this->DATA['GROUP_NAME'] = $this->login->loginGetAcl()['group_name'] ?? '';
$this->DATA['ACCESS_LEVEL'] = $this->login->loginGetAcl()['base'] ?? '';
// below is old and to removed when edit_body.tpl is updates
$this->DATA['GROUP_LEVEL'] = $this->DATA['ACCESS_LEVEL'];
$PAGES = $this->login->loginGetPages();
//$this->form->log->debug('menu', $this->form->log->prAr($PAGES));
// build nav from $PAGES ...
if (!isset($PAGES) || !is_array($PAGES)) {
$PAGES = [];
}
$menuarray = [];
foreach ($PAGES as $PAGE_CUID => $PAGE_DATA) {
if ($PAGE_DATA['menu'] && $PAGE_DATA['online']) {
@@ -574,7 +575,7 @@ class EditBase
$set_admin_stylesheet = $set_admin_stylesheet ?? ADMIN_STYLESHEET;
$set_default_encoding = $set_default_encoding ?? DEFAULT_ENCODING;
$set_css = $set_css ?? LAYOUT . CSS;
$set_css = $set_js ?? LAYOUT . JS;
$set_js = $set_js ?? LAYOUT . JS;
$set_root = $set_root ?? ROOT;
$set_content_path = $set_content_path ?? CONTENT_PATH;

View File

@@ -69,12 +69,16 @@
* - sets the SQL query (will be set with the $query parameter from method)
* if u leave the parameter free the class will try to use this var, but this
* method is not so reccomended
* $params
* - array for query parameters, if not set, ignored
* $num_rows
* - the number of rows returned by a SELECT or alterd bei UPDATE/INSERT
* $num_fields
* - the number of fields from the SELECT, is usefull if you do a SELECT *
* $field_names
* - array of field names (in the order of the return)
* $field_types
* - array of field types
* $insert_id
* - for INSERT with auto_increment PK, the ID is stored here
* $error_msg
@@ -258,7 +262,6 @@ use CoreLibs\Create\Uids;
// below no ignore is needed if we want to use PgSql interface checks with PHP 8.0
// as main system. Currently all @var sets are written as object
/** @#phan-file-suppress PhanUndeclaredTypeProperty,PhanUndeclaredTypeParameter,PhanUndeclaredTypeReturnType */
class IO
{
@@ -286,10 +289,12 @@ class IO
private $to_encoding = '';
/** @var string */
private $query; // the query string at the moment
/** @var array<mixed> */
private $params; // current params for query
// only inside
// basic vars
/** @var \PgSql\Connection|false|null */ // replace object with PgSql\Connection|
private $dbh; // the dbh handler, if disconnected by command is null, bool:false/int:-1 on error,
private $dbh; // the dbh handler, if disconnected by command is null, bool:false on error,
/** @var bool */
private $db_debug = false; // DB_DEBUG ... (if set prints out debug msgs)
/** @var string */
@@ -321,8 +326,10 @@ class IO
private $num_rows; // how many rows have been found
/** @var int */
private $num_fields; // how many fields has the query
/** @var array<mixed> */
private $field_names = []; // array with the field names of the current query
/** @var array<string> array with the field names of the current query */
private $field_names = [];
/** @var array<string> field type names */
private $field_types = [];
/** @var array<mixed> */
private $insert_id_arr = []; // always return as array, even if only one
/** @var string */
@@ -405,9 +412,9 @@ class IO
$db_debug_override ??
// from db config setting
$db_config['db_debug'] ??
// should be handled from outside
// [DEPRECATED] should be handled from outside
$_SESSION['DB_DEBUG'] ??
// globals should be deprecated
// [DEPRECATED] globals should be deprecated
$GLOBALS['DB_DEBUG'] ??
false
);
@@ -648,17 +655,20 @@ class IO
/**
* calls the basic class debug with strip command
* @param string $debug_id group id for debug
* @param string $error_string error message or debug data
* @param string $id db debug group
* @param string $type query identifier (Q, I, etc)
* @return void has no return
* @param string $debug_id group id for debug
* @param string $error_string error message or debug data
* @param string $id db debug group
* @param string $type query identifier (Q, I, etc)
* @param array<mixed> $error_data Optional error data as array
* Will be printed after main error string
* @return void
*/
protected function __dbDebug(
string $debug_id,
string $error_string,
string $id = '',
string $type = ''
string $type = '',
array $error_data = []
): void {
// NOTE prefix allows html for echo output, will be stripped on file print
$prefix = '';
@@ -679,6 +689,11 @@ class IO
if ($prefix) {
$prefix .= '- ';
}
if ($error_data !== []) {
$error_string .= '<br>['
. $this->log->prAr($error_data)
. ']';
}
$this->log->debug($debug_id, $error_string, true, $prefix);
}
@@ -860,20 +875,31 @@ class IO
/**
* for debug purpose replaces $1, $2, etc with actual data
* @param string $stm_name prepared statement name
* @param array<mixed> $data the data array
* @return string string of query with data inside
* @param string $query Query to replace values in
* @param array<mixed> $data The data array
* @return string string of query with data inside
*/
private function __dbDebugPrepare(string $stm_name, array $data = []): string
private function __dbDebugPrepare(string $query, array $data = []): string
{
// skip anything if there is no data
if ($data === []) {
return $query;
}
// get the keys from data array
$keys = array_keys($data);
// because the placeholders start with $ and at 1, we need to increase each key and prefix it with a $ char
// because the placeholders start with $ and at 1,
// we need to increase each key and prefix it with a $ char
for ($i = 0, $iMax = count($keys); $i < $iMax; $i++) {
$keys[$i] = '$' . ($keys[$i] + 1);
// prefix data set with parameter pos
$data[$i] = $keys[$i] . ':' . $data[$i];
}
// simply replace the $1, $2, ... with the actual data and return it
return str_replace(array_reverse($keys), array_reverse($data), $this->prepare_cursor[$stm_name]['query']);
return str_replace(
array_reverse($keys),
array_reverse($data),
$query
);
}
/**
@@ -977,6 +1003,33 @@ class IO
return $return;
}
/**
* Checks if the placeholder count in the query matches the params given
* on call
*
* @param string $query Query to check
* @param int $params_count The parms count expected
* @return bool True for params count ok, else false
*/
private function __dbCheckQueryParams(string $query, int $params_count): bool
{
// 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);
$placeholder_count = count(array_unique($match[1]));
if ($params_count != $placeholder_count) {
$this->__dbError(
23,
false,
'Array data count does not match prepared fields. Need: '
. $placeholder_count . ', has: '
. $params_count
);
return false;
}
return true;
}
/**
* sub function for dbExec and dbExecAsync
* - checks query is set
@@ -985,13 +1038,17 @@ class IO
* - checks for insert if returning is set/pk name
* - sets internal hash for query
* - checks multiple call count
* @param string $query query string
* @param string $pk_name primary key
* [if set to NULL no returning will be added]
* @return string|false queryt hash OR bool false on error
* @param string $query Query string
* @param array<mixed> $params Query params, needed for hash creation
* @param string $pk_name primary key
* [if set to NULL no returning will be added]
* @return string|false queryt hash OR bool false on error
*/
private function __dbPrepareExec(string $query, string $pk_name): string|false
{
private function __dbPrepareExec(
string $query,
array $params,
string $pk_name
): string|false {
// reset current cursor before exec
$this->cursor = false;
// clear matches for regex lookups
@@ -1001,6 +1058,8 @@ class IO
$this->returning_id = false;
// set the query
$this->query = $query;
// current params
$this->params = $params;
// no query set
if (empty($this->query)) {
$this->__dbError(11);
@@ -1066,10 +1125,18 @@ class IO
// $this->debug('DB IO', 'Q: '.$this->query.', RETURN: '.$this->returning_id);
// for DEBUG, only on first time ;)
if ($this->db_debug) {
$this->__dbDebug('db', $this->query, '__dbPrepareExec', 'Q');
$this->__dbDebug(
'db',
$this->__dbDebugPrepare(
$this->query,
$this->params
),
'__dbPrepareExec',
($this->params === [] ? 'Q' : 'Qp'),
);
}
// import protection, hash needed
$query_hash = $this->dbGetQueryHash($this->query);
$query_hash = $this->dbGetQueryHash($this->query, $this->params);
// if the array index does not exists set it 0
if (!array_key_exists($query_hash, $this->query_called)) {
$this->query_called[$query_hash] = 0;
@@ -1121,7 +1188,11 @@ class IO
// set field names
$this->field_names = [];
for ($i = 0; $i < $this->num_fields; $i++) {
$this->field_names[] = $this->db_functions->__dbFieldName($this->cursor, $i);
$this->field_names[] = $this->db_functions->__dbFieldName($this->cursor, $i) ?: '';
}
$this->field_types = [];
for ($i = 0; $i < $this->num_fields; $i++) {
$this->field_types[] = $this->db_functions->__dbFieldType($this->cursor, $i) ?: '';
}
} elseif ($this->__checkQueryForInsert($this->query)) {
// if not select do here
@@ -1745,6 +1816,8 @@ class IO
* 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)
* Wrapper for dbReturnParams
*
* @param string $query Query string
* @param int $cache reset status: default: USE_CACHE
* USE_CACHE/0: normal read from cache on second run
@@ -1760,6 +1833,41 @@ class IO
string $query,
int $cache = self::USE_CACHE,
bool $assoc_only = false
): array|false {
return $this->dbReturnParams($query, [], $cache, $assoc_only);
}
/**
* single running function, if called creates hash from
* query string and so can itself call exec/return calls
* caches data, so next time called with IDENTICAL (!!!!)
* [this means 1:1 bit to bit identical query] returns cached
* 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, 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 array<mixed> $params Query parameters
* @param int $cache reset status: default: USE_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
* 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>|false return array data or false on error/end
*/
public function dbReturnParams(
string $query,
array $params = [],
int $cache = self::USE_CACHE,
bool $assoc_only = false
): array|false {
$this->__dbErrorReset();
if (!$query) {
@@ -1767,7 +1875,7 @@ class IO
return false;
}
// create hash from query ...
$query_hash = $this->dbGetQueryHash($query);
$query_hash = $this->dbGetQueryHash($query, $params);
// pre declare array
if (!isset($this->cursor_ext[$query_hash])) {
$this->cursor_ext[$query_hash] = [
@@ -1787,6 +1895,8 @@ class IO
'pos' => 0,
// the query used in this call
'query' => '',
// parameter
'params' => [],
// cache flag from method call
'cache_flag' => $cache,
// flag if we only have assoc data
@@ -1816,6 +1926,13 @@ class IO
$this->__dbError(17, false, $this->cursor_ext[$query_hash]['query']);
return false;
}
// set the query parameters
$this->cursor_ext[$query_hash]['params'] = $params;
// check if params count matches
// checks if the params count given matches the expected count
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
return false;
}
// set first call to false
$first_call = false;
// init return als false
@@ -1851,8 +1968,18 @@ class IO
if (!$this->__dbCheckConnectionOk()) {
return false;
}
$this->cursor_ext[$query_hash]['cursor'] =
$this->db_functions->__dbQuery($this->cursor_ext[$query_hash]['query']);
if ($this->cursor_ext[$query_hash]['params'] === []) {
$this->cursor_ext[$query_hash]['cursor'] =
$this->db_functions->__dbQuery(
$this->cursor_ext[$query_hash]['query']
);
} else {
$this->cursor_ext[$query_hash]['cursor'] =
$this->db_functions->__dbQueryParams(
$this->cursor_ext[$query_hash]['query'],
$this->cursor_ext[$query_hash]['params']
);
}
// if still no cursor ...
if (!$this->cursor_ext[$query_hash]['cursor']) {
if ($this->db_debug) {
@@ -1889,6 +2016,16 @@ class IO
);
}
$this->field_names = $this->cursor_ext[$query_hash]['field_names'];
// field types
$this->cursor_ext[$query_hash]['field_types'] = [];
for ($i = 0; $i < $this->cursor_ext[$query_hash]['num_fields']; $i++) {
$this->cursor_ext[$query_hash]['field_types'][] =
$this->db_functions->__dbFieldType(
$this->cursor_ext[$query_hash]['cursor'],
$i
);
}
$this->field_types = $this->cursor_ext[$query_hash]['field_types'];
// reset first call var
$first_call = false;
// reset the internal pos counter
@@ -2009,9 +2146,10 @@ class IO
* like num_rows, num_fields, etc depending on query
* for INSERT INTO queries it is highly recommended to set the pk_name to avoid an
* additional read from the database for the PK NAME
* Wrapper for dbExecParams without params
* @param string $query the query, if not given,
* the query class var will be used
* if this was not set, method will quit with a 0 (failure)
* if this was not set, method will quit with false
* @param string $pk_name optional primary key name, for insert id
* return if the pk name is very different
* if pk name is table name and _id, pk_name
@@ -2019,16 +2157,50 @@ class IO
* if NULL is given here, no RETURNING will be auto added
* @return \PgSql\Result|false cursor for this query or false on error
*/
public function dbExec(string $query = '', string $pk_name = ''): \PgSql\Result|false
{
public function dbExec(
string $query = '',
string $pk_name = ''
): \PgSql\Result|false {
// just calls the same without any params
// which will trigger normal pg_query call
return $this->dbExecParams($query, [], $pk_name);
}
/**
* Execute any query, but with the use of placeholders
*
* @param string $query Query, if not given, query class var will be used
* if this was not set, method will quit with false
* @param array<mixed> $params Parameters to be replaced.
* NOTE: bytea data cannot be used here (pg_query_params)
* @param string $pk_name Optional primary key name, for insert id
* return if the pk name is very different
* if pk name is table name and _id, pk_name
* is not needed to be set
* if NULL is given here, no RETURNING will be auto added
* @return \PgSql\Result|false cursor for this query or false on error
*/
public function dbExecParams(
string $query = '',
array $params = [],
string $pk_name = ''
): \PgSql\Result|false {
$this->__dbErrorReset();
// prepare and check if we can actually run it
if ($this->__dbPrepareExec($query, $pk_name) === false) {
if ($this->__dbPrepareExec($query, $params, $pk_name) === false) {
// bail if no query hash set
return false;
}
// checks if the params count given matches the expected count
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
return false;
}
// ** actual db exec call
$cursor = $this->db_functions->__dbQuery($this->query);
if ($params === []) {
$cursor = $this->db_functions->__dbQuery($this->query);
} else {
$cursor = $this->db_functions->__dbQueryParams($this->query, $params);
}
// if we faield, just set the master cursors to false too
$this->cursor = $cursor;
if ($cursor === false) {
@@ -2079,12 +2251,30 @@ class IO
/**
* returns the FIRST row of the given query
* wrapper for dbReturnRowParms
* @param string $query the query to be executed
* @param bool $assoc_only if true, only return assoc entry (default false)
* @return array<mixed>|false row array or false on error
*/
public function dbReturnRow(string $query, bool $assoc_only = false): array|false
{
return $this->dbReturnRowParams($query, [], $assoc_only);
}
/**
* Returns the first row only for the given query
* Uses db_query_params
*
* @param string $query the query to be executed
* @param array<mixed> $params params to be used in query
* @param bool $assoc_only if true, only return assoc entry (default false)
* @return array<mixed>|false row array or false on error
*/
public function dbReturnRowParams(
string $query,
array $params = [],
bool $assoc_only = false
): array|false {
$this->__dbErrorReset();
if (!$query) {
$this->__dbError(11);
@@ -2096,7 +2286,11 @@ class IO
$this->__dbError(17, false, $query);
return false;
}
$cursor = $this->dbExec($query);
// 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;
}
@@ -2105,13 +2299,31 @@ class IO
}
/**
* createds an array of hashes of the query (all data)
* creates an array of hashes of the query (all data)
* Wrapper for dbReturnArrayParams
* @param string $query the query to be executed
* @param bool $assoc_only if true, only name ref are returned (default true)
* @return array<mixed>|false array of hashes (row -> fields), false on error
*/
public function dbReturnArray(string $query, bool $assoc_only = true): array|false
{
return $this->dbReturnArrayParams($query, [], $assoc_only);
}
/**
* Creates an array of hashes of all data returned from the query
* uses db_query_param
*
* @param string $query the query to be executed
* @param array<mixed> $params params to be used in query
* @param bool $assoc_only if true, only name ref are returned (default true)
* @return array<mixed>|false array of hashes (row -> fields), false on error
*/
public function dbReturnArrayParams(
string $query,
array $params = [],
bool $assoc_only = true
): array|false {
$this->__dbErrorReset();
if (!$query) {
$this->__dbError(11);
@@ -2122,17 +2334,16 @@ class IO
$this->__dbError(17, false, $query);
return false;
}
$cursor = $this->dbExec($query);
// 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;
}
$rows = [];
while (is_array($res = $this->dbFetchArray($cursor, $assoc_only))) {
// $data = [];
// for ($i = 0; $i < $this->num_fields; $i++) {
// $data[$this->field_names[$i]] = $res[$this->field_names[$i]] ?? null;
// }
// $rows[] = $data;
$rows[] = $res;
}
return $rows;
@@ -2144,13 +2355,15 @@ class IO
/**
* resets all data stored to this query
* @param string $query The Query whose cache should be cleaned
* @return bool false if query not found, true if success
* @param string $query The Query whose cache should be cleaned
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return bool False if query not found, true if success
*/
public function dbCacheReset(string $query): bool
public function dbCacheReset(string $query, array $params = []): bool
{
$this->__dbErrorReset();
$query_hash = $this->dbGetQueryHash($query);
$query_hash = $this->dbGetQueryHash($query, $params);
// clears cache for this query
if (empty($this->cursor_ext[$query_hash]['query'])) {
$this->__dbError(18);
@@ -2168,24 +2381,27 @@ class IO
* returns the full array for cursor ext
* or cursor for one query
* or detail data fonr one query cursor data
* @param string|null $query Query string, if not null convert to hash
* and return set cursor ext for only this
* if not found or null return null
* @param string $query_field [=''] optional query field to get
*
* @param string|null $query Query string, if not null convert to hash
* and return set cursor ext for only this
* if not found or null return null
* @param array<mixed> $params Optional params for query hash get
* @param string $query_field [=''] optional query field to get
* @return array<mixed>|string|int|\PgSql\Result|null
* Cursor Extended array full if no parameter
* Key is hash string from query run
* Or cursor data entry if query field is set
* If nothing found return null
* Cursor Extended array full if no parameter
* Key is hash string from query run
* Or cursor data entry if query field is set
* If nothing found return null
*/
public function dbGetCursorExt(
$query = null,
?string $query = null,
array $params = [],
string $query_field = ''
): array|string|int|\PgSql\Result|null {
if ($query === null) {
return $this->cursor_ext;
}
$query_hash = $this->dbGetQueryHash($query);
$query_hash = $this->dbGetQueryHash($query, $params);
if (
is_array($this->cursor_ext) &&
isset($this->cursor_ext[$query_hash])
@@ -2202,33 +2418,39 @@ class IO
/**
* returns the current position the read out
* @param string $query query to find in cursor_ext
* @return int|false query position (row pos), false on error
*
* @param string $query Query to find in cursor_ext
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return int|false query position (row pos), false on error
*/
public function dbGetCursorPos(string $query): int|false
public function dbGetCursorPos(string $query, array $params = []): int|false
{
$this->__dbErrorReset();
if (!$query) {
$this->__dbError(11);
return false;
}
$query_hash = $this->dbGetQueryHash($query);
$query_hash = $this->dbGetQueryHash($query, $params);
return (int)$this->cursor_ext[$query_hash]['pos'];
}
/**
* returns the number of rows for the current select query
* @param string $query query to find in cursor_ext
* @return int|false query position (row pos), false on error
*
* @param string $query Query to find in cursor_ext
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return int|false query position (row pos), false on error
*/
public function dbGetCursorNumRows(string $query): int|false
public function dbGetCursorNumRows(string $query, array $params = []): int|false
{
$this->__dbErrorReset();
if (!$query) {
$this->__dbError(11);
return false;
}
$query_hash = $this->dbGetQueryHash($query);
$query_hash = $this->dbGetQueryHash($query, $params);
return (int)$this->cursor_ext[$query_hash]['num_rows'];
}
@@ -2239,22 +2461,27 @@ class IO
/**
* resets the call times for the max query called to 0
* USE CAREFULLY: rather make the query prepare -> execute
* @param string $query query string
* @return void has no return
*
* @param string $query query string
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return void
*/
public function dbResetQueryCalled(string $query): void
public function dbResetQueryCalled(string $query, array $params = []): void
{
$this->query_called[$this->dbGetQueryHash($query)] = 0;
$this->query_called[$this->dbGetQueryHash($query, $params)] = 0;
}
/**
* gets how often a query was called already
* @param string $query query string
* @return int count of times the query was executed
* @param string $query query string
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return int count of times the query was executed
*/
public function dbGetQueryCalled(string $query): int
public function dbGetQueryCalled(string $query, array $params = []): int
{
$query_hash = $this->dbGetQueryHash($query);
$query_hash = $this->dbGetQueryHash($query, $params);
if (!empty($this->query_called[$query_hash])) {
return $this->query_called[$query_hash];
} else {
@@ -2268,7 +2495,8 @@ class IO
/**
* prepares a query
* for INSERT INTO queries it is highly recommended to set the pk_name to avoid an additional
* for INSERT INTO queries it is highly recommended
* to set the pk_name to avoid an additional
* read from the database for the PK NAME
* @param string $stm_name statement name
* @param string $query queryt string to run
@@ -2432,7 +2660,15 @@ class IO
return false;
}
if ($this->db_debug) {
$this->__dbDebug('db', $this->__dbDebugPrepare($stm_name, $data), 'dbExecPrep', 'Q');
$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) {
@@ -2471,27 +2707,58 @@ class IO
// ***************************
/**
* executres the query async so other methods can be run during this
* for INSERT INTO queries it is highly recommended to set the pk_name
* to avoid an additional read from the database for the PK NAME
* executes the query async so other methods can be run at the same time
* Wrapper for dbExecParamsAsync
* NEEDS : dbCheckAsync
* @param string $query query to run
* @param string $pk_name optional primary key name, only used with
* insert for returning call
* @return bool true if async query was sent ok,
* false if error happened
* false on error
*/
public function dbExecAsync(string $query, string $pk_name = ''): bool
{
return $this->dbExecParamsAsync($query, [], $pk_name);
}
/**
* eexecutes the query async so other methods can be run at the same time
* Runs with db_send_query_params
* NEEDS : dbCheckAsync
*
* @param string $query query to run
* @param array<mixed> $params
* @param string $pk_name optional primary key name, only used with
* insert for returning call
* @return bool true if async query was sent ok,
* false on error
*/
public function dbExecParamsAsync(
string $query,
array $params = [],
string $pk_name = ''
): bool {
$this->__dbErrorReset();
// prepare and check if we can actually run the query
if (($query_hash = $this->__dbPrepareExec($query, $pk_name)) === false) {
if (
($query_hash = $this->__dbPrepareExec($query, $params, $pk_name)) === false
) {
// bail if no hash set
return false;
}
// checks if the params count given matches the expected count
if ($this->__dbCheckQueryParams($query, count($params)) === false) {
return false;
}
// ** actual db exec call
if ($params === []) {
$status = $this->db_functions->__dbSendQuery($this->query);
} else {
$status = $this->db_functions->__dbSendQueryParams($this->query, $params);
}
// run the async query, this just returns true or false
// the actually result is in dbCheckAsync
if (!$this->db_functions->__dbSendQuery($this->query)) {
if (!$status) {
// if failed, process here
$this->__dbError(40);
return false;
@@ -2503,6 +2770,42 @@ class IO
}
}
/**
* TODO write dbPrepareAsync
* Asnychronus prepare call
* NEEDS : dbCheckAsync
*
* @param string $stm_name
* @param string $query
* @param string $pk_name
* @return bool
*/
public function dbPrepareAsync(
string $stm_name,
string $query,
string $pk_name = ''
): bool {
$status = $this->db_functions->__dbSendPrepare($stm_name, $query);
return $status;
}
/**
* TODO write dbExecuteAsync
* Asynchronus execute call
* NEEDS : dbCheckAsync
*
* @param string $stm_name
* @param array<mixed> $data
* @return bool
*/
public function dbExecuteAsync(
string $stm_name,
array $data = []
): bool {
$status = $this->db_functions->__dbSendExecute($stm_name, $data);
return $status;
}
/**
* checks a previous async query and returns data if finished
* NEEDS : dbExecAsync
@@ -2953,6 +3256,7 @@ class IO
/**
* Return current database handler
*
* @return \PgSql\Connection|false|null
*/
public function dbGetDbh(): \PgSql\Connection|false|null
@@ -2963,16 +3267,25 @@ class IO
/**
* Returns hash for query
* Hash is used in all internal storage systems for return data
* @param string $query The query to create the hash from
* @return string Hash, as set by hash lpng
*
* @param string $query The query to create the hash from
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return string Hash, as set by hash long
*/
public function dbGetQueryHash(string $query): string
public function dbGetQueryHash(string $query, array $params = []): string
{
return Hash::__hashLong($query);
return Hash::__hashLong(
$query . (
$params !== [] ?
'#' . json_encode($params) : ''
)
);
}
/**
* Get current set query
*
* @return string Current set query string
*/
public function dbGetQuery(): string
@@ -2982,6 +3295,7 @@ class IO
/**
* Clear current query
*
* @return void
*/
public function dbResetQuery(): void
@@ -2989,6 +3303,26 @@ class IO
$this->query = '';
}
/**
* Get current set params
*
* @return array<mixed>
*/
public function dbGetParams(): array
{
return $this->params;
}
/**
* Rset current set params
*
* @return void
*/
public function dbResetParams(): void
{
$this->params = [];
}
// ***************************
// INTERNAL VARIABLES READ POST QUERY RUN
// ***************************
@@ -3031,12 +3365,14 @@ class IO
*
* Replacement for insert_id_ext array access before
*
* @param string|null $key
* @param integer|null $pos
* @return array<mixed>|string|int|null
* @param string|null $key Key to find in insert_id_arr
* @param integer|null $pos Multiple in array, which row to search in
* @return array<mixed>|string|int|null Return value, null for error/not found
*/
public function dbGetReturningExt(?string $key = null, ?int $pos = null): array|string|int|null
{
public function dbGetReturningExt(
?string $key = null,
?int $pos = null
): array|string|int|null {
// return as is if key is null
if ($key === null) {
if (count($this->insert_id_arr) == 1) {
@@ -3080,6 +3416,7 @@ class IO
/**
* Always returns the returning block as an array
*
* @return array<mixed> All returning data as array. even if one row only
*/
public function dbGetReturningArray(): array
@@ -3091,6 +3428,7 @@ class IO
* returns current number of rows that where
* affected by UPDATE/SELECT, etc
* null on empty
*
* @return int|null Number of rows or null if not set
*/
public function dbGetNumRows(): ?int
@@ -3100,6 +3438,7 @@ class IO
/**
* Number of fields in select query
*
* @return integer|null Number of fields in select or null if not set
*/
public function dbGetNumFields(): ?int
@@ -3109,13 +3448,26 @@ class IO
/**
* Return field names from query
* @return array<mixed> Field names as array
* Order based on order in query
*
* @return array<string> Field names as array
*/
public function dbGetFieldNames(): array
{
return $this->field_names;
}
/**
* Return field types from query
* Order based on order in query, use field names to get position
*
* @return array<string> Field types as array
*/
public function dbGetFieldTypes(): array
{
return $this->field_types;
}
/**
* Returns the value for given key in statement
* Will write error if statemen id does not exist
@@ -3129,8 +3481,10 @@ class IO
* Not ethat returnin_id also can return false
* but will not set an error entry
*/
public function dbGetPrepareCursorValue(string $stm_name, string $key): null|string|int|bool
{
public function dbGetPrepareCursorValue(
string $stm_name,
string $key
): null|string|int|bool {
// if no statement name
if (empty($stm_name)) {
$this->__dbError(

View File

@@ -42,6 +42,15 @@ interface SqlFunctions
*/
public function __dbSendQuery(string $query): bool;
/**
* Undocumented function
*
* @param string $query
* @param array<mixed> $params
* @return bool
*/
public function __dbSendQueryParams(string $query, array $params): bool;
/**
* Undocumented function
*
@@ -74,6 +83,24 @@ interface SqlFunctions
*/
public function __dbExecute(string $name, array $data): \PgSql\Result|false;
/**
* Undocumented function
*
* @param string $name
* @param string $query
* @return bool
*/
public function __dbSendPrepare(string $name, string $query): bool;
/**
* Undocumented function
*
* @param string $name
* @param array<mixed> $params
* @return bool
*/
public function __dbSendExecute(string $name, array $params): bool;
/**
* Undocumented function
*
@@ -99,6 +126,15 @@ interface SqlFunctions
*/
public function __dbFieldName(\PgSql\Result|false $cursor, int $i): string|false;
/**
* Undocumented function
*
* @param \PgSql\Result|false $cursor
* @param int $i
* @return string|false
*/
public function __dbFieldType(\PgSql\Result|false $cursor, int $i): string|false;
/**
* Undocumented function
*

View File

@@ -33,7 +33,11 @@
* pg_affected_rows (*)
* pg_fetch_array
* pg_query
* pg_query_params
* pg_send_query
* pg_send_query_params
* pg_send_prepare
* pg_send_execute
* pg_get_result
* pg_connection_busy
* pg_close
@@ -50,6 +54,7 @@ namespace CoreLibs\DB\SQL;
// below no ignore is needed if we want to use PgSql interface checks with PHP 8.0
// as main system. Currently all @var sets are written as object
/** @#phan-file-suppress PhanUndeclaredTypeProperty,PhanUndeclaredTypeParameter,PhanUndeclaredTypeReturnType */
/** @phan-file-suppress PhanTypeMismatchArgumentInternal, PhanTypeMismatchReturn */
class PgSQL implements Interface\SqlFunctions
{
@@ -93,8 +98,7 @@ class PgSQL implements Interface\SqlFunctions
}
/**
* Proposed
* wrapperf or pg_query_params for queries in the style of
* wrapper for pg_query_params for queries in the style of
* SELECT foo FROM bar WHERE foobar = $1
*
* @param string $query Query string with placeholders $1, ..
@@ -132,6 +136,22 @@ class PgSQL implements Interface\SqlFunctions
return $result ? true : false;
}
/**
* sends an async query to the server with params
*
* @param string $query Query string with placeholders $1, ..
* @param array<mixed> $params Matching parameters for each placerhold
* @return bool true/false Query sent successful status
*/
public function __dbSendQueryParams(string $query, array $params): bool
{
if (is_bool($this->dbh)) {
return false;
}
$result = pg_send_query_params($this->dbh, $query, $params);
return $result ? true : false;
}
/**
* wrapper for pg_get_result
*
@@ -208,6 +228,38 @@ class PgSQL implements Interface\SqlFunctions
return $result;
}
/**
* Asnyc send for a prepared statement
*
* @param string $name
* @param string $query
* @return bool
*/
public function __dbSendPrepare(string $name, string $query): bool
{
if (is_bool($this->dbh)) {
return false;
}
$result = pg_send_prepare($this->dbh, $name, $query);
return $result ? true : false;
}
/**
* Asnyc ssend for a prepared statement execution
*
* @param string $name
* @param array<mixed> $params
* @return bool
*/
public function __dbSendExecute(string $name, array $params): bool
{
if (is_bool($this->dbh)) {
return false;
}
$result = pg_send_execute($this->dbh, $name, $params);
return $result ? true : false;
}
/**
* wrapper for pg_num_rows
*
@@ -251,6 +303,21 @@ class PgSQL implements Interface\SqlFunctions
return pg_field_name($cursor, $i);
}
/**
* wrapper for pg_field_name
*
* @param \PgSql\Result|false $cursor cursor
* @param int $i field position
* @return string|false field type name or false
*/
public function __dbFieldType(\PgSql\Result|false $cursor, int $i): string|false
{
if (is_bool($cursor)) {
return false;
}
return pg_field_type($cursor, $i);
}
/**
* wrapper for pg_fetch_array
* if through/true false, use __dbResultType(true)

View File

@@ -251,22 +251,22 @@ class Logging
'debug',
$this->options['debug_all'] ??
// for user login, should be handled outside like globals
$_SESSION['DEBUG_ALL'] ??
$GLOBALS['DEBUG_ALL'] ??
$_SESSION['DEBUG_ALL'] ?? // DEPRECATED
$GLOBALS['DEBUG_ALL'] ?? // DEPRECATED
false
);
$this->setLogLevelAll(
'print',
$this->options['print_all'] ??
// for user login, should be handled outside like globals
$_SESSION['DEBUG_ALL'] ??
$GLOBALS['PRINT_ALL'] ??
$_SESSION['DEBUG_ALL'] ?? // DEPRECATED
$GLOBALS['PRINT_ALL'] ?? // DEPRECATED
false
);
$this->setLogLevelAll(
'echo',
$this->options['echo_all'] ??
$GLOBALS['ECHO_ALL'] ??
$GLOBALS['ECHO_ALL'] ?? // DEPRECATED
false
);
@@ -274,32 +274,32 @@ class Logging
// add file date is default on
$this->setGetLogPrintFileDate(
$this->options['print_file_date'] ??
$GLOBALS['LOG_PRINT_FILE_DATE'] ??
$GLOBALS['LOG_PRINT_FILE_DATE'] ?? // DEPRECATED
true
);
// all other logging file name flags are off
$this->setLogPer(
'level',
$this->options['per_level'] ??
$GLOBALS['LOG_PER_LEVEL'] ??
$GLOBALS['LOG_PER_LEVEL'] ?? // DEPRECATED
false
);
$this->setLogPer(
'class',
$this->options['per_class'] ??
$GLOBALS['LOG_PER_CLASS'] ??
$GLOBALS['LOG_PER_CLASS'] ?? // DEPRECATED
false
);
$this->setLogPer(
'page',
$this->options['per_page'] ??
$GLOBALS['LOG_PER_PAGE'] ??
$GLOBALS['LOG_PER_PAGE'] ?? // DEPRECATED
false
);
$this->setLogPer(
'run',
$this->options['per_run'] ??
$GLOBALS['LOG_PER_RUN'] ??
$GLOBALS['LOG_PER_RUN'] ?? // DEPRECATED
false
);
// set log per date

View File

@@ -21,6 +21,7 @@ class GetLocale
* @param string|null $encoding override encoding
* @param string|null $path override path
* @return array<string,string> locale, domain, encoding, path
* @deprecated use GetLocale::setLocaleSession(...) instead
*/
public static function setLocale(
?string $locale = null,
@@ -28,6 +29,10 @@ class GetLocale
?string $encoding = null,
?string $path = null
): array {
trigger_error(
'Use \CoreLibs\Language\GetLocale::setLocaleSession(...) instead',
E_USER_DEPRECATED
);
// locale must match at least basic rules
if (
empty($locale) ||
@@ -137,6 +142,113 @@ class GetLocale
'path' => $path,
];
}
/**
* NOTE: For getting the login info via login class use ->loginGetLocale()
*
* Set locale from session or from override parameters
* This is the prefered version to setLocale
* It usese the following SESSION VARIABLES
* DEFAULT_LOCALE
* DEFAULT_DOMAIN
* DEFAULT_CHARSET (should be set from DEFAULT_LOCALE)
* LOCALE_PATH
* in the return array, null set invalid information
*
* @param string $locale override locale
* @param string $domain override domain
* @param string $encoding override encoding
* @param string $path override path
* @return array<string,string> locale, domain, encoding, path
* @return array<string,string|null> Return list of set locale information
* @deprecated This version will be removed in a future version use ACL\Login->loginGetLocale() instead
*/
public static function setLocaleFromSession(
string $locale,
string $domain,
string $encoding,
string $path
): array {
// locale must match at least basic rules
if (
!empty($_SESSION['DEFAULT_LOCALE']) &&
preg_match("/^[-A-Za-z0-9_.@]+$/", $_SESSION['DEFAULT_LOCALE'])
) {
// parse from session (logged in)
$locale = $_SESSION['DEFAULT_LOCALE'];
} elseif (
empty($locale) ||
!preg_match("/^[-A-Za-z0-9_.@]+$/", $locale)
) {
$locale = null;
}
// if domain is set, must be alphanumeric, if not unset
if (
!empty($_SESSION['DEFAULT_DOMAIN']) &&
preg_match("/^\w+$/", $_SESSION['DEFAULT_DOMAIN'])
) {
$domain = $_SESSION['DEFAULT_DOMAIN'];
} elseif (
empty($domain) ||
!preg_match("/^\w+$/", $domain)
) {
$domain = null;
}
// check that override encoding matches locale encoding
// if locale encoding is set
preg_match('/(?:\\.(?P<charset>[-A-Za-z0-9_]+))/', $locale ?? '', $matches);
$locale_encoding = $matches['charset'] ?? null;
if (!empty($locale_encoding)) {
$encoding = strtoupper($locale_encoding);
} elseif (
!empty($_SESSION['DEFAULT_CHARSET']) &&
preg_match("/^[-A-Za-z0-9_]+$/", $_SESSION['DEFAULT_CHARSET'])
) {
$encoding = $_SESSION['DEFAULT_CHARSET'];
} elseif (
empty($encoding) ||
// not valid encoding
!preg_match("/^[-A-Za-z0-9_]+$/", $encoding)
) {
$encoding = null;
}
// path checks if set, if not valid path unset to default BASE path
if (
!empty($_SESSION['LOCALE_PATH']) &&
is_dir($_SESSION['LOCALE_PATH'])
) {
$path = $_SESSION['LOCALE_PATH'];
} elseif (
empty($path) ||
!is_dir($path)
) {
$path = null;
}
// extract lang & country from locale string, else set to en
if (
preg_match(
// lang
'/^(?P<lang>[a-z]{2,3})'
// country code
. '(?:_(?P<country>[A-Z]{2}))?/',
$locale ?? '',
$matches
)
) {
$lang = ($matches['lang'] ?? 'en')
// add country only if set
. (!empty($matches['country']) ? '_' . $matches['country'] : '');
} else {
$lang = null;
}
return [
'locale' => $locale,
'lang' => $lang,
'domain' => $domain,
'encoding' => $encoding,
'path' => $path,
];
}
}
// __END__

View File

@@ -32,12 +32,18 @@ use CoreLibs\Language\Core\GetTextReader;
class L10n
{
/** @var string the default fallback encoding if nothing is set */
public const DEFAULT_CHARSET = 'UTF-8';
/** @var string the current locale */
private $locale = '';
/** @var string the SET locale as WHERE the domain file is */
private $locale_set = '';
/** @var string the default selected/active domain */
private $domain = '';
/** @var string encoding, as from locale or set from outside */
private $override_encoding = self::DEFAULT_CHARSET;
/** @var string encoding set during the parse Locale */
private $encoding = '';
/** @var array<string,array<string,GetTextReader>> locale > domain = translator */
private $domains = [];
/** @var array<string,string> bound paths for domains */
@@ -71,15 +77,18 @@ class L10n
* if locale is not empty will load translation
* else getTranslator needs to be called
*
* @param string $locale language name, default empty string
* will return self instance
* @param string $domain override CONTENT_PATH . $encoding name for mo file
* @param string $path path, if empty fallback on default internal path
* @param string $locale language name, default empty string
* will return self instance
* @param string $domain override CONTENT_PATH . $encoding name for mo file
* @param string $path path, if empty fallback on default internal path
* @param string $encoding Optional encoding, should be set if locale has
* no encoding, defaults to UTF-8
*/
public function __construct(
string $locale = '',
string $domain = '',
string $path = ''
string $path = '',
string $encoding = ''
) {
// auto load language only if at least locale and domain is set
// New: path must be set too, or we fall through
@@ -103,7 +112,7 @@ class L10n
$path = $domain;
$domain = $_domain;
}
$this->getTranslator($locale, $domain, $path);
$this->getTranslator($locale, $domain, $path, $encoding);
}
}
@@ -137,13 +146,15 @@ class L10n
*
* @param string $locale language name, if not set, try previous set
* @param string $domain set name for mo file, if not set, try previous set
* @param string $path path, if not set try to get from paths array, else self
* @param string $path path, if not set try to get from paths array, else self
* @param string $override_encoding if locale does not env encoding set, use this one
* @return GetTextReader the main gettext reader object
*/
public function getTranslator(
string $locale = '',
string $domain = '',
string $path = ''
string $path = '',
string $override_encoding = '',
): GetTextReader {
// set local if not from parameter
if (empty($locale)) {
@@ -153,11 +164,16 @@ class L10n
if (empty($domain)) {
$domain = $this->domain;
}
// override encoding for unset
if (!empty($override_encoding)) {
$this->override_encoding = $override_encoding;
}
// store old settings
$old_mofile = $this->mofile;
$old_lang = $this->locale;
$old_lang_set = $this->locale_set;
$old_domain = $this->domain;
$old_encoding = $this->encoding;
$old_base_locale_path = $this->base_locale_path;
$old_base_content_path = $this->base_content_path;
@@ -186,6 +202,7 @@ class L10n
// now we loop over lang compositions to get the base path
// then we check
$locales = $this->listLocales($locale);
$encoding = $this->getEncodingFromLocale($locale);
foreach ($locales as $_locale) {
$this->base_content_path = $_locale . DIRECTORY_SEPARATOR
. 'LC_MESSAGES' . DIRECTORY_SEPARATOR;
@@ -202,6 +219,7 @@ class L10n
if (is_readable($this->mofile)) {
// locale and domain current wanted
$this->locale = $locale;
$this->encoding = $encoding;
$this->domain = $domain;
// set empty domains path with current locale
if (empty($this->domains[$locale])) {
@@ -225,6 +243,7 @@ class L10n
$this->mofile = $old_mofile;
$this->locale = $old_lang;
$this->locale_set = $old_lang_set;
$this->encoding = $old_encoding;
$this->domain = $old_domain;
$this->base_locale_path = $old_base_locale_path;
$this->base_content_path = $old_base_content_path;
@@ -258,21 +277,36 @@ class L10n
return $this->l10n;
}
/**
* Extract encoding from Locale, or fallback to override one if not set
*
* @param string $locale
* @return string
*/
private function getEncodingFromLocale(string $locale): string
{
// extract charset from $locale
// if not set get override encoding
preg_match('/(?:\\.(?P<charset>[-A-Za-z0-9_]+))/', $locale, $matches);
return $matches['charset'] ?? $this->override_encoding;
}
/**
* Get the local as array same to the GetLocale::setLocale return
* This does not set from outside, but only what is set in the l10n class
*
* @return array{locale: string, lang: string|null, domain: string, encoding: string|null, path: string}
* @return array{locale: string, lang: string, lang_short: string, domain: string, encoding: string, path: string}
*/
public function getLocaleAsArray(): array
{
$locale = L10n::parseLocale($this->getLocale());
return [
'locale' => $this->getLocale(),
'lang' => $locale['lang']
'lang' => ($locale['lang'] ?? '')
. (!empty($locale['country']) ? '_' . $locale['country'] : ''),
'lang_short' => $locale['lang'] ?? '',
'domain' => $this->getDomain(),
'encoding' => $locale['charset'],
'encoding' => $this->getEncoding(),
'path' => $this->getBaseLocalePath(),
];
}
@@ -515,6 +549,37 @@ class L10n
return $this->locale_set;
}
/**
* Set override encoding
*
* @param string $encoding
* @return void
*/
public function setOverrideEncoding(string $encoding): void
{
$this->override_encoding = $encoding;
}
/**
* return current set override encoding
*
* @return string
*/
public function getOverrideEncoding(): string
{
return $this->override_encoding;
}
/**
* Current set encoding
*
* @return string
*/
public function getEncoding(): string
{
return $this->encoding;
}
/**
* get current set language
*

View File

@@ -277,6 +277,8 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
private $acl_admin = 0;
/** @var array<mixed> */
public $security_level;
/** @var array<string,mixed> Login ACL */
public $login_acl = [];
// layout publics
/** @var int */
public $table_width;
@@ -308,7 +310,8 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
* @param array<mixed> $db_config db config array, mandatory
* @param \CoreLibs\Debug\Logging $log Logging class
* @param \CoreLibs\Language\L10n $l10n l10n language class
* @param array<string,string> $locale locale array from ::setLocale
* @param array<string,mixed> $login_acl Login ACL array,
* at least base/admin should be set
* @param array<mixed>|null $table_arrays Override table array data
* instead of try to load from
* include file
@@ -318,7 +321,7 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
array $db_config,
\CoreLibs\Debug\Logging $log,
\CoreLibs\Language\L10n $l10n,
array $locale,
array $login_acl,
?array $table_arrays = null,
) {
// init logger if not set
@@ -327,19 +330,19 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
$this->log->setLogPer('class', false);
// init the language class
$this->l = $l10n;
// legacy lang vars set
// parse and read, legacy stuff
$locale = $this->l->getLocaleAsArray();
$this->encoding = $locale['encoding'];
$this->lang = $locale['lang'];
// get first part from lang
$this->lang_short = explode('_', $locale['lang'])[0];
$this->domain = $this->l->getDomain();
$this->lang_dir = $this->l->getBaseLocalePath();
$this->lang_short = $locale['lang_short'];
$this->domain = $locale['domain'];
$this->lang_dir = $locale['path'];
// load config array
// get table array definitions for current page name
$this->login_acl = $login_acl;
// security settings
$this->base_acl_level = (int)$_SESSION['BASE_ACL_LEVEL'];
$this->acl_admin = (int)$_SESSION['ADMIN'];
$this->base_acl_level = $this->login_acl['base'] ?? 0;
$this->acl_admin = $this->login_acl['admin'] ?? 0;
// replace any non valid variable names and set my page name
$this->my_page_name = str_replace(
@@ -377,7 +380,6 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
$this->base_acl_level,
$this->acl_admin
);
// $this->log->debug('SESSION FORM', 'sessin: ' . $this->log->prAr($_SESSION));
// here should be a check if the config_array is correct ...
if (isset($config_array['show_fields']) && is_array($config_array['show_fields'])) {
$this->field_array = $config_array['show_fields'];

View File

@@ -160,13 +160,11 @@ class SmartyExtend extends \Smarty
* also registers the getvar caller plugin
*
* @param \CoreLibs\Language\L10n $l10n l10n language class
* @param array<string,string> $locale locale data read from setLocale
* @param string|null $cache_id
* @param string|null $compile_id
*/
public function __construct(
\CoreLibs\Language\L10n $l10n,
array $locale,
?string $cache_id = null,
?string $compile_id = null
) {
@@ -192,13 +190,12 @@ class SmartyExtend extends \Smarty
// iinit lang
$this->l10n = $l10n;
// parse and read, legacy stuff
$locale = $this->l10n->getLocaleAsArray();
$this->encoding = $locale['encoding'];
$this->lang = $locale['lang'];
// get first part from lang
$this->lang_short = explode('_', $locale['lang'])[0];
$this->domain = $this->l10n->getDomain();
$this->locale_set = $this->l10n->getLocaleSet();
$this->lang_dir = $this->l10n->getBaseLocalePath();
$this->lang_short = $locale['lang_short'];
$this->domain = $locale['domain'];
$this->lang_dir = $locale['path'];
// opt load functions so we can use legacy init for smarty run perhaps
\CoreLibs\Language\L10n::loadFunctions();
@@ -455,92 +452,95 @@ class SmartyExtend extends \Smarty
* wrapper call for setSmartyVars
* this is for frontend type and will not set any only admin needed variables
*
* @param string|null $compile_dir BASE . TEMPLATES_C
* @param string|null $cache_dir BASE . CACHE
* @param string|null $set_js JS
* @param string|null $set_css CSS
* @param string|null $set_font FONT
* @param string|null $set_default_encoding DEFAULT_ENCODING
* @param string|null $set_g_title G_TITLE
* @param string|null $set_stylesheet STYLESHEET
* @param string|null $set_javascript JAVASCRIPT
* @param \CoreLibs\Admin\Backend|null $cms Optinal Admin Backend for
* smarty variables merge
* @param array<string,string> $options list with the following value:
* compile_dir :BASE . TEMPLATES_C
* cache_dir :BASE . CACHE
* js :JS
* css :CSS
* font :FONT
* default_encoding :DEFAULT_ENCODING
* g_title :G_TITLE
* stylesheet :STYLESHEET
* javascript :JAVASCRIPT
* @param array<string,mixed> $smarty_data array of three keys
* that hold smarty set strings
* HEADER, DATA, DEBUG_DATA
* @return void
*/
public function setSmartyVarsFrontend(
?string $compile_dir = null,
?string $cache_dir = null,
?string $set_js = null,
?string $set_css = null,
?string $set_font = null,
?string $set_default_encoding = null,
?string $set_g_title = null,
?string $set_stylesheet = null,
?string $set_javascript = null,
?\CoreLibs\Admin\Backend $cms = null
array $options,
array $smarty_data
): void {
$this->setSmartyVars(
false,
$cms,
$compile_dir,
$cache_dir,
$set_js,
$set_css,
$set_font,
$set_default_encoding,
$set_g_title,
$smarty_data,
null,
$options['compile_dir'] ?? null,
$options['cache_dir'] ?? null,
$options['js'] ?? null,
$options['css'] ?? null,
$options['font'] ?? null,
$options['default_encoding'] ?? null,
$options['g_title'] ?? null,
null,
null,
null,
$set_stylesheet,
$set_javascript
null,
null,
$options['stylesheet'] ?? null,
$options['javascript'] ?? null
);
}
/**
* wrapper call for setSmartyVars
* this is only for admin interface and will set additional variables
* @param string|null $compile_dir BASE . TEMPLATES_C
* @param string|null $cache_dir BASE . CACHE
* @param string|null $set_js JS
* @param string|null $set_css CSS
* @param string|null $set_font FONT
* @param string|null $set_default_encoding DEFAULT_ENCODING
* @param string|null $set_g_title G_TITLE
* @param string|null $set_admin_stylesheet ADMIN_STYLESHEET
* @param string|null $set_admin_javascript ADMIN_JAVASCRIPT
* @param string|null $set_page_width PAGE_WIDTH
* @param array<string,string> $options list with the following value:
* compile_dir :BASE . TEMPLATES_C
* cache_dir :BASE . CACHE
* js :JS
* css :CSS
* font :FONT
* default_encoding :DEFAULT_ENCODING
* g_title :G_TITLE
* admin_stylesheet :ADMIN_STYLESHEET
* admin_javascript :ADMIN_JAVASCRIPT
* page_width :PAGE_WIDTH
* content_path :CONTENT_PATH
* user_name :_SESSION['USER_NAME']
* @param \CoreLibs\Admin\Backend|null $cms Optinal Admin Backend for
* smarty variables merge
* @return void
*/
public function setSmartyVarsAdmin(
?string $compile_dir = null,
?string $cache_dir = null,
?string $set_js = null,
?string $set_css = null,
?string $set_font = null,
?string $set_default_encoding = null,
?string $set_g_title = null,
?string $set_admin_stylesheet = null,
?string $set_admin_javascript = null,
?string $set_page_width = null,
array $options,
?\CoreLibs\Admin\Backend $cms = null
): void {
// if we have cms data, check for array blocks and build
$smarty_data = [];
if ($cms !== null) {
$smarty_data = [
'HEADER' => $cms->HEADER,
'DATA' => $cms->DATA,
'DEBUG_DATA' => $cms->DEBUG_DATA
];
}
$this->setSmartyVars(
true,
$smarty_data,
$cms,
$compile_dir,
$cache_dir,
$set_js,
$set_css,
$set_font,
$set_g_title,
$set_default_encoding,
$set_admin_stylesheet,
$set_admin_javascript,
$set_page_width,
$options['compile_dir'] ?? null,
$options['cache_dir'] ?? null,
$options['js'] ?? null,
$options['css'] ?? null,
$options['font'] ?? null,
$options['g_title'] ?? null,
$options['default_encoding'] ?? null,
$options['admin_stylesheet'] ?? null,
$options['admin_javascript'] ?? null,
$options['page_width'] ?? null,
$options['content_path'] ?? null,
$options['user_name'] ?? null,
null,
null
);
@@ -552,6 +552,7 @@ class SmartyExtend extends \Smarty
*
* @param bool $admin_call default false
* will set admin only variables
* @param array<string,mixed> $smarty_data smarty data to merge
* @param \CoreLibs\Admin\Backend|null $cms Optinal Admin Backend for
* smarty variables merge
* @param string|null $compile_dir BASE . TEMPLATES_C
@@ -564,12 +565,15 @@ class SmartyExtend extends \Smarty
* @param string|null $set_admin_stylesheet ADMIN_STYLESHEET
* @param string|null $set_admin_javascript ADMIN_JAVASCRIPT
* @param string|null $set_page_width PAGE_WIDTH
* @param string|null $set_content_path CONTENT_PATH (only if $cms set and admin)
* @param string|null $set_user_name _SESSION['USER_NAME']
* @param string|null $set_stylesheet STYLESHEET
* @param string|null $set_javascript JAVASCRIPT
* @return void
*/
private function setSmartyVars(
bool $admin_call,
array $smarty_data = [],
?\CoreLibs\Admin\Backend $cms = null,
?string $compile_dir = null,
?string $cache_dir = null,
@@ -581,8 +585,10 @@ class SmartyExtend extends \Smarty
?string $set_admin_stylesheet = null,
?string $set_admin_javascript = null,
?string $set_page_width = null,
?string $set_content_path = null,
?string $set_user_name = null,
?string $set_stylesheet = null,
?string $set_javascript = null
?string $set_javascript = null,
): void {
// trigger deprecation
if (
@@ -597,7 +603,8 @@ class SmartyExtend extends \Smarty
$admin_call === true && (
$set_admin_stylesheet === null ||
$set_admin_javascript === null ||
$set_page_width === null
$set_page_width === null ||
$set_user_name === null
)
) ||
(
@@ -605,6 +612,9 @@ class SmartyExtend extends \Smarty
$set_stylesheet === null ||
$set_javascript === null
)
) ||
(
$admin_call === true && $cms !== null && $set_content_path === null
)
) {
/** @deprecated setSmartyVars call without parameters */
@@ -624,24 +634,12 @@ class SmartyExtend extends \Smarty
$set_admin_stylesheet = $set_admin_stylesheet ?? ADMIN_STYLESHEET;
$set_admin_javascript = $set_admin_javascript ?? ADMIN_JAVASCRIPT;
$set_page_width = $set_page_width ?? PAGE_WIDTH;
$set_content_path = $set_content_path ?? CONTENT_PATH;
$set_stylesheet = $set_stylesheet ?? STYLESHEET;
$set_javascript = $set_javascript ?? JAVASCRIPT;
// depreacte call globals cms on null 4mcs
if (
$cms === null &&
isset($GLOBALS['cms'])
) {
/** @deprecated setSmartyVars globals cms is deprecated */
trigger_error(
'Calling setSmartyVars without cms parameter when needed is deprecated',
E_USER_DEPRECATED
);
}
// this is ugly
$cms = $cms ?? $GLOBALS['cms'] ?? null;
if ($cms instanceof \CoreLibs\Admin\Backend) {
$this->mergeCmsSmartyVars($cms);
}
$set_user_name = $set_user_name ?? $_SESSION['USER_NAME'] ?? '';
// merge additional smarty data
$this->mergeCmsSmartyVars($smarty_data);
// trigger flags
$this->HEADER['USE_PROTOTYPE'] = $this->USE_PROTOTYPE;
@@ -683,12 +681,27 @@ class SmartyExtend extends \Smarty
$this->DATA['FORM_ACTION'] = $this->FORM_ACTION;
// special for admin
if ($admin_call === true) {
// depreacte call globals cms on null 4mcs
if (
$cms === null &&
isset($GLOBALS['cms'])
) {
/** @deprecated setSmartyVars globals cms is deprecated */
trigger_error(
'Calling setSmartyVars without cms parameter when needed is deprecated',
E_USER_DEPRECATED
);
}
// this is ugly
$cms = $cms ?? $GLOBALS['cms'] ?? null;
// set ACL extra show
if ($cms instanceof \CoreLibs\Admin\Backend) {
$this->DATA['show_ea_extra'] = $cms->acl['show_ea_extra'] ?? false;
$this->DATA['ADMIN'] = $cms->acl['admin'] ?? 0;
// top menu
$this->DATA['nav_menu'] = $cms->adbTopMenu();
$this->DATA['nav_menu'] = $cms->adbTopMenu(
$set_content_path
);
$this->DATA['nav_menu_count'] = count($this->DATA['nav_menu']);
// messages = ['msg' =>, 'class' => 'error/warning/...']
$this->DATA['messages'] = $cms->messages;
@@ -734,7 +747,7 @@ class SmartyExtend extends \Smarty
$this->DATA['JS_FLATPICKR'] = $this->JS_FLATPICKR;
$this->DATA['JS_FILE_UPLOADER'] = $this->JS_FILE_UPLOADER;
// user name
$this->DATA['USER_NAME'] = !empty($_SESSION['USER_NAME']) ? $_SESSION['USER_NAME'] : '';
$this->DATA['USER_NAME'] = $set_user_name;
// the template part to include into the body
$this->DATA['TEMPLATE_NAME'] = $this->TEMPLATE_NAME;
$this->DATA['CONTENT_INCLUDE'] = $this->CONTENT_INCLUDE;
@@ -748,18 +761,18 @@ class SmartyExtend extends \Smarty
/**
* merge outside object HEADER/DATA/DEBUG_DATA vars into the smarty class
*
* @param \CoreLibs\Admin\Backend $cms object that has header/data/debug_data
* @param array<string,mixed> $smarty_data array that has header/data/debug_data
* @return void
*/
public function mergeCmsSmartyVars(\CoreLibs\Admin\Backend $cms): void
public function mergeCmsSmartyVars(array $smarty_data): void
{
// array merge HEADER, DATA, DEBUG DATA
foreach (['HEADER', 'DATA', 'DEBUG_DATA'] as $ext_smarty) {
if (
isset($cms->{$ext_smarty}) &&
is_array($cms->{$ext_smarty})
isset($smarty_data[$ext_smarty]) &&
is_array($smarty_data[$ext_smarty])
) {
$this->{$ext_smarty} = array_merge($this->{$ext_smarty}, $cms->{$ext_smarty});
$this->{$ext_smarty} = array_merge($this->{$ext_smarty}, $smarty_data[$ext_smarty]);
}
}
}

View File

@@ -7,6 +7,14 @@ namespace tests;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
/*
Not yet covered tests:
- loginGetLocale
- loginGetHeaderColor
- loginGetPages
- loginGetEuid
*/
/**
* Test class for ACL\Login
* @coversDefaultClass \CoreLibs\ACL\Login
@@ -1114,6 +1122,7 @@ final class CoreLibsACLLoginTest extends TestCase
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
@@ -1796,6 +1805,7 @@ final class CoreLibsACLLoginTest extends TestCase
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
@@ -1909,6 +1919,7 @@ final class CoreLibsACLLoginTest extends TestCase
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
@@ -1996,6 +2007,7 @@ final class CoreLibsACLLoginTest extends TestCase
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
@@ -2091,6 +2103,7 @@ final class CoreLibsACLLoginTest extends TestCase
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,13 @@ use PHPUnit\Framework\TestCase;
*/
final class CoreLibsLanguageGetLocaleTest extends TestCase
{
public const SITE_ENCODING = 'UTF-8';
public const SITE_LOCALE = 'en_US.UTF-8';
public const SITE_DOMAIN = 'admin';
public const LOCALE_PATH = __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR;
/**
* set all constant variables that must be set before call
*
@@ -22,7 +29,7 @@ final class CoreLibsLanguageGetLocaleTest extends TestCase
public static function setUpBeforeClass(): void
{
// default web page encoding setting
if (!defined('DEFAULT_ENCODING')) {
/* if (!defined('DEFAULT_ENCODING')) {
define('DEFAULT_ENCODING', 'UTF-8');
}
if (!defined('DEFAULT_LOCALE')) {
@@ -35,9 +42,9 @@ final class CoreLibsLanguageGetLocaleTest extends TestCase
}
if (!defined('SITE_LOCALE')) {
define('SITE_LOCALE', DEFAULT_LOCALE);
}
} */
// just set
if (!defined('BASE')) {
/* if (!defined('BASE')) {
define('BASE', str_replace('/configs', '', __DIR__) . DIRECTORY_SEPARATOR);
}
if (!defined('INCLUDES')) {
@@ -51,7 +58,7 @@ final class CoreLibsLanguageGetLocaleTest extends TestCase
}
if (!defined('CONTENT_PATH')) {
define('CONTENT_PATH', 'frontend' . DIRECTORY_SEPARATOR);
}
} */
// array session
$_SESSION = [];
global $_SESSION;
@@ -62,7 +69,7 @@ final class CoreLibsLanguageGetLocaleTest extends TestCase
*
* @return array<mixed>
*/
public function setLocaleProvider(): array
/* public function setLocaleProvider(): array
{
return [
// 0: locale
@@ -233,7 +240,7 @@ final class CoreLibsLanguageGetLocaleTest extends TestCase
// TODO invalid params (bad path) (no override)
// TODO param calls, but with override set
];
}
} */
/**
* Undocumented function
@@ -252,7 +259,7 @@ final class CoreLibsLanguageGetLocaleTest extends TestCase
* @param string|null $deprecation_message
* @return void
*/
public function testsetLocale(
/* public function testsetLocale(
?string $language,
?string $domain,
?string $encoding,
@@ -347,6 +354,214 @@ final class CoreLibsLanguageGetLocaleTest extends TestCase
// unset all vars
$_SESSION = [];
unset($GLOBALS['OVERRIDE_LANG']);
} */
/**
* all the test data
*
* @return array<mixed>
*/
public function setLocaleFromSessionProvider(): array
{
return [
// 0: locale
// 1: domain
// 2: encoding
// 3: path
// 4: SESSION: DEFAULT_LOCALE
// 5: SESSION: DEFAULT_CHARSET
// 5: SESSION: DEFAULT_DOMAIN
// 6: SESSION: LOCALE_PATH
// 6: expected array
// 7: deprecation message
'all session vars set' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'ja_JP.UTF-8', 'UTF-8', 'admin', __DIR__ . '/locale_other/',
// return array
[
'locale' => 'ja_JP.UTF-8',
'lang' => 'ja_JP',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// param lang and domain (no override)
'no session set, only parameters' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
null, null, null, null,
// return array
[
'locale' => 'en_US.UTF-8',
'lang' => 'en_US',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// special parse session check for locales
'all session vars set, short lang' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'ja', 'UTF-8', 'admin', __DIR__ . '/locale_other/',
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// lang with modifier
// param lang and domain (no override)
'long locale, domain, encoding params, no sessions' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'de_CH.UTF-8@euro', 'admin', 'UTF-8', __DIR__ . '/includes/locale/',
// return array
[
'locale' => 'de_CH.UTF-8@euro',
'lang' => 'de_CH',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// missing session values check
// special parse session check for locales
'session missing encoding, set from parameters' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'ja', null, 'admin', __DIR__ . '/locale_other/',
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// null return check for invalid entries
'no session set, only parameters, all invalid' => [
// lang, domain, encoding, path
'###', '&&&&', '$$$$', 'foo_bar_path',
// SESSION SETTINGS: locale, charset, domain, path
null, null, null, null,
// return array
[
'locale' => null,
'lang' => null,
'domain' => null,
'encoding' => null,
'path' => null,
],
],
// invalid session names, fall backup
'all session vars are invalid, fallback' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'###', '&&&&', '$$$$', 'foo_bar_path',
// return array
[
'locale' => 'en_US.UTF-8',
'lang' => 'en_US',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
];
}
/**
* Undocumented function
*
* @covers ::setLocale
* @dataProvider setLocaleFromSessionProvider
* @testdox lang settings lang $language, domain $domain, encoding $encoding, path $path; session lang: $SESSION_DEFAULT_LOCALE, session char: $SESSION_DEFAULT_CHARSET [$_dataName]
*
* @param string| $language
* @param string| $domain
* @param string| $encoding
* @param string| $path
* @param string|null $SESSION_DEFAULT_LOCALE
* @param string|null $SESSION_DEFAULT_CHARSET
* @param string|null $SESSION_DEFAULT_DOMAIN
* @param string|null $SESSION_LOCALE_PATH
* @param array<mixed> $expected
* @return void
*/
public function testsetLocaleFromSession(
string $language,
string $domain,
string $encoding,
string $path,
?string $SESSION_DEFAULT_LOCALE,
?string $SESSION_DEFAULT_CHARSET,
?string $SESSION_DEFAULT_DOMAIN,
?string $SESSION_LOCALE_PATH,
array $expected,
): void {
$return_lang_settings = [];
global $_SESSION;
// set override
if ($SESSION_DEFAULT_LOCALE !== null) {
$_SESSION['DEFAULT_LOCALE'] = $SESSION_DEFAULT_LOCALE;
}
if ($SESSION_DEFAULT_CHARSET !== null) {
$_SESSION['DEFAULT_CHARSET'] = $SESSION_DEFAULT_CHARSET;
}
if ($SESSION_DEFAULT_DOMAIN !== null) {
$_SESSION['DEFAULT_DOMAIN'] = $SESSION_DEFAULT_DOMAIN;
}
if ($SESSION_LOCALE_PATH !== null) {
$_SESSION['LOCALE_PATH'] = $SESSION_LOCALE_PATH;
}
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocaleFromSession(
$language,
$domain,
$encoding,
$path
);
// print "RETURN: " . print_r($return_lang_settings, true) . "\n";
foreach (
[
'locale', 'lang', 'domain', 'encoding', 'path'
] as $key
) {
$value = $expected[$key];
if (
!empty($value) &&
strpos($value, "/") === 0
) {
// this is regex
$this->assertMatchesRegularExpression(
$value,
$return_lang_settings[$key] ?? '',
'assert regex failed for ' . $key
);
} else {
// assert equal
$this->assertEquals(
$value,
$return_lang_settings[$key],
'assert equal failed for ' . $key
);
}
}
// unset all vars
$_SESSION = [];
unset($GLOBALS['OVERRIDE_LANG']);
}
}

View File

@@ -84,94 +84,141 @@ final class CoreLibsLanguageL10nTest extends TestCase
{
return [
// 0: locale
// 1: domain
// 2: encoding
// 1: encoding
// 2: domain
// 3: path
// 4: locale expected
// 5: locale set expected
// 6: lang expected
// 7: encoding expected
// 8: domain exepcted
// 9: context (null for none)
// 10: test string in
// 11: test translated
// 12: deprecation message (until removed)
// 7: lang short expected
// 8: encoding expected
// 9: domain exepcted
// 10: context (null for none)
// 11: test string in
// 12: test translated
// 13: deprecation message (until removed)
// new style load
'gettext load en' => [
'en_US.UTF-8',
'UTF-8',
'frontend',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
//
// 4, 5, 6, 7, 8, 9
'en_US.UTF-8',
'en_US',
'en_US',
'en',
'UTF-8',
'frontend',
// 10
null,
// 11, 12
'Original',
'Translated frontend en_US',
// 13
null,
],
'gettext load en' => [
'en_US.UTF-8',
'UTF-8',
'frontend',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
//
'en_US.UTF-8',
'en_US',
'en_US',
'en',
'UTF-8',
'frontend',
//
'context',
//
'Original',
'Original context frontend en_US',
//
null,
],
'gettext load ja' => [
'ja_JP.UTF-8',
'UTF-8',
'admin',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
//
'ja_JP.UTF-8',
'ja_JP',
'ja_JP',
'ja',
'UTF-8',
'admin',
//
null,
//
'Original',
'Translated admin ja_JP',
//
null,
],
// load short locale with different encoding
'gettext load short ja no encoding' => [
'ja',
'SJIS',
'admin',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
//
'ja',
'ja',
'ja',
'ja',
'SJIS',
'admin',
//
null,
//
'Original',
'Translated admin ja_JP',
//
null,
],
// mixed path and domain [DEPRECATED]
'mixed path and domain [DEPRECATED]' => [
'en_US.UTF-8',
'UTF-8',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
'frontend',
//
'en_US.UTF-8',
'en_US',
'en_US',
'en',
'UTF-8',
'frontend',
//
'context',
//
'Original',
'Original context frontend en_US',
//
'L10n constructor parameter switch is no longer supported. domain is 2nd, path is 3rd parameter'
],
// unset path
'unset path with locale and domain [DEPRECATED]' => [
'ja_JP.UTF-8',
'UTF-8',
'admin',
null,
//
'ja_JP.UTF-8',
'ja_JP',
'ja_JP',
'ja',
'UTF-8',
'admin',
//
null,
//
'Original',
'Translated admin ja_JP',
//
'Empty path parameter is no longer allowed if locale and domain are set',
],
// null set
@@ -179,15 +226,20 @@ final class CoreLibsLanguageL10nTest extends TestCase
'',
'',
'',
'',
//
'',
'',
'',
'',
'', // unset on empty call
'',
//
null,
//
'Original',
'Original',
//
null,
]
];
@@ -201,11 +253,13 @@ final class CoreLibsLanguageL10nTest extends TestCase
* @testdox check l10n init with Locale $locale, Path $path, Domain $domain, Legacy: $legacy with $context [$_dataName]
*
* @param string|null $locale
* @param string|null $encoding
* @param string|null $domain
* @param string|null $path
* @param string $locale_expected
* @param string $locale_set_expected
* @param string $lang_expected
* @param string $lang_short_expected
* @param string $encoding_expected
* @param string $domain_expected
* @param string|null $context
@@ -216,11 +270,13 @@ final class CoreLibsLanguageL10nTest extends TestCase
*/
public function testL10nObject(
?string $locale,
?string $encoding,
?string $domain,
?string $path,
string $locale_expected,
string $locale_set_expected,
string $lang_expected,
string $lang_short_expected,
string $encoding_expected,
string $domain_expected,
?string $context,
@@ -241,16 +297,18 @@ final class CoreLibsLanguageL10nTest extends TestCase
if ($locale === null) {
$l10n = new \CoreLibs\Language\L10n();
} elseif ($domain === null) {
// same as if locale is null
// deprecated, locale + domain must be set, handled like empty calls
$l10n = new \CoreLibs\Language\L10n($locale);
} elseif ($path === null) {
// deprecated, path must be set
// deprecated, path must be set, will thow DEPRECATION error, handled like empty
$l10n = new \CoreLibs\Language\L10n($locale, $domain);
} else {
} elseif ($encoding === null) {
// if encoding not found will be UTF-8
$l10n = new \CoreLibs\Language\L10n($locale, $domain, $path);
} else {
$l10n = new \CoreLibs\Language\L10n($locale, $domain, $path, $encoding);
}
restore_error_handler();
// print "LOC: " . $locale . ", " . $l10n->getLocale() . ", " . $locale_expected . "\n";
// print "MO: " . $l10n->getMoFile() . "\n";
$this->assertEquals(
$locale_expected,
@@ -286,6 +344,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
[
'locale' => $locale_expected,
'lang' => $lang_expected,
'lang_short' => $lang_short_expected,
'domain' => $domain_expected,
'encoding' => $encoding_expected,
'path' => $path

View File

@@ -0,0 +1 @@
ja_JP