2023-01-31 00:30:04 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace EesyPHP;
|
|
|
|
|
|
|
|
use Exception;
|
|
|
|
use Smarty;
|
|
|
|
use Smarty_Security;
|
2023-02-12 00:30:36 +01:00
|
|
|
use League\MimeTypeDetection\ExtensionMimeTypeDetector;
|
2023-01-31 00:30:04 +01:00
|
|
|
|
|
|
|
class Tpl {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Smarty object
|
|
|
|
* @var \Smarty
|
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
public static $smarty;
|
2023-01-31 00:30:04 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Smarty_Security object
|
|
|
|
* @var \Smarty_Security|null
|
|
|
|
*/
|
|
|
|
public static $smarty_security_policy = null;
|
|
|
|
|
2023-02-14 01:21:52 +01:00
|
|
|
/**
|
|
|
|
* Core Smarty templates directory
|
|
|
|
* @var string
|
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
public static $core_templates_directory;
|
2023-02-14 01:21:52 +01:00
|
|
|
|
2023-01-31 00:30:04 +01:00
|
|
|
/**
|
2023-02-13 00:42:20 +01:00
|
|
|
* Smarty templates directories path with their priority
|
|
|
|
* @var array<string,int>
|
2023-01-31 00:30:04 +01:00
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
public static $templates_directories = array();
|
2023-01-31 00:30:04 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Smarty cache templates directory path
|
|
|
|
* @var string
|
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
public static $templates_c_dir;
|
2023-01-31 00:30:04 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Enable/disable AJAX returned data debugging in logs
|
|
|
|
* @var bool
|
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
public static $_debug_ajax;
|
2023-01-31 00:30:04 +01:00
|
|
|
|
2023-02-14 01:21:52 +01:00
|
|
|
/**
|
|
|
|
* Core static directory
|
|
|
|
* @var string|null
|
|
|
|
*/
|
|
|
|
public static $core_static_directory = null;
|
|
|
|
|
2023-02-12 00:30:36 +01:00
|
|
|
/**
|
2023-02-13 00:42:20 +01:00
|
|
|
* Static directories path with their priority
|
|
|
|
* @var array<string,array>
|
2023-02-12 00:30:36 +01:00
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
private static $static_directories = array();
|
2023-02-12 00:30:36 +01:00
|
|
|
|
2023-01-31 00:30:04 +01:00
|
|
|
/**
|
|
|
|
* CSS files to load in next displayed page
|
|
|
|
* @var array<string>
|
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
private static $css_files = array();
|
2023-01-31 00:30:04 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* JavaScript files to load in next displayed page
|
|
|
|
* @var array<string>
|
|
|
|
*/
|
2023-02-16 01:53:08 +01:00
|
|
|
private static $js_files = array();
|
2023-01-31 00:30:04 +01:00
|
|
|
|
2023-02-12 00:30:36 +01:00
|
|
|
/**
|
|
|
|
* MIME type detector object
|
|
|
|
* @var null|string
|
|
|
|
*/
|
|
|
|
private static $static_root_url;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MIME type detector object
|
|
|
|
* @var ExtensionMimeTypeDetector|null
|
|
|
|
*/
|
|
|
|
private static $mime_type_detector = null;
|
|
|
|
|
2023-01-31 00:30:04 +01:00
|
|
|
/**
|
|
|
|
* Initialization
|
|
|
|
* @param string $templates_dir Smarty templates directory path
|
2023-02-13 00:42:20 +01:00
|
|
|
* (optional, default: from templates.directory config key)
|
2023-01-31 00:30:04 +01:00
|
|
|
* @param string $templates_c_dir Smarty cache templates directory path
|
2023-02-13 00:42:20 +01:00
|
|
|
* (optional, default: from templates.cache_directory config key)
|
2023-01-31 00:30:04 +01:00
|
|
|
* @param bool $debug_ajax Enable/disable AJAX returned data debugging in logs
|
2023-02-13 00:42:20 +01:00
|
|
|
* (optional, default: from templates.debug_ajax or debug_ajax config keys if set,
|
2023-02-08 02:27:15 +01:00
|
|
|
* false otherwise)
|
2023-02-12 00:30:36 +01:00
|
|
|
* @param bool $static_root_url Configure custom root URL path for static files
|
2023-02-13 00:42:20 +01:00
|
|
|
* (optional, default: from templates.static_root_url config key if set,
|
2023-02-12 00:30:36 +01:00
|
|
|
* '/static' otherwise. Set to False to disable)
|
2023-01-31 00:30:04 +01:00
|
|
|
* @return void
|
|
|
|
*/
|
2023-02-12 00:30:36 +01:00
|
|
|
public static function init($templates_dir=null, $templates_c_dir=null, $debug_ajax=null,
|
|
|
|
$static_root_url=null) {
|
2023-02-13 00:42:20 +01:00
|
|
|
// Handle templates directories
|
2023-02-14 01:21:52 +01:00
|
|
|
self :: $core_templates_directory = realpath(__DIR__."/../templates");
|
|
|
|
self :: register_templates_directory(self :: $core_templates_directory);
|
2023-02-08 02:27:15 +01:00
|
|
|
if (is_null($templates_dir))
|
2023-02-13 00:42:20 +01:00
|
|
|
$templates_dir = App::get('templates.directory', null, 'string');
|
|
|
|
if ($templates_dir) {
|
|
|
|
if (!is_dir($templates_dir))
|
|
|
|
Log :: fatal("Template directory not found (%s)", $templates_dir);
|
|
|
|
self :: register_templates_directory($templates_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle and check templates_c directories
|
2023-02-08 02:27:15 +01:00
|
|
|
if (is_null($templates_c_dir))
|
2023-02-13 00:42:20 +01:00
|
|
|
$templates_c_dir = App::get('templates.cache_directory', null, 'string');
|
|
|
|
if ($templates_c_dir) {
|
|
|
|
if (!is_dir($templates_c_dir) || !is_writable($templates_c_dir)) {
|
|
|
|
Log :: fatal(
|
|
|
|
"Template cache directory not found or not writable (%s)",
|
|
|
|
$templates_c_dir);
|
|
|
|
return;
|
|
|
|
}
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
2023-02-13 00:42:20 +01:00
|
|
|
else {
|
|
|
|
$public_root_url = Url :: public_root_url();
|
|
|
|
if ($public_root_url != '/') {
|
|
|
|
$unique_name = preg_replace('#^https?://#', '', $public_root_url);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$root_directory_path = App::root_directory_path();
|
|
|
|
if ($root_directory_path == '.') {
|
|
|
|
Log :: fatal(
|
|
|
|
'Fail to compute a unique templates cache directory for this application. An public '.
|
|
|
|
'root URL or an application root directory must be set if you do not provide it at '.
|
|
|
|
'initialization (or via config parameter).');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$unique_name = $root_directory_path;
|
|
|
|
if (substr($unique_name, 0, 1) == '/')
|
|
|
|
$unique_name = substr($unique_name, 1);
|
|
|
|
if (substr($unique_name, -1) == '/')
|
|
|
|
$unique_name = substr($unique_name, 0, -1);
|
|
|
|
}
|
2023-02-14 01:21:52 +01:00
|
|
|
$templates_c_dir = sys_get_temp_dir().'/'.str_replace(
|
2023-02-13 00:42:20 +01:00
|
|
|
'/', '_', "eesyphp_templates_cache_$unique_name"
|
|
|
|
);
|
|
|
|
if (!is_dir($templates_c_dir) && !mkdir($templates_c_dir)) {
|
|
|
|
Log :: fatal(
|
|
|
|
'Fail to create application templates cache directory (%s)',
|
|
|
|
$templates_c_dir);
|
|
|
|
return;
|
|
|
|
}
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
|
|
|
self :: $smarty = new Smarty();
|
2023-02-14 01:21:52 +01:00
|
|
|
self :: $smarty->setTemplateDir(self :: $core_templates_directory);
|
2023-01-31 00:30:04 +01:00
|
|
|
self :: $smarty->setCompileDir($templates_c_dir);
|
2023-02-13 00:42:20 +01:00
|
|
|
self :: $smarty->registerResource('Tpl', new TplSmartyResource());
|
2023-02-08 02:27:15 +01:00
|
|
|
if (is_null($debug_ajax))
|
2023-02-13 00:42:20 +01:00
|
|
|
$debug_ajax = App::get('templates.debug_ajax', App::get('debug_ajax'));
|
2023-01-31 00:30:04 +01:00
|
|
|
self :: $_debug_ajax = boolval($debug_ajax);
|
|
|
|
Log :: register_fatal_error_handler(array('\\EesyPHP\\Tpl', 'fatal_error'));
|
2023-02-12 00:30:36 +01:00
|
|
|
|
|
|
|
if (is_null($static_root_url))
|
2023-02-13 00:42:20 +01:00
|
|
|
$static_root_url = App::get('templates.static_root_url', 'static/', 'string');
|
2023-02-12 00:30:36 +01:00
|
|
|
if ($static_root_url) {
|
|
|
|
if (substr($static_root_url, 0, 1) == '/')
|
|
|
|
$static_root_url = substr($static_root_url, 1);
|
|
|
|
if (substr($static_root_url, -1) != '/')
|
|
|
|
$static_root_url = "$static_root_url/";
|
|
|
|
self :: $static_root_url = $static_root_url;
|
2023-02-14 01:21:52 +01:00
|
|
|
self :: $core_static_directory = realpath(__DIR__."/../static");
|
|
|
|
self :: register_static_directory(self :: $core_static_directory, 100);
|
2023-02-12 00:30:36 +01:00
|
|
|
self :: register_function('static_url', array('EesyPHP\\Tpl', 'smarty_static_url'));
|
|
|
|
|
|
|
|
foreach(App :: get('templates.static_directories', array(), 'array') as $path)
|
|
|
|
self :: register_static_directory($path);
|
2023-02-15 19:00:25 +01:00
|
|
|
|
|
|
|
self :: register_function('var_dump', array('EesyPHP\\Tpl', 'smarty_var_dump'));
|
2023-02-12 00:30:36 +01:00
|
|
|
}
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enable security in mode to limit functions (in IF clauses) and modifiers usable from
|
|
|
|
* template files
|
|
|
|
* @param array<string>|null $functions List of function names granted in IF clauses
|
|
|
|
* @param array<string>|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;
|
|
|
|
}
|
|
|
|
|
2023-02-15 23:51:11 +01:00
|
|
|
/**
|
|
|
|
* Get errors
|
|
|
|
* @return array<string>
|
|
|
|
*/
|
|
|
|
public static function get_errors() {
|
|
|
|
if(isset($_SESSION['errors']) && is_array($_SESSION['errors']))
|
|
|
|
return $_SESSION['errors'];
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get messages
|
|
|
|
* @return array<string>
|
|
|
|
*/
|
|
|
|
public static function get_messages() {
|
|
|
|
if(isset($_SESSION['messages']) && is_array($_SESSION['messages']))
|
|
|
|
return $_SESSION['messages'];
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Purge messages
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function purge_errors() {
|
|
|
|
if(isset($_SESSION['errors']))
|
|
|
|
unset($_SESSION['errors']);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Purge messages
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function purge_messages() {
|
|
|
|
if(isset($_SESSION['messages']))
|
|
|
|
unset($_SESSION['messages']);
|
|
|
|
}
|
|
|
|
|
2023-01-31 00:30:04 +01:00
|
|
|
/**
|
|
|
|
* Register CSS file(s) to load on next displayed page
|
2023-02-12 00:30:36 +01:00
|
|
|
* @param string|array<string> $args CSS files to load
|
2023-01-31 00:30:04 +01:00
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function add_css_file(...$args) {
|
2023-02-12 00:30:36 +01:00
|
|
|
// Check if the first argument is a custom static root URL
|
|
|
|
$root_url = self :: $static_root_url;
|
|
|
|
if (
|
|
|
|
$args && is_string($args[0]) && array_key_exists(
|
|
|
|
self :: clean_static_root_url($args[0]),
|
|
|
|
self :: $static_directories
|
|
|
|
)
|
|
|
|
)
|
|
|
|
$root_url = self :: clean_static_root_url(array_shift($args));
|
2023-01-31 00:30:04 +01:00
|
|
|
foreach ($args as $files) {
|
|
|
|
if (!is_array($files)) $files = array($files);
|
|
|
|
foreach ($files as $file) {
|
2023-02-12 00:30:36 +01:00
|
|
|
$path = $root_url.$file;
|
|
|
|
if (!in_array($path, self :: $css_files))
|
|
|
|
self :: $css_files[] = $path;
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register JS file(s) to load on next displayed page
|
2023-02-12 00:30:36 +01:00
|
|
|
* @param string|array<string> $args JS files to load
|
2023-01-31 00:30:04 +01:00
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function add_js_file(...$args) {
|
2023-02-12 00:30:36 +01:00
|
|
|
// Check if the first argument is a custom static root URL
|
|
|
|
$root_url = self :: $static_root_url;
|
|
|
|
if (
|
|
|
|
$args && is_string($args[0]) && array_key_exists(
|
|
|
|
self :: clean_static_root_url($args[0]),
|
|
|
|
self :: $static_directories
|
|
|
|
)
|
|
|
|
)
|
|
|
|
$root_url = self :: clean_static_root_url(array_shift($args));
|
2023-01-31 00:30:04 +01:00
|
|
|
foreach ($args as $files) {
|
|
|
|
if (!is_array($files)) $files = array($files);
|
|
|
|
foreach ($files as $file) {
|
2023-02-12 00:30:36 +01:00
|
|
|
$path = $root_url.$file;
|
|
|
|
if (!in_array($path, self :: $js_files))
|
|
|
|
self :: $js_files[] = $path;
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Define common variables
|
|
|
|
* @param string|null $pagetitle The page title
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
protected static function define_common_variables($pagetitle=null) {
|
2023-02-13 00:42:20 +01:00
|
|
|
self :: assign('public_root_url', Url :: public_root_url());
|
2023-01-31 00:30:04 +01:00
|
|
|
self :: assign('pagetitle', $pagetitle);
|
2023-02-13 00:42:20 +01:00
|
|
|
self :: assign('main_pagetitle', App::get('main_pagetitle', null, 'string'));
|
|
|
|
self :: assign('session_key', isset($_SESSION['session_key'])?$_SESSION['session_key']:null);
|
|
|
|
|
|
|
|
// Handle CSS & JS files included
|
|
|
|
self :: add_css_file(App::get('templates.included_css_files', array(), 'array'));
|
|
|
|
self :: add_js_file(App::get('templates.included_js_files', array(), 'array'));
|
2023-01-31 00:30:04 +01:00
|
|
|
|
|
|
|
// Messages
|
2023-02-15 23:51:11 +01:00
|
|
|
self :: assign('errors', self :: get_errors());
|
|
|
|
self :: assign('messages', self :: get_messages());
|
2023-01-31 00:30:04 +01:00
|
|
|
|
|
|
|
// Files inclusions
|
|
|
|
self :: assign('css', self :: $css_files);
|
|
|
|
self :: assign('js', self :: $js_files);
|
|
|
|
|
2023-02-14 01:21:52 +01:00
|
|
|
// I18n text domains
|
|
|
|
self :: assign('CORE_TEXT_DOMAIN', I18n :: CORE_TEXT_DOMAIN);
|
|
|
|
self :: assign('TEXT_DOMAIN', I18n :: TEXT_DOMAIN);
|
|
|
|
|
2023-01-31 00:30:04 +01:00
|
|
|
// Authenticated user info
|
2023-02-25 05:02:27 +01:00
|
|
|
if (Auth::user())
|
|
|
|
self :: assign('auth_user', Auth::user());
|
2023-02-27 16:35:35 +01:00
|
|
|
|
|
|
|
// Webstats JS code
|
|
|
|
Tpl :: assign(
|
|
|
|
'webstats_js_code',
|
|
|
|
App::get('webstats_js_code', null, 'string'));
|
2023-02-27 16:58:28 +01:00
|
|
|
|
|
|
|
// Upload max size
|
|
|
|
if (App::get('upload_max_filesize', null, 'int'))
|
|
|
|
Tpl :: assign(
|
|
|
|
'upload_max_filesize',
|
|
|
|
App::get('upload_max_filesize', null, 'int'));
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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) {
|
2023-02-14 01:21:52 +01:00
|
|
|
Log :: fatal(I18n::_("No template specified."));
|
2023-01-31 00:30:04 +01:00
|
|
|
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);
|
2023-02-13 00:42:20 +01:00
|
|
|
self :: $smarty->display("Tpl:$template");
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
|
|
|
catch (Exception $e) {
|
|
|
|
Log :: exception($e, "Smarty - An exception occured displaying template '$template'");
|
2023-02-27 18:53:40 +01:00
|
|
|
Hook :: trigger('after_displaying_template', array('success' => false));
|
|
|
|
$sentry_span->finish();
|
2023-01-31 00:30:04 +01:00
|
|
|
if ($template != 'fatal_error.tpl')
|
2023-02-14 01:21:52 +01:00
|
|
|
Log :: fatal(I18n::_("An error occurred while displaying this page."));
|
2023-01-31 00:30:04 +01:00
|
|
|
return;
|
|
|
|
}
|
2023-02-15 23:51:11 +01:00
|
|
|
self :: purge_errors();
|
|
|
|
self :: purge_messages();
|
2023-02-27 18:53:40 +01:00
|
|
|
Hook :: trigger('after_displaying_template', array('success' => true));
|
2023-01-31 00:30:04 +01:00
|
|
|
$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);
|
|
|
|
|
2023-02-15 23:51:11 +01:00
|
|
|
$data['messages'] = self :: get_messages();
|
|
|
|
if (!$data['messages']) unset($data['messages']);
|
|
|
|
self :: purge_messages();
|
|
|
|
|
|
|
|
$data['errors'] = self :: get_errors();
|
|
|
|
if (!$data['errors']) unset($data['errors']);
|
|
|
|
self :: purge_errors();
|
|
|
|
|
2023-01-31 00:30:04 +01:00
|
|
|
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() {
|
2023-02-16 01:53:08 +01:00
|
|
|
return self :: $smarty instanceof Smarty;
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-02-13 00:42:20 +01:00
|
|
|
* Get the templates directories path
|
|
|
|
* @return array<string>
|
|
|
|
*/
|
|
|
|
public static function templates_directories() {
|
|
|
|
return array_keys(self :: $templates_directories);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register a templates directory
|
|
|
|
* @param string $path The templates directory path
|
|
|
|
* @param int|null $priority The priority of this templates directory
|
|
|
|
* (optional, default: prior than all other registered directories)
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function register_templates_directory($path, $priority=null) {
|
|
|
|
if (!is_dir($path)) {
|
|
|
|
Log :: fatal(
|
|
|
|
'register_templates_directory(%s): this templates directory does not exists',
|
|
|
|
$path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (substr($path, -1) == '/')
|
|
|
|
$path = substr($path, 0, -1);
|
|
|
|
if (is_null($priority)) {
|
|
|
|
$priority = (
|
|
|
|
!empty(self :: $templates_directories)?
|
|
|
|
max(self :: $templates_directories) + 1:
|
|
|
|
100
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Log :: trace(
|
|
|
|
'Register templates directory "%s" with priority %d',
|
|
|
|
$path, $priority);
|
|
|
|
self :: $templates_directories[$path] = $priority;
|
|
|
|
arsort(self :: $templates_directories);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolve templates path against registered templates directories
|
|
|
|
* @param string $path
|
|
|
|
* @return string|false
|
2023-01-31 00:30:04 +01:00
|
|
|
*/
|
2023-02-13 00:42:20 +01:00
|
|
|
public static function resolve_templates_path($path) {
|
|
|
|
foreach(array_keys(self :: $templates_directories) as $dir) {
|
|
|
|
$fullpath = "$dir/$path";
|
|
|
|
if (file_exists($fullpath)) {
|
|
|
|
Log::trace('Templates file "%s" resolved as "%s"', $path, $fullpath);
|
|
|
|
return $fullpath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Log::trace('Templates file "%s" not found', $path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the content of a Smarty template file.
|
|
|
|
*
|
|
|
|
* @param string $template The template name (eg: base.tpl)
|
|
|
|
*
|
|
|
|
* @return string The content of the Smarty template file
|
|
|
|
**/
|
|
|
|
public static function get_template_source($template) {
|
|
|
|
$path = self :: resolve_templates_path($template);
|
|
|
|
if (!is_readable($path)) {
|
|
|
|
// No error return with Smarty3 and highter because it's call
|
|
|
|
// template name in lower first systematically
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return file_get_contents($path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the timestamp of the last change of a Smarty
|
|
|
|
* template file.
|
|
|
|
*
|
|
|
|
* @param string $template The template name (eg: empty.tpl)
|
|
|
|
*
|
|
|
|
* @return int|null The timestamp of the last change of the Smarty template file
|
|
|
|
**/
|
|
|
|
public static function get_template_timestamp($template) {
|
|
|
|
$path = self :: resolve_templates_path($template);
|
|
|
|
if (is_file($path)) {
|
|
|
|
$time = filemtime($path);
|
|
|
|
if ($time)
|
|
|
|
return $time;
|
|
|
|
}
|
|
|
|
return null;
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|
2023-02-12 00:30:36 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Clean static root URL helper
|
|
|
|
* @param string $value
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function clean_static_root_url($value) {
|
|
|
|
if (substr($value, 0, 1) == '/')
|
|
|
|
$value = substr($value, 1);
|
|
|
|
if (substr($value, -1) != '/')
|
|
|
|
$value = "$value/";
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
2023-02-13 00:42:20 +01:00
|
|
|
/**
|
|
|
|
* Get the static directories path
|
|
|
|
* @return array<string>
|
|
|
|
*/
|
|
|
|
public static function static_directories() {
|
|
|
|
$result = array();
|
|
|
|
foreach(self :: $static_directories as $root_url => $dirs)
|
|
|
|
foreach(array_keys($dirs) as $dir)
|
|
|
|
if (!in_array($dir, $result))
|
|
|
|
$result[] = $dir;
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2023-02-12 00:30:36 +01:00
|
|
|
/**
|
|
|
|
* Register a static directory
|
|
|
|
* @param string $path The static directory path
|
|
|
|
* @param int|null $priority The priority of this static directory
|
|
|
|
* (optional, default: prior than all other registered directories)
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function register_static_directory($path, $priority=null, $root_url=null) {
|
|
|
|
if (is_null($root_url)) {
|
|
|
|
if (!self :: $static_root_url)
|
|
|
|
Log :: fatal(
|
|
|
|
'register_static_directory(%s): no root URL provided and no default value configured',
|
|
|
|
$path);
|
|
|
|
$root_url = self :: $static_root_url;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!array_key_exists($root_url, self :: $static_directories)) {
|
|
|
|
self :: $static_directories[$root_url] = array();
|
|
|
|
if (is_null($priority)) $priority = 100;
|
|
|
|
$pattern = "#^(?P<root_url>$root_url)(?P<path>.*)#";
|
|
|
|
Log :: trace(
|
|
|
|
'Register static file URL handler for root URL "%s" with pattern "%s" and directory '.
|
|
|
|
'"%s" (priority: %d)', $root_url, $pattern, $path, $priority);
|
|
|
|
Url :: add_url_handler(
|
|
|
|
$pattern,
|
|
|
|
array('EesyPHP\\Tpl', 'handle_static_file'),
|
2023-02-15 18:58:17 +01:00
|
|
|
null, // additionnal info
|
2023-02-12 00:30:36 +01:00
|
|
|
false, // authenticated
|
|
|
|
false, // override
|
|
|
|
false, // API mode
|
|
|
|
array('GET') // methods
|
|
|
|
);
|
|
|
|
if (is_null(self :: $mime_type_detector))
|
|
|
|
self :: $mime_type_detector = new ExtensionMimeTypeDetector();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (is_null($priority)) {
|
|
|
|
$priority = max(self :: $static_directories[$root_url]);
|
|
|
|
$priority++;
|
|
|
|
}
|
|
|
|
Log :: trace(
|
|
|
|
'Register additionnal static directory "%s" for root URL "%s" (priority: %d)',
|
|
|
|
$path, $root_url, $priority);
|
|
|
|
}
|
|
|
|
|
2023-02-13 00:42:20 +01:00
|
|
|
if (substr($path, -1) == '/')
|
2023-02-12 00:30:36 +01:00
|
|
|
$path = substr($path, 0, -1);
|
|
|
|
self :: $static_directories[$root_url][$path] = $priority;
|
|
|
|
arsort(self :: $static_directories[$root_url]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolve static path against registered static directories
|
|
|
|
* @param string $path
|
|
|
|
* @return string|false
|
|
|
|
*/
|
|
|
|
public static function resolve_static_path($root_url, $path) {
|
|
|
|
if (!array_key_exists($root_url, self :: $static_directories)) {
|
|
|
|
Log::error(
|
|
|
|
'No static directory registered for root URL "%s". Can no resolve static file "%s" path.',
|
|
|
|
$root_url, $path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
foreach(array_keys(self :: $static_directories[$root_url]) as $dir) {
|
|
|
|
$fullpath = "$dir/$path";
|
|
|
|
if (file_exists($fullpath))
|
|
|
|
return $fullpath;
|
|
|
|
}
|
|
|
|
Log::trace('Static file "%s%s" not found', $root_url, $path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle URL request for static file
|
|
|
|
* Note: this URL handler is registered in EesyPHP\Url by self::init().
|
|
|
|
* @see self::init()
|
|
|
|
* @param UrlRequest $request
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function handle_static_file($request) {
|
|
|
|
$path = self :: resolve_static_path($request->root_url, $request->path);
|
|
|
|
Log::trace('Resolved static file path for "%s": "%s"', $request->path, $path);
|
|
|
|
if (!$path)
|
|
|
|
Url :: trigger_error_404($request);
|
|
|
|
$mime_type = self :: $mime_type_detector->detectMimeTypeFromFile($path);
|
|
|
|
Log::trace('MIME type detected for "%s" is "%s"', $path, $mime_type);
|
|
|
|
dump_file($path, $mime_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to retrieve static file URL
|
|
|
|
* @param string $path The file path
|
|
|
|
* @return string|false
|
|
|
|
*/
|
|
|
|
public static function static_url($path) {
|
|
|
|
if (self :: $static_root_url)
|
|
|
|
return self :: $static_root_url.$path;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Smarty function to print static file URL
|
|
|
|
* @param array<string,mixed> $params Parameters from template file
|
|
|
|
* @param Smarty $smarty The smarty object
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function smarty_static_url($params, $smarty) {
|
|
|
|
if (!isset($params['path'])) return;
|
|
|
|
$url = self :: static_url($params['path']);
|
|
|
|
if ($url) echo $url;
|
|
|
|
}
|
2023-02-15 19:00:25 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Smarty function to dump variable using var_dump()
|
|
|
|
* @param array<string,mixed> $params Parameters from template file
|
|
|
|
* @param Smarty $smarty The smarty object
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public static function smarty_var_dump($params, $smarty) {
|
|
|
|
if (!isset($params['data'])) return;
|
|
|
|
var_dump($params['data']);
|
|
|
|
}
|
2023-01-31 00:30:04 +01:00
|
|
|
}
|