2020-04-18 00:51:33 +02:00
< ? php
2021-07-28 17:13:10 +02:00
/*
* Configured URL patterns :
*
* Example :
*
* array (
* '|get/(?P<name>[a-zA-Z0-9]+)$|' => array (
* 'handler' => 'get' ,
* 'authenticated' => true ,
* 'api_mode' => false ,
* 'methods' => array ( 'GET' ),
* ),
* '|get/all$|' => => array (
* 'handler' => 'get_all' ,
* 'authenticated' => true ,
* 'api_mode' => false ,
* 'methods' => array ( 'GET' , 'POST' ),
* ),
* )
*
*/
2020-04-18 00:51:33 +02:00
$url_patterns = array ();
2021-07-28 17:13:10 +02:00
/**
* Add an URL pattern
*
* @ param [ in ] $pattern string The URL pattern ( required )
* @ param [ in ] $handler callable The URL pattern handler ( must be callable , required )
* @ param [ in ] $authenticated boolean Permit to define if this URL is accessible only for authenticated users ( optional , default : true )
* @ param [ in ] $override boolean Allow override if a command already exists with the same name ( optional , default : false )
* @ param [ in ] $api_mode boolean Enable API mode ( optional , default : false )
* @ param [ in ] $methods array | null HTTP method ( optional , default : array ( 'GET' , 'POST' ))
**/
function add_url_handler ( $pattern , $handler = null , $authenticated = false , $override = true , $api_mode = false , $methods = null ) {
if ( is_null ( $methods ))
$methods = array ( 'GET' , 'POST' );
elseif ( ! is_array ( $methods ))
$methods = array ( $methods );
global $url_patterns ;
if ( is_array ( $pattern )) {
if ( is_null ( $handler ))
foreach ( $pattern as $p => $h )
add_url_handler ( $p , $h , $authenticated , $override , $api_mode , $methods );
else
foreach ( $pattern as $p )
add_url_handler ( $p , $handler , $authenticated , $override , $api_mode , $methods );
}
else {
if ( ! isset ( $url_patterns [ $pattern ])) {
$url_patterns [ $pattern ] = array (
'handler' => $handler ,
'authenticated' => $authenticated ,
'api_mode' => $api_mode ,
'methods' => $methods ,
);
}
elseif ( $override ) {
logging ( 'DEBUG' , " URL : override pattern ' $pattern ' with handler ' $handler ' (old handler = ' " . $url_patterns [ $pattern ] . " ') " );
$url_patterns [ $pattern ] = array (
'handler' => $handler ,
'authenticated' => $authenticated ,
'api_mode' => $api_mode ,
'methods' => $methods ,
);
}
else {
logging ( 'DEBUG' , " URL : pattern ' $pattern ' already defined : do not override. " );
}
}
2020-04-18 00:51:33 +02:00
}
/*
* Error 404 page
*/
2021-07-28 17:13:10 +02:00
/**
* Error 404 handler
*
* @ param [ in ] $request UrlRequest | null The request ( optional , default : null )
*
* @ retval void
**/
function error_404 ( $request = null ) {
display_template ( 'error_404.tpl' , _ ( " Whoops ! Page not found " ));
exit ();
2020-04-18 00:51:33 +02:00
}
$_404_url_handler = 'error_404' ;
function set_404_url_handler ( $handler = null ) {
2021-07-28 17:13:10 +02:00
global $_404_url_handler ;
$_404_url_handler = $handler ;
2020-04-18 00:51:33 +02:00
}
/*
2021-07-28 17:13:10 +02:00
* Interprets the requested URL and return the corresponding UrlRequest object
2020-04-18 00:51:33 +02:00
*
2021-07-28 17:13:10 +02:00
* @ param [ in ] $default_url string | null The default URL if current one does not
* match with any configured pattern .
2020-04-18 00:51:33 +02:00
*
2021-07-28 17:13:10 +02:00
* @ retval UrlRequest The UrlRequest object corresponding to the the requested URL .
*/
function get_request ( $default_url = null ) {
global $url_patterns , $_404_url_handler ;
$current_url = get_current_url ();
if ( $current_url === false ) {
logging ( 'FATAL' , _ ( 'Unable to determine the requested page. If the problem persists, please contact support.' ));
exit ();
}
if ( ! is_array ( $url_patterns )) {
logging ( 'FATAL' , 'URL : No URL patterns configured !' );
exit ();
}
logging ( 'DEBUG' , " URL : current url = ' $current_url ' " );
logging ( 'DEBUG' , " URL : check current url with the following URL patterns : \n - " . implode ( " \n - " , array_keys ( $url_patterns )));
foreach ( $url_patterns as $pattern => $handler_infos ) {
$m = url_match ( $pattern , $current_url , $handler_infos [ 'methods' ]);
if ( is_array ( $m )) {
$request = new UrlRequest ( $current_url , $handler_infos , $m );
// Reset last redirect
if ( isset ( $_SESSION [ 'last_redirect' ]))
unset ( $_SESSION [ 'last_redirect' ]);
logging ( 'DEBUG' , " URL : result : \n " . varDump ( $request , 1 ));
return $request ;
}
}
if ( $default_url !== false ) {
logging ( 'DEBUG' , " Current url match with no pattern. Redirect to default url (' $default_url ') " );
redirect ( $default_url );
exit ();
}
// Error 404
$api_mode = ( strpos ( $current_url , 'api/' ) === 0 );
logging ( 'DEBUG' , " Current URL match with no pattern. Use error 404 handler (API mode= $api_mode ). " );
return new UrlRequest (
$current_url ,
array (
'handler' => $_404_url_handler ,
'authenticated' => false ,
'api_mode' => $api_mode ,
)
);
}
/**
* Check if the current requested URL match with a specific pattern
2020-04-18 00:51:33 +02:00
*
2021-07-28 17:13:10 +02:00
* @ param [ in ] $pattern string The URL pattern
* @ param [ in ] $current_url string | false The current URL ( optional )
* @ param [ in ] $methods array | null HTTP method ( optional , default : no check )
2020-04-18 00:51:33 +02:00
*
2021-07-28 17:13:10 +02:00
* @ retval array | false The URL info if pattern matched , false otherwise .
**/
function url_match ( $pattern , $current_url = false , $methods = null ) {
if ( $methods && ! in_array ( $_SERVER [ 'REQUEST_METHOD' ], $methods ))
return false ;
if ( $current_url === false ) {
$current_url = get_current_url ();
if ( ! $current_url ) return False ;
}
if ( preg_match ( $pattern , $current_url , $m )) {
logging ( 'DEBUG' , " URL : Match found with pattern ' $pattern ' : \n \t " . str_replace ( " \n " , " \n \t " , print_r ( $m , 1 )));
return $m ;
}
return False ;
}
/*
* Retreive current requested URL and return it
2020-04-18 00:51:33 +02:00
*
2021-07-28 17:13:10 +02:00
* @ retval string | false The current request URL or false if fail
**/
function get_current_url () {
logging ( 'DEBUG' , " URL : request URI = ' " . $_SERVER [ 'REQUEST_URI' ] . " ' " );
$base = get_rewrite_base ();
logging ( 'DEBUG' , " URL : rewrite base = ' $base ' " );
if ( $_SERVER [ 'REQUEST_URI' ] == $base )
return '' ;
if ( substr ( $_SERVER [ 'REQUEST_URI' ], 0 , strlen ( $base )) != $base ) {
logging ( 'ERROR' , " URL : request URI ( " . $_SERVER [ 'REQUEST_URI' ] . " ) does not start with rewrite base ( $base ) " );
return False ;
}
$current_url = substr ( $_SERVER [ 'REQUEST_URI' ], strlen ( $base ));
// URL contain params ?
$params_start = strpos ( $current_url , '?' );
if ( $params_start !== false )
// Params detected, remove it
// No url / currrent url start by '?' ?
if ( $params_start == 0 )
return '' ;
else
return substr ( $current_url , 0 , $params_start );
return $current_url ;
2020-04-18 00:51:33 +02:00
}
2021-07-28 17:13:10 +02:00
/**
* Try to detect rewrite base from public root URL
*
* @ retval string The detected rewrite base
**/
2020-04-18 00:51:33 +02:00
function get_rewrite_base () {
2021-07-28 17:13:10 +02:00
global $public_root_url ;
if ( preg_match ( '|^https?://[^/]+/(.*)$|' , $public_root_url , $m ))
return '/' . remove_trailing_slash ( $m [ 1 ]) . '/' ;
elseif ( preg_match ( '|^/(.*)$|' , $public_root_url , $m ))
return '/' . remove_trailing_slash ( $m [ 1 ]) . '/' ;
return '/' ;
2020-04-18 00:51:33 +02:00
}
2021-07-28 17:13:10 +02:00
/**
* Trigger redirect to specified URL ( or homepage if omited )
*
* @ param [ in ] $go string | false The destination URL
*
* @ retval void
**/
2020-04-18 00:51:33 +02:00
function redirect ( $go = false ) {
2021-07-28 17:13:10 +02:00
global $public_root_url ;
if ( $go === false )
$go = " " ;
if ( is_absolute_url ( $go ))
$url = $go ;
elseif ( isset ( $public_root_url ) && $public_root_url ) {
// Check $public_root_url end
if ( substr ( $public_root_url , - 1 ) == '/' ) {
$public_root_url = substr ( $public_root_url , 0 , - 1 );
}
$url = " $public_root_url / $go " ;
}
else
$url = " / $go " ;
// Prevent loop
if ( isset ( $_SESSION [ 'last_redirect' ]) && $_SESSION [ 'last_redirect' ] == $url )
logging ( 'FATAL' , _ ( 'Unable to determine the requested page (loop detected). If the problem persists, please contact support.' ));
else
$_SESSION [ 'last_redirect' ] = $url ;
logging ( 'DEBUG' , " redirect( $go ) => Redirect to : < $url > " );
header ( " Location: $url " );
exit ();
}
/**
* Handle the current requested URL
*
* @ param [ in ] $default_url string | null The default URL if current one does not
* match with any configured pattern .
*
* @ retval void
**/
function handle_request ( $default_url = null ) {
global $smarty , $api_mode ;
$request = get_request ( $default_url );
if ( ! is_callable ( $request -> handler )) {
logging ( 'ERROR' , " URL handler function " . $request -> handler . " () does not exists ! " );
logging ( 'FATAL' , _ ( " This request cannot be processed. " ));
}
if ( $request -> api_mode )
$api_mode = true ;
if ( isset ( $smarty ) && $smarty )
$smarty -> assign ( 'request' , $request );
// Check authentication (if need)
if ( $request -> authenticated && function_exists ( 'force_authentication' ))
force_authentication ();
try {
return call_user_func ( $request -> handler , $request );
}
catch ( Exception $e ) {
log_exception ( $e , " An exception occured running URL handler function " . $request -> handler . " () " );
logging ( 'FATAL' , _ ( " This request could not be processed correctly. " ));
}
2020-04-18 00:51:33 +02:00
}
2021-07-28 17:13:10 +02:00
/**
* Remove trailing slash in specified URL
*
* @ param [ in ] $url string The URL
*
* @ retval string The specified URL without trailing slash
**/
2020-04-18 00:51:33 +02:00
function remove_trailing_slash ( $url ) {
2021-07-28 17:13:10 +02:00
if ( $url == '/' )
return $url ;
elseif ( substr ( $url , - 1 ) == '/' )
return substr ( $url , 0 , - 1 );
return $url ;
2020-04-18 00:51:33 +02:00
}
2021-07-28 17:13:10 +02:00
/**
* Check an AJAX request and trigger a fatal error on fail
*
* Check if session key is present and valid and set AJAX
* mode .
*
* @ param [ in ] $session_key string The current session key ( optional )
*
* @ retval void
**/
2020-04-18 00:51:33 +02:00
function check_ajax_request ( $session_key = null ) {
2021-07-28 17:13:10 +02:00
global $ajax , $debug_ajax ;
$ajax = true ;
if ( check_session_key ( $session_key ))
fatal_error ( 'Invalid request' );
if ( $debug_ajax )
logging ( 'DEBUG' , " Ajax Request : " . vardump ( $_REQUEST ));
}
/**
* Get the public absolute URL
*
* @ param [ in ] $relative_url string | null Relative URL to convert ( Default : current URL )
*
* @ retval string The public absolute URL
**/
function get_absolute_url ( $relative_url = null ) {
global $public_root_url ;
if ( ! is_string ( $relative_url ))
$relative_url = get_current_url ();
if ( $public_root_url [ 0 ] == '/' ) {
logging ( 'DEBUG' , " URL :: get_absolute_url( $relative_url ): configured public root URL is relative ( $public_root_url ) => try to detect it from current request infos. " );
$public_root_url = 'http' . ( isset ( $_SERVER [ 'HTTPS' ]) && $_SERVER [ 'HTTPS' ] == 'on' ? 's' : '' ) . '://' . $_SERVER [ 'HTTP_HOST' ] . $public_root_url ;
logging ( 'DEBUG' , " URL :: get_absolute_url( $relative_url ): detected public_root_url: $public_root_url " );
}
if ( substr ( $relative_url , 0 , 1 ) == '/' )
$relative_url = substr ( $url , 1 );
$url = remove_trailing_slash ( $public_root_url ) . " / $relative_url " ;
logging ( 'DEBUG' , " URL :: get_absolute_url( $relative_url ): result = $url " );
return $url ;
}
2020-04-18 00:51:33 +02:00
2021-07-28 17:13:10 +02:00
/**
* Check if specified URL is absolute
*
* @ param [ in ] $url string The URL to check
*
* @ retval boolean True if specified URL is absolute , False otherwise
**/
function is_absolute_url ( $url ) {
return boolval ( preg_match ( '#^https?://#' , $url ));
}
/*
* Add parameter in specified URL
*
* @ param [ in ] & $url string The reference of the URL
* @ param [ in ] $param string The parameter name
* @ param [ in ] $value string The parameter value
* @ param [ in ] $encode boolean Set if parameter value must be URL encoded ( optional , default : true )
*
* @ retval string | null The completed URL
*/
function add_url_parameter ( & $url , $param , $value , $encode = true ) {
if ( strpos ( $url , '?' ) === false )
$url .= '?' ;
else
$url .= '&' ;
$url .= " $param = " . ( $encode ? urlencode ( $value ) : $value );
return $url ;
}
/**
* URL request abstraction
*
* @ author Benjamin Renard < brenard @ easter - eggs . com >
*/
class UrlRequest {
2020-04-18 00:51:33 +02:00
2021-07-28 17:13:10 +02:00
// The URL requested handler
private $current_url = null ;
// The URL requested handler
private $handler = null ;
// Request need authentication ?
private $authenticated = true ;
// API mode enabled ?
private $api_mode = false ;
// Parameters detected on requested URL
private $url_params = array ();
public function __construct ( $current_url , $handler_infos , $url_params = array ()) {
$this -> current_url = $current_url ;
$this -> handler = $handler_infos [ 'handler' ];
$this -> authenticated = ( isset ( $handler_infos [ 'authenticated' ]) ? boolval ( $handler_infos [ 'authenticated' ]) : true );
$this -> api_mode = ( isset ( $handler_infos [ 'api_mode' ]) ? boolval ( $handler_infos [ 'api_mode' ]) : false );
$this -> url_params = $url_params ;
}
/**
* Get request info
*
* @ param [ in ] $key string The name of the info
*
* @ retval mixed The value
**/
public function __get ( $key ) {
if ( $key == 'current_url' )
return $this -> current_url ;
if ( $key == 'handler' )
return $this -> handler ;
if ( $key == 'authenticated' )
return $this -> authenticated ;
if ( $key == 'api_mode' )
return $this -> api_mode ;
if ( $key == 'referer' )
return $this -> get_referer ();
if ( $key == 'http_method' )
return $_SERVER [ 'REQUEST_METHOD' ];
if ( array_key_exists ( $key , $this -> url_params )) {
return urldecode ( $this -> url_params [ $key ]);
}
// Unknown key, log warning
logging ( 'WARNING' , " __get( $key ): invalid property requested \n " . get_debug_backtrace_context ());
}
/**
* Check is request info is set
*
* @ param [ in ] $key string The name of the info
*
* @ retval boolval True is info is set , False otherwise
**/
public function __isset ( $key ) {
if ( in_array ( $key , array ( 'current_url' , 'handler' , 'authenticated' )))
return True ;
return array_key_exists ( $key , $this -> url_params );
}
2021-07-28 18:18:36 +02:00
/**
* Get request parameter
*
* @ param [ in ] $parameter string The name of the parameter
* @ param [ in ] $decode string If true , the parameter value will be urldecoded ( optional , default : true )
*
* @ retval mixed The value or false if parameter does not exists
**/
public function get_param ( $parameter , $decode = true ) {
if ( array_key_exists ( $parameter , $this -> url_params )) {
if ( $decode )
return urldecode ( $this -> url_params [ $parameter ]);
return $this -> url_params [ $parameter ];
}
return false ;
}
2021-07-28 17:13:10 +02:00
/*
* Get request referer ( if known )
*
* @ retval string | null The request referer URL if known , null otherwise
*/
public function get_referer () {
if ( isset ( $_SERVER [ 'HTTP_REFERER' ]) && $_SERVER [ 'HTTP_REFERER' ])
return $_SERVER [ 'HTTP_REFERER' ];
return null ;
}
2020-04-18 00:51:33 +02:00
}