Tpl: Add stuff to handle static files

* Move example application in example sub-directory
* Widely use App::get() instead of Config::get()
This commit is contained in:
Benjamin Renard 2023-02-12 00:30:36 +01:00
parent f2edf4910a
commit 4f47dc056d
1148 changed files with 319 additions and 2959 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
.*.swp
# Exclude composer installed libs
/vendor
/composer.lock
# Common UNIX user home directory files
/.bash*
/.vim*

View File

@ -26,7 +26,8 @@
"sentry/sdk": "^3.3",
"ext-pdo": "^7.3",
"ext-json": "^7.3",
"ext-yaml": "^2.0"
"ext-yaml": "^2.0",
"league/mime-type-detection": "^1.11"
},
"require-dev": {
"phpstan/phpstan": "^1.9"

2866
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
<?php
use EesyPHP\App;
use EesyPHP\Config;
use EesyPHP\I18n;
use EesyPHP\SentrySpan;
@ -25,7 +24,7 @@ $root_dir_path = realpath(dirname($script).'/../');
set_include_path($root_dir_path.'/includes' . PATH_SEPARATOR . get_include_path());
// Load composer autoload.php
require("$root_dir_path/vendor/autoload.php");
require("$root_dir_path/../vendor/autoload.php");
// Initialize EesyPHP application
App::init(
@ -34,6 +33,11 @@ App::init(
'overwrite_config_files' => array(
"$root_dir_path/includes/config.local.yml",
),
'templates' => array(
'static_directories' => array(
"$root_dir_path/static"
),
),
),
$root_dir_path
);

View File

@ -1,6 +1,6 @@
<?php
use EesyPHP\Config;
use EesyPHP\App;
use EesyPHP\Db;
use EesyPHP\Hook;
use EesyPHP\Log;
@ -8,12 +8,12 @@ use EesyPHP\Log;
use Unidecode\Unidecode;
$db = new Db(
Config::get('db.dsn', null, 'string'),
Config::get('db.user', null, 'string'),
Config::get('db.password', null, 'string'),
Config::get('db.options', array(), 'array'),
Config::get('db.date_format', null, 'string'),
Config::get('db.datetime_format', null, 'string'),
App::get('db.dsn', null, 'string'),
App::get('db.user', null, 'string'),
App::get('db.password', null, 'string'),
App::get('db.options', array(), 'array'),
App::get('db.date_format', null, 'string'),
App::get('db.datetime_format', null, 'string'),
);
/*
@ -154,7 +154,7 @@ function search_items($params) {
global $db;
// Detect PgSQL backend
$is_pgsql = (strpos(Config::get('db.dsn', '', 'string'), "pgsql:") === 0);
$is_pgsql = (strpos(App::get('db.dsn', '', 'string'), "pgsql:") === 0);
$where = array();
if (isset($params['status']) && $params['status'] && $params['status'] != 'all')

View File

@ -1,6 +1,6 @@
<?php
use EesyPHP\Config;
use EesyPHP\App;
use EesyPHP\Date;
use EesyPHP\Hook;
use EesyPHP\Log;
@ -23,13 +23,13 @@ Tpl :: enable_security_mode(
);
// Defined some global template variables
Tpl :: assign('public_root_url', Config::get('public_root_url', '/', 'string'));
Tpl :: assign('main_pagetitle', Config::get('main_pagetitle', null, 'string'));
Tpl :: assign('public_root_url', App::get('public_root_url', '/', 'string'));
Tpl :: assign('main_pagetitle', App::get('main_pagetitle', null, 'string'));
Tpl :: assign('session_key', $_SESSION['session_key']);
// Handle CSS & JS files included
Tpl :: add_css_file(Config::get('included_css_files', array(), 'array'));
Tpl :: add_js_file(Config::get('included_js_files', array(), 'array'));
Tpl :: add_css_file(App::get('included_css_files', array(), 'array'));
Tpl :: add_js_file(App::get('included_js_files', array(), 'array'));
function define_common_template_variables($event) {
global $status_list, $admin;
@ -41,7 +41,7 @@ function define_common_template_variables($event) {
Tpl :: assign('admin', isset($admin) && $admin);
Tpl :: assign(
'webstats_js_code',
Config::get('webstats_js_code', null, 'string'));
App::get('webstats_js_code', null, 'string'));
}
Hook :: register('before_displaying_template', 'define_common_template_variables');

View File

@ -102,11 +102,11 @@ function handle_search($request) {
Tpl :: assign('nbs_by_page', $nbs_by_page);
Tpl :: assign('status_list', $status_list);
Tpl :: add_js_file(array(
Tpl :: add_js_file(
'lib/bootstrap4dialog/dist/js/bootstrap4dialog.min.js',
'js/myconfirm.js',
'js/search.js'
));
);
Tpl :: display("search.tpl", _("Search"));
}
@ -124,10 +124,10 @@ function handle_show($request) {
Tpl :: assign('item', $item);
// Dialog
Tpl :: add_js_file(array(
Tpl :: add_js_file(
'lib/bootstrap4dialog/dist/js/bootstrap4dialog.min.js',
'js/myconfirm.js',
));
);
Tpl :: display(
"show.tpl", _("Element %s"),

View File

@ -1,30 +1,29 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
<meta name="description" content=""/>
<meta name="author" content=""/>
<base href="{$public_root_url}/"/>
{block name="head"}{/block}
<link rel="icon" href="images/favicon.png">
<link rel="icon" href="{static_url path="images/favicon.png"}"/>
<title>{$main_pagetitle}{if $pagetitle} - {$pagetitle}{/if}</title>
<!-- Bootstrap -->
<link href="lib/bootstrap4/css/bootstrap.min.css" rel="stylesheet">
<link href="{static_url path="lib/bootstrap4/css/bootstrap.min.css"}" rel="stylesheet"/>
<!-- Font Awesome -->
<link href="lib/Fork-Awesome-1.1.7/css/fork-awesome.min.css" rel="stylesheet">
<link href="{static_url path="lib/Fork-Awesome-1.1.7/css/fork-awesome.min.css"}" rel="stylesheet"/>
<link href="css/style.css" rel="stylesheet">
{foreach $css as $file}
<link href="{$file}" rel="stylesheet">
<link href="{static_url path="css/style.css"}" rel="stylesheet"/>
{foreach $css as $path}
<link href="{$path|escape:"quotes"}" rel="stylesheet"/>
{/foreach}
</head>
<body>
@ -34,7 +33,7 @@
{block name="navbar"}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="">
<img id="logo" src="images/logo.png" alt="Logo" title="Logo"/>
<img id="logo" src="{static_url path="images/logo.png"}" alt="Logo" title="Logo"/>
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@ -89,12 +88,12 @@
<!-- Jquery & Bootstrap -->
<script src="lib/jquery-3.4.1.min.js"></script>
<script src="lib/bootstrap4/js/bootstrap.bundle.min.js"></script>
<script src="{static_url path="lib/jquery-3.4.1.min.js"}"></script>
<script src="{static_url path="lib/bootstrap4/js/bootstrap.bundle.min.js"}"></script>
<!-- Other libs & JavaScript scripts -->
{foreach $js as $file}
<script language="javascript" src="{$file}"></script>
{foreach $js as $path}
<script language="javascript" src="{$path|escape:"quotes"}"></script>
{/foreach}
{if $webstats_js_code}{$webstats_js_code}{/if}

View File

@ -2,11 +2,12 @@ parameters:
level: 5
paths:
- src
- includes
- public_html
- bin/eesyphp
- example
excludePaths:
- includes/config.local.php
- example/includes/config.local.php
- example/data/tmp/templates_c
universalObjectCratesClasses:
- EesyPHP\UrlRequest
ignoreErrors:
-
message: "#Instantiated class Mail_mime not found\\.#"
@ -23,5 +24,5 @@ parameters:
-
message: "#Variable \\$status_list might not be defined\\.#"
paths:
- includes/cli.php
- example/includes/cli.php

View File

@ -40,35 +40,43 @@ class App {
}
// Load overwrite configuration file
foreach (self :: get_option('overwrite_config_files', array(), 'array') as $file) {
foreach (self :: get('overwrite_config_files', array(), 'array') as $file) {
$file = Config::replace_variables($file);
if (is_file($file)) Config::load($file, true);
}
if (self :: get_option('sentry.enabled', true, 'bool'))
if (self :: get('sentry.enabled', true, 'bool'))
SentryIntegration :: init();
$sentry_transaction = new SentryTransaction();
$sentry_span = new SentrySpan('app.init', 'Application initialization');
// Define upload_tmp_dir
if (is_string(Config::get('upload_tmp_directory')))
ini_set('upload_tmp_dir', Config::get('upload_tmp_directory'));
if (is_string(self::get('upload_tmp_directory')))
ini_set('upload_tmp_dir', self::get('upload_tmp_directory'));
if (self :: get_option('log.enabled', true, 'bool'))
if (self :: get('log.enabled', true, 'bool'))
Log::init();
if (self :: get_option('session.enabled', true, 'bool'))
if (self :: get('session.enabled', true, 'bool'))
Session::init();
if (self :: get_option('template.enabled', true, 'bool'))
if (self :: get('template.enabled', true, 'bool'))
Tpl :: init();
if (self :: get_option('url.enabled', true, 'bool'))
if (self :: get('url.enabled', true, 'bool'))
Url::init();
if (self :: get_option('mail.enabled', true, 'bool'))
if (self :: get('mail.enabled', true, 'bool'))
Email :: init();
if (self :: get_option('i18n.enabled', true, 'bool'))
if (self :: get('i18n.enabled', true, 'bool'))
I18n::init();
$sentry_span->finish();
}
/**
* Check if the application is initialized
* @return bool
*/
public static function initialized() {
return !is_null(self :: $root_directory_path);
}
/**
* Get a specific option value
*
@ -82,7 +90,7 @@ class App {
* is a string, split the value by comma (optional, default: true)
* @return mixed The configuration variable value
**/
public static function get_option($key, $default=null, $cast=null, $split=true) {
public static function get($key, $default=null, $cast=null, $split=true) {
return Config::get(
$key,
Config::loaded()?Config::get($key, $default, $cast, $split):$default,

View File

@ -68,31 +68,31 @@ class Email {
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 = Config::get('email.sender', null, 'string');
$sender = App::get('email.sender', null, 'string');
if ($sender) self :: $sender = $sender;
if (is_null($send_method))
$send_method = Config::get('email.send_method', null, 'string');
$send_method = App::get('email.send_method', null, 'string');
if ($send_method) self :: $send_method = $send_method;
if (is_null($send_params))
$send_params = Config::get('email.send_params', null, 'array');
$send_params = App::get('email.send_params', null, 'array');
if ($send_params) self :: $send_params = $send_params;
if (is_null($catch_all))
$catch_all = Config::get('email.catch_all');
$catch_all = App::get('email.catch_all');
if ($catch_all) self :: $catch_all = $catch_all;
if (is_null($headers))
$headers = Config::get('email.headers', null, 'array');
$headers = App::get('email.headers', null, 'array');
if ($headers) self :: $headers = $headers;
if (is_null($php_mail_path))
$php_mail_path = Config::get('email.php_mail_path', null, 'string');
$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 = Config::get('email.php_mail_mime_path', null, 'string');
$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;
}

View File

@ -36,13 +36,13 @@ class I18n {
*/
public static function init($root_path=null, $default_locale=null) {
if (is_null($root_path))
self :: $root_path = Config::get(
self :: $root_path = App::get(
'i18n.root_directory', '${root_directory_path}/locales', 'string');
if (!is_null($root_path))
self :: $root_path = $root_path;
if (is_null($default_locale))
self :: $default_locale = Config::get('i18n.default_locale', null, 'string');
self :: $default_locale = App::get('i18n.default_locale', null, 'string');
if (!is_null($default_locale))
self :: $default_locale = $default_locale;
@ -68,7 +68,10 @@ class I18n {
else {
$lang = Locale::lookup(
self :: get_available_langs(),
Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']),
Locale::acceptFromHttp(
isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])?
$_SERVER['HTTP_ACCEPT_LANGUAGE']:null
),
true,
Locale::getPrimaryLanguage(self :: $default_locale)
);
@ -111,13 +114,13 @@ class I18n {
Log :: trace("Test: "._('Hello world !'));
// JS translation file
$js_translation_file = "translations/$lang.js";
if (
php_sapi_name() != "cli"
&& is_file(App :: root_directory_path()."/public_html/$js_translation_file")
&& Tpl :: initialized()
) {
Tpl :: add_js_file(array("lib/babel.js", "js/translation.js", $js_translation_file));
Tpl :: register_static_directory(self :: $root_path, null, 'locales/');
Tpl :: add_js_file("lib/babel.js", "js/translation.js");
Tpl :: add_js_file("locales/", "$lang.js");
}
if (php_sapi_name() == 'cli') {

View File

@ -72,19 +72,19 @@ class Log {
if ($filepath)
self :: $filepath = $filepath;
elseif (php_sapi_name() == 'cli')
self :: $filepath = Config::get(
'log.cli_logfile_path', Config::get('log.cli_file_path'));
self :: $filepath = App::get(
'log.cli_logfile_path', App::get('log.cli_file_path'));
else
self :: $filepath = Config::get('log.file_path');
self :: $filepath = App::get('log.file_path');
// Set log level
self :: set_level($level?$level:Config::get('log.level'));
self :: set_level($level?$level:App::get('log.level'));
// Log PHP errors
if (!is_null($php_errors_levels)) {
self :: $php_errors_levels = $php_errors_levels;
}
elseif ($levels = Config::get('log.php_errors_levels', array(), 'array')) {
elseif ($levels = App::get('log.php_errors_levels', array(), 'array')) {
$code = 'self :: $php_errors_levels = ';
while($level = array_shift($levels)) {
if (!is_string($level)) continue;

View File

@ -38,11 +38,11 @@ class SentryIntegration {
public static function init($dsn=null, $traces_sample_rate=null,
$php_error_types=null) {
\Sentry\init([
'dsn' => $dsn?$dsn:Config::get('sentry.dsn'),
'dsn' => $dsn?$dsn:App::get('sentry.dsn'),
'traces_sample_rate' => (
$traces_sample_rate?
$traces_sample_rate:
Config::get('sentry.traces_sample_rate', 0.2, 'float')
App::get('sentry.traces_sample_rate', 0.2, 'float')
),
]);
@ -57,7 +57,7 @@ class SentryIntegration {
});
if (!is_array($php_error_types))
$php_error_types = Config::get(
$php_error_types = App::get(
'sentry.php_error_types', self :: $php_error_types, 'array'
);
self :: $php_error_types = array();

View File

@ -27,7 +27,7 @@ class Session {
// Define session max duration
if (is_null($max_duration))
$max_duration = Config::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;
@ -44,7 +44,7 @@ class Session {
// Handle session timeout
if (is_null($timeout))
$timeout = Config::get('session.timeout', null, 'int');
$timeout = App::get('session.timeout', null, 'int');
if (is_int($timeout) && $timeout) {
if (!isset($_SESSION['session_last_access'])) {
Log :: debug('Set initial session last access');

View File

@ -5,6 +5,7 @@ namespace EesyPHP;
use Exception;
use Smarty;
use Smarty_Security;
use League\MimeTypeDetection\ExtensionMimeTypeDetector;
class Tpl {
@ -38,6 +39,12 @@ class Tpl {
*/
public static bool $_debug_ajax;
/**
* Static directories
* @var array
*/
private static array $static_directories = array();
/**
* CSS files to load in next displayed page
* @var array<string>
@ -50,6 +57,18 @@ class Tpl {
*/
private static array $js_files = array();
/**
* 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;
/**
* Initialization
* @param string $templates_dir Smarty templates directory path
@ -59,14 +78,18 @@ class Tpl {
* @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)
* @param bool $static_root_url Configure custom root URL path for static files
* (optional, default: from template.static_root_url config key if set,
* '/static' otherwise. Set to False to disable)
* @return void
*/
public static function init($templates_dir=null, $templates_c_dir=null, $debug_ajax=null) {
public static function init($templates_dir=null, $templates_c_dir=null, $debug_ajax=null,
$static_root_url=null) {
// Check templates/templates_c directories
if (is_null($templates_dir))
$templates_dir = Config::get('template.directory', null, 'string');
$templates_dir = App::get('template.directory', null, 'string');
if (is_null($templates_c_dir))
$templates_c_dir = Config::get('template.cache_directory', null, 'string');
$templates_c_dir = App::get('template.cache_directory', null, 'string');
if (!$templates_dir || !is_dir($templates_dir)) {
Log :: fatal(
"Template directory not found (%s)",
@ -83,9 +106,25 @@ class Tpl {
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'));
$debug_ajax = App::get('template.debug_ajax', App::get('debug_ajax'));
self :: $_debug_ajax = boolval($debug_ajax);
Log :: register_fatal_error_handler(array('\\EesyPHP\\Tpl', 'fatal_error'));
if (is_null($static_root_url))
$static_root_url = App::get('template.static_root_url', 'static/', 'string');
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;
$default_static_directory = realpath(__DIR__."/../static");
self :: register_static_directory($default_static_directory, 100);
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);
}
}
/**
@ -175,30 +214,50 @@ class Tpl {
/**
* Register CSS file(s) to load on next displayed page
* @param array<string|array<string>> $args CSS files to load
* @param string|array<string> $args CSS files to load
* @return void
*/
public static function add_css_file(...$args) {
// 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));
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;
$path = $root_url.$file;
if (!in_array($path, self :: $css_files))
self :: $css_files[] = $path;
}
}
}
/**
* Register JS file(s) to load on next displayed page
* @param array<string|array<string>> $args JS files to load
* @param string|array<string> $args JS files to load
* @return void
*/
public static function add_js_file(...$args) {
// 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));
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;
$path = $root_url.$file;
if (!in_array($path, self :: $js_files))
self :: $js_files[] = $path;
}
}
}
@ -360,4 +419,128 @@ class Tpl {
public static function templates_directory() {
return isset(self :: $templates_directory)?self :: $templates_directory:null;
}
/**
* 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;
}
/**
* 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'),
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);
}
if (substr($path, -1) == PATH_SEPARATOR)
$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;
}
}

View File

@ -57,7 +57,7 @@ class Url {
*/
public static function init($public_root_url=null, $api_mode=false) {
if (is_null($public_root_url))
$public_root_url = Config::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) {
// Check URL end
if (substr(self :: $public_root_url, -1) == '/')
@ -201,6 +201,15 @@ class Url {
return false;
}
/**
* Trigger a 404 HTTP error
* @param UrlRequest|null $request Current UrlRequest object (optional, default: null)
* @return void
*/
public static function trigger_error_404($request=null) {
call_user_func_array(self :: $error_404_handler, array($request));
}
/**
* Interprets the requested URL and return the corresponding UrlRequest object

View File

@ -2,6 +2,8 @@
namespace EesyPHP;
use League\MimeTypeDetection\ExtensionMimeTypeDetector;
/*
* Parser/formater values helpers
*/
@ -120,12 +122,28 @@ function cast($value, $type, $split=false) {
/*
* Generic file/directory helpers
*/
function dump_file($file_path, $max_age=3600) {
/**
* Dump file content to propose its download
* @param string $file_path The file path
* @param string|null $mime_type The file MIME type (optional, default: auto-detected)
* @param int|null $max_age Max age in second of this file in browser cache (optional,
* default: null=1h, set to False to disable Cache-Control header)
* @return void
*/
function dump_file($file_path, $mime_type=null, $max_age=null) {
if (is_file($file_path)) {
header('Content-Type: '.mime_content_type($file_path));
if (is_null($mime_type)) {
$detector = new ExtensionMimeTypeDetector();
$mime_type = $detector->detectMimeTypeFromFile($file_path);
Log::trace('MIME type detected for "%s" is "%s"', $file_path, $mime_type);
}
header("Content-Type: $mime_type");
$last_modified_time = filemtime($file_path);
$etag = md5_file($file_path);
header("Cache-Control: max-age=$max_age, must-revalidate");
$max_age = is_null($max_age)?3600:$max_age;
if ($max_age)
header("Cache-Control: max-age=$max_age, must-revalidate");
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
header("Etag: $etag");
@ -147,8 +165,7 @@ function dump_file($file_path, $max_age=3600) {
readfile($file_path);
exit();
}
header("HTTP/1.1 404 Not found");
exit();
Url :: trigger_error_404();
}
function delete_directory($dir, $recursive=true) {

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 470 KiB

After

Width:  |  Height:  |  Size: 470 KiB

Some files were not shown because too many files have changed in this diff Show More