diff --git a/src/ACL/Login.php b/src/ACL/Login.php index b7e490e..d41dd33 100644 --- a/src/ACL/Login.php +++ b/src/ACL/Login.php @@ -196,7 +196,12 @@ class Login /** @var array options */ private $options = []; /** @var array locale options: locale, domain, encoding (opt), path */ - private $locale = []; + private $locale = [ + 'locale' => '', + 'domain' => '', + 'encoding' => '', + 'path' => '', + ]; /** @var \CoreLibs\Debug\Logging logger */ public $log; @@ -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[-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 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 + */ + 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__ diff --git a/src/Admin/Backend.php b/src/Admin/Backend.php index 3f03a46..2ea4804 100644 --- a/src/Admin/Backend.php +++ b/src/Admin/Backend.php @@ -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 $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(); diff --git a/src/Admin/EditBase.php b/src/Admin/EditBase.php index 30f71c9..3933d53 100644 --- a/src/Admin/EditBase.php +++ b/src/Admin/EditBase.php @@ -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 $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 $locale locale array from ::setLocale, - * null auto set + * @param \CoreLibs\ACL\Login $login login class for ACL settings + * @param array $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; diff --git a/src/DB/IO.php b/src/DB/IO.php index e593d22..9f878e9 100644 --- a/src/DB/IO.php +++ b/src/DB/IO.php @@ -405,9 +405,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 ); diff --git a/src/Debug/Logging.php b/src/Debug/Logging.php index bae2136..de4e710 100644 --- a/src/Debug/Logging.php +++ b/src/Debug/Logging.php @@ -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 diff --git a/src/Language/GetLocale.php b/src/Language/GetLocale.php index f10dc4d..1f7842f 100644 --- a/src/Language/GetLocale.php +++ b/src/Language/GetLocale.php @@ -21,6 +21,7 @@ class GetLocale * @param string|null $encoding override encoding * @param string|null $path override path * @return array 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 locale, domain, encoding, path + * @return array 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[-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[a-z]{2,3})' + // country code + . '(?:_(?P[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__ diff --git a/src/Language/L10n.php b/src/Language/L10n.php index 09c2cae..75db228 100644 --- a/src/Language/L10n.php +++ b/src/Language/L10n.php @@ -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> locale > domain = translator */ private $domains = []; /** @var array 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[-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 * diff --git a/src/Output/Form/Generate.php b/src/Output/Form/Generate.php index 9c33aa1..65555bc 100644 --- a/src/Output/Form/Generate.php +++ b/src/Output/Form/Generate.php @@ -277,6 +277,8 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO private $acl_admin = 0; /** @var array */ public $security_level; + /** @var array 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 $db_config db config array, mandatory * @param \CoreLibs\Debug\Logging $log Logging class * @param \CoreLibs\Language\L10n $l10n l10n language class - * @param array $locale locale array from ::setLocale + * @param array $login_acl Login ACL array, + * at least base/admin should be set * @param array|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']; diff --git a/src/Template/SmartyExtend.php b/src/Template/SmartyExtend.php index 6e87d9e..8fcbfda 100644 --- a/src/Template/SmartyExtend.php +++ b/src/Template/SmartyExtend.php @@ -160,13 +160,11 @@ class SmartyExtend extends \Smarty * also registers the getvar caller plugin * * @param \CoreLibs\Language\L10n $l10n l10n language class - * @param array $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(); @@ -566,6 +563,7 @@ class SmartyExtend extends \Smarty * @param string|null $set_page_width PAGE_WIDTH * @param string|null $set_stylesheet STYLESHEET * @param string|null $set_javascript JAVASCRIPT + * @param string|null $set_user_name _SESSION['USER_NAME'] * @return void */ private function setSmartyVars( @@ -582,7 +580,8 @@ class SmartyExtend extends \Smarty ?string $set_admin_javascript = null, ?string $set_page_width = null, ?string $set_stylesheet = null, - ?string $set_javascript = null + ?string $set_javascript = null, + ?string $set_user_name = null, ): void { // trigger deprecation if ( @@ -597,7 +596,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 ) ) || ( @@ -626,6 +626,7 @@ class SmartyExtend extends \Smarty $set_page_width = $set_page_width ?? PAGE_WIDTH; $set_stylesheet = $set_stylesheet ?? STYLESHEET; $set_javascript = $set_javascript ?? JAVASCRIPT; + $set_user_name = $set_user_name ?? $_SESSION['USER_NAME'] ?? ''; // depreacte call globals cms on null 4mcs if ( $cms === null && @@ -734,7 +735,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; diff --git a/test/phpunit/ACL/CoreLibsACLLoginTest.php b/test/phpunit/ACL/CoreLibsACLLoginTest.php index 361e8ed..bd55d22 100644 --- a/test/phpunit/ACL/CoreLibsACLLoginTest.php +++ b/test/phpunit/ACL/CoreLibsACLLoginTest.php @@ -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, diff --git a/test/phpunit/Language/CoreLibsLanguageGetLocaleTest.php b/test/phpunit/Language/CoreLibsLanguageGetLocaleTest.php index f8c9c45..fa05341 100644 --- a/test/phpunit/Language/CoreLibsLanguageGetLocaleTest.php +++ b/test/phpunit/Language/CoreLibsLanguageGetLocaleTest.php @@ -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 */ - 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 + */ + 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 $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']); } } diff --git a/test/phpunit/Language/CoreLibsLanguageL10nTest.php b/test/phpunit/Language/CoreLibsLanguageL10nTest.php index 453e188..ca1e088 100644 --- a/test/phpunit/Language/CoreLibsLanguageL10nTest.php +++ b/test/phpunit/Language/CoreLibsLanguageL10nTest.php @@ -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 diff --git a/test/phpunit/Language/includes/locale/ja b/test/phpunit/Language/includes/locale/ja new file mode 120000 index 0000000..5f64dd2 --- /dev/null +++ b/test/phpunit/Language/includes/locale/ja @@ -0,0 +1 @@ +ja_JP \ No newline at end of file