Make core libs set their default config values in App

This permit to homogenize the method to store it and permit an access to 
all config default values.
Futhermore, core libs init() methods now does not handle parameters: all 
are taken from config.
This commit is contained in:
Benjamin Renard 2023-03-01 16:22:11 +01:00
parent 1e59f1b815
commit 83f1445799
Signed by: bn8
GPG key ID: 3E2E1CE1907115BC
14 changed files with 326 additions and 269 deletions

View file

@ -39,13 +39,30 @@ class App {
exit(1); exit(1);
} }
// Set config default values
App :: set_defaults(
array(
'overwrite_config_files' => array(),
'upload_tmp_directory' => null,
'upload_max_filesize' => null,
'sentry.enabled' => true,
'log.enabled' => true,
'session.enabled' => true,
'templates.enabled' => true,
'url.enabled' => true,
'mail.enabled' => true,
'i18n.enabled' => true,
'cli.enabled' => true,
)
);
// Load overwrite configuration file // Load overwrite configuration file
foreach (self :: get('overwrite_config_files', array(), 'array') as $file) { foreach (self :: get('overwrite_config_files', null, 'array') as $file) {
$file = Config::replace_variables($file); $file = Config::replace_variables($file);
if (is_file($file)) Config::load($file, true); if (is_file($file)) Config::load($file, true);
} }
if (self :: get('sentry.enabled', true, 'bool')) if (self :: get('sentry.enabled', null, 'bool'))
SentryIntegration :: init(); SentryIntegration :: init();
$sentry_transaction = new SentryTransaction(); $sentry_transaction = new SentryTransaction();
$sentry_span = new SentrySpan('app.init', 'Application initialization'); $sentry_span = new SentrySpan('app.init', 'Application initialization');
@ -60,13 +77,13 @@ class App {
Config :: ini_set('post_max_size', strval(self::get('upload_max_filesize', null, 'int') * 1.1)); Config :: ini_set('post_max_size', strval(self::get('upload_max_filesize', null, 'int') * 1.1));
} }
if (self :: get('log.enabled', true, 'bool')) if (self :: get('log.enabled', null, 'bool'))
Log::init(); Log::init();
if (self :: get('session.enabled', true, 'bool')) if (self :: get('session.enabled', null, 'bool'))
Session::init(); Session::init();
if (self :: get('templates.enabled', true, 'bool')) if (self :: get('templates.enabled', null, 'bool'))
Tpl :: init(); Tpl :: init();
if (self :: get('url.enabled', true, 'bool')) { if (self :: get('url.enabled', null, 'bool')) {
Url::init(); Url::init();
Url :: add_url_handler(null, array('EesyPHP\\App', 'handle_homepage')); Url :: add_url_handler(null, array('EesyPHP\\App', 'handle_homepage'));
} }
@ -74,11 +91,11 @@ class App {
Auth :: init(); Auth :: init();
Url :: add_url_handler('#^logout$#', array('EesyPHP\\App', 'handle_logout'), null, false); Url :: add_url_handler('#^logout$#', array('EesyPHP\\App', 'handle_logout'), null, false);
} }
if (self :: get('mail.enabled', true, 'bool')) if (self :: get('mail.enabled', null, 'bool'))
Email :: init(); Email :: init();
if (self :: get('i18n.enabled', true, 'bool')) if (self :: get('i18n.enabled', null, 'bool'))
I18n::init(); I18n::init();
if (self :: get('cli.enabled', true, 'bool')) if (self :: get('cli.enabled', null, 'bool'))
Cli::init(); Cli::init();
$sentry_span->finish(); $sentry_span->finish();
} }
@ -175,6 +192,32 @@ class App {
return Config::set($key, $value); return Config::set($key, $value);
} }
/**
* Set a specific option default value
*
* @param string $key The configuration variable key
* @param mixed $value The configuration variable default value
* @return boolean
**/
public static function set_default($key, $value) {
return Config::set("default.$key", $value, self :: $options);
}
/**
* Set a specific options default value
*
* @param array<string,mixed> $values Associative array of configuration variables name and
* default values
* @return boolean
**/
public static function set_defaults($values) {
$error = false;
foreach($values as $key => $value)
if (!self :: set_default($key, $value))
$error = true;
return !$error;
}
/** /**
* Retreive application root directory path * Retreive application root directory path
* @return string|null * @return string|null

View file

@ -36,7 +36,17 @@ class Auth {
* @return void * @return void
*/ */
public static function init() { public static function init() {
if (!self :: enabled()) return; // Set config default values
App :: set_default(
'auth',
array(
'methods' => array(),
'backends' => array(),
'enabled' => self :: enabled(),
'allow_multiple_match' => null,
'allow_multiple_match_with_valid_password' => null,
)
);
self :: $methods = array(); self :: $methods = array();
foreach(App::get('auth.methods', array(), 'array') as $method) { foreach(App::get('auth.methods', array(), 'array') as $method) {
if (!$method || !is_string($method)) { if (!$method || !is_string($method)) {

View file

@ -25,6 +25,20 @@ class Cas extends Method {
// In phpstan context, do not initialize // In phpstan context, do not initialize
if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__')) if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__'))
return true; return true;
// Set config default values
App :: set_default(
'auth.cas',
array(
'host' => null,
'port' => 443,
'context' => '/idp/cas',
'version' => '2.0',
'logout' => true,
'fake_authenticated_user' => null,
'debug_log_file' => null,
'ca_cert_certificate_path' => null,
)
);
self :: $fake_authenticated_user = App :: get( self :: $fake_authenticated_user = App :: get(
'auth.cas.fake_authenticated_user', null, 'string'); 'auth.cas.fake_authenticated_user', null, 'string');
if (self :: $fake_authenticated_user) return true; if (self :: $fake_authenticated_user) return true;
@ -37,7 +51,7 @@ class Cas extends Method {
return false; return false;
} }
$cas_version = App :: get('auth.cas.version', '2.0', 'string'); $cas_version = App :: get('auth.cas.version', null, 'string');
$supported_cas_versions = phpCAS::getSupportedProtocols(); $supported_cas_versions = phpCAS::getSupportedProtocols();
if (!array_key_exists($cas_version, $supported_cas_versions)) { if (!array_key_exists($cas_version, $supported_cas_versions)) {
Log :: error( Log :: error(
@ -51,8 +65,8 @@ class Cas extends Method {
phpCAS::client( phpCAS::client(
$cas_version, $cas_version,
App :: get('auth.cas.host'), App :: get('auth.cas.host'),
App :: get('auth.cas.port', 443, 'int'), App :: get('auth.cas.port', null, 'int'),
App :: get('auth.cas.context', '/idp/cas', 'string'), App :: get('auth.cas.context', null, 'string'),
Url :: get_absolute_url("/") Url :: get_absolute_url("/")
); );
if (App :: get('auth.cas.ca_cert_certificate_path')) if (App :: get('auth.cas.ca_cert_certificate_path'))
@ -109,7 +123,7 @@ class Cas extends Method {
* @return void * @return void
*/ */
public static function logout() { public static function logout() {
if (App :: get('auth.cas.logout', true, 'bool') && !self :: $fake_authenticated_user) { if (App :: get('auth.cas.logout', null, 'bool') && !self :: $fake_authenticated_user) {
if (App :: get('auth.cas.logout_url')) { if (App :: get('auth.cas.logout_url')) {
Url :: redirect(App :: get('auth.cas.logout_url')); Url :: redirect(App :: get('auth.cas.logout_url'));
exit(); exit();

View file

@ -69,14 +69,28 @@ class Db extends Backend {
* @return boolean * @return boolean
*/ */
public static function init() { public static function init() {
// Set config default values
App :: set_default(
'auth.db',
array(
'dsn' => null,
'user' => null,
'password' => null,
'options' => array(),
'users_table' => 'users',
'username_field' => 'username',
'password_field' => 'password',
'exposed_fields' => array('name', 'mail'),
)
);
self :: $dsn = App::get('auth.db.dsn', null, 'string'); self :: $dsn = App::get('auth.db.dsn', null, 'string');
self :: $user = App::get('auth.db.user', null, 'string'); self :: $user = App::get('auth.db.user', null, 'string');
self :: $password = App::get('auth.db.password', null, 'string'); self :: $password = App::get('auth.db.password', null, 'string');
self :: $options = App::get('auth.db.options', array(), 'array'); self :: $options = App::get('auth.db.options', null, 'array');
self :: $users_table = App::get('auth.db.users_table', 'users', 'string'); self :: $users_table = App::get('auth.db.users_table', null, 'string');
self :: $username_field = App::get('auth.db.username_field', 'username', 'string'); self :: $username_field = App::get('auth.db.username_field', null, 'string');
self :: $password_field = App::get('auth.db.password_field', 'password', 'string'); self :: $password_field = App::get('auth.db.password_field', null, 'string');
self :: $exposed_fields = App::get('auth.db.exposed_fields', array('name', 'mail'), 'array'); self :: $exposed_fields = App::get('auth.db.exposed_fields', null, 'array');
return boolval(self :: $dsn); return boolval(self :: $dsn);
} }

View file

@ -16,6 +16,13 @@ class Form extends Method {
* @return boolean * @return boolean
*/ */
public static function init() { public static function init() {
// Set config default values
App :: set_default(
'auth.login_form',
array(
'display_other_methods' => array(),
)
);
Url :: add_url_handler('#^login$#', array('EesyPHP\\Auth\\Form', 'handle_login'), null, false); Url :: add_url_handler('#^login$#', array('EesyPHP\\Auth\\Form', 'handle_login'), null, false);
Hook :: register('logged_in', array('\\EesyPHP\\Auth\\Form', 'logged_in_hook')); Hook :: register('logged_in', array('\\EesyPHP\\Auth\\Form', 'logged_in_hook'));
return true; return true;

View file

@ -29,9 +29,18 @@ class Http extends Method {
* @return boolean * @return boolean
*/ */
public static function init() { public static function init() {
self :: $method = App::get('auth.http.method', 'PHP_AUTH', 'string'); // Set default config values
App :: set_default(
'auth.http',
array(
'method' => 'PHP_AUTH',
'realm' => _('Authentication required'),
'trust_without_password_challenge' => false,
)
);
self :: $method = App::get('auth.http.method', null, 'string');
self :: $realm = App::get( self :: $realm = App::get(
'auth.http.realm', _('Authentication required'), 'string'); 'auth.http.realm', null, 'string');
return true; return true;
} }
@ -91,7 +100,7 @@ class Http extends Method {
return null; return null;
} }
if (App :: get('auth.http.trust_without_password_challenge', false, 'bool')) if (App :: get('auth.http.trust_without_password_challenge', null, 'bool'))
$user = Auth :: get_user($auth_data['username']); $user = Auth :: get_user($auth_data['username']);
else else
$user = Auth :: authenticate($auth_data['username'], $auth_data['password']); $user = Auth :: authenticate($auth_data['username'], $auth_data['password']);

View file

@ -29,10 +29,24 @@ class Ldap extends Backend {
private static $connection = null; private static $connection = null;
/** /**
* Default LDAP user attributes configuration * Initialize
* @var array<string,array> * @return bool
*/ */
private static $default_user_attributes = array( public static function init() {
// Set default config values
App :: set_default(
'auth.ldap',
array(
'host' => array(),
'port' => null,
'basedn' => null,
'binddn' => null,
'bindpw' => null,
'starttls' => false,
'user_filter_by_uid' => 'uid=[username]',
'user_basedn' => null,
'bind_with_username' => false,
'user_attributes' => array(
'login' => array( 'login' => array(
'ldap_name' => 'uid', 'ldap_name' => 'uid',
'type' => 'string', 'type' => 'string',
@ -51,15 +65,12 @@ class Ldap extends Backend {
'multivalued' => false, 'multivalued' => false,
'default' => null, 'default' => null,
), ),
),
'netldap2_path' => 'Net/LDAP2.php',
)
); );
/**
* Initialize
* @return bool
*/
public static function init() {
if (!class_exists('Net_LDAP2')) { if (!class_exists('Net_LDAP2')) {
$path = App::get('auth.ldap.netldap2_path', 'Net/LDAP2.php', 'string'); $path = App::get('auth.ldap.netldap2_path', null, 'string');
if (!@include($path)) { if (!@include($path)) {
Log::error('Fail to load Net_LDAP2 (%s)', $path); Log::error('Fail to load Net_LDAP2 (%s)', $path);
return false; return false;
@ -73,11 +84,11 @@ class Ldap extends Backend {
} }
self :: $ldap_config = array ( self :: $ldap_config = array (
'host' => implode(' ', App :: get('auth.ldap.host', array(), 'array')), 'host' => implode(' ', App :: get('auth.ldap.host', null, 'array')),
'basedn' => App :: get('auth.ldap.basedn', null, 'string'), 'basedn' => App :: get('auth.ldap.basedn', null, 'string'),
'binddn' => App :: get('auth.ldap.bind_dn', null, 'string'), 'binddn' => App :: get('auth.ldap.bind_dn', null, 'string'),
'bindpw' => App :: get('auth.ldap.bind_password', null, 'string'), 'bindpw' => App :: get('auth.ldap.bind_password', null, 'string'),
'starttls' => App :: get('starttls', false, 'bool'), 'starttls' => App :: get('starttls', null, 'bool'),
); );
if ($port = App :: get('auth.ldap.port', null, 'int')) if ($port = App :: get('auth.ldap.port', null, 'int'))
self :: $ldap_config['port'] = $port; self :: $ldap_config['port'] = $port;
@ -202,7 +213,7 @@ class Ldap extends Backend {
* @return \EesyPHP\Auth\User|null|false The user object if found, null it not, false in case of error * @return \EesyPHP\Auth\User|null|false The user object if found, null it not, false in case of error
*/ */
public static function get_user($username) { public static function get_user($username) {
$attrs = App::get('auth.ldap.user_attributes', self :: $default_user_attributes, 'array'); $attrs = App::get('auth.ldap.user_attributes', null, 'array');
$attrs_names = array(); $attrs_names = array();
foreach($attrs as $attr => $attr_config) { foreach($attrs as $attr => $attr_config) {
$name = Config::get("ldap_name", $attr, 'string', false, $attr_config); $name = Config::get("ldap_name", $attr, 'string', false, $attr_config);
@ -215,7 +226,7 @@ class Ldap extends Backend {
$users = self :: search( $users = self :: search(
str_replace( str_replace(
'[username]', Net_LDAP2_Filter::escape($username), '[username]', Net_LDAP2_Filter::escape($username),
App::get('auth.ldap.user_filter_by_uid', 'uid=[username]', 'string') App::get('auth.ldap.user_filter_by_uid', null, 'string')
), ),
$attrs_names, $attrs_names,
App::get('auth.ldap.user_basedn', null, 'string') App::get('auth.ldap.user_basedn', null, 'string')
@ -261,7 +272,7 @@ class Ldap extends Backend {
public static function check_password($user, $password) { public static function check_password($user, $password) {
$config = self :: $ldap_config; $config = self :: $ldap_config;
$config['binddn'] = ( $config['binddn'] = (
App::get('auth.ldap.bind_with_username', false, 'bool')? App::get('auth.ldap.bind_with_username', null, 'bool')?
$user->username: $user->username:
$user->dn $user->dn
); );

View file

@ -11,89 +11,44 @@ use finfo;
class Email { class Email {
/** /**
* Default sender * Initialization
* @var string|null; * @return void
*/ */
protected static $sender = null; public static function init() {
// Set config default values
App :: set_default(
'email',
array(
// Default sender
'sender' => null,
/** /**
* Sending method : * Sending method :
* - mail : use PHP mail function * - mail : use PHP mail function
* - sendmail : use sendmail system command * - sendmail : use sendmail system command
* - smtp : use an SMTP server (PHP PEAR Net_SMTP required) * - smtp : use an SMTP server (PHP PEAR Net_SMTP required)
* @var string
*/ */
protected static $send_method = 'mail'; 'send_method' => null,
/** /**
* Sending parameters * Sending parameters
* @see http://pear.php.net/manual/en/package.mail.mail.factory.php * @see http://pear.php.net/manual/en/package.mail.mail.factory.php
* @var array|null
*/ */
protected static $send_params = null; 'send_params' => array(),
/** // Catch all sent email recipient
* Catch all sent email recipient 'catch_all' => null,
* @var string|array<string>|null
*/
protected static $catch_all = null;
/** // Default headers to add on all sent emails
* Default headers to add on all sent emails 'headers' => array(),
* @var array<string>
*/
protected static $headers = array();
/** // PHP PEAR Mail lib path
* PHP PEAR Mail lib path 'php_mail_path' => 'Mail.php',
* @var string
*/
protected static $php_mail_path = 'Mail.php';
/** // PHP PEAR Mail_mime lib path
* PHP PEAR Mail lib path 'php_mail_mime_path' => 'Mail/mime.php',
* @var string )
*/ );
protected static $php_mail_mime_path = 'Mail/mime.php';
/**
* Initialization
* @param string|null $php_mail_path PHP PEAR Mail lib path (optional, default: from
* email.php_mail_path config key if set, 'Mail.php' otherwise)
* @param string|null $php_mail_mime_path PHP PEAR Mail lib path (optional, default: from
* email.php_mail_mime_path config key if set, 'Mail/mime.php' otherwise)
* @return void
*/
public static function init($sender=null, $send_method=null, $send_params=null, $catch_all=null,
$headers=null, $php_mail_path=null, $php_mail_mime_path=null) {
if (is_null($sender))
$sender = App::get('email.sender', null, 'string');
if ($sender) self :: $sender = $sender;
if (is_null($send_method))
$send_method = App::get('email.send_method', null, 'string');
if ($send_method) self :: $send_method = $send_method;
if (is_null($send_params))
$send_params = App::get('email.send_params', null, 'array');
if ($send_params) self :: $send_params = $send_params;
if (is_null($catch_all))
$catch_all = App::get('email.catch_all');
if ($catch_all) self :: $catch_all = $catch_all;
if (is_null($headers))
$headers = App::get('email.headers', null, 'array');
if ($headers) self :: $headers = $headers;
if (is_null($php_mail_path))
$php_mail_path = App::get('email.php_mail_path', null, 'string');
if ($php_mail_path) self :: $php_mail_path = $php_mail_path;
if (is_null($php_mail_mime_path))
$php_mail_mime_path = App::get('email.php_mail_mime_path', null, 'string');
if ($php_mail_mime_path) self :: $php_mail_mime_path = $php_mail_mime_path;
} }
@ -116,24 +71,29 @@ class Email {
public static function send($from, $to, $subject, $msg, $html=false, $attachments=null, public static function send($from, $to, $subject, $msg, $html=false, $attachments=null,
$headers=null, $encoding=null, $eol=null) { $headers=null, $encoding=null, $eol=null) {
if (!class_exists('Mail')) if (!class_exists('Mail'))
require_once(self :: $php_mail_path); require_once(App :: get('php_mail_path', null, 'string'));
if (!class_exists('Mail_mime')) if (!class_exists('Mail_mime'))
require_once(self :: $php_mail_mime_path); require_once(App :: get('php_mail_mime_path', null, 'string'));
$mail_obj = Mail::factory(self :: $send_method, self :: $send_params); $mail_obj = Mail::factory(
App :: get('email.send_method', null, 'string'),
App :: get('email.send_params', null, 'array')
);
if (!$headers) $headers = array(); if (!$headers) $headers = array();
$headers = array_merge($headers, self :: $headers); $headers = array_merge($headers, App :: get('email.headers', null, 'array'));
Log :: trace( Log :: trace(
'Mail catch all: %s', 'Mail catch all: %s',
self :: $catch_all? App :: get('email.catch_all')?
vardump(self :: $catch_all):'not set' vardump(App :: get('email.catch_all')):'not set'
); );
if (self :: $catch_all) { if (App :: get('email.catch_all')) {
Log :: debug( Log :: debug(
'Mail catch to %s', 'Mail catch to %s',
is_array(self :: $catch_all)?implode(',', self :: $catch_all):self :: $catch_all is_array(App :: get('email.catch_all'))?
implode(',', App :: get('email.catch_all')):
App :: get('email.catch_all')
); );
$msg .= sprintf( $msg .= sprintf(
( (
@ -144,8 +104,9 @@ class Email {
(is_array($to)?implode(',', $to):$to)); (is_array($to)?implode(',', $to):$to));
$headers["X-Orig-To"] = $to; $headers["X-Orig-To"] = $to;
$to = ( $to = (
is_array(self :: $catch_all)? is_array(App :: get('email.catch_all'))?
implode(',', self :: $catch_all):self :: $catch_all implode(',', App :: get('email.catch_all')):
App :: get('email.catch_all')
); );
} }
@ -159,7 +120,7 @@ class Email {
unset($headers['From']); unset($headers['From']);
} }
elseif (!$from) { elseif (!$from) {
$from = self :: $sender; $from = App::get('email.sender');
} }
$headers["To"] = $to; $headers["To"] = $to;
@ -170,7 +131,7 @@ class Email {
foreach(array_keys($headers) as $header) { foreach(array_keys($headers) as $header) {
if(in_array(strtoupper($header), array('BCC', 'CC'))) { if(in_array(strtoupper($header), array('BCC', 'CC'))) {
if (self :: $catch_all) { if (App :: get('email.catch_all')) {
Log :: debug("Mail catched: remove $header header"); Log :: debug("Mail catched: remove $header header");
$msg .= sprintf( $msg .= sprintf(
( (

View file

@ -35,25 +35,21 @@ class I18n {
* Detect best translation language and configure the translation * Detect best translation language and configure the translation
* system. * system.
* *
* @param string|null $root_path The root directory path of translation files
* (optional, default: from i18n.root_directory config key if set,
* '${root_directory_path}/locales' otherwise)
* @param string|null $default_locale The default locale
* (optional, default: from i18n.default_locale config key if set,
* 'en_US.UTF8' otherwise)
* @return void * @return void
*/ */
public static function init($root_path=null, $default_locale=null) { public static function init() {
if (is_null($root_path)) // Set config default values
self :: $root_path = App::get( App :: set_default(
'i18n.root_directory', '${root_directory_path}/locales', 'string'); 'i18n',
if (!is_null($root_path)) array(
self :: $root_path = $root_path; 'root_directory' => '${root_directory_path}/locales',
'default_locale' => null,
)
);
if (is_null($default_locale)) self :: $root_path = App::get(
'i18n.root_directory', null, 'string');
$default_locale = App::get('i18n.default_locale', null, 'string'); $default_locale = App::get('i18n.default_locale', null, 'string');
if (!is_null($default_locale))
self :: $default_locale = $default_locale;
if (!class_exists('Locale')) { if (!class_exists('Locale')) {
Log :: error('Locale PHP class does not exist. May be php-intl is not installed?'); Log :: error('Locale PHP class does not exist. May be php-intl is not installed?');

View file

@ -38,12 +38,6 @@ class Log {
'FATAL' => 5, 'FATAL' => 5,
); );
/*
* Default log level
* @var string
*/
protected static $default_level = 'WARNING';
/* /*
* Current log level * Current log level
* @var string|null * @var string|null
@ -63,42 +57,46 @@ class Log {
/** /**
* Initialization * Initialization
* @param string $filepath The log file path
* (optional, default: from log.file_path or log.cli_file_path is set)
* @param string|null $level The log level
* (optional, default: from log.level config key if set, otherwise,
* see self :: $default_level)
* @param int|null $php_errors_levels PHP errors level as expected by set_error_handler()
* (optional, default: from log.php_errors_levels if set, E_ALL & ~E_STRICT
* if level is TRACE or DEBUG, and E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
* otherwise)
* @return void * @return void
*/ */
public static function init($filepath=null, $level=null, $php_errors_levels=null) { public static function init() {
if ($filepath) // Set config default values
self :: $filepath = $filepath; App :: set_default(
elseif (php_sapi_name() == 'cli') 'log',
array(
'level' => 'WARNING',
'file_path' => null,
'cli_file_path' => '${log.file_path}',
'default_locale' => null,
'error_log_fallback' => true,
'php_errors_levels' => array(), // Depend of effective log level, see below
)
);
self :: $filepath = App::get( self :: $filepath = App::get(
'log.cli_logfile_path', App::get('log.cli_file_path')); php_sapi_name() == 'cli'?'log.cli_logfile_path':'log.file_path'
else );
self :: $filepath = App::get('log.file_path');
// PHP error_log() fallback // PHP error_log() fallback
self :: $error_log_fallback = App::get('log.error_log_fallback', true, 'bool'); self :: $error_log_fallback = App::get('log.error_log_fallback', null, 'bool');
// Set log level: // Set log level:
// Note: in Phpstan context, force FATAL level // Note: in Phpstan context, force FATAL level
if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__')) if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__'))
self :: set_level('FATAL'); self :: set_level('FATAL');
else else
self :: set_level($level?$level:App::get('log.level')); self :: set_level(App::get('log.level', null, 'string'));
App :: set_default(
'log.php_errors_levels',
in_array(self :: $level, array('DEBUG', 'TRACE'))?
array('E_ALL', '~E_STRICT'):
array('E_ALL', '~E_STRICT', '~E_NOTICE', '~E_DEPRECATED')
);
// Log PHP errors // Log PHP errors
if (!is_null($php_errors_levels)) { $levels = App::get('log.php_errors_levels', array(), 'array');
self :: $php_errors_levels = $php_errors_levels; if ($levels) {
} self :: $php_errors_levels = E_ALL;
elseif ($levels = App::get('log.php_errors_levels', array(), 'array')) {
$code = 'self :: $php_errors_levels = '; $code = 'self :: $php_errors_levels = ';
while($level = array_shift($levels)) { while($level = array_shift($levels)) {
if (!is_string($level)) continue; if (!is_string($level)) continue;
@ -125,14 +123,8 @@ class Log {
} }
$code .= ";"; $code .= ";";
eval($code); eval($code);
}
elseif (in_array(self :: $level, array('DEBUG', 'TRACE'))) {
self :: $php_errors_levels = E_ALL & ~E_STRICT;
}
else {
self :: $php_errors_levels = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED;
}
set_error_handler(array('EesyPHP\\Log', 'on_php_error'), self :: $php_errors_levels); set_error_handler(array('EesyPHP\\Log', 'on_php_error'), self :: $php_errors_levels);
}
// Log uncatched exceptions // Log uncatched exceptions
set_exception_handler(array('EesyPHP\\Log', 'exception')); set_exception_handler(array('EesyPHP\\Log', 'exception'));
@ -162,7 +154,13 @@ class Log {
public static function log($level, $message, ...$extra_args) { public static function log($level, $message, ...$extra_args) {
global $argv; global $argv;
if (!array_key_exists($level, self :: $levels)) $level = self :: $default_level; if (!array_key_exists($level, self :: $levels)) {
self :: warning(
"Invalid log level specified logging the message %s, use 'WARNING':\n%s",
$message, self :: get_debug_backtrace_context()
);
$level = 'WARNING';
}
if (self :: $levels[$level] < self :: $levels[self :: $level]) return true; if (self :: $levels[$level] < self :: $levels[self :: $level]) return true;
if(self :: $filepath && is_null(self :: $file_fd)) { if(self :: $filepath && is_null(self :: $file_fd)) {
self :: $file_fd = fopen(self :: $filepath, 'a'); self :: $file_fd = fopen(self :: $filepath, 'a');
@ -337,13 +335,13 @@ class Log {
public static function set_level($level=null) { public static function set_level($level=null) {
// Set default log level (if not defined or invalid) // Set default log level (if not defined or invalid)
if (is_null($level)) { if (is_null($level)) {
self :: $level = self :: $default_level; self :: $level = App::get_default('log.level', null, 'string');
} }
elseif (!array_key_exists($level, self :: $levels)) { elseif (!array_key_exists($level, self :: $levels)) {
self :: $level = self :: $default_level; self :: $level = App::get_default('log.level', null, 'string');
self :: warning( self :: warning(
"Invalid log level value found in configuration (%s). ". "Invalid log level value found in configuration (%s). ".
"Set as default (%s).", vardump($level), self :: $default_level); "Set as default (%s).", vardump($level), self :: $level);
} }
else { else {
self :: $level = $level; self :: $level = $level;

View file

@ -18,35 +18,31 @@ class SentryIntegration {
* @see https://www.php.net/manual/fr/errorfunc.constants.php * @see https://www.php.net/manual/fr/errorfunc.constants.php
* @var array<int> * @var array<int>
*/ */
protected static $php_error_types = array( protected static $php_error_types;
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
E_RECOVERABLE_ERROR,E_DEPRECATED,
);
/** /**
* Initialization * Initialization
* @param string|null $dsn Sentry DSN
* (optional, default: from sentry.dsn config key if set, null otherwise)
* @param float|null $traces_sample_rate Sentry traces sample rate
* (optional, default: from sentry.traces_sample_rate config key if set,
* 0.2 otherwise)
* @param array<int>|null $php_error_types Types of PHP error to log in Sentry
* (optional, default: from sentry.php_error_types config key if set,
* otherwise, see self::$php_error_types)
* @return void * @return void
*/ */
public static function init($dsn=null, $traces_sample_rate=null, public static function init() {
$php_error_types=null) {
// In phpstan context, do not initialize // In phpstan context, do not initialize
if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__')) if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__'))
return; return;
\Sentry\init([ // Set config default values
'dsn' => $dsn?$dsn:App::get('sentry.dsn'), App :: set_default(
'traces_sample_rate' => ( 'sentry',
$traces_sample_rate? array(
$traces_sample_rate: 'dsn' => null,
App::get('sentry.traces_sample_rate', 0.2, 'float') 'traces_sample_rate' => 0.2,
'php_error_types' => array(
'E_ERROR', 'E_PARSE', 'E_CORE_ERROR', 'E_COMPILE_ERROR', 'E_USER_ERROR',
'E_RECOVERABLE_ERROR', 'E_DEPRECATED',
), ),
)
);
\Sentry\init([
'dsn' => App::get('sentry.dsn'),
'traces_sample_rate' => App::get('sentry.traces_sample_rate', null, 'float'),
]); ]);
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void { \Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
@ -56,12 +52,8 @@ class SentryIntegration {
]); ]);
}); });
if (!is_array($php_error_types))
$php_error_types = App::get(
'sentry.php_error_types', self :: $php_error_types, 'array'
);
self :: $php_error_types = array(); self :: $php_error_types = array();
foreach($php_error_types as $php_error_type) { foreach(App::get('sentry.php_error_types', null, 'array') as $php_error_type) {
if (is_string($php_error_type) && defined($php_error_type)) if (is_string($php_error_type) && defined($php_error_type))
$php_error_type = constant($php_error_type); $php_error_type = constant($php_error_type);
if (!is_int($php_error_type)) continue; if (!is_int($php_error_type)) continue;

View file

@ -11,30 +11,30 @@ class Session {
* Session max duration (in seconds, default: 12h) * Session max duration (in seconds, default: 12h)
* @var int * @var int
*/ */
protected static $max_duration = 12 * 60 * 60; protected static $max_duration;
/** /**
* Initialization * Initialization
* @param int|null $max_duration Session max duration in second
* (optional, default: from session.max_duration config key if set, 12h otherwise)
* @param int|null $timeout Session inactivity timeout in second
* (optional, default: from session.timeout config key if set, no timeout otherwise)
* @return void * @return void
*/ */
public static function init($max_duration=null, $timeout=null) { public static function init() {
// In CLI or Phpstan context, do not initialize // In CLI or Phpstan context, do not initialize
if ( if (
php_sapi_name() == "cli" php_sapi_name() == "cli"
|| (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__')) || (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__'))
) )
return; return;
// Set config default values
App :: set_default(
'session',
array(
'max_duration' => 43200, // 12h
'timeout' => null,
)
);
// Define session max duration // Define session max duration
if (is_null($max_duration)) self :: $max_duration = App::get('session.max_duration', null, 'int');
$max_duration = App::get('session.max_duration', null, 'int');
if (is_int($max_duration))
self :: $max_duration = $max_duration;
Config :: ini_set('session.gc_maxlifetime', strval(self :: $max_duration)); Config :: ini_set('session.gc_maxlifetime', strval(self :: $max_duration));
Config :: ini_set('session.cookie_lifetime', strval(self :: $max_duration)); Config :: ini_set('session.cookie_lifetime', strval(self :: $max_duration));
@ -47,9 +47,8 @@ class Session {
} }
// Handle session timeout // Handle session timeout
if (is_null($timeout))
$timeout = App::get('session.timeout', null, 'int'); $timeout = App::get('session.timeout', null, 'int');
if (is_int($timeout) && $timeout) { if ($timeout) {
if (!isset($_SESSION['session_last_access'])) { if (!isset($_SESSION['session_last_access'])) {
Log :: debug('Set initial session last access'); Log :: debug('Set initial session last access');
$_SESSION['session_last_access'] = time(); $_SESSION['session_last_access'] = time();

View file

@ -33,12 +33,6 @@ class Tpl {
*/ */
public static $templates_directories = array(); public static $templates_directories = array();
/**
* Smarty cache templates directory path
* @var string
*/
public static $templates_c_dir;
/** /**
* Enable/disable AJAX returned data debugging in logs * Enable/disable AJAX returned data debugging in logs
* @var bool * @var bool
@ -83,27 +77,37 @@ class Tpl {
/** /**
* Initialization * Initialization
* @param string $templates_dir Smarty templates directory path
* (optional, default: from templates.directory config key)
* @param string $templates_c_dir Smarty cache templates directory path
* (optional, default: from templates.cache_directory config key)
* @param bool $debug_ajax Enable/disable AJAX returned data debugging in logs
* (optional, default: from templates.debug_ajax or debug_ajax config keys if set,
* false otherwise)
* @param bool $static_root_url Configure custom root URL path for static files
* (optional, default: from templates.static_root_url config key if set,
* '/static' otherwise. Set to False to disable)
* @return void * @return void
*/ */
public static function init($templates_dir=null, $templates_c_dir=null, $debug_ajax=null, public static function init() {
$static_root_url=null) {
// In phpstan context, do not initialize // In phpstan context, do not initialize
if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__')) if (defined('__PHPSTAN_RUNNING__') && constant('__PHPSTAN_RUNNING__'))
return; return;
// Set config default values
App :: set_default(
'templates',
array(
// Main Smarty templates directory path
'directory' => null,
// Smarty cache templates directory path
// Default: see below, compute only if not set
'cache_directory' => null,
'main_pagetitle' => null,
'static_root_url' => 'static/',
'static_directories' => array(),
'included_css_files' => array(),
'included_js_files' => array(),
'webstats_js_code' => null,
'upload_max_filesize' => null,
'debug_ajax' => App::get('debug_ajax', false, 'bool'),
)
);
// Handle templates directories // Handle templates directories
self :: $core_templates_directory = realpath(__DIR__."/../templates"); self :: $core_templates_directory = realpath(__DIR__."/../templates");
self :: register_templates_directory(self :: $core_templates_directory); self :: register_templates_directory(self :: $core_templates_directory);
if (is_null($templates_dir))
$templates_dir = App::get('templates.directory', null, 'string'); $templates_dir = App::get('templates.directory', null, 'string');
if ($templates_dir) { if ($templates_dir) {
if (!is_dir($templates_dir)) if (!is_dir($templates_dir))
@ -112,7 +116,6 @@ class Tpl {
} }
// Handle and check templates_c directories // Handle and check templates_c directories
if (is_null($templates_c_dir))
$templates_c_dir = App::get('templates.cache_directory', null, 'string'); $templates_c_dir = App::get('templates.cache_directory', null, 'string');
if ($templates_c_dir) { if ($templates_c_dir) {
if (!is_dir($templates_c_dir) || !is_writable($templates_c_dir)) { if (!is_dir($templates_c_dir) || !is_writable($templates_c_dir)) {
@ -151,18 +154,17 @@ class Tpl {
$templates_c_dir); $templates_c_dir);
return; return;
} }
App :: set_default('templates.cache_directory', $templates_c_dir);
} }
self :: $smarty = new Smarty(); self :: $smarty = new Smarty();
self :: $smarty->setTemplateDir(self :: $core_templates_directory); self :: $smarty->setTemplateDir(self :: $core_templates_directory);
self :: $smarty->setCompileDir($templates_c_dir); self :: $smarty->setCompileDir($templates_c_dir);
self :: $smarty->registerResource('Tpl', new TplSmartyResource()); self :: $smarty->registerResource('Tpl', new TplSmartyResource());
if (is_null($debug_ajax)) $debug_ajax = App::get('templates.debug_ajax', null, 'bool');
$debug_ajax = App::get('templates.debug_ajax', App::get('debug_ajax'));
self :: $_debug_ajax = boolval($debug_ajax); self :: $_debug_ajax = boolval($debug_ajax);
Log :: register_fatal_error_handler(array('\\EesyPHP\\Tpl', 'fatal_error')); Log :: register_fatal_error_handler(array('\\EesyPHP\\Tpl', 'fatal_error'));
if (is_null($static_root_url)) $static_root_url = App::get('templates.static_root_url', null, 'string');
$static_root_url = App::get('templates.static_root_url', 'static/', 'string');
if ($static_root_url) { if ($static_root_url) {
if (substr($static_root_url, 0, 1) == '/') if (substr($static_root_url, 0, 1) == '/')
$static_root_url = substr($static_root_url, 1); $static_root_url = substr($static_root_url, 1);
@ -173,7 +175,7 @@ class Tpl {
self :: register_static_directory(self :: $core_static_directory, 100); self :: register_static_directory(self :: $core_static_directory, 100);
self :: register_function('static_url', array('EesyPHP\\Tpl', 'smarty_static_url')); self :: register_function('static_url', array('EesyPHP\\Tpl', 'smarty_static_url'));
foreach(App :: get('templates.static_directories', array(), 'array') as $path) foreach(App :: get('templates.static_directories', null, 'array') as $path)
self :: register_static_directory($path); self :: register_static_directory($path);
self :: register_function('var_dump', array('EesyPHP\\Tpl', 'smarty_var_dump')); self :: register_function('var_dump', array('EesyPHP\\Tpl', 'smarty_var_dump'));
@ -365,8 +367,8 @@ class Tpl {
self :: assign('session_key', isset($_SESSION['session_key'])?$_SESSION['session_key']:null); self :: assign('session_key', isset($_SESSION['session_key'])?$_SESSION['session_key']:null);
// Handle CSS & JS files included // Handle CSS & JS files included
self :: add_css_file(App::get('templates.included_css_files', array(), 'array')); self :: add_css_file(App::get('templates.included_css_files', null, 'array'));
self :: add_js_file(App::get('templates.included_js_files', array(), 'array')); self :: add_js_file(App::get('templates.included_js_files', null, 'array'));
// Messages // Messages
self :: assign('errors', self :: get_errors()); self :: assign('errors', self :: get_errors());

View file

@ -58,22 +58,23 @@ class Url {
/** /**
* Initialization * Initialization
* @param string|null $public_root_url The application public root URL
* (optional, default: from public_root_url config key)
* @param bool $api_mode Enable/disable API mode
* @return void * @return void
*/ */
public static function init($public_root_url=null, $api_mode=false) { public static function init() {
// Set default config values
App :: set_default('public_root_url', null);
App :: set_default('api_mode', false);
if (php_sapi_name() == 'cli-server' && getenv('EESYPHP_SERVE_URL')) if (php_sapi_name() == 'cli-server' && getenv('EESYPHP_SERVE_URL'))
$public_root_url = getenv('EESYPHP_SERVE_URL'); $public_root_url = getenv('EESYPHP_SERVE_URL');
else if (is_null($public_root_url)) else
$public_root_url = App::get('public_root_url', null, 'string'); $public_root_url = App::get('public_root_url', null, 'string');
if (is_string($public_root_url) && $public_root_url) { if (is_string($public_root_url) && $public_root_url) {
// Remove trailing slash // Remove trailing slash
$public_root_url = rtrim($public_root_url, '/'); $public_root_url = rtrim($public_root_url, '/');
self :: $public_root_url = $public_root_url?$public_root_url:null; self :: $public_root_url = $public_root_url?$public_root_url:null;
} }
self :: $_api_mode = boolval($api_mode); self :: $_api_mode = boolval(App::get('api_mode', null, 'bool'));
} }
/** /**