*/ private static array $css_files = array(); /** * JavaScript files to load in next displayed page * @var array */ private static array $js_files = array(); /** * Initialization * @param string $templates_dir Smarty templates directory path * (optional, default: from template.directory config key) * @param string $templates_c_dir Smarty cache templates directory path * (optional, default: from template.cache_directory config key) * @param bool $debug_ajax Enable/disable AJAX returned data debugging in logs * (optional, default: from template.debug_ajax or debug_ajax config keys if set, * false otherwise) * @return void */ public static function init($templates_dir=null, $templates_c_dir=null, $debug_ajax=null) { // Check templates/templates_c directories if (is_null($templates_dir)) $templates_dir = Config::get('template.directory', null, 'string'); if (is_null($templates_c_dir)) $templates_c_dir = Config::get('template.cache_directory', null, 'string'); if (!$templates_dir || !is_dir($templates_dir)) { Log :: fatal( "Template directory not found (%s)", $templates_dir?$templates_dir:'not set'); return; } if (!$templates_c_dir || !is_dir($templates_c_dir) || !is_writable($templates_c_dir)) { Log :: fatal( "Template cache directory not found or not writable (%s)", $templates_c_dir?$templates_c_dir:'not set'); return; } self :: $smarty = new Smarty(); self :: $smarty->setTemplateDir($templates_dir); self :: $smarty->setCompileDir($templates_c_dir); if (is_null($debug_ajax)) $debug_ajax = Config::get('template.debug_ajax', Config::get('debug_ajax')); self :: $_debug_ajax = boolval($debug_ajax); Log :: register_fatal_error_handler(array('\\EesyPHP\\Tpl', 'fatal_error')); } /** * Enable security in mode to limit functions (in IF clauses) and modifiers usable from * template files * @param array|null $functions List of function names granted in IF clauses * @param array|null $modifiers List of modifier names granted * @return void */ public static function enable_security_mode($functions=null, $modifiers=null) { // Define security policy self :: $smarty_security_policy = new Smarty_Security(self :: $smarty); // Allow functions in IF clauses if (is_array($functions)) foreach($functions as $function) self :: $smarty_security_policy->php_functions[] = $function; // Allow modifier functions if (is_array($modifiers)) foreach($modifiers as $modifier) self :: $smarty_security_policy->php_modifiers[] = $modifier; // Enable security self :: $smarty -> enableSecurity(self :: $smarty_security_policy); // Initialize errors & messages session variables if (!isset($_SESSION['errors'])) $_SESSION['errors'] = array(); if (!isset($_SESSION['messages'])) $_SESSION['messages'] = array(); } /** * Register a function usable from template files * @param string $name The function name * @param callable $callable The function * @return void */ public static function register_function($name, $callable) { self :: $smarty -> registerPlugin("function", $name, $callable); } /** * Assign template variable * @param string $name The variable name * @param mixed $value The variable value * @return void */ public static function assign($name, $value) { self :: $smarty -> assign($name, $value); } /** * Add error message * @param string $error The message * @param array $extra_args Extra arguments to use to compute error message using sprintf * @return void */ public static function add_error($error, ...$extra_args) { // If extra arguments passed, format error message using sprintf if ($extra_args) { $error = call_user_func_array( 'sprintf', array_merge(array($error), $extra_args) ); } $_SESSION['errors'][] = $error; } /** * Add informational message * @param string $message The message * @param array $extra_args Extra arguments to use to compute message using sprintf * @return void */ public static function add_message($message, ...$extra_args) { // If extra arguments passed, format message using sprintf if ($extra_args) { $message = call_user_func_array( 'sprintf', array_merge(array($message), $extra_args) ); } $_SESSION['messages'][] = $message; } /** * Register CSS file(s) to load on next displayed page * @param array> $args CSS files to load * @return void */ public static function add_css_file(...$args) { foreach ($args as $files) { if (!is_array($files)) $files = array($files); foreach ($files as $file) { if (!in_array($file, self :: $css_files)) self :: $css_files[] = $file; } } } /** * Register JS file(s) to load on next displayed page * @param array> $args JS files to load * @return void */ public static function add_js_file(...$args) { foreach ($args as $files) { if (!is_array($files)) $files = array($files); foreach ($files as $file) { if (!in_array($file, self :: $js_files)) self :: $js_files[] = $file; } } } /** * Define common variables * @param string|null $pagetitle The page title * @return void */ protected static function define_common_variables($pagetitle=null) { global $auth_user; self :: assign('pagetitle', $pagetitle); // Messages self :: assign('errors', (isset($_SESSION['errors'])?$_SESSION['errors']:array())); self :: assign('messages', (isset($_SESSION['messages'])?$_SESSION['messages']:array())); // Files inclusions self :: assign('css', self :: $css_files); self :: assign('js', self :: $js_files); // Authenticated user info if (isset($auth_user)) self :: assign('auth_user', $auth_user); } /** * Display the template * @param string $template The template to display * @param string|null $pagetitle The page title (optional) * @param array $extra_args Extra arguments to use to compute the page title using sprintf * @return void */ public static function display($template, $pagetitle=null, ...$extra_args) { if (!$template) { Log :: fatal(_("No template specified.")); return; } // If refresh parameter is present, remove it and redirect if (isset($_GET['refresh'])) { unset($_GET['refresh']); $url = Url :: get_current_url(); if (!empty($_GET)) $url .= '?'.http_build_query($_GET); Url :: redirect($url); return; } $sentry_span = new SentrySpan('smarty.display_template', "Display Smarty template"); // If extra arguments passed, format pagetitle using sprintf if ($pagetitle && $extra_args) { $pagetitle = call_user_func_array( 'sprintf', array_merge(array($pagetitle), $extra_args) ); } try { Hook :: trigger('before_displaying_template'); self :: define_common_variables($pagetitle); self :: $smarty->display($template); } catch (Exception $e) { Log :: exception($e, "Smarty - An exception occured displaying template '$template'"); if ($template != 'fatal_error.tpl') Log :: fatal(_("An error occurred while displaying this page.")); return; } unset($_SESSION['errors']); unset($_SESSION['messages']); Hook :: trigger('after_displaying_template'); $sentry_span->finish(); } /** * Display AJAX return * @param array|null $data AJAX returned data (optional) * @param bool $pretty AJAX returned data * (optional, default: true if $_REQUEST['pretty'] is set, False otherwise) * @return void */ public static function display_ajax_return($data=null, $pretty=false) { if (!is_array($data)) $data = array(); // Adjust HTTP error code on unsuccessfull request elseif (isset($data['success']) && !$data['success'] && http_response_code() == 200) http_response_code(400); if (isset($_SESSION['messages']) && !empty($_SESSION['messages'])) { $data['messages'] = $_SESSION['messages']; unset($_SESSION['messages']); } if (isset($_SESSION['errors']) && !empty($_SESSION['errors'])) { $data['errors'] = $_SESSION['errors']; unset($_SESSION['errors']); } if (self :: $_debug_ajax) Log :: debug("AJAX Response : ".vardump($data)); header('Content-Type: application/json'); echo json_encode($data, (($pretty||isset($_REQUEST['pretty']))?JSON_PRETTY_PRINT:0)); exit(); } /** * Handle a fatal error * @param string $error The error message * @param array $extra_args Extra arguments to use to compute the error message using sprintf * @return void */ public static function fatal_error($error, ...$extra_args) { // If extra arguments passed, format error message using sprintf if ($extra_args) { $error = call_user_func_array( 'sprintf', array_merge(array($error), $extra_args) ); } if (php_sapi_name() == "cli") die("FATAL ERROR : $error\n"); // Set HTTP reponse code to 500 http_response_code(500); // Handle API mode if (Url :: api_mode()) { self :: display_ajax_return(array('success' => false, 'error' => $error)); return; } self :: assign('fatal_error', $error); self :: display('fatal_error.tpl'); exit(); } /** * Get/set AJAX debug mode * @param bool|null $value If boolean, the current API mode will be changed * @return bool Current API mode */ public static function debug_ajax($value=null) { if (is_bool($value)) self :: $_debug_ajax = $value; return self :: $_debug_ajax; } /** * Check if initialized * @return bool */ public static function initialized() { return isset(self :: $smarty); } /** * Get the templates directory path * @return string|null */ public static function templates_directory() { return isset(self :: $templates_directory)?self :: $templates_directory:null; } }