Compare commits
No commits in common. "cf6ea5480b2340b98b19a5e598cca31e9bc7d690" and "6fdc5447f1b2929f305f11bae588d31e4eb48f3c" have entirely different histories.
cf6ea5480b
...
6fdc5447f1
30 changed files with 1577 additions and 2176 deletions
|
@ -5,4 +5,4 @@ require realpath(dirname(__FILE__).'/..')."/includes/core.php";
|
||||||
if (is_callable('handle_cli_args'))
|
if (is_callable('handle_cli_args'))
|
||||||
handle_cli_args();
|
handle_cli_args();
|
||||||
else
|
else
|
||||||
Log :: fatal("An error occured initializing CLI : handle_cli_args() function not found.");
|
logging('FATAL', "An error occured initializing CLI : handle_cli_args() function not found.");
|
||||||
|
|
|
@ -7,14 +7,6 @@
|
||||||
"email": "info@easter-eggs.com"
|
"email": "info@easter-eggs.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"EesyPHP\\": "src/"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"src/functions.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"require": {
|
"require": {
|
||||||
"envms/fluentpdo": "^1.1",
|
"envms/fluentpdo": "^1.1",
|
||||||
"pear/console_table": "^1.3",
|
"pear/console_table": "^1.3",
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Check;
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
$cli_commands=array();
|
$cli_commands=array();
|
||||||
function add_cli_command($command, $handler, $short_desc, $usage_args=false, $long_desc=false,
|
function add_cli_command($command, $handler, $short_desc, $usage_args=false, $long_desc=false,
|
||||||
$override=false) {
|
$override=false) {
|
||||||
global $cli_commands;
|
global $cli_commands;
|
||||||
if (array_key_exists($command, $cli_commands) && !$override) {
|
if (array_key_exists($command, $cli_commands) && !$override) {
|
||||||
Log :: error(_("The CLI command '%s' already exists."), $command);
|
logging('ERROR', _("The CLI command '%s' already exists."), $command);
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_callable($handler)) {
|
if (!is_callable($handler)) {
|
||||||
Log :: error(_("The CLI command '%s' handler is not callable !"), $command);
|
logging('ERROR', _("The CLI command '%s' handler is not callable !"), $command);
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,8 +135,8 @@ function handle_cli_args() {
|
||||||
if (!$cli_command)
|
if (!$cli_command)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
Log :: debug(
|
logging(
|
||||||
"Run %s command %s with argument(s) '%s'.",
|
'DEBUG', "Run %s command %s with argument(s) '%s'.",
|
||||||
basename($argv[0]), $cli_command, implode("', '", $command_args)
|
basename($argv[0]), $cli_command, implode("', '", $command_args)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -149,7 +146,7 @@ function handle_cli_args() {
|
||||||
exit($result?0:1);
|
exit($result?0:1);
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
Log :: exception($e, _("An exception occured running command %s"), $cli_command);
|
log_exception($e, _("An exception occured running command %s"), $cli_command);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +208,7 @@ function cli_list($command_args) {
|
||||||
|
|
||||||
$items = search_items($params);
|
$items = search_items($params);
|
||||||
if (!is_array($items)) {
|
if (!is_array($items)) {
|
||||||
Log :: error("Invalid DB info return.\n");
|
logging("ERROR", "Invalid DB info return.\n");
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,14 +257,14 @@ add_cli_command(
|
||||||
);
|
);
|
||||||
|
|
||||||
function cli_show($command_args) {
|
function cli_show($command_args) {
|
||||||
if (count($command_args) != 1 || !Check :: id($command_args[0]))
|
if (count($command_args) != 1 || !check_id($command_args[0]))
|
||||||
usage(_('You must provide a valid ID.'));
|
usage(_('You must provide a valid ID.'));
|
||||||
|
|
||||||
$item_id = $command_args[0];
|
$item_id = $command_args[0];
|
||||||
$item = get_item($item_id);
|
$item = get_item($item_id);
|
||||||
|
|
||||||
if (!$item)
|
if (!$item)
|
||||||
Log :: fatal(_("Item #%s not found."), $item_id);
|
logging('FATAL', _("Item #%s not found."), $item_id);
|
||||||
|
|
||||||
print_item_info($item);
|
print_item_info($item);
|
||||||
return True;
|
return True;
|
||||||
|
@ -284,14 +281,14 @@ function cli_delete($command_args) {
|
||||||
usage(_('You must provide item ID.'));
|
usage(_('You must provide item ID.'));
|
||||||
|
|
||||||
// Check URI
|
// Check URI
|
||||||
if (!Check :: id($command_args[0]))
|
if (!check_id($command_args[0]))
|
||||||
Log :: fatal(_("Invalid item ID"));
|
logging('FATAL', _("Invalid item ID"));
|
||||||
|
|
||||||
// Check exist
|
// Check exist
|
||||||
$item_id = $command_args[0];
|
$item_id = $command_args[0];
|
||||||
$item = get_item($item_id);
|
$item = get_item($item_id);
|
||||||
if (!$item)
|
if (!$item)
|
||||||
Log :: fatal(_("Item #%s not found."), $item_id);
|
logging('FATAL', _("Item #%s not found."), $item_id);
|
||||||
|
|
||||||
print_item_info($item);
|
print_item_info($item);
|
||||||
|
|
||||||
|
@ -300,13 +297,13 @@ function cli_delete($command_args) {
|
||||||
$handle = fopen ("php://stdin","r");
|
$handle = fopen ("php://stdin","r");
|
||||||
$line = fgets($handle);
|
$line = fgets($handle);
|
||||||
if(trim($line) != 'yes'){
|
if(trim($line) != 'yes'){
|
||||||
Log :: warning(_("User cancel"));
|
logging('WARNING', _("User cancel"));
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
echo "\n";
|
echo "\n";
|
||||||
|
|
||||||
if (!delete_item($item['id']))
|
if (!delete_item($item['id']))
|
||||||
Log :: fatal(_("An error occured deleting item #%d."), $item_id);
|
logging('FATAL', _("An error occured deleting item #%d."), $item_id);
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
@ -321,7 +318,7 @@ function cli_export($command_args) {
|
||||||
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://output'), 'w');
|
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://output'), 'w');
|
||||||
export_items($fd);
|
export_items($fd);
|
||||||
fclose($fd);
|
fclose($fd);
|
||||||
Log :: info("Items export to '".(count($command_args) >= 1?$command_args[0]:'STDOUT')."'.");
|
logging('INFO', "Items export to '".(count($command_args) >= 1?$command_args[0]:'STDOUT')."'.");
|
||||||
}
|
}
|
||||||
add_cli_command(
|
add_cli_command(
|
||||||
'export',
|
'export',
|
||||||
|
@ -334,8 +331,8 @@ function cli_restore($command_args) {
|
||||||
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://stdin'), 'r');
|
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://stdin'), 'r');
|
||||||
restore_items($fd);
|
restore_items($fd);
|
||||||
fclose($fd);
|
fclose($fd);
|
||||||
Log :: info(
|
logging(
|
||||||
"Items restored from '%s'",
|
'INFO', "Items restored from '%s'",
|
||||||
(count($command_args) >= 1?$command_args[0]:'STDIN')
|
(count($command_args) >= 1?$command_args[0]:'STDIN')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -357,7 +354,7 @@ function cli_cron($command_args) {
|
||||||
case '-m':
|
case '-m':
|
||||||
case '--max-age':
|
case '--max-age':
|
||||||
$i++;
|
$i++;
|
||||||
if(!Check :: id($command_args[$i]))
|
if(!check_id($command_args[$i]))
|
||||||
usage('Invalid -m|--max-age clause');
|
usage('Invalid -m|--max-age clause');
|
||||||
$item_max_age = $command_args[$i];
|
$item_max_age = $command_args[$i];
|
||||||
break;
|
break;
|
||||||
|
@ -371,36 +368,37 @@ function cli_cron($command_args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_int($item_max_age) || $item_max_age <= 0)
|
if (!is_int($item_max_age) || $item_max_age <= 0)
|
||||||
Log :: fatal(
|
logging(
|
||||||
|
'FATAL',
|
||||||
'Invalid $item_max_age value set in configuration: it\'s must be a positive integer.');
|
'Invalid $item_max_age value set in configuration: it\'s must be a positive integer.');
|
||||||
Log :: debug("cli_cron(): item max age = $item_max_age day(s)");
|
logging('DEBUG', "cli_cron(): item max age = $item_max_age day(s)");
|
||||||
|
|
||||||
$limit = time() - ($item_max_age * 86400);
|
$limit = time() - ($item_max_age * 86400);
|
||||||
Log :: debug("Handle items expiration with creation date limit ".format_time($limit).".");
|
logging('DEBUG', "Handle items expiration with creation date limit ".format_time($limit).".");
|
||||||
|
|
||||||
$items = search_items(array('all' => true));
|
$items = search_items(array('all' => true));
|
||||||
$error = false;
|
$error = false;
|
||||||
foreach($items['items'] as $item) {
|
foreach($items['items'] as $item) {
|
||||||
if ($item['date'] < $limit) {
|
if ($item['date'] < $limit) {
|
||||||
if ($just_try) {
|
if ($just_try) {
|
||||||
Log :: debug('Just-try mode: do not really delete item #%s (%s, creation date: %s)',
|
logging('DEBUG', 'Just-try mode: do not really delete item #%s (%s, creation date: %s)',
|
||||||
$item['id'], $item['name'], format_time($item['date'])
|
$item['id'], $item['name'], format_time($item['date'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (delete_item($item['id'])) {
|
else if (delete_item($item['id'])) {
|
||||||
Log :: info('Item #%s (%s) deleted (creation date: %s)',
|
logging('INFO', 'Item #%s (%s) deleted (creation date: %s)',
|
||||||
$item['id'], $item['name'], format_time($item['date'])
|
$item['id'], $item['name'], format_time($item['date'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: error('Fail to delete item "%s" (%s, creation date: %s)',
|
logging('ERROR', 'Fail to delete item "%s" (%s, creation date: %s)',
|
||||||
$item['id'], $item['name'], format_time($item['date'])
|
$item['id'], $item['name'], format_time($item['date'])
|
||||||
);
|
);
|
||||||
$error = true;
|
$error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: debug('Item "%s" (%s) still valid (creation date: %s)',
|
logging('DEBUG', 'Item "%s" (%s) still valid (creation date: %s)',
|
||||||
$item['id'], $item['name'], format_time($item['date'])
|
$item['id'], $item['name'], format_time($item['date'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Email;
|
|
||||||
use EesyPHP\Log;
|
|
||||||
use EesyPHP\SentryIntegration;
|
|
||||||
use EesyPHP\SentrySpan;
|
|
||||||
use EesyPHP\SentryTransaction;
|
|
||||||
use EesyPHP\Url;
|
|
||||||
|
|
||||||
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
|
error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
|
||||||
|
|
||||||
// Root directory path
|
// Root directory path
|
||||||
|
@ -29,6 +22,9 @@ set_include_path($root_dir_path.'/includes' . PATH_SEPARATOR . get_include_path(
|
||||||
// Load composer autoload.php
|
// Load composer autoload.php
|
||||||
require("$root_dir_path/vendor/autoload.php");
|
require("$root_dir_path/vendor/autoload.php");
|
||||||
|
|
||||||
|
// API mode
|
||||||
|
$api_mode = false;
|
||||||
|
|
||||||
// Load configuration
|
// Load configuration
|
||||||
require_once('translation.php');
|
require_once('translation.php');
|
||||||
require_once('config.inc.php');
|
require_once('config.inc.php');
|
||||||
|
@ -38,11 +34,7 @@ if (is_file("$root_dir_path/includes/config.local.php")) {
|
||||||
require "$root_dir_path/includes/config.local.php";
|
require "$root_dir_path/includes/config.local.php";
|
||||||
}
|
}
|
||||||
|
|
||||||
SentryIntegration :: init(
|
require_once 'sentry.php';
|
||||||
isset($sentry_dsn)?$sentry_dsn:null,
|
|
||||||
isset($sentry_traces_sample_rate)?$sentry_traces_sample_rate:null,
|
|
||||||
isset($sentry_php_error_types)?$sentry_php_error_types:null,
|
|
||||||
);
|
|
||||||
$sentry_transaction = new SentryTransaction();
|
$sentry_transaction = new SentryTransaction();
|
||||||
|
|
||||||
$sentry_span = new SentrySpan('core.init', 'Core initialization');
|
$sentry_span = new SentrySpan('core.init', 'Core initialization');
|
||||||
|
@ -51,13 +43,7 @@ $sentry_span = new SentrySpan('core.init', 'Core initialization');
|
||||||
if (isset($upload_tmp_dir))
|
if (isset($upload_tmp_dir))
|
||||||
ini_set('upload_tmp_dir', $upload_tmp_dir);
|
ini_set('upload_tmp_dir', $upload_tmp_dir);
|
||||||
|
|
||||||
if (!isset($log_file))
|
require_once('logging.php');
|
||||||
die('Log file path not configured');
|
|
||||||
Log::init(
|
|
||||||
$log_file,
|
|
||||||
isset($log_level)?$log_level:null,
|
|
||||||
isset($log_php_errors_levels)?$log_php_errors_levels:null
|
|
||||||
);
|
|
||||||
require_once('functions.php');
|
require_once('functions.php');
|
||||||
require_once('session.php');
|
require_once('session.php');
|
||||||
|
|
||||||
|
@ -69,21 +55,14 @@ $status_list = array (
|
||||||
'archived' => ___('Archived'),
|
'archived' => ___('Archived'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
require_once('hooks.php');
|
||||||
require_once('cli.php');
|
require_once('cli.php');
|
||||||
require_once('translation-cli.php');
|
require_once('translation-cli.php');
|
||||||
require_once('smarty.php');
|
require_once('smarty.php');
|
||||||
Url::init(isset($public_root_url)?$public_root_url:null);
|
require_once('url.php');
|
||||||
require_once('url-helpers.php');
|
require_once('url-helpers.php');
|
||||||
require_once('db.php');
|
require_once('db.php');
|
||||||
Email :: init(
|
require_once('mail.php');
|
||||||
isset($mail_sender)?$mail_sender:null,
|
|
||||||
isset($mail_send_method)?$mail_send_method:null,
|
|
||||||
isset($mail_send_params)?$mail_send_params:null,
|
|
||||||
isset($mail_catch_all)?$mail_catch_all:null,
|
|
||||||
isset($mail_headers)?$mail_headers:null,
|
|
||||||
isset($php_mail_path)?$php_mail_path:null,
|
|
||||||
isset($php_mail_mime_path)?$php_mail_mime_path:null,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Initialize translation
|
// Initialize translation
|
||||||
init_translation();
|
init_translation();
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Hook;
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
use Unidecode\Unidecode;
|
use Unidecode\Unidecode;
|
||||||
|
|
||||||
if (!isset($db_dsn)) {
|
if (!isset($db_dsn)) {
|
||||||
Log :: fatal('Database DSN not configured');
|
logging('FATAL', 'Database DSN not configured');
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,12 +33,12 @@ try {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log :: debug($msg);
|
logging('DEBUG',$msg);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
Log :: error("Fail to connect to DB (DSN : '$db_dsn') : ".$e->getMessage());
|
logging('ERROR',"Fail to connect to DB (DSN : '$db_dsn') : ".$e->getMessage());
|
||||||
Log :: fatal(_('Unable to connect to the database.'));
|
logging("FATAL", _('Unable to connect to the database.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -114,7 +111,7 @@ function get_items($orderby='id', $raw_values=false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: error("Error retreiving items info from database : ".$e->getMessage());
|
logging('ERROR', "Error retreiving items info from database : ".$e->getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +134,7 @@ function get_item($id, $raw_values=false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: error("Error retreiving item #$id info from database : ".$e->getMessage());
|
logging('ERROR', "Error retreiving item #$id info from database : ".$e->getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -152,13 +149,13 @@ function add_item($values) {
|
||||||
|
|
||||||
if ($result !== false) {
|
if ($result !== false) {
|
||||||
$item = get_item($result);
|
$item = get_item($result);
|
||||||
Log :: info("New item #$result added");
|
logging('INFO', "New item #$result added");
|
||||||
Hook :: trigger('item_added', $item);
|
trigger_hook('item_added', $item);
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: error("Error creating item in database : ".$e->getMessage());
|
logging('ERROR', "Error creating item in database : ".$e->getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -183,20 +180,20 @@ function update_item($id, $changes) {
|
||||||
-> execute();
|
-> execute();
|
||||||
|
|
||||||
if ($result !== false) {
|
if ($result !== false) {
|
||||||
Log :: info("Item #$id updated");
|
logging('INFO', "Item #$id updated");
|
||||||
Hook :: trigger('item_updated', $item);
|
trigger_hook('item_updated', $item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: error("Error updating item #$id in database : ".$e->getMessage());
|
logging('ERROR', "Error updating item #$id in database : ".$e->getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function change_item_status($id, $status) {
|
function change_item_status($id, $status) {
|
||||||
if (update_item($id, array('status' => $status))) {
|
if (update_item($id, array('status' => $status))) {
|
||||||
Log :: info("Status of item #$id changed to $status.");
|
logging('INFO', "Status of item #$id changed to $status.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -214,12 +211,12 @@ function delete_item($id) {
|
||||||
-> execute();
|
-> execute();
|
||||||
|
|
||||||
if ($result !== false) {
|
if ($result !== false) {
|
||||||
Log :: info("Item #$id deleted");
|
logging('INFO', "Item #$id deleted");
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: error("Error deleting item #$id from database : ".$e->getMessage());
|
logging('ERROR', "Error deleting item #$id from database : ".$e->getMessage());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +308,7 @@ function search_items($params) {
|
||||||
-> execute();
|
-> execute();
|
||||||
|
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
Log :: error('search_items() : search in DB return false');
|
logging('ERROR', 'search_items() : search in DB return false');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +344,7 @@ function search_items($params) {
|
||||||
$result_count = $query_count -> execute();
|
$result_count = $query_count -> execute();
|
||||||
|
|
||||||
if ($result_count === false) {
|
if ($result_count === false) {
|
||||||
Log :: debug('search_items() : search for count in DB return false');
|
logging('DEBUG', 'search_items() : search for count in DB return false');
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
$count = $result_count -> fetch();
|
$count = $result_count -> fetch();
|
||||||
|
@ -363,7 +360,7 @@ function search_items($params) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: exception(
|
log_exception(
|
||||||
$e, "An exception occured searching items with params %s infos from database : ",
|
$e, "An exception occured searching items with params %s infos from database : ",
|
||||||
preg_replace("/\n[ \t]*/", " ", print_r($params, true))
|
preg_replace("/\n[ \t]*/", " ", print_r($params, true))
|
||||||
);
|
);
|
||||||
|
@ -406,12 +403,12 @@ function restore_items($fd=null) {
|
||||||
$result = $fpdo -> deleteFrom('item')
|
$result = $fpdo -> deleteFrom('item')
|
||||||
-> execute();
|
-> execute();
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
Log :: error("An unknown error occured truncating item table in database.");
|
logging('ERROR', "An unknown error occured truncating item table in database.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: error("Error truncating item table in database : ".$e->getMessage());
|
logging('ERROR', "Error truncating item table in database : ".$e->getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,20 +450,21 @@ function restore_items($fd=null) {
|
||||||
$restored++;
|
$restored++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: error("Unkwown error occured restoring item from line #$line :\n".print_r($values, true));
|
logging('ERROR', "Unkwown error occured restoring item from line #$line :\n".print_r($values, true));
|
||||||
$error = true;
|
$error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: error(
|
logging(
|
||||||
|
'ERROR',
|
||||||
"Error restoring item from line #$line : ".$e->getMessage()."\n".print_r($values, true));
|
"Error restoring item from line #$line : ".$e->getMessage()."\n".print_r($values, true));
|
||||||
$error = true;
|
$error = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log :: info("$restored items restored");
|
logging('INFO', "$restored items restored");
|
||||||
|
|
||||||
// Trigger hooks
|
// Trigger hooks
|
||||||
Hook :: trigger('items_restored');
|
trigger_hook('items_restored');
|
||||||
|
|
||||||
return !$error;
|
return !$error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,85 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Check;
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check values helpers
|
* Check values helpers
|
||||||
*/
|
*/
|
||||||
|
function check_name($name) {
|
||||||
|
if (preg_match('/^[\w \-]{2,}$/iu',$name))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_id(&$id) {
|
||||||
|
if (is_int($id))
|
||||||
|
return true;
|
||||||
|
if (preg_match('/^[0-9]+$/', $id)) {
|
||||||
|
$id = intval($id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_search_pattern($pattern) {
|
||||||
|
foreach(preg_split('/\s+/', trim($pattern)) as $word) {
|
||||||
|
if (!check_id($word) && !check_name($word))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_time(&$time) {
|
||||||
|
if (!is_int($time)) {
|
||||||
|
if (preg_match('/^[0-9]+$/', $time))
|
||||||
|
$time = intval($time);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ($time >= 1577833200); // 2020-01-01 - date of birth of this soft
|
||||||
|
}
|
||||||
|
|
||||||
function check_status($status) {
|
function check_status($status) {
|
||||||
global $status_list;
|
global $status_list;
|
||||||
return array_key_exists($status, $status_list);
|
return array_key_exists($status, $status_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_description($comment) {
|
||||||
|
if (preg_match("/^[\p{L}0-9\p{P}\p{Zs}\p{Zl}\p{Sc}\=\+]+$/uim", $comment))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_email($value, $domain=NULL, $checkDns=true) {
|
||||||
|
$regex = '/^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/';
|
||||||
|
|
||||||
|
if (!preg_match($regex, $value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$nd = explode('@', $value);
|
||||||
|
$nd=$nd[1];
|
||||||
|
|
||||||
|
if ($domain) {
|
||||||
|
if(is_array($domain)) {
|
||||||
|
if (!in_array($nd,$domain)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if($nd!=$domain) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($checkDns && function_exists('checkdnsrr')) {
|
||||||
|
if (!(checkdnsrr($nd, 'MX') || checkdnsrr($nd, 'A'))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handling item POST data
|
* Handling item POST data
|
||||||
*/
|
*/
|
||||||
|
@ -18,11 +87,11 @@ function handle_item_post_data(&$info, $enabled_fields=null, $required_fields=nu
|
||||||
&$changes=null) {
|
&$changes=null) {
|
||||||
$field_errors=array();
|
$field_errors=array();
|
||||||
if (isset($_POST['submit'])) {
|
if (isset($_POST['submit'])) {
|
||||||
Log :: debug('POST data : '.vardump($_POST));
|
logging('DEBUG', 'POST data : '.vardump($_POST));
|
||||||
// Name
|
// Name
|
||||||
if (!$enabled_fields || in_array('name', $enabled_fields)) {
|
if (!$enabled_fields || in_array('name', $enabled_fields)) {
|
||||||
if (isset($_POST['name'])) {
|
if (isset($_POST['name'])) {
|
||||||
if (Check :: name($_POST['name'])) {
|
if (check_name($_POST['name'])) {
|
||||||
$info['name'] = $_POST['name'];
|
$info['name'] = $_POST['name'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -49,10 +118,10 @@ function handle_item_post_data(&$info, $enabled_fields=null, $required_fields=nu
|
||||||
isset($_POST['description']) &&
|
isset($_POST['description']) &&
|
||||||
(!$enabled_fields || in_array('description', $enabled_fields))
|
(!$enabled_fields || in_array('description', $enabled_fields))
|
||||||
) {
|
) {
|
||||||
if (Check :: is_empty(trim($_POST['description']))) {
|
if (check_is_empty(trim($_POST['description']))) {
|
||||||
$info['description'] = null;
|
$info['description'] = null;
|
||||||
}
|
}
|
||||||
else if (Check :: description($_POST['description'])) {
|
else if (check_description($_POST['description'])) {
|
||||||
$info['description'] = $_POST['description'];
|
$info['description'] = $_POST['description'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -66,7 +135,7 @@ function handle_item_post_data(&$info, $enabled_fields=null, $required_fields=nu
|
||||||
foreach ($required_fields as $field) {
|
foreach ($required_fields as $field) {
|
||||||
if (array_key_exists($field, $field_errors))
|
if (array_key_exists($field, $field_errors))
|
||||||
continue;
|
continue;
|
||||||
if (array_key_exists($field, $info) && !is_null($info[$field]) && !Check :: is_empty($info))
|
if (array_key_exists($field, $info) && !is_null($info[$field]) && !check_is_empty($info))
|
||||||
continue;
|
continue;
|
||||||
$field_errors[$field] = "Cette information est obligatoire.";
|
$field_errors[$field] = "Cette information est obligatoire.";
|
||||||
}
|
}
|
||||||
|
@ -182,6 +251,23 @@ function format_callable($callable) {
|
||||||
return vardump($callable);
|
return vardump($callable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_is_empty($val) {
|
||||||
|
switch(gettype($val)) {
|
||||||
|
case "boolean":
|
||||||
|
case "integer":
|
||||||
|
case "double":
|
||||||
|
case "object":
|
||||||
|
case "resource":
|
||||||
|
return False;
|
||||||
|
case "array":
|
||||||
|
case "string":
|
||||||
|
if ($val == "0") return false;
|
||||||
|
return empty($val);
|
||||||
|
case "NULL":
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic file/directory helpers
|
* Generic file/directory helpers
|
||||||
*/
|
*/
|
||||||
|
@ -222,18 +308,18 @@ function delete_directory($dir, $recursive=true) {
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
if (is_dir("$dir/$file")) {
|
if (is_dir("$dir/$file")) {
|
||||||
if (!delete_directory("$dir/$file", true)) {
|
if (!delete_directory("$dir/$file", true)) {
|
||||||
Log :: error("delete_directory($dir) : Fail to delete sub-directory '$dir/$file'.");
|
logging('ERROR', "delete_directory($dir) : Fail to delete sub-directory '$dir/$file'.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!unlink("$dir/$file")) {
|
else if (!unlink("$dir/$file")) {
|
||||||
Log :: error("delete_directory($dir) : Fail to delete '$dir/$file'.");
|
logging('ERROR', "delete_directory($dir) : Fail to delete '$dir/$file'.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!empty($files)) {
|
else if (!empty($files)) {
|
||||||
Log :: error("delete_directory($dir) : Directory is not empty.");
|
logging('ERROR', "delete_directory($dir) : Directory is not empty.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return rmdir($dir);
|
return rmdir($dir);
|
||||||
|
@ -259,7 +345,7 @@ function run_external_command($command, $data_stdin=null, $escape_command_args=t
|
||||||
$command = implode(' ', $command);
|
$command = implode(' ', $command);
|
||||||
if ($escape_command_args)
|
if ($escape_command_args)
|
||||||
$command = escapeshellcmd($command);
|
$command = escapeshellcmd($command);
|
||||||
Log :: debug("Run external command: '$command'");
|
logging('DEBUG', "Run external command: '$command'");
|
||||||
$descriptorspec = array(
|
$descriptorspec = array(
|
||||||
0 => array("pipe", "r"), // stdin
|
0 => array("pipe", "r"), // stdin
|
||||||
1 => array("pipe", "w"), // stdout
|
1 => array("pipe", "w"), // stdout
|
||||||
|
@ -268,7 +354,7 @@ function run_external_command($command, $data_stdin=null, $escape_command_args=t
|
||||||
$process = proc_open($command, $descriptorspec, $pipes);
|
$process = proc_open($command, $descriptorspec, $pipes);
|
||||||
|
|
||||||
if (!is_resource($process)) {
|
if (!is_resource($process)) {
|
||||||
Log :: error("Fail to run external command: '$command'");
|
logging('ERROR', "Fail to run external command: '$command'");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,7 +372,7 @@ function run_external_command($command, $data_stdin=null, $escape_command_args=t
|
||||||
$return_value = proc_close($process);
|
$return_value = proc_close($process);
|
||||||
|
|
||||||
$error = (!empty($stderr) || $return_value != 0);
|
$error = (!empty($stderr) || $return_value != 0);
|
||||||
Log :: log(
|
logging(
|
||||||
($error?'ERROR':'DEBUG'),
|
($error?'ERROR':'DEBUG'),
|
||||||
"External command ".($error?"error":"result").":\n".
|
"External command ".($error?"error":"result").":\n".
|
||||||
"\tCommand : $command\n".
|
"\tCommand : $command\n".
|
||||||
|
@ -299,25 +385,4 @@ function run_external_command($command, $data_stdin=null, $escape_command_args=t
|
||||||
return array($return_value, $stdout, $stderr);
|
return array($return_value, $stdout, $stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check an AJAX request and trigger a fatal error on fail
|
|
||||||
*
|
|
||||||
* Check if session key is present and valid and set AJAX
|
|
||||||
* mode.
|
|
||||||
*
|
|
||||||
* @param string|null $session_key string The current session key (optional)
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
function check_ajax_request($session_key=null) {
|
|
||||||
global $ajax, $debug_ajax;
|
|
||||||
$ajax = true;
|
|
||||||
|
|
||||||
if (check_session_key($session_key))
|
|
||||||
fatal_error('Invalid request');
|
|
||||||
|
|
||||||
if ($debug_ajax)
|
|
||||||
Log :: debug("Ajax Request : ".vardump($_REQUEST));
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
||||||
|
|
105
includes/hooks.php
Normal file
105
includes/hooks.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$hooks = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered a hook on a specific event
|
||||||
|
*
|
||||||
|
* @param $event string The event name
|
||||||
|
* @param $callable callable The callable to run on event
|
||||||
|
* @param $param mixed Paremeter that will be pass to the callable
|
||||||
|
* Use an array if you have multiple parameters to pass
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function register_hook($event, $callable, $param=NULL) {
|
||||||
|
global $hooks;
|
||||||
|
if (!array_key_exists($event, $hooks))
|
||||||
|
$hooks[$event] = array();
|
||||||
|
$hooks[$event][] = array (
|
||||||
|
'callable' => $callable,
|
||||||
|
'param' => $param,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run triggered actions on specific event
|
||||||
|
*
|
||||||
|
* @param $event string HookEvent name
|
||||||
|
*
|
||||||
|
* @return boolean True if all triggered actions succefully runned, false otherwise
|
||||||
|
*/
|
||||||
|
function trigger_hook($event_name, $event_data=null) {
|
||||||
|
global $hooks;
|
||||||
|
$return = true;
|
||||||
|
|
||||||
|
if (isset($hooks[$event_name]) && is_array($hooks[$event_name])) {
|
||||||
|
if ($event_name == 'all')
|
||||||
|
$event = new HookEvent($event_data['event_name'], $event_data['event_data']);
|
||||||
|
else
|
||||||
|
$event = new HookEvent($event_name, $event_data);
|
||||||
|
foreach ($hooks[$event_name] as $e) {
|
||||||
|
if (is_callable($e['callable'])) {
|
||||||
|
try {
|
||||||
|
call_user_func_array($e['callable'],array($event, &$e['param']));
|
||||||
|
}
|
||||||
|
catch(Exception $e) {
|
||||||
|
log_exception(
|
||||||
|
$e, "An exception occured running hook ".format_callable($e['callable']).
|
||||||
|
" on event $event_name");
|
||||||
|
$return = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logging(
|
||||||
|
'ERROR',
|
||||||
|
"The hook ".format_callable($e['callable'])." on event $event_name is not callable.");
|
||||||
|
$return = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logging('DEBUG', "No hook registered for event $event_name.");
|
||||||
|
|
||||||
|
// Handle 'all' event
|
||||||
|
if ($event_name != 'all') {
|
||||||
|
trigger_hook (
|
||||||
|
'all',
|
||||||
|
array (
|
||||||
|
'event_name' => $event_name,
|
||||||
|
'event_data' => $event_data,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HookEvent implements JsonSerializable {
|
||||||
|
private $name;
|
||||||
|
private $data;
|
||||||
|
|
||||||
|
function __construct($name, $data) {
|
||||||
|
$this -> name = $name;
|
||||||
|
$this -> data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __get($key) {
|
||||||
|
if ($key == 'name')
|
||||||
|
return $this -> name;
|
||||||
|
elseif ($key == 'data')
|
||||||
|
return $this -> data;
|
||||||
|
elseif (is_array($this -> data) && array_key_exists($key, $this -> data))
|
||||||
|
return $this -> data[$key];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function jsonSerialize() {
|
||||||
|
return array (
|
||||||
|
'name' => $this -> name,
|
||||||
|
'data' => $this -> data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
256
includes/logging.php
Normal file
256
includes/logging.php
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration :
|
||||||
|
* // Log file
|
||||||
|
* $log_file='/path/to/app.log';
|
||||||
|
*
|
||||||
|
* // Log level (DEBUG / INFO / WARNING / ERROR / FATAL)
|
||||||
|
* $log_level='INFO';
|
||||||
|
*
|
||||||
|
* // Log PHP errors levels (as specified to set_error_handler())
|
||||||
|
* // $log_php_errors_levels = E_ALL & ~E_STRICT;
|
||||||
|
|
||||||
|
* // Log PHP errors levels (as specified to set_error_handler())
|
||||||
|
* // Default:
|
||||||
|
* // - In TRACE or DEBUG: E_ALL & ~E_STRICT
|
||||||
|
* // - Otherwise: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
|
||||||
|
* // $log_php_errors_levels = E_ALL & ~E_STRICT;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Log file descriptor (Do not change !!!)
|
||||||
|
$_log_file_fd = null;
|
||||||
|
|
||||||
|
// Log Levels
|
||||||
|
$_log_levels = array(
|
||||||
|
'TRACE' => 0,
|
||||||
|
'DEBUG' => 1,
|
||||||
|
'INFO' => 2,
|
||||||
|
'WARNING' => 3,
|
||||||
|
'ERROR' => 4,
|
||||||
|
'FATAL' => 5,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Custom fatal error handler
|
||||||
|
$_fatal_error_handler = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message
|
||||||
|
* @param string $level The message level (key of $_log_levels)
|
||||||
|
* @param string $message The message to log
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
function logging($level, $message) {
|
||||||
|
global $log_file, $_log_file_fd, $_log_levels, $log_level, $argv,
|
||||||
|
$_fatal_error_handler, $auth_user;
|
||||||
|
|
||||||
|
if (!array_key_exists($level, $_log_levels)) $level = 'INFO';
|
||||||
|
$level_id = $_log_levels[$level];
|
||||||
|
|
||||||
|
$log_level_id = $_log_levels[$log_level];
|
||||||
|
|
||||||
|
if ($level_id < $log_level_id) return true;
|
||||||
|
if(is_null($_log_file_fd)) {
|
||||||
|
$_log_file_fd = fopen($log_file, 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If more than 2 arguments passed, format message using sprintf
|
||||||
|
if (func_num_args() > 2) {
|
||||||
|
$message = call_user_func_array(
|
||||||
|
'sprintf',
|
||||||
|
array_merge(array($message), array_slice(func_get_args(), 2))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (php_sapi_name() == "cli") {
|
||||||
|
$msg = implode(' - ', array(
|
||||||
|
date('Y/m/d H:i:s'),
|
||||||
|
basename($argv[0]),
|
||||||
|
$level,
|
||||||
|
$message
|
||||||
|
))."\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$msg = array(
|
||||||
|
date('Y/m/d H:i:s'),
|
||||||
|
$_SERVER['REQUEST_URI'],
|
||||||
|
$_SERVER['REMOTE_ADDR'],
|
||||||
|
);
|
||||||
|
if (isset($auth_user))
|
||||||
|
$msg[] = ($auth_user['username']?$auth_user['username']:'anonymous');
|
||||||
|
$msg[] = $level;
|
||||||
|
$msg[] = $message;
|
||||||
|
$msg = implode(' - ', $msg)."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite($_log_file_fd, $msg);
|
||||||
|
|
||||||
|
if ($level == 'FATAL')
|
||||||
|
if (!is_null($_fatal_error_handler))
|
||||||
|
call_user_func($_fatal_error_handler, $message);
|
||||||
|
elseif (function_exists('fatal_error'))
|
||||||
|
fatal_error($message);
|
||||||
|
else
|
||||||
|
die("\n$message\n\n");
|
||||||
|
elseif (php_sapi_name() == "cli")
|
||||||
|
echo $msg;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default log level (if not defined or invalid)
|
||||||
|
$default_log_level = 'WARNING';
|
||||||
|
if (!isset($log_level)) {
|
||||||
|
$log_level = $default_log_level;
|
||||||
|
}
|
||||||
|
elseif (!array_key_exists($log_level, $_log_levels)) {
|
||||||
|
$invalid_value = $log_level;
|
||||||
|
$log_level = $default_log_level;
|
||||||
|
logging(
|
||||||
|
$log_level, "Invalid log level value found in configuration (%s). ".
|
||||||
|
"Set as default (%s).", $invalid_value, $log_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a contextual fatal error handler
|
||||||
|
* @param null|callable $handler The fatal error handler (set as null to reset)
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function register_fatal_error_handler($handler) {
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
|
if ($handler && !is_callable($handler))
|
||||||
|
logging('FATAL', 'Fatal handler provided is not callable !');
|
||||||
|
global $_fatal_error_handler;
|
||||||
|
$_fatal_error_handler = ($handler?$handler:null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change of current log file
|
||||||
|
* @param string $file The new log file path
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function change_log_file($file) {
|
||||||
|
global $log_file, $_log_file_fd;
|
||||||
|
if ($file == $log_file) return True;
|
||||||
|
if ($_log_file_fd) {
|
||||||
|
fclose($_log_file_fd);
|
||||||
|
$_log_file_fd = false;
|
||||||
|
}
|
||||||
|
$log_file = $file;
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*******************************************************************************
|
||||||
|
* Handle exception logging
|
||||||
|
*******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current backtrace
|
||||||
|
* @param int $ignore_last The number of last levels to ignore
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function get_debug_backtrace_context($ignore_last=0) {
|
||||||
|
$traces = debug_backtrace();
|
||||||
|
|
||||||
|
// Also ignore this function it self
|
||||||
|
$ignore_last++;
|
||||||
|
|
||||||
|
if (!is_array($traces) || count($traces) <= $ignore_last)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
$msg = array();
|
||||||
|
for ($i=$ignore_last; $i < count($traces); $i++) {
|
||||||
|
$trace = array("#$i");
|
||||||
|
if (isset($traces[$i]['file']))
|
||||||
|
$trace[] = $traces[$i]['file'].(isset($traces[$i]['line'])?":".$traces[$i]['line']:"");
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
|
if (isset($traces[$i]['class']) && isset($traces[$i]['function']))
|
||||||
|
$trace[] = implode(" ", array(
|
||||||
|
$traces[$i]['class'],
|
||||||
|
$traces[$i]['type'],
|
||||||
|
$traces[$i]['function']. "()"));
|
||||||
|
elseif (isset($traces[$i]['function']))
|
||||||
|
$trace[] = $traces[$i]['function']. "()";
|
||||||
|
$msg[] = implode(" - ", $trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode("\n", $msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an exception
|
||||||
|
* @param Throwable $exception
|
||||||
|
* @param string|null $prefix The prefix of the log message
|
||||||
|
* (optional, default: "An exception occured")
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function log_exception($exception, $prefix=null) {
|
||||||
|
if (function_exists('log_in_sentry'))
|
||||||
|
log_in_sentry($exception);
|
||||||
|
// If more than 2 arguments passed, format prefix message using sprintf
|
||||||
|
if ($prefix && func_num_args() > 2) {
|
||||||
|
$prefix = call_user_func_array(
|
||||||
|
'sprintf',
|
||||||
|
array_merge(array($prefix), array_slice(func_get_args(), 2))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
logging(
|
||||||
|
"ERROR", "%s:\n%s\n## %s:%d : %s",
|
||||||
|
($prefix?$prefix:"An exception occured"),
|
||||||
|
get_debug_backtrace_context(1),
|
||||||
|
$exception->getFile(), $exception->getLine(),
|
||||||
|
$exception->getMessage());
|
||||||
|
}
|
||||||
|
set_exception_handler('log_exception');
|
||||||
|
|
||||||
|
/*
|
||||||
|
*******************************************************************************
|
||||||
|
* Handle PHP error logging
|
||||||
|
*******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert PHP error number to the corresponding label
|
||||||
|
* @param int $errno
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function errno2type($errno) {
|
||||||
|
$constants = get_defined_constants();
|
||||||
|
if (is_array($constants))
|
||||||
|
foreach($constants as $label => $value)
|
||||||
|
if ($value == $errno && preg_match('/^E_(.*)$/', $label, $m))
|
||||||
|
return $m[1];
|
||||||
|
return 'UNKNOWN ERROR #'.$errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a PHP error
|
||||||
|
* Note: method design to be used as callable by set_error_handler()
|
||||||
|
* @param int $errno The error number
|
||||||
|
* @param string $errstr The error message
|
||||||
|
* @param string $errfile The filename that the error was raised in
|
||||||
|
* @param int $errline The line number where the error was raised
|
||||||
|
* @return false Return false to let the normal error handler continues.
|
||||||
|
*/
|
||||||
|
function log_php_error($errno, $errstr, $errfile, $errline) {
|
||||||
|
$msg = sprintf(
|
||||||
|
"A PHP error occured : [%s] %s\nFile : %s (line : %d)",
|
||||||
|
errno2type($errno), $errstr, $errfile, $errline
|
||||||
|
);
|
||||||
|
logging("ERROR", $msg);
|
||||||
|
if (function_exists('log_php_error_in_sentry'))
|
||||||
|
log_php_error_in_sentry($errno, $msg);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
if (isset($log_php_errors_levels))
|
||||||
|
set_error_handler('log_php_error', $log_php_errors_levels);
|
||||||
|
elseif (in_array($log_level, array('DEBUG', 'TRACE')))
|
||||||
|
set_error_handler('log_php_error', E_ALL & ~E_STRICT);
|
||||||
|
else
|
||||||
|
set_error_handler('log_php_error', E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
|
||||||
|
|
||||||
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
135
includes/mail.php
Normal file
135
includes/mail.php
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Load PHP PEAR Mail and Mail_mime libs
|
||||||
|
require_once(isset($php_mail_path)?$php_mail_path:"Mail.php");
|
||||||
|
require_once(isset($php_mail_mime_path)?$php_mail_mime_path:"Mail/mime.php");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an email
|
||||||
|
*
|
||||||
|
* @param string|null $from Email sender
|
||||||
|
* @param string|array<string> $to Email recipient(s)
|
||||||
|
* @param string $subject Email subject
|
||||||
|
* @param string $msg Email body
|
||||||
|
* @param boolean $html Set to true to send an HTML email (default: false)
|
||||||
|
* @param array<string,string>|null $attachments Email attachments as an array with
|
||||||
|
* filepath as key and filename as value
|
||||||
|
* @param array<string,string>|null $headers Email headers
|
||||||
|
* @param string|null $encoding Email encoding (default: utf8)
|
||||||
|
* @param string|null $eol End of line string (default : \n)
|
||||||
|
*
|
||||||
|
* @return boolean true If mail was sent, false otherwise
|
||||||
|
*/
|
||||||
|
function send_mail($from, $to, $subject, $msg, $html=false, $attachments=null, $headers=null,
|
||||||
|
$encoding=null, $eol=null) {
|
||||||
|
global $mail_send_method, $mail_headers, $mail_send_params, $mail_sender, $mail_catch_all;
|
||||||
|
$mail_obj = & Mail::factory($mail_send_method, $mail_send_params);
|
||||||
|
|
||||||
|
if (!$headers) $headers = array();
|
||||||
|
if(isset($mail_headers) && is_array($mail_headers)) {
|
||||||
|
$headers = array_merge($headers, $mail_headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
logging(
|
||||||
|
'TRACE', 'Mail catch all: %s',
|
||||||
|
isset($mail_catch_all) && $mail_catch_all?
|
||||||
|
vardump($mail_catch_all):'not set'
|
||||||
|
);
|
||||||
|
if (isset($mail_catch_all) && $mail_catch_all) {
|
||||||
|
logging(
|
||||||
|
'DEBUG', 'Mail catch to %s',
|
||||||
|
is_array($mail_catch_all)?implode(',', $mail_catch_all):$mail_catch_all
|
||||||
|
);
|
||||||
|
$msg .= sprintf(
|
||||||
|
(
|
||||||
|
$html?
|
||||||
|
_("</hr><p><small>Mail initialy intended for %s.</small></p>"):
|
||||||
|
_("\n\n\nMail initialy intended for %s.")
|
||||||
|
),
|
||||||
|
(is_array($to)?implode(',', $to):$to));
|
||||||
|
$headers["X-Orig-To"] = $to;
|
||||||
|
$to = (
|
||||||
|
is_array($mail_catch_all)?
|
||||||
|
implode(',', $mail_catch_all):$mail_catch_all
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($subject) {
|
||||||
|
$headers["Subject"] = $subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($headers['From'])) {
|
||||||
|
if (!$from)
|
||||||
|
$from = $headers['From'];
|
||||||
|
unset($headers['From']);
|
||||||
|
}
|
||||||
|
elseif (!$from) {
|
||||||
|
$from = $mail_sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers["To"] = $to;
|
||||||
|
|
||||||
|
$to = array (
|
||||||
|
'To' => $to
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach(array_keys($headers) as $header) {
|
||||||
|
if(in_array(strtoupper($header), array('BCC', 'CC'))) {
|
||||||
|
if (isset($mail_catch_all) && $mail_catch_all) {
|
||||||
|
logging('DEBUG', "Mail catched: remove $header header");
|
||||||
|
$msg .= sprintf(
|
||||||
|
(
|
||||||
|
$html?
|
||||||
|
_("<p><small>%s: %s</small></p>"):
|
||||||
|
_("\n%s: %s")
|
||||||
|
),
|
||||||
|
strtoupper($header),
|
||||||
|
(is_array($headers[$header])?implode(',', $headers[$header]):$headers[$header]));
|
||||||
|
unset($headers[$header]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$to[strtoupper($header)] = $headers[$header];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$encoding) $encoding = "utf8";
|
||||||
|
$mime = new Mail_mime(
|
||||||
|
array(
|
||||||
|
'eol' => ($eol?$eol:"\n"),
|
||||||
|
($html?'html_charset':'text_charset') => $encoding,
|
||||||
|
'head_charset' => $encoding,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($from)
|
||||||
|
$mime->setFrom($from);
|
||||||
|
|
||||||
|
if ($subject)
|
||||||
|
$mime->setSubject($subject);
|
||||||
|
|
||||||
|
if ($html)
|
||||||
|
$mime->setHTMLBody($msg);
|
||||||
|
else
|
||||||
|
$mime->setTXTBody($msg);
|
||||||
|
|
||||||
|
if (is_array($attachments) && !empty($attachments)) {
|
||||||
|
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||||
|
foreach ($attachments as $file => $filename) {
|
||||||
|
$mime->addAttachment($file, $finfo->file($file), $filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = $mime->get();
|
||||||
|
$headers = $mime->headers($headers);
|
||||||
|
|
||||||
|
$ret = $mail_obj -> send($to, $headers, $body);
|
||||||
|
|
||||||
|
if (PEAR::isError($ret)) {
|
||||||
|
$msg = "Error sending email: ".$ret -> getMessage();
|
||||||
|
logging('ERROR', $msg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
213
includes/sentry.php
Normal file
213
includes/sentry.php
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration :
|
||||||
|
*
|
||||||
|
* // Log PHP errors in Sentry: list of errors types to logs
|
||||||
|
* // Note: must also match with $log_php_errors_levels.
|
||||||
|
* // See: https://www.php.net/manual/fr/errorfunc.constants.php
|
||||||
|
* $sentry_php_error_types = array(
|
||||||
|
* E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
|
||||||
|
* E_RECOVERABLE_ERROR,E_DEPRECATED,
|
||||||
|
* );
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Init Sentry (if its DSN is configured)
|
||||||
|
if (isset($sentry_dsn) && $sentry_dsn) {
|
||||||
|
\Sentry\init([
|
||||||
|
'dsn' => $sentry_dsn,
|
||||||
|
'traces_sample_rate' => (
|
||||||
|
isset($sentry_traces_sample_rate) ?
|
||||||
|
$sentry_traces_sample_rate : 0.2
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
|
||||||
|
global $auth_user;
|
||||||
|
$scope->setUser([
|
||||||
|
'id' => isset($auth_user) && $auth_user?$auth_user['uid']:null,
|
||||||
|
'email' => isset($auth_user) && $auth_user?$auth_user['mail']:null,
|
||||||
|
'segment' => isset($auth_user) && $auth_user?$auth_user['type']:null,
|
||||||
|
'ip_address' => $_SERVER['REMOTE_ADDR'],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an exception or a message in Sentry
|
||||||
|
* @param string|Exception $msg
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function log_in_sentry($msg) {
|
||||||
|
global $sentry_dsn;
|
||||||
|
if (!isset($sentry_dsn) || !$sentry_dsn) {
|
||||||
|
logging('TRACE', 'Sentry DSN not configured, do not log this error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_string($msg)) {
|
||||||
|
logging('DEBUG', 'Error logged in Sentry');
|
||||||
|
\Sentry\captureMessage($msg);
|
||||||
|
}
|
||||||
|
elseif ($msg instanceof Exception) {
|
||||||
|
logging('DEBUG', 'Exception logged in Sentry');
|
||||||
|
\Sentry\captureException($msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a PHP error in Sentry
|
||||||
|
* @param int $errno The error number
|
||||||
|
* @param string $msg The error message
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function log_php_error_in_sentry($errno, $msg) {
|
||||||
|
global $sentry_php_error_types;
|
||||||
|
if (
|
||||||
|
isset($sentry_php_error_types)
|
||||||
|
&& is_array($sentry_php_error_types)
|
||||||
|
&& in_array($errno, $sentry_php_error_types)
|
||||||
|
)
|
||||||
|
log_in_sentry($msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Performance monitoring
|
||||||
|
*/
|
||||||
|
|
||||||
|
class SentryTransaction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sentry transaction object
|
||||||
|
* @var \Sentry\Tracing\Transaction
|
||||||
|
*/
|
||||||
|
private $transaction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sentry transaction context object
|
||||||
|
* @var \Sentry\Tracing\TransactionContext
|
||||||
|
*/
|
||||||
|
private $context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor: start a Sentry transaction
|
||||||
|
* @param string|null $op The operation name
|
||||||
|
* @param string|null $name The transaction name
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($op=null, $name=null) {
|
||||||
|
// Setup context for the full transaction
|
||||||
|
$this->context = new \Sentry\Tracing\TransactionContext();
|
||||||
|
$this->context->setName(
|
||||||
|
$name?$name:
|
||||||
|
(php_sapi_name()=='cli'?'CLI execution':'HTTP request')
|
||||||
|
);
|
||||||
|
$this->context->setOp(
|
||||||
|
$op?$op:
|
||||||
|
(php_sapi_name()=='cli'?'cli.command':'http.request')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Start the transaction
|
||||||
|
$this->transaction = \Sentry\startTransaction($this->context);
|
||||||
|
|
||||||
|
// Set the current transaction as the current span so we can retrieve it later
|
||||||
|
\Sentry\SentrySdk::getCurrentHub()->setSpan($this->transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor: Stop the current Sentry transaction
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __destruct() {
|
||||||
|
SentrySpan :: finishAll();
|
||||||
|
$this->transaction->finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal Sentry Span object implementation
|
||||||
|
* This internal implementation principally permit to keep trace of new span parent
|
||||||
|
* and list of started spans.
|
||||||
|
*/
|
||||||
|
class SentrySpan {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep trace of started Sentry spans
|
||||||
|
* @var array<int,mixed>
|
||||||
|
*/
|
||||||
|
private static $_started_spans = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique ID of the Sentry span
|
||||||
|
* Note: internal ID used as key in self::$_started_spans
|
||||||
|
* @var int|null
|
||||||
|
*/
|
||||||
|
private $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent of the Sentry span
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
private $parent = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The context of the Sentry span
|
||||||
|
* @var null|\Sentry\Tracing\SpanContext
|
||||||
|
*/
|
||||||
|
private $context = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Sentry span object
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
private $span = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sentry span constructor
|
||||||
|
* @param string|null $op The operation name
|
||||||
|
* @param string|null $name The span name
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($op, $name) {
|
||||||
|
$this -> parent = \Sentry\SentrySdk::getCurrentHub()->getSpan();
|
||||||
|
// Check if we have a parent span (this is the case if we started a transaction earlier)
|
||||||
|
if (is_null($this -> parent)) return;
|
||||||
|
|
||||||
|
while (is_null($this -> id)) {
|
||||||
|
$this -> id = rand();
|
||||||
|
if (isset(self :: $_started_spans[$this -> id]))
|
||||||
|
$this -> id = null;
|
||||||
|
}
|
||||||
|
$this -> context = new \Sentry\Tracing\SpanContext();
|
||||||
|
$this -> context->setOp($op);
|
||||||
|
$this -> context->setDescription($name);
|
||||||
|
$this -> span = $this->parent->startChild($this -> context);
|
||||||
|
|
||||||
|
// Set the current span to the span we just started
|
||||||
|
\Sentry\SentrySdk::getCurrentHub()->setSpan($this -> span);
|
||||||
|
|
||||||
|
self :: $_started_spans[$this -> id] = $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the span (if started)
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function finish() {
|
||||||
|
if (!$this -> span) return;
|
||||||
|
$this -> span -> finish();
|
||||||
|
unset(self::$_started_spans[$this -> id]);
|
||||||
|
\Sentry\SentrySdk::getCurrentHub()->setSpan($this -> parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish all started spans
|
||||||
|
* @see SentryTransaction::__destruct()
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function finishAll() {
|
||||||
|
foreach (array_reverse(self :: $_started_spans) as $id => $span)
|
||||||
|
$span -> finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
@ -1,7 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
if (php_sapi_name() == "cli")
|
if (php_sapi_name() == "cli")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -22,17 +19,18 @@ if (!isset($_SESSION['session_key'])) {
|
||||||
// Handle session timeout
|
// Handle session timeout
|
||||||
if (isset($session_timeout) && $session_timeout) {
|
if (isset($session_timeout) && $session_timeout) {
|
||||||
if (!isset($_SESSION['session_last_access'])) {
|
if (!isset($_SESSION['session_last_access'])) {
|
||||||
Log :: debug('Set initial session last access');
|
logging('DEBUG', 'Set initial session last access');
|
||||||
$_SESSION['session_last_access'] = time();
|
$_SESSION['session_last_access'] = time();
|
||||||
}
|
}
|
||||||
elseif ($_SESSION['session_last_access'] > (time() - $session_timeout)) {
|
elseif ($_SESSION['session_last_access'] > (time() - $session_timeout)) {
|
||||||
Log :: debug(
|
logging(
|
||||||
|
'DEBUG',
|
||||||
'Session timeout not expired, update session last access '.
|
'Session timeout not expired, update session last access '.
|
||||||
'(Previous value : '.$_SESSION['session_last_access'].')');
|
'(Previous value : '.$_SESSION['session_last_access'].')');
|
||||||
$_SESSION['session_last_access'] = time();
|
$_SESSION['session_last_access'] = time();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: info('Session destroyed due to inactivity');
|
logging('INFO', 'Session destroyed due to inactivity');
|
||||||
session_destroy();
|
session_destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
use EesyPHP\SentrySpan;
|
|
||||||
use EesyPHP\SentryTransaction;
|
|
||||||
use EesyPHP\Url;
|
|
||||||
|
|
||||||
if (php_sapi_name() == "cli")
|
if (php_sapi_name() == "cli")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -62,7 +57,7 @@ elseif (method_exists($smarty,'registerPlugin')) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: fatal(_('Smarty version not supported.'));
|
logging('FATAL', _('Smarty version not supported.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure templates/templates_c directories
|
// Configure templates/templates_c directories
|
||||||
|
@ -70,8 +65,8 @@ if (
|
||||||
!isset($smarty_templates_dir)
|
!isset($smarty_templates_dir)
|
||||||
|| !is_dir($smarty_templates_dir)
|
|| !is_dir($smarty_templates_dir)
|
||||||
)
|
)
|
||||||
Log :: fatal(
|
logging(
|
||||||
"Template directory not found (%s)",
|
'FATAL', "Template directory not found (%s)",
|
||||||
isset($smarty_templates_dir)?$smarty_templates_dir:'not set');
|
isset($smarty_templates_dir)?$smarty_templates_dir:'not set');
|
||||||
else
|
else
|
||||||
$smarty->setTemplateDir($smarty_templates_dir);
|
$smarty->setTemplateDir($smarty_templates_dir);
|
||||||
|
@ -81,8 +76,8 @@ if (
|
||||||
|| !is_dir($smarty_templates_c_dir)
|
|| !is_dir($smarty_templates_c_dir)
|
||||||
|| !is_writable($smarty_templates_c_dir)
|
|| !is_writable($smarty_templates_c_dir)
|
||||||
)
|
)
|
||||||
Log :: fatal(
|
logging(
|
||||||
"Template cache directory not found or not writable (%s)",
|
'FATAL', "Template cache directory not found or not writable (%s)",
|
||||||
isset($smarty_templates_c_dir)?$smarty_templates_c_dir:'not set');
|
isset($smarty_templates_c_dir)?$smarty_templates_c_dir:'not set');
|
||||||
else
|
else
|
||||||
$smarty->setCompileDir($smarty_templates_c_dir);
|
$smarty->setCompileDir($smarty_templates_c_dir);
|
||||||
|
@ -184,15 +179,15 @@ function _defineCommonTemplateVariables($template, $pagetitle) {
|
||||||
|
|
||||||
function display_template($template, $pagetitle=false) {
|
function display_template($template, $pagetitle=false) {
|
||||||
if (!$template)
|
if (!$template)
|
||||||
Log :: fatal(_("No template specified."));
|
logging("FATAL", _("No template specified."));
|
||||||
|
|
||||||
// If refresh parameter is present, remove it and redirect
|
// If refresh parameter is present, remove it and redirect
|
||||||
if (isset($_GET['refresh'])) {
|
if (isset($_GET['refresh'])) {
|
||||||
unset($_GET['refresh']);
|
unset($_GET['refresh']);
|
||||||
$url = Url :: get_current_url();
|
$url = get_current_url();
|
||||||
if (!empty($_GET))
|
if (!empty($_GET))
|
||||||
$url .= '?'.http_build_query($_GET);
|
$url .= '?'.http_build_query($_GET);
|
||||||
Url :: redirect($url);
|
redirect($url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,9 +208,9 @@ function display_template($template, $pagetitle=false) {
|
||||||
unset($_SESSION['messages']);
|
unset($_SESSION['messages']);
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
Log :: exception($e, "Smarty - An exception occured displaying template '$template'");
|
log_exception($e, "Smarty - An exception occured displaying template '$template'");
|
||||||
if ($template != 'fatal_error.tpl')
|
if ($template != 'fatal_error.tpl')
|
||||||
Log :: fatal(_("An error occurred while displaying this page."));
|
logging("FATAL", _("An error occurred while displaying this page."));
|
||||||
}
|
}
|
||||||
|
|
||||||
$sentry_span->finish();
|
$sentry_span->finish();
|
||||||
|
@ -239,7 +234,7 @@ function display_ajax_return($data=null, $pretty=false) {
|
||||||
unset($_SESSION['errors']);
|
unset($_SESSION['errors']);
|
||||||
}
|
}
|
||||||
if ($debug_ajax)
|
if ($debug_ajax)
|
||||||
Log :: debug("Ajax Response : ".vardump($data));
|
logging('DEBUG',"Ajax Response : ".vardump($data));
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
echo json_encode($data, (($pretty||isset($_REQUEST['pretty']))?JSON_PRETTY_PRINT:0));
|
echo json_encode($data, (($pretty||isset($_REQUEST['pretty']))?JSON_PRETTY_PRINT:0));
|
||||||
exit();
|
exit();
|
||||||
|
@ -247,7 +242,7 @@ function display_ajax_return($data=null, $pretty=false) {
|
||||||
|
|
||||||
$ajax=false;
|
$ajax=false;
|
||||||
function fatal_error($error) {
|
function fatal_error($error) {
|
||||||
global $smarty, $ajax;
|
global $smarty, $ajax, $api_mode;
|
||||||
|
|
||||||
// If more than one arguments passed, format error message using sprintf
|
// If more than one arguments passed, format error message using sprintf
|
||||||
if (func_num_args() > 1) {
|
if (func_num_args() > 1) {
|
||||||
|
@ -263,7 +258,7 @@ function fatal_error($error) {
|
||||||
// Set HTTP reponse code to 500
|
// Set HTTP reponse code to 500
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
|
|
||||||
if ($ajax || Url :: api_mode())
|
if ($ajax || $api_mode)
|
||||||
display_ajax_return(array('success' => false, 'error' => $error));
|
display_ajax_return(array('success' => false, 'error' => $error));
|
||||||
|
|
||||||
$smarty->assign('fatal_error', $error);
|
$smarty->assign('fatal_error', $error);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
********************************************************************
|
********************************************************************
|
||||||
* Translations CLI commands *
|
* Translations CLI commands *
|
||||||
|
@ -58,7 +56,7 @@ function cli_extract_messages($command_args) {
|
||||||
false // do not escape command args (already done)
|
false // do not escape command args (already done)
|
||||||
);
|
);
|
||||||
if (!is_array($php_files) || $php_files[0] != 0) {
|
if (!is_array($php_files) || $php_files[0] != 0) {
|
||||||
Log :: fatal(_("Fail to list PHP files."));
|
logging('FATAL', _("Fail to list PHP files."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract messages from PHP files using xgettext
|
// Extract messages from PHP files using xgettext
|
||||||
|
@ -75,7 +73,7 @@ function cli_extract_messages($command_args) {
|
||||||
$php_files[1] // Pass PHP files list via STDIN
|
$php_files[1] // Pass PHP files list via STDIN
|
||||||
);
|
);
|
||||||
if (!is_array($result) || $result[0] != 0)
|
if (!is_array($result) || $result[0] != 0)
|
||||||
Log :: fatal(_("Fail to extract messages from PHP files using xgettext."));
|
logging('FATAL', _("Fail to extract messages from PHP files using xgettext."));
|
||||||
|
|
||||||
|
|
||||||
// List JS files to parse
|
// List JS files to parse
|
||||||
|
@ -85,7 +83,7 @@ function cli_extract_messages($command_args) {
|
||||||
false // do not escape command args (already done)
|
false // do not escape command args (already done)
|
||||||
);
|
);
|
||||||
if (!is_array($js_files) || $js_files[0] != 0) {
|
if (!is_array($js_files) || $js_files[0] != 0) {
|
||||||
Log :: fatal(_("Fail to list JS files."));
|
logging('FATAL', _("Fail to list JS files."));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract messages from JS files using xgettext
|
// Extract messages from JS files using xgettext
|
||||||
|
@ -102,7 +100,7 @@ function cli_extract_messages($command_args) {
|
||||||
$js_files[1] // Pass JS files list via STDIN
|
$js_files[1] // Pass JS files list via STDIN
|
||||||
);
|
);
|
||||||
if (!is_array($result) || $result[0] != 0)
|
if (!is_array($result) || $result[0] != 0)
|
||||||
Log :: fatal(_("Fail to extract messages from JS files using xgettext."));
|
logging('FATAL', _("Fail to extract messages from JS files using xgettext."));
|
||||||
|
|
||||||
// Extract messages from templates files using tsmarty2c.php
|
// Extract messages from templates files using tsmarty2c.php
|
||||||
$result = run_external_command(
|
$result = run_external_command(
|
||||||
|
@ -113,7 +111,8 @@ function cli_extract_messages($command_args) {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (!is_array($result) || $result[0] != 0)
|
if (!is_array($result) || $result[0] != 0)
|
||||||
Log :: fatal(
|
logging(
|
||||||
|
'FATAL',
|
||||||
_("Fail to extract messages from template files using tsmarty2c.php script."));
|
_("Fail to extract messages from template files using tsmarty2c.php script."));
|
||||||
|
|
||||||
$fd = fopen("$root_lang_dir/headers.pot", 'w');
|
$fd = fopen("$root_lang_dir/headers.pot", 'w');
|
||||||
|
@ -140,7 +139,7 @@ function cli_extract_messages($command_args) {
|
||||||
"-o", "$root_lang_dir/messages.pot",
|
"-o", "$root_lang_dir/messages.pot",
|
||||||
));
|
));
|
||||||
if (!is_array($result) || $result[0] != 0)
|
if (!is_array($result) || $result[0] != 0)
|
||||||
Log :: fatal(_("Fail to merge messages using msgcat."));
|
logging('FATAL', _("Fail to merge messages using msgcat."));
|
||||||
}
|
}
|
||||||
add_cli_command(
|
add_cli_command(
|
||||||
'extract_messages',
|
'extract_messages',
|
||||||
|
@ -163,14 +162,14 @@ function cli_update_messages($command_args) {
|
||||||
$compendium_args = array();
|
$compendium_args = array();
|
||||||
foreach ($command_args as $path) {
|
foreach ($command_args as $path) {
|
||||||
if (!file_exists($path))
|
if (!file_exists($path))
|
||||||
Log :: fatal(_("Compendium file %s not found."), $path);
|
logging('FATAL', _("Compendium file %s not found."), $path);
|
||||||
$compendium_args[] = '-C';
|
$compendium_args[] = '-C';
|
||||||
$compendium_args[] = $path;
|
$compendium_args[] = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
$pot_file = "$root_lang_dir/messages.pot";
|
$pot_file = "$root_lang_dir/messages.pot";
|
||||||
if (!is_file($pot_file))
|
if (!is_file($pot_file))
|
||||||
Log :: fatal(_("POT file not found (%s). Please run extract_messages first."), $pot_file);
|
logging('FATAL', _("POT file not found (%s). Please run extract_messages first."), $pot_file);
|
||||||
|
|
||||||
if ($dh = opendir($root_lang_dir)) {
|
if ($dh = opendir($root_lang_dir)) {
|
||||||
$error = False;
|
$error = False;
|
||||||
|
@ -182,13 +181,13 @@ function cli_update_messages($command_args) {
|
||||||
)
|
)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Log :: debug(_("Lang directory '%s' found"), $file);
|
logging('DEBUG', _("Lang directory '%s' found"), $file);
|
||||||
|
|
||||||
// Check LC_MESSAGES directory exists
|
// Check LC_MESSAGES directory exists
|
||||||
$lang = $file;
|
$lang = $file;
|
||||||
$lang_dir = $root_lang_dir . '/' . $file . '/LC_MESSAGES' ;
|
$lang_dir = $root_lang_dir . '/' . $file . '/LC_MESSAGES' ;
|
||||||
if (!is_dir($lang_dir)) {
|
if (!is_dir($lang_dir)) {
|
||||||
Log :: debug(_("LC_MESSAGES directory not found in lang '%s' directory, ignore it."),
|
logging('DEBUG', _("LC_MESSAGES directory not found in lang '%s' directory, ignore it."),
|
||||||
$lang);
|
$lang);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -203,7 +202,7 @@ function cli_update_messages($command_args) {
|
||||||
if (is_array($result) && $result[0] == 0) {
|
if (is_array($result) && $result[0] == 0) {
|
||||||
$created = true;
|
$created = true;
|
||||||
} else {
|
} else {
|
||||||
Log :: error(_("Fail to init messages in %s PO file using msginit (%s)."),
|
logging('ERROR', _("Fail to init messages in %s PO file using msginit (%s)."),
|
||||||
$lang, $po_file);
|
$lang, $po_file);
|
||||||
$error = True;
|
$error = True;
|
||||||
}
|
}
|
||||||
|
@ -221,20 +220,20 @@ function cli_update_messages($command_args) {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (!is_array($result) || $result[0] != 0) {
|
if (!is_array($result) || $result[0] != 0) {
|
||||||
Log :: error(_("Fail to update messages in %s PO file using msgmerge (%s)."),
|
logging('ERROR', _("Fail to update messages in %s PO file using msgmerge (%s)."),
|
||||||
$lang, $po_file);
|
$lang, $po_file);
|
||||||
$error = True;
|
$error = True;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif (!$created) {
|
elseif (!$created) {
|
||||||
Log :: debug(_("PO file not found in lang '%s' directory, ignore it."), $lang);
|
logging('DEBUG', _("PO file not found in lang '%s' directory, ignore it."), $lang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir($dh);
|
closedir($dh);
|
||||||
return !$error;
|
return !$error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log :: fatal(_("Fail to open root lang directory (%s)."), $root_dir_path);
|
logging('FATAL', _("Fail to open root lang directory (%s)."), $root_dir_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
add_cli_command(
|
add_cli_command(
|
||||||
|
@ -269,28 +268,29 @@ function cli_compile_messages($command_args) {
|
||||||
if (dirname($real_lang_dir) != '.' || !is_dir($root_lang_dir . '/' . $real_lang_dir))
|
if (dirname($real_lang_dir) != '.' || !is_dir($root_lang_dir . '/' . $real_lang_dir))
|
||||||
continue;
|
continue;
|
||||||
$lang = $file;
|
$lang = $file;
|
||||||
Log :: debug(_("Lang alias symlink found: %s -> %s"), $lang, $real_lang_dir);
|
logging('DEBUG', _("Lang alias symlink found: %s -> %s"), $lang, $real_lang_dir);
|
||||||
|
|
||||||
// Create JSON catalog symlink (if not exists)
|
// Create JSON catalog symlink (if not exists)
|
||||||
$js_link = "$root_dir_path/public_html/translations/$lang.js";
|
$js_link = "$root_dir_path/public_html/translations/$lang.js";
|
||||||
$link_target = "$real_lang_dir.js";
|
$link_target = "$real_lang_dir.js";
|
||||||
if (!file_exists($js_link)) {
|
if (!file_exists($js_link)) {
|
||||||
if (symlink($link_target, $js_link)) {
|
if (symlink($link_target, $js_link)) {
|
||||||
Log :: info(_("JSON catalog symlink for %s -> %s created (%s)"),
|
logging('INFO', _("JSON catalog symlink for %s -> %s created (%s)"),
|
||||||
$lang, $real_lang_dir, $js_link);
|
$lang, $real_lang_dir, $js_link);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: error(_("Fail to create JSON catalog symlink for %s -> %s (%s)"),
|
logging('ERROR', _("Fail to create JSON catalog symlink for %s -> %s (%s)"),
|
||||||
$lang, $real_lang_dir, $js_link);
|
$lang, $real_lang_dir, $js_link);
|
||||||
$error = True;
|
$error = True;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif (readlink($js_link) == $link_target) {
|
elseif (readlink($js_link) == $link_target) {
|
||||||
Log :: debug(_("JSON catalog symlink for %s -> %s already exist (%s)"),
|
logging('DEBUG', _("JSON catalog symlink for %s -> %s already exist (%s)"),
|
||||||
$lang, $real_lang_dir, $js_link);
|
$lang, $real_lang_dir, $js_link);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: warning(
|
logging(
|
||||||
|
'WARNING',
|
||||||
_("JSON catalog file for %s already exist, but it's not a symlink to %s (%s)"),
|
_("JSON catalog file for %s already exist, but it's not a symlink to %s (%s)"),
|
||||||
$lang, $real_lang_dir, $js_link
|
$lang, $real_lang_dir, $js_link
|
||||||
);
|
);
|
||||||
|
@ -299,13 +299,13 @@ function cli_compile_messages($command_args) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log :: debug(_("Lang directory '%s' found"), $file);
|
logging('DEBUG', _("Lang directory '%s' found"), $file);
|
||||||
|
|
||||||
// Check LC_MESSAGES directory exists
|
// Check LC_MESSAGES directory exists
|
||||||
$lang = $file;
|
$lang = $file;
|
||||||
$lang_dir = $root_lang_dir . '/' . $file . '/LC_MESSAGES' ;
|
$lang_dir = $root_lang_dir . '/' . $file . '/LC_MESSAGES' ;
|
||||||
if (!is_dir($lang_dir)) {
|
if (!is_dir($lang_dir)) {
|
||||||
Log :: debug(_("LC_MESSAGES directory not found in lang '%s' directory, ignore it."),
|
logging('DEBUG', _("LC_MESSAGES directory not found in lang '%s' directory, ignore it."),
|
||||||
$lang);
|
$lang);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ function cli_compile_messages($command_args) {
|
||||||
// Test .PO file is present
|
// Test .PO file is present
|
||||||
$po_file = $lang_dir . '/' . TEXT_DOMAIN . '.po';
|
$po_file = $lang_dir . '/' . TEXT_DOMAIN . '.po';
|
||||||
if (!is_file($po_file)) {
|
if (!is_file($po_file)) {
|
||||||
Log :: debug(_("PO file not found in lang '%s' directory, ignore it."),
|
logging('DEBUG', _("PO file not found in lang '%s' directory, ignore it."),
|
||||||
$lang);
|
$lang);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,8 @@ function cli_compile_messages($command_args) {
|
||||||
array("msgfmt", "-o", $mo_file, $po_file)
|
array("msgfmt", "-o", $mo_file, $po_file)
|
||||||
);
|
);
|
||||||
if (!is_array($result) || $result[0] != 0) {
|
if (!is_array($result) || $result[0] != 0) {
|
||||||
Log :: error(
|
logging(
|
||||||
|
'ERROR',
|
||||||
_("Fail to compile messages from %s PO file as MO file using msgfmt (%s)."),
|
_("Fail to compile messages from %s PO file as MO file using msgfmt (%s)."),
|
||||||
$lang, $po_file
|
$lang, $po_file
|
||||||
);
|
);
|
||||||
|
@ -336,24 +337,24 @@ function cli_compile_messages($command_args) {
|
||||||
$json_catalog = po2json($lang, $po_file);
|
$json_catalog = po2json($lang, $po_file);
|
||||||
$js_file = "$root_dir_path/public_html/translations/$lang.js";
|
$js_file = "$root_dir_path/public_html/translations/$lang.js";
|
||||||
if(!$fd = fopen($js_file, 'w')) {
|
if(!$fd = fopen($js_file, 'w')) {
|
||||||
Log :: error(_("Fail to open %s JSON catalog file in write mode (%s)."),
|
logging('ERROR', _("Fail to open %s JSON catalog file in write mode (%s)."),
|
||||||
$lang, $js_file);
|
$lang, $js_file);
|
||||||
$error = True;
|
$error = True;
|
||||||
}
|
}
|
||||||
elseif (fwrite($fd, sprintf("translations_data = %s;", $json_catalog)) === false) {
|
elseif (fwrite($fd, sprintf("translations_data = %s;", $json_catalog)) === false) {
|
||||||
Log :: error(_("Fail to write %s JSON catalog in file (%s)."),
|
logging('ERROR', _("Fail to write %s JSON catalog in file (%s)."),
|
||||||
$lang, $js_file);
|
$lang, $js_file);
|
||||||
$error = True;
|
$error = True;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Log :: info(_("%s JSON catalog writed (%s)."), $lang, $js_file);
|
logging('INFO', _("%s JSON catalog writed (%s)."), $lang, $js_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir($dh);
|
closedir($dh);
|
||||||
|
|
||||||
return !$error;
|
return !$error;
|
||||||
}
|
}
|
||||||
Log :: fatal(_("Fail to open root lang directory (%s)."), $root_dir_path);
|
logging('FATAL', _("Fail to open root lang directory (%s)."), $root_dir_path);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
add_cli_command(
|
add_cli_command(
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
// Gettext text domain
|
// Gettext text domain
|
||||||
define('TEXT_DOMAIN', 'DEFAULT');
|
define('TEXT_DOMAIN', 'DEFAULT');
|
||||||
|
|
||||||
|
@ -16,7 +14,7 @@ define('TEXT_DOMAIN', 'DEFAULT');
|
||||||
function get_available_langs($as_locales=false) {
|
function get_available_langs($as_locales=false) {
|
||||||
global $root_lang_dir;
|
global $root_lang_dir;
|
||||||
if (!is_dir($root_lang_dir))
|
if (!is_dir($root_lang_dir))
|
||||||
Log :: fatal("Root land directory not found ($root_lang_dir)");
|
logging('FATAL', "Root land directory not found ($root_lang_dir)");
|
||||||
$langs = array(($as_locales?'en_US.UTF8':'en'));
|
$langs = array(($as_locales?'en_US.UTF8':'en'));
|
||||||
if ($dh = opendir($root_lang_dir)) {
|
if ($dh = opendir($root_lang_dir)) {
|
||||||
while (($file = readdir($dh)) !== false) {
|
while (($file = readdir($dh)) !== false) {
|
||||||
|
@ -33,7 +31,7 @@ function get_available_langs($as_locales=false) {
|
||||||
closedir($dh);
|
closedir($dh);
|
||||||
}
|
}
|
||||||
$langs = array_unique($langs);
|
$langs = array_unique($langs);
|
||||||
Log :: trace('Available '.($as_locales?'locales':'languages').': '.implode(', ', $langs));
|
logging('TRACE', 'Available '.($as_locales?'locales':'languages').': '.implode(', ', $langs));
|
||||||
return $langs;
|
return $langs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +80,7 @@ function init_translation() {
|
||||||
$root_lang_dir = "$root_dir_path/lang";
|
$root_lang_dir = "$root_dir_path/lang";
|
||||||
|
|
||||||
if (!class_exists('Locale')) {
|
if (!class_exists('Locale')) {
|
||||||
Log :: error('Locale PHP class does not exist. May be php-intl is not installed?');
|
logging('ERROR', 'Locale PHP class does not exist. May be php-intl is not installed?');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +88,11 @@ function init_translation() {
|
||||||
if (php_sapi_name() != "cli") {
|
if (php_sapi_name() != "cli") {
|
||||||
if (isset($_REQUEST['lang']) && in_array($_REQUEST['lang'], $available_langs)) {
|
if (isset($_REQUEST['lang']) && in_array($_REQUEST['lang'], $available_langs)) {
|
||||||
$lang = $_REQUEST['lang'];
|
$lang = $_REQUEST['lang'];
|
||||||
Log :: trace("Select lang from request parameter: '$lang'");
|
logging('TRACE', "Select lang from request parameter: '$lang'");
|
||||||
}
|
}
|
||||||
elseif (isset($_SESSION['lang']) && in_array($_SESSION['lang'], $available_langs) && !isset($_REQUEST['reset_lang'])) {
|
elseif (isset($_SESSION['lang']) && in_array($_SESSION['lang'], $available_langs) && !isset($_REQUEST['reset_lang'])) {
|
||||||
$lang = $_SESSION['lang'];
|
$lang = $_SESSION['lang'];
|
||||||
Log :: trace("Restore lang from session: '$lang'");
|
logging('TRACE', "Restore lang from session: '$lang'");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$lang = Locale::lookup(
|
$lang = Locale::lookup(
|
||||||
|
@ -103,7 +101,7 @@ function init_translation() {
|
||||||
true,
|
true,
|
||||||
Locale::getPrimaryLanguage($default_locale)
|
Locale::getPrimaryLanguage($default_locale)
|
||||||
);
|
);
|
||||||
Log :: trace("Best lang found is '$lang'");
|
logging('TRACE', "Best lang found is '$lang'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -114,32 +112,32 @@ function init_translation() {
|
||||||
if ($sys_current)
|
if ($sys_current)
|
||||||
$lang = Locale::getPrimaryLanguage($sys_current);
|
$lang = Locale::getPrimaryLanguage($sys_current);
|
||||||
if (is_null($lang)) {
|
if (is_null($lang)) {
|
||||||
Log :: trace('No configured lang detected from CLI env, use default.');
|
logging('TRACE', 'No configured lang detected from CLI env, use default.');
|
||||||
$lang = Locale::getPrimaryLanguage($default_locale);
|
$lang = Locale::getPrimaryLanguage($default_locale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Log :: trace("Lang detected from CLI env : '$lang'");
|
logging('TRACE', "Lang detected from CLI env : '$lang'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep selected lang in session
|
// Keep selected lang in session
|
||||||
$_SESSION['lang'] = $lang;
|
$_SESSION['lang'] = $lang;
|
||||||
|
|
||||||
$locale = lang2locale($lang);
|
$locale = lang2locale($lang);
|
||||||
Log :: trace("Matching locale found with language '$lang' is '$locale'");
|
logging('TRACE', "Matching locale found with language '$lang' is '$locale'");
|
||||||
|
|
||||||
// Gettext firstly look the LANGUAGE env variable, so set it
|
// Gettext firstly look the LANGUAGE env variable, so set it
|
||||||
if (!putenv("LANGUAGE=$locale"))
|
if (!putenv("LANGUAGE=$locale"))
|
||||||
Log :: error("Fail to set LANGUAGE variable in environnement to '$locale'");
|
logging('ERROR', "Fail to set LANGUAGE variable in environnement to '$locale'");
|
||||||
|
|
||||||
// Set the locale
|
// Set the locale
|
||||||
if (setlocale(LC_ALL, $locale) === false)
|
if (setlocale(LC_ALL, $locale) === false)
|
||||||
Log :: error("An error occured setting locale to '$locale'");
|
logging('ERROR', "An error occured setting locale to '$locale'");
|
||||||
|
|
||||||
// Configure and set the text domain
|
// Configure and set the text domain
|
||||||
$fullpath = bindtextdomain(TEXT_DOMAIN, $root_lang_dir);
|
$fullpath = bindtextdomain(TEXT_DOMAIN, $root_lang_dir);
|
||||||
Log :: trace("Text domain fullpath is '$fullpath'.");
|
logging('TRACE', "Text domain fullpath is '$fullpath'.");
|
||||||
Log :: trace("Text domain is '".textdomain(TEXT_DOMAIN)."'.");
|
logging('TRACE', "Text domain is '".textdomain(TEXT_DOMAIN)."'.");
|
||||||
Log :: trace("Test: "._('Hello world !'));
|
logging('TRACE', "Test: "._('Hello world !'));
|
||||||
|
|
||||||
// JS translation file
|
// JS translation file
|
||||||
$js_translation_file = "translations/$lang.js";
|
$js_translation_file = "translations/$lang.js";
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Check;
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
function get_item_from_url($id, $fatal=false) {
|
function get_item_from_url($id, $fatal=false) {
|
||||||
if (!Check :: id($id))
|
if (!check_id($id))
|
||||||
Log :: fatal(_('Invalid element identifier.'));
|
logging('FATAL', _('Invalid element identifier.'));
|
||||||
|
|
||||||
$item = get_item($id);
|
$item = get_item($id);
|
||||||
if(!is_array($item)) {
|
if(!is_array($item)) {
|
||||||
$error = sprintf(_("Item #% s not found."), $id);
|
$error = sprintf(_("Item #% s not found."), $id);
|
||||||
if ($fatal)
|
if ($fatal)
|
||||||
Log :: fatal($error);
|
logging('FATAL', $error);
|
||||||
add_error($error);
|
add_error($error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use EesyPHP\Check;
|
|
||||||
use EesyPHP\Log;
|
|
||||||
use EesyPHP\Url;
|
|
||||||
|
|
||||||
use function EesyPHP\vardump;
|
|
||||||
|
|
||||||
if (php_sapi_name() == "cli")
|
if (php_sapi_name() == "cli")
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
function handle_homepage($request) {
|
function handle_homepage($request) {
|
||||||
display_template("homepage.tpl", _("Hello world !"));
|
display_template("homepage.tpl", _("Hello world !"));
|
||||||
}
|
}
|
||||||
Url :: add_url_handler('#^$#', 'handle_homepage');
|
add_url_handler('#^$#', 'handle_homepage');
|
||||||
|
|
||||||
function handle_search($request) {
|
function handle_search($request) {
|
||||||
global $smarty, $status_list;
|
global $smarty, $status_list;
|
||||||
|
@ -30,9 +24,9 @@ function handle_search($request) {
|
||||||
'order_direction' => 'ASC',
|
'order_direction' => 'ASC',
|
||||||
);
|
);
|
||||||
if (isset($_REQUEST['clear']) && $_REQUEST['clear']=='true')
|
if (isset($_REQUEST['clear']) && $_REQUEST['clear']=='true')
|
||||||
Url :: redirect($request -> current_url);
|
redirect($request -> current_url);
|
||||||
}
|
}
|
||||||
Log :: debug('Request params : '.vardump($_REQUEST));
|
logging('DEBUG', 'Request params : '.vardump($_REQUEST));
|
||||||
|
|
||||||
$status_list['all'] = _('Any');
|
$status_list['all'] = _('Any');
|
||||||
if (isset($_REQUEST['status'])) {
|
if (isset($_REQUEST['status'])) {
|
||||||
|
@ -45,7 +39,7 @@ function handle_search($request) {
|
||||||
if (isset($_REQUEST['pattern'])) {
|
if (isset($_REQUEST['pattern'])) {
|
||||||
if (trim($_REQUEST['pattern']) == '')
|
if (trim($_REQUEST['pattern']) == '')
|
||||||
$_SESSION['search']['pattern'] = false;
|
$_SESSION['search']['pattern'] = false;
|
||||||
else if (Check :: search_pattern($_REQUEST['pattern']))
|
else if (check_search_pattern($_REQUEST['pattern']))
|
||||||
$_SESSION['search']['pattern'] = $_REQUEST['pattern'];
|
$_SESSION['search']['pattern'] = $_REQUEST['pattern'];
|
||||||
else
|
else
|
||||||
$smarty -> assign('pattern_error', true);
|
$smarty -> assign('pattern_error', true);
|
||||||
|
@ -88,7 +82,7 @@ function handle_search($request) {
|
||||||
$_SESSION['search']['nb_by_page']=$nbs_by_page[0];
|
$_SESSION['search']['nb_by_page']=$nbs_by_page[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Log :: debug('Search params : '.vardump($_SESSION['search']));
|
logging('DEBUG', 'Search params : '.vardump($_SESSION['search']));
|
||||||
$result = search_items($_SESSION['search']);
|
$result = search_items($_SESSION['search']);
|
||||||
if (!is_array($result))
|
if (!is_array($result))
|
||||||
fatal_error(
|
fatal_error(
|
||||||
|
@ -109,7 +103,7 @@ function handle_search($request) {
|
||||||
|
|
||||||
display_template("search.tpl", _("Search"));
|
display_template("search.tpl", _("Search"));
|
||||||
}
|
}
|
||||||
Url :: add_url_handler('|^item/?$|', 'handle_search');
|
add_url_handler('|^item/?$|', 'handle_search');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* One item pages
|
* One item pages
|
||||||
|
@ -120,7 +114,7 @@ function handle_show($request) {
|
||||||
|
|
||||||
$item = get_item_from_url($request -> id);
|
$item = get_item_from_url($request -> id);
|
||||||
if (!$item)
|
if (!$item)
|
||||||
Url :: error_404();
|
error_404();
|
||||||
|
|
||||||
$smarty->assign('item', $item);
|
$smarty->assign('item', $item);
|
||||||
|
|
||||||
|
@ -135,7 +129,7 @@ function handle_show($request) {
|
||||||
(is_array($item)?$item['name']:"#".$request -> id)
|
(is_array($item)?$item['name']:"#".$request -> id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Url :: add_url_handler('|^item/(?P<id>[0-9]+)$|', 'handle_show');
|
add_url_handler('|^item/(?P<id>[0-9]+)$|', 'handle_show');
|
||||||
|
|
||||||
function handle_create($request) {
|
function handle_create($request) {
|
||||||
global $smarty, $status_list;
|
global $smarty, $status_list;
|
||||||
|
@ -146,14 +140,14 @@ function handle_create($request) {
|
||||||
$item = add_item($info);
|
$item = add_item($info);
|
||||||
if (is_array($item)) {
|
if (is_array($item)) {
|
||||||
add_message(_("The element '% s' has been created."), $item['name']);
|
add_message(_("The element '% s' has been created."), $item['name']);
|
||||||
Url :: redirect('item/'.$item['id']);
|
redirect('item/'.$item['id']);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
add_error(_("An error occurred while saving this item."));
|
add_error(_("An error occurred while saving this item."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log :: debug('Validated data : '.vardump($info));
|
logging('DEBUG', 'Validated data : '.vardump($info));
|
||||||
Log :: debug('Fields errors : '.vardump($field_errors));
|
logging('DEBUG', 'Fields errors : '.vardump($field_errors));
|
||||||
if (isset($_POST['submit']) && !empty($field_errors))
|
if (isset($_POST['submit']) && !empty($field_errors))
|
||||||
add_error(
|
add_error(
|
||||||
_("There are errors preventing this item from being saved. ".
|
_("There are errors preventing this item from being saved. ".
|
||||||
|
@ -165,7 +159,7 @@ function handle_create($request) {
|
||||||
|
|
||||||
display_template("form.tpl", _("New"));
|
display_template("form.tpl", _("New"));
|
||||||
}
|
}
|
||||||
Url :: add_url_handler('|^item/new$|', 'handle_create');
|
add_url_handler('|^item/new$|', 'handle_create');
|
||||||
|
|
||||||
function handle_modify($request) {
|
function handle_modify($request) {
|
||||||
global $smarty, $status_list;
|
global $smarty, $status_list;
|
||||||
|
@ -174,7 +168,7 @@ function handle_modify($request) {
|
||||||
if(is_array($item)) {
|
if(is_array($item)) {
|
||||||
if (!can_modify($item)) {
|
if (!can_modify($item)) {
|
||||||
add_error(_('You cannot edit this item.'));
|
add_error(_('You cannot edit this item.'));
|
||||||
Url :: redirect('item/'.$item['id']);
|
redirect('item/'.$item['id']);
|
||||||
}
|
}
|
||||||
$info = array();
|
$info = array();
|
||||||
$field_errors = handle_item_post_data($info);
|
$field_errors = handle_item_post_data($info);
|
||||||
|
@ -184,21 +178,21 @@ function handle_modify($request) {
|
||||||
if ($value != $item[$key])
|
if ($value != $item[$key])
|
||||||
$changes[$key] = $value;
|
$changes[$key] = $value;
|
||||||
}
|
}
|
||||||
Log :: debug('Changes : '.vardump($changes));
|
logging('DEBUG', 'Changes : '.vardump($changes));
|
||||||
if (empty($changes)) {
|
if (empty($changes)) {
|
||||||
add_message(_("You have not made any changes to element '% s'."), $item['name']);
|
add_message(_("You have not made any changes to element '% s'."), $item['name']);
|
||||||
Url :: redirect('item/'.$item['id']);
|
redirect('item/'.$item['id']);
|
||||||
}
|
}
|
||||||
else if (update_item($item['id'], $changes) === true) {
|
else if (update_item($item['id'], $changes) === true) {
|
||||||
add_message(_("The element '% s' has been updated successfully."), $item['name']);
|
add_message(_("The element '% s' has been updated successfully."), $item['name']);
|
||||||
Url :: redirect('item/'.$item['id']);
|
redirect('item/'.$item['id']);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
add_error(_("An error occurred while updating this item."));
|
add_error(_("An error occurred while updating this item."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log :: debug('Validated data : '.vardump($info));
|
logging('DEBUG', 'Validated data : '.vardump($info));
|
||||||
Log :: debug('Fields errors : '.vardump($field_errors));
|
logging('DEBUG', 'Fields errors : '.vardump($field_errors));
|
||||||
$smarty->assign('submited', isset($_POST['submit']));
|
$smarty->assign('submited', isset($_POST['submit']));
|
||||||
if (isset($_POST['submit']) && !empty($field_errors))
|
if (isset($_POST['submit']) && !empty($field_errors))
|
||||||
add_error(
|
add_error(
|
||||||
|
@ -210,7 +204,7 @@ function handle_modify($request) {
|
||||||
$smarty -> assign('status_list', $status_list);
|
$smarty -> assign('status_list', $status_list);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Url :: error_404();
|
error_404();
|
||||||
}
|
}
|
||||||
|
|
||||||
display_template(
|
display_template(
|
||||||
|
@ -218,7 +212,7 @@ function handle_modify($request) {
|
||||||
(is_array($item)?$item['name']:"#".$request -> id)
|
(is_array($item)?$item['name']:"#".$request -> id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Url :: add_url_handler('|^item/(?P<id>[0-9]+)/modify$|', 'handle_modify');
|
add_url_handler('|^item/(?P<id>[0-9]+)/modify$|', 'handle_modify');
|
||||||
|
|
||||||
function handle_archive($request) {
|
function handle_archive($request) {
|
||||||
global $smarty;
|
global $smarty;
|
||||||
|
@ -226,7 +220,7 @@ function handle_archive($request) {
|
||||||
$item = get_item_from_url($request -> id);
|
$item = get_item_from_url($request -> id);
|
||||||
if(!is_array($item)) {
|
if(!is_array($item)) {
|
||||||
add_error(_("Item #% s not found."), $request -> id);
|
add_error(_("Item #% s not found."), $request -> id);
|
||||||
Url :: redirect('item');
|
redirect('item');
|
||||||
}
|
}
|
||||||
elseif ($item['status'] == 'archived') {
|
elseif ($item['status'] == 'archived') {
|
||||||
add_message(_("This item is already archived."));
|
add_message(_("This item is already archived."));
|
||||||
|
@ -240,9 +234,9 @@ function handle_archive($request) {
|
||||||
else {
|
else {
|
||||||
add_error(_('An error occurred while archiving this item.'));
|
add_error(_('An error occurred while archiving this item.'));
|
||||||
}
|
}
|
||||||
Url :: redirect('item/'.$item['id']);
|
redirect('item/'.$item['id']);
|
||||||
}
|
}
|
||||||
Url :: add_url_handler('|^item/(?P<id>[0-9]+)/archive$|', 'handle_archive');
|
add_url_handler('|^item/(?P<id>[0-9]+)/archive$|', 'handle_archive');
|
||||||
|
|
||||||
function handle_delete($request) {
|
function handle_delete($request) {
|
||||||
global $smarty;
|
global $smarty;
|
||||||
|
@ -259,10 +253,10 @@ function handle_delete($request) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
add_error(_('An error occurred while deleting this item.'));
|
add_error(_('An error occurred while deleting this item.'));
|
||||||
Url :: redirect('item/'.$item['id']);
|
redirect('item/'.$item['id']);
|
||||||
}
|
}
|
||||||
Url :: redirect('item');
|
redirect('item');
|
||||||
}
|
}
|
||||||
Url :: add_url_handler('|^item/(?P<id>[0-9]+)/delete$|', 'handle_delete');
|
add_url_handler('|^item/(?P<id>[0-9]+)/delete$|', 'handle_delete');
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
||||||
|
|
613
includes/url.php
Normal file
613
includes/url.php
Normal file
|
@ -0,0 +1,613 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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'),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
$url_patterns =array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an URL pattern
|
||||||
|
*
|
||||||
|
* @param string|array $pattern The URL pattern or an array of patterns (required)
|
||||||
|
* @param callable $handler The URL pattern handler (must be callable, required)
|
||||||
|
* @param boolean $authenticated Permit to define if this URL is accessible only for
|
||||||
|
* authenticated users (optional, default: true if the
|
||||||
|
* special force_authentication function is defined,
|
||||||
|
* false otherwise)
|
||||||
|
* @param boolean $override Allow override if a command already exists with the
|
||||||
|
* same name (optional, default: false)
|
||||||
|
* @param boolean $api_mode Enable API mode (optional, default: false)
|
||||||
|
* @param array|string|null $methods HTTP method (optional, default: array('GET', 'POST'))
|
||||||
|
**/
|
||||||
|
function add_url_handler($pattern, $handler=null, $authenticated=null, $override=true,
|
||||||
|
$api_mode=false, $methods=null) {
|
||||||
|
$authenticated = (
|
||||||
|
is_null($authenticated)?
|
||||||
|
function_exists('force_authentication'):
|
||||||
|
(bool)$authenticated
|
||||||
|
);
|
||||||
|
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 '%s' with handler '%s' (old handler = '%s')".
|
||||||
|
$pattern, format_callable($handler), vardump($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.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show error page
|
||||||
|
*
|
||||||
|
* @param $request UrlRequest|null The request (optional, default: null)
|
||||||
|
* @param $error_code int|null The HTTP error code (optional, default: 400)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
function error_page($request=null, $error_code=null) {
|
||||||
|
global $smarty;
|
||||||
|
$http_errors = array(
|
||||||
|
400 => array(
|
||||||
|
'pagetitle' => _("Bad request"),
|
||||||
|
'message' => _("Invalid request."),
|
||||||
|
),
|
||||||
|
401 => array(
|
||||||
|
'pagetitle' => _("Authentication required"),
|
||||||
|
'message' => _("You have to be authenticated to access to this page."),
|
||||||
|
),
|
||||||
|
403 => array(
|
||||||
|
'pagetitle' => _("Access denied"),
|
||||||
|
'message' => _("You do not have access to this application. If you think this is an error, please contact support."),
|
||||||
|
),
|
||||||
|
404 => array(
|
||||||
|
'pagetitle' => _("Whoops ! Page not found"),
|
||||||
|
'message' => _("The requested page can not be found."),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$error_code = ($error_code?intval($error_code):400);
|
||||||
|
if (array_key_exists($error_code, $http_errors))
|
||||||
|
$error = $http_errors[intval($error_code)];
|
||||||
|
else
|
||||||
|
$error = array(
|
||||||
|
'pagetitle' => _('Error'),
|
||||||
|
'message' => _('An unknown error occurred. If problem persist, please contact support.'),
|
||||||
|
);
|
||||||
|
http_response_code($error_code);
|
||||||
|
|
||||||
|
$smarty -> assign('message', $error['message']);
|
||||||
|
display_template('error_page.tpl', $error['pagetitle']);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error 404 page
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error 404 handler
|
||||||
|
*
|
||||||
|
* @param UrlRequest|null $request The request (optional, default: null)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
function error_404($request=null) {
|
||||||
|
error_page($request, 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$_404_url_handler = 'error_404';
|
||||||
|
function set_404_url_handler($handler=null) {
|
||||||
|
global $_404_url_handler;
|
||||||
|
$_404_url_handler = $handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interprets the requested URL and return the corresponding UrlRequest object
|
||||||
|
*
|
||||||
|
* @param $default_url string|null The default URL if current one does not
|
||||||
|
* match with any configured pattern.
|
||||||
|
*
|
||||||
|
* @return 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(
|
||||||
|
'TRACE',
|
||||||
|
"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('TRACE', "URL : result :\n".vardump($request));
|
||||||
|
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
|
||||||
|
*
|
||||||
|
* @param string $pattern The URL pattern
|
||||||
|
* @param string|false $current_url The current URL (optional)
|
||||||
|
* @param array|null $methods HTTP method (optional, default: no check)
|
||||||
|
*
|
||||||
|
* @return 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, true)));
|
||||||
|
return $m;
|
||||||
|
}
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retreive current requested URL and return it
|
||||||
|
*
|
||||||
|
* @return string|false The current request URL or false if fail
|
||||||
|
**/
|
||||||
|
function get_current_url() {
|
||||||
|
logging('TRACE', "URL : request URI = '".$_SERVER['REQUEST_URI']."'");
|
||||||
|
|
||||||
|
$base = get_rewrite_base();
|
||||||
|
logging('TRACE', "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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to detect rewrite base from public root URL
|
||||||
|
*
|
||||||
|
* @return string The detected rewrite base
|
||||||
|
**/
|
||||||
|
function get_rewrite_base() {
|
||||||
|
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 '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger redirect to specified URL (or homepage if omited)
|
||||||
|
*
|
||||||
|
* @param string|false $go The destination URL
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
function redirect($go=false) {
|
||||||
|
global $public_root_url;
|
||||||
|
|
||||||
|
if ($go===false)
|
||||||
|
$go = "";
|
||||||
|
// If more than one argument passed, format URL using sprintf & urlencode parameters
|
||||||
|
elseif (func_num_args() > 1)
|
||||||
|
$go = call_user_func_array(
|
||||||
|
'sprintf',
|
||||||
|
array_merge(
|
||||||
|
array($go),
|
||||||
|
array_map('urlencode', array_slice(func_get_args(), 1))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
*
|
||||||
|
* Note: if the route required that user is authenticated, this method will
|
||||||
|
* invoke the force_authentication() special function (or trigger a fatal error
|
||||||
|
* if it's not defined).
|
||||||
|
*
|
||||||
|
* @param string|null $default_url The default URL if current one does not
|
||||||
|
* match with any configured pattern.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
function handle_request($default_url=null) {
|
||||||
|
global $smarty, $api_mode;
|
||||||
|
|
||||||
|
$sentry_span = new SentrySpan('http.handle_request', 'Handle the HTTP request');
|
||||||
|
|
||||||
|
$request = get_request($default_url);
|
||||||
|
|
||||||
|
if (!is_callable($request -> handler)) {
|
||||||
|
logging(
|
||||||
|
'ERROR', "URL handler function %s does not exists !",
|
||||||
|
format_callable($request -> handler));
|
||||||
|
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)
|
||||||
|
if (function_exists('force_authentication'))
|
||||||
|
force_authentication();
|
||||||
|
else
|
||||||
|
logging('FATAL', _("Authentication required but force_authentication function is not defined."));
|
||||||
|
|
||||||
|
try {
|
||||||
|
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."));
|
||||||
|
}
|
||||||
|
$sentry_span->finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove trailing slash in specified URL
|
||||||
|
*
|
||||||
|
* @param string $url The URL
|
||||||
|
*
|
||||||
|
* @return string The specified URL without trailing slash
|
||||||
|
**/
|
||||||
|
function remove_trailing_slash($url) {
|
||||||
|
if ($url == '/')
|
||||||
|
return $url;
|
||||||
|
elseif (substr($url, -1) == '/')
|
||||||
|
return substr($url, 0, -1);
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check an AJAX request and trigger a fatal error on fail
|
||||||
|
*
|
||||||
|
* Check if session key is present and valid and set AJAX
|
||||||
|
* mode.
|
||||||
|
*
|
||||||
|
* @param string|null $session_key string The current session key (optional)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
function check_ajax_request($session_key=null) {
|
||||||
|
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 string|null $relative_url Relative URL to convert (Default: current URL)
|
||||||
|
*
|
||||||
|
* @return 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($relative_url, 1);
|
||||||
|
$url = remove_trailing_slash($public_root_url)."/$relative_url";
|
||||||
|
logging('DEBUG', "URL :: get_absolute_url($relative_url): result = $url");
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if specified URL is absolute
|
||||||
|
*
|
||||||
|
* @param string $url The URL to check
|
||||||
|
*
|
||||||
|
* @return 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 string &$url The reference of the URL
|
||||||
|
* @param string $param The parameter name
|
||||||
|
* @param string $value The parameter value
|
||||||
|
* @param boolean $encode Set if parameter value must be URL encoded (optional, default: true)
|
||||||
|
*
|
||||||
|
* @return string 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 {
|
||||||
|
|
||||||
|
// 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 string $key The name of the info
|
||||||
|
*
|
||||||
|
* @return 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set request info
|
||||||
|
*
|
||||||
|
* @param string $key The name of the info
|
||||||
|
* @param mixed $value The value of the info
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
**/
|
||||||
|
public function __set($key, $value) {
|
||||||
|
if ($key == 'referer')
|
||||||
|
$_SERVER['HTTP_REFERER'] = $value;
|
||||||
|
elseif ($key == 'http_method')
|
||||||
|
$_SERVER['REQUEST_METHOD'] = $value;
|
||||||
|
else
|
||||||
|
$this->url_params[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check is request info is set
|
||||||
|
*
|
||||||
|
* @param string $key The name of the info
|
||||||
|
*
|
||||||
|
* @return bool True is info is set, False otherwise
|
||||||
|
**/
|
||||||
|
public function __isset($key) {
|
||||||
|
if (
|
||||||
|
in_array(
|
||||||
|
$key, array('current_url', 'handler', 'authenticated',
|
||||||
|
'api_mode', 'referer', 'http_method')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return True;
|
||||||
|
return array_key_exists($key, $this->url_params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get request parameter
|
||||||
|
*
|
||||||
|
* @param string $parameter The name of the parameter
|
||||||
|
* @param bool $decode If true, the parameter value will be urldecoded
|
||||||
|
* (optional, default: true)
|
||||||
|
*
|
||||||
|
* @return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get request referer (if known)
|
||||||
|
*
|
||||||
|
* @return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
10
phpstan.neon
10
phpstan.neon
|
@ -1,7 +1,6 @@
|
||||||
parameters:
|
parameters:
|
||||||
level: 5
|
level: 5
|
||||||
paths:
|
paths:
|
||||||
- src
|
|
||||||
- includes
|
- includes
|
||||||
- public_html
|
- public_html
|
||||||
- bin
|
- bin
|
||||||
|
@ -10,20 +9,21 @@ parameters:
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
-
|
-
|
||||||
message: "#Instantiated class Mail_mime not found\\.#"
|
message: "#Instantiated class Mail_mime not found\\.#"
|
||||||
path: src/Email.php
|
path: includes/mail.php
|
||||||
-
|
-
|
||||||
message: "#Call to method (setFrom|setSubject|setHTMLBody|setTXTBody|get|headers|addAttachment)\\(\\) on an unknown class Mail_mime\\.#"
|
message: "#Call to method (setFrom|setSubject|setHTMLBody|setTXTBody|get|headers|addAttachment)\\(\\) on an unknown class Mail_mime\\.#"
|
||||||
path: src/Email.php
|
path: includes/mail.php
|
||||||
-
|
-
|
||||||
message: "#Call to static method factory\\(\\) on an unknown class Mail\\.#"
|
message: "#Call to static method factory\\(\\) on an unknown class Mail\\.#"
|
||||||
path: src/Email.php
|
path: includes/mail.php
|
||||||
-
|
-
|
||||||
message: "#Call to static method isError\\(\\) on an unknown class PEAR\\.#"
|
message: "#Call to static method isError\\(\\) on an unknown class PEAR\\.#"
|
||||||
path: src/Email.php
|
path: includes/mail.php
|
||||||
-
|
-
|
||||||
message: "#Variable \\$root_dir_path might not be defined\\.#"
|
message: "#Variable \\$root_dir_path might not be defined\\.#"
|
||||||
paths:
|
paths:
|
||||||
- includes/config.inc.php
|
- includes/config.inc.php
|
||||||
|
- "#Access to private property UrlRequest::\\$(handler|api_mode|authenticated)\\.#"
|
||||||
-
|
-
|
||||||
message: "#Variable \\$status_list might not be defined\\.#"
|
message: "#Variable \\$status_list might not be defined\\.#"
|
||||||
paths:
|
paths:
|
||||||
|
|
|
@ -3,9 +3,7 @@
|
||||||
include '../includes/core.php';
|
include '../includes/core.php';
|
||||||
include 'url-public.php';
|
include 'url-public.php';
|
||||||
|
|
||||||
use EesyPHP\Url;
|
|
||||||
|
|
||||||
$default_url='';
|
$default_url='';
|
||||||
Url :: handle_request();
|
handle_request();
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
class Check {
|
|
||||||
public static function name($name) {
|
|
||||||
if (preg_match('/^[\w \-]{2,}$/iu',$name))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function id(&$id) {
|
|
||||||
if (is_int($id))
|
|
||||||
return true;
|
|
||||||
if (preg_match('/^[0-9]+$/', $id)) {
|
|
||||||
$id = intval($id);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function search_pattern($pattern) {
|
|
||||||
foreach(preg_split('/\s+/', trim($pattern)) as $word) {
|
|
||||||
if (!self :: id($word) && !self :: name($word))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function time(&$time) {
|
|
||||||
if (!is_int($time)) {
|
|
||||||
if (preg_match('/^[0-9]+$/', $time))
|
|
||||||
$time = intval($time);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ($time >= 1577833200); // 2020-01-01 - date of birth of this soft
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function description($comment) {
|
|
||||||
if (preg_match("/^[\p{L}0-9\p{P}\p{Zs}\p{Zl}\p{Sc}\=\+]+$/uim", $comment))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function email($value, $domain=NULL, $checkDns=true) {
|
|
||||||
$regex = '/^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]+))$/';
|
|
||||||
|
|
||||||
if (!preg_match($regex, $value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$nd = explode('@', $value);
|
|
||||||
$nd=$nd[1];
|
|
||||||
|
|
||||||
if ($domain) {
|
|
||||||
if(is_array($domain)) {
|
|
||||||
if (!in_array($nd,$domain)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if($nd!=$domain) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($checkDns && function_exists('checkdnsrr')) {
|
|
||||||
if (!(checkdnsrr($nd, 'MX') || checkdnsrr($nd, 'A'))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function is_empty($val) {
|
|
||||||
switch(gettype($val)) {
|
|
||||||
case "boolean":
|
|
||||||
case "integer":
|
|
||||||
case "double":
|
|
||||||
case "object":
|
|
||||||
case "resource":
|
|
||||||
return False;
|
|
||||||
case "array":
|
|
||||||
case "string":
|
|
||||||
if ($val == "0") return false;
|
|
||||||
return empty($val);
|
|
||||||
case "NULL":
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
211
src/Email.php
211
src/Email.php
|
@ -1,211 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
use PEAR;
|
|
||||||
use Mail;
|
|
||||||
use Mail_mime;
|
|
||||||
|
|
||||||
use finfo;
|
|
||||||
|
|
||||||
class Email {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default sender
|
|
||||||
* @var string|null;
|
|
||||||
*/
|
|
||||||
protected static $sender = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sending method :
|
|
||||||
* - mail : use PHP mail function
|
|
||||||
* - sendmail : use sendmail system command
|
|
||||||
* - smtp : use an SMTP server (PHP PEAR Net_SMTP required)
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected static $send_method = 'mail';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sending parameters
|
|
||||||
* @see http://pear.php.net/manual/en/package.mail.mail.factory.php
|
|
||||||
* @var array|null
|
|
||||||
*/
|
|
||||||
protected static $send_params = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Catch all sent email recipient
|
|
||||||
* @var string|array<string>|null
|
|
||||||
*/
|
|
||||||
protected static $catch_all = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default headers to add on all sent emails
|
|
||||||
* @var array<string>
|
|
||||||
*/
|
|
||||||
protected static $headers = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PHP PEAR Mail lib path
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected static $php_mail_path = 'Mail.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PHP PEAR Mail lib path
|
|
||||||
* @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: Mail.php)
|
|
||||||
* @param string|null $php_mail_mime_path PHP PEAR Mail lib path (optional, default: Mail/mime.php)
|
|
||||||
* @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 ($sender) self :: $sender = $sender;
|
|
||||||
if ($send_method) self :: $send_method = $send_method;
|
|
||||||
if ($send_params) self :: $send_params = $send_params;
|
|
||||||
if ($catch_all) self :: $catch_all = $catch_all;
|
|
||||||
if ($headers) self :: $headers = $headers;
|
|
||||||
if ($php_mail_path) self :: $php_mail_path = $php_mail_path;
|
|
||||||
if ($php_mail_mime_path) self :: $php_mail_mime_path = $php_mail_mime_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an email
|
|
||||||
*
|
|
||||||
* @param string|null $from Email sender
|
|
||||||
* @param string|array<string> $to Email recipient(s)
|
|
||||||
* @param string $subject Email subject
|
|
||||||
* @param string $msg Email body
|
|
||||||
* @param boolean $html Set to true to send an HTML email (default: false)
|
|
||||||
* @param array<string,string>|null $attachments Email attachments as an array with
|
|
||||||
* filepath as key and filename as value
|
|
||||||
* @param array<string,string>|null $headers Email headers
|
|
||||||
* @param string|null $encoding Email encoding (default: utf8)
|
|
||||||
* @param string|null $eol End of line string (default : \n)
|
|
||||||
*
|
|
||||||
* @return boolean true If mail was sent, false otherwise
|
|
||||||
*/
|
|
||||||
public static function send($from, $to, $subject, $msg, $html=false, $attachments=null,
|
|
||||||
$headers=null, $encoding=null, $eol=null) {
|
|
||||||
if (!class_exists('Mail'))
|
|
||||||
require_once(self :: $php_mail_path);
|
|
||||||
if (!class_exists('Mail_mime'))
|
|
||||||
require_once(self :: $php_mail_mime_path);
|
|
||||||
|
|
||||||
$mail_obj = Mail::factory(self :: $send_method, self :: $send_params);
|
|
||||||
|
|
||||||
if (!$headers) $headers = array();
|
|
||||||
$headers = array_merge($headers, self :: $headers);
|
|
||||||
|
|
||||||
Log :: trace(
|
|
||||||
'Mail catch all: %s',
|
|
||||||
self :: $catch_all?
|
|
||||||
vardump(self :: $catch_all):'not set'
|
|
||||||
);
|
|
||||||
if (self :: $catch_all) {
|
|
||||||
Log :: debug(
|
|
||||||
'Mail catch to %s',
|
|
||||||
is_array(self :: $catch_all)?implode(',', self :: $catch_all):self :: $catch_all
|
|
||||||
);
|
|
||||||
$msg .= sprintf(
|
|
||||||
(
|
|
||||||
$html?
|
|
||||||
_("</hr><p><small>Mail initialy intended for %s.</small></p>"):
|
|
||||||
_("\n\n\nMail initialy intended for %s.")
|
|
||||||
),
|
|
||||||
(is_array($to)?implode(',', $to):$to));
|
|
||||||
$headers["X-Orig-To"] = $to;
|
|
||||||
$to = (
|
|
||||||
is_array(self :: $catch_all)?
|
|
||||||
implode(',', self :: $catch_all):self :: $catch_all
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($subject) {
|
|
||||||
$headers["Subject"] = $subject;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($headers['From'])) {
|
|
||||||
if (!$from)
|
|
||||||
$from = $headers['From'];
|
|
||||||
unset($headers['From']);
|
|
||||||
}
|
|
||||||
elseif (!$from) {
|
|
||||||
$from = self :: $sender;
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers["To"] = $to;
|
|
||||||
|
|
||||||
$to = array (
|
|
||||||
'To' => $to
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach(array_keys($headers) as $header) {
|
|
||||||
if(in_array(strtoupper($header), array('BCC', 'CC'))) {
|
|
||||||
if (self :: $catch_all) {
|
|
||||||
Log :: debug("Mail catched: remove $header header");
|
|
||||||
$msg .= sprintf(
|
|
||||||
(
|
|
||||||
$html?
|
|
||||||
_("<p><small>%s: %s</small></p>"):
|
|
||||||
_("\n%s: %s")
|
|
||||||
),
|
|
||||||
strtoupper($header),
|
|
||||||
(is_array($headers[$header])?implode(',', $headers[$header]):$headers[$header]));
|
|
||||||
unset($headers[$header]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$to[strtoupper($header)] = $headers[$header];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$encoding) $encoding = "utf8";
|
|
||||||
$mime = new Mail_mime(
|
|
||||||
array(
|
|
||||||
'eol' => ($eol?$eol:"\n"),
|
|
||||||
($html?'html_charset':'text_charset') => $encoding,
|
|
||||||
'head_charset' => $encoding,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($from)
|
|
||||||
$mime->setFrom($from);
|
|
||||||
|
|
||||||
if ($subject)
|
|
||||||
$mime->setSubject($subject);
|
|
||||||
|
|
||||||
if ($html)
|
|
||||||
$mime->setHTMLBody($msg);
|
|
||||||
else
|
|
||||||
$mime->setTXTBody($msg);
|
|
||||||
|
|
||||||
if (is_array($attachments) && !empty($attachments)) {
|
|
||||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
|
||||||
foreach ($attachments as $file => $filename) {
|
|
||||||
$mime->addAttachment($file, $finfo->file($file), $filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$body = $mime->get();
|
|
||||||
$headers = $mime->headers($headers);
|
|
||||||
|
|
||||||
$ret = $mail_obj -> send($to, $headers, $body);
|
|
||||||
|
|
||||||
if (PEAR::isError($ret)) {
|
|
||||||
$msg = "Error sending email: ".$ret -> getMessage();
|
|
||||||
Log :: error($msg);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
89
src/Hook.php
89
src/Hook.php
|
@ -1,89 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class Hook {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registered hooks
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected static $hooks = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registered a hook on a specific event
|
|
||||||
*
|
|
||||||
* @param $event string The event name
|
|
||||||
* @param $callable callable The callable to run on event
|
|
||||||
* @param $param mixed Paremeter that will be pass to the callable
|
|
||||||
* Use an array if you have multiple parameters to pass
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function register($event, $callable, $param=NULL) {
|
|
||||||
if (!array_key_exists($event, self :: $hooks))
|
|
||||||
self :: $hooks[$event] = array();
|
|
||||||
self :: $hooks[$event][] = array (
|
|
||||||
'callable' => $callable,
|
|
||||||
'param' => $param,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run triggered actions on specific event
|
|
||||||
*
|
|
||||||
* @param $event string Hook event name
|
|
||||||
* @param $event_data mixed Hook event data (optional, default: null)
|
|
||||||
*
|
|
||||||
* @return boolean True if all triggered actions succefully runned, false otherwise
|
|
||||||
*/
|
|
||||||
public static function trigger($event_name, $event_data=null) {
|
|
||||||
$return = true;
|
|
||||||
|
|
||||||
if (isset(self :: $hooks[$event_name]) && is_array(self :: $hooks[$event_name])) {
|
|
||||||
if ($event_name == 'all')
|
|
||||||
$event = new HookEvent($event_data['event_name'], $event_data['event_data']);
|
|
||||||
else
|
|
||||||
$event = new HookEvent($event_name, $event_data);
|
|
||||||
foreach (self :: $hooks[$event_name] as $e) {
|
|
||||||
if (is_callable($e['callable'])) {
|
|
||||||
try {
|
|
||||||
call_user_func_array($e['callable'],array($event, &$e['param']));
|
|
||||||
}
|
|
||||||
catch(Exception $e) {
|
|
||||||
Log :: exception(
|
|
||||||
$e, "An exception occured running hook ".format_callable($e['callable']).
|
|
||||||
" on event $event_name");
|
|
||||||
$return = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log :: error(
|
|
||||||
"The hook ".format_callable($e['callable'])." on event $event_name is not callable.");
|
|
||||||
$return = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Log :: debug("No hook registered for event $event_name.");
|
|
||||||
|
|
||||||
// Handle 'all' event
|
|
||||||
if ($event_name != 'all') {
|
|
||||||
self :: trigger (
|
|
||||||
'all',
|
|
||||||
array (
|
|
||||||
'event_name' => $event_name,
|
|
||||||
'event_data' => $event_data,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
|
@ -1,34 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
use JsonSerializable;
|
|
||||||
|
|
||||||
class HookEvent implements JsonSerializable {
|
|
||||||
private $name;
|
|
||||||
private $data;
|
|
||||||
|
|
||||||
function __construct($name, $data) {
|
|
||||||
$this -> name = $name;
|
|
||||||
$this -> data = $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
function __get($key) {
|
|
||||||
if ($key == 'name')
|
|
||||||
return $this -> name;
|
|
||||||
elseif ($key == 'data')
|
|
||||||
return $this -> data;
|
|
||||||
elseif (is_array($this -> data) && array_key_exists($key, $this -> data))
|
|
||||||
return $this -> data[$key];
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function jsonSerialize() {
|
|
||||||
return array (
|
|
||||||
'name' => $this -> name,
|
|
||||||
'data' => $this -> data,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
363
src/Log.php
363
src/Log.php
|
@ -1,363 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
use EesyPHP\SentryIntegration;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
|
|
||||||
class Log {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Log file path
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected static $filepath = null;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Log file descriptor
|
|
||||||
* @var resource|null
|
|
||||||
*/
|
|
||||||
protected static $file_fd = null;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Log Levels
|
|
||||||
* @var array(string,int)
|
|
||||||
*/
|
|
||||||
protected static $levels = array(
|
|
||||||
'TRACE' => 0,
|
|
||||||
'DEBUG' => 1,
|
|
||||||
'INFO' => 2,
|
|
||||||
'WARNING' => 3,
|
|
||||||
'ERROR' => 4,
|
|
||||||
'FATAL' => 5,
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default log level
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected static string $default_level = 'WARNING';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Current log level
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected static $level = null;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Log PHP errors levels (as specified to set_error_handler())
|
|
||||||
* Default (set in self::init() method):
|
|
||||||
* - In TRACE or DEBUG: E_ALL & ~E_STRICT
|
|
||||||
* - Otherwise: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
|
|
||||||
*/
|
|
||||||
protected static $php_errors_levels = null;
|
|
||||||
|
|
||||||
// Custom fatal error handler
|
|
||||||
protected static $fatal_error_handler = null;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialization
|
|
||||||
* @param string $filepath
|
|
||||||
* @param string|null $level
|
|
||||||
* @param int|null $php_errors_levels
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function init($filepath, $level=null, $php_errors_levels=null) {
|
|
||||||
self :: $filepath = $filepath;
|
|
||||||
|
|
||||||
// Set default log level (if not defined or invalid)
|
|
||||||
if (is_null($level)) {
|
|
||||||
self :: $level = self :: $default_level;
|
|
||||||
}
|
|
||||||
elseif (!array_key_exists($level, self :: $levels)) {
|
|
||||||
self :: $level = self :: $default_level;
|
|
||||||
self :: warning(
|
|
||||||
"Invalid log level value found in configuration (%s). ".
|
|
||||||
"Set as default (%s).", $level, self :: $default_level);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self :: $level = $level;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log PHP errors
|
|
||||||
if (!is_null($php_errors_levels))
|
|
||||||
self :: $php_errors_levels = $php_errors_levels;
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Log uncatched exceptions
|
|
||||||
set_exception_handler(array('EesyPHP\\Log', 'exception'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a message
|
|
||||||
* @param string $level The message level (key of self :: $levels)
|
|
||||||
* @param string $message The message to log
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
public static function log($level, $message, ...$extra_args) {
|
|
||||||
global $auth_user, $argv;
|
|
||||||
|
|
||||||
if (!array_key_exists($level, self :: $levels)) $level = self :: $default_level;
|
|
||||||
if (self :: $levels[$level] < self :: $levels[self :: $level]) return true;
|
|
||||||
if(is_null(self :: $file_fd)) {
|
|
||||||
self :: $file_fd = fopen(self :: $filepath, 'a');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extra arguments passed, format message using sprintf
|
|
||||||
if ($extra_args) {
|
|
||||||
$message = call_user_func_array(
|
|
||||||
'sprintf',
|
|
||||||
array_merge(array($message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (php_sapi_name() == "cli") {
|
|
||||||
$msg = implode(' - ', array(
|
|
||||||
date('Y/m/d H:i:s'),
|
|
||||||
basename($argv[0]),
|
|
||||||
$level,
|
|
||||||
$message
|
|
||||||
))."\n";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$msg = array(
|
|
||||||
date('Y/m/d H:i:s'),
|
|
||||||
$_SERVER['REQUEST_URI'],
|
|
||||||
$_SERVER['REMOTE_ADDR'],
|
|
||||||
);
|
|
||||||
if (isset($auth_user))
|
|
||||||
$msg[] = ($auth_user['username']?$auth_user['username']:'anonymous');
|
|
||||||
$msg[] = $level;
|
|
||||||
$msg[] = $message;
|
|
||||||
$msg = implode(' - ', $msg)."\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite(self :: $file_fd, $msg);
|
|
||||||
|
|
||||||
if ($level == 'FATAL')
|
|
||||||
if (!is_null(self :: $fatal_error_handler))
|
|
||||||
call_user_func(self :: $fatal_error_handler, $message);
|
|
||||||
elseif (function_exists('fatal_error'))
|
|
||||||
fatal_error($message);
|
|
||||||
else
|
|
||||||
die("\n$message\n\n");
|
|
||||||
elseif (php_sapi_name() == "cli")
|
|
||||||
echo $msg;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a trace message
|
|
||||||
* @param string $message The message to log
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
public static function trace($message, ...$extra_args) {
|
|
||||||
return call_user_func_array(
|
|
||||||
array('EesyPHP\\Log', 'log'),
|
|
||||||
array_merge(array('TRACE', $message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a debug message
|
|
||||||
* @param string $message The message to log
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
public static function debug($message, ...$extra_args) {
|
|
||||||
return call_user_func_array(
|
|
||||||
array('EesyPHP\\Log', 'log'),
|
|
||||||
array_merge(array('DEBUG', $message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an info message
|
|
||||||
* @param string $message The message to log
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
public static function info($message, ...$extra_args) {
|
|
||||||
return call_user_func_array(
|
|
||||||
array('EesyPHP\\Log', 'log'),
|
|
||||||
array_merge(array('INFO', $message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an warning message
|
|
||||||
* @param string $message The message to log
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
public static function warning($message, ...$extra_args) {
|
|
||||||
return call_user_func_array(
|
|
||||||
array('EesyPHP\\Log', 'log'),
|
|
||||||
array_merge(array('WARNING', $message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an error message
|
|
||||||
* @param string $message The message to log
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
public static function error($message, ...$extra_args) {
|
|
||||||
return call_user_func_array(
|
|
||||||
array('EesyPHP\\Log', 'log'),
|
|
||||||
array_merge(array('ERROR', $message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an fatal message
|
|
||||||
* @param string $message The message to log
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
public static function fatal($message, ...$extra_args) {
|
|
||||||
return call_user_func_array(
|
|
||||||
array('EesyPHP\\Log', 'log'),
|
|
||||||
array_merge(array('FATAL', $message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a contextual fatal error handler
|
|
||||||
* @param null|callable $handler The fatal error handler (set as null to reset)
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function register_fatal_error_handler($handler) {
|
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
if ($handler && !is_callable($handler))
|
|
||||||
self :: fatal('Invalid fatal error handler provided: it is not callable !');
|
|
||||||
self :: $fatal_error_handler = ($handler?$handler:null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change of current log file
|
|
||||||
* @param string $file The new log file path
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function change_filepath($file) {
|
|
||||||
if ($file == self :: $filepath) return True;
|
|
||||||
if (self :: $file_fd) {
|
|
||||||
fclose(self :: $file_fd);
|
|
||||||
self :: $file_fd = null;
|
|
||||||
}
|
|
||||||
self :: $filepath = $file;
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*******************************************************************************
|
|
||||||
* Handle exception logging
|
|
||||||
*******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current backtrace
|
|
||||||
* @param int $ignore_last The number of last levels to ignore
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function get_debug_backtrace_context($ignore_last=0) {
|
|
||||||
$traces = debug_backtrace();
|
|
||||||
|
|
||||||
// Also ignore this function it self
|
|
||||||
$ignore_last++;
|
|
||||||
|
|
||||||
if (!is_array($traces) || count($traces) <= $ignore_last)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
$msg = array();
|
|
||||||
for ($i=$ignore_last; $i < count($traces); $i++) {
|
|
||||||
$trace = array("#$i");
|
|
||||||
if (isset($traces[$i]['file']))
|
|
||||||
$trace[] = $traces[$i]['file'].(isset($traces[$i]['line'])?":".$traces[$i]['line']:"");
|
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
if (isset($traces[$i]['class']) && isset($traces[$i]['function']))
|
|
||||||
$trace[] = implode(" ", array(
|
|
||||||
$traces[$i]['class'],
|
|
||||||
$traces[$i]['type'],
|
|
||||||
$traces[$i]['function']. "()"));
|
|
||||||
elseif (isset($traces[$i]['function']))
|
|
||||||
$trace[] = $traces[$i]['function']. "()";
|
|
||||||
$msg[] = implode(" - ", $trace);
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode("\n", $msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an exception
|
|
||||||
* @param Throwable $exception
|
|
||||||
* @param string|null $prefix The prefix of the log message
|
|
||||||
* (optional, default: "An exception occured")
|
|
||||||
* @param array $extra_args Extra arguments to use to compute prefix using sprintf
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function exception($exception, $prefix=null, ...$extra_args) {
|
|
||||||
SentryIntegration :: log($exception);
|
|
||||||
// If extra arguments passed, format prefix message using sprintf
|
|
||||||
if ($prefix && $extra_args) {
|
|
||||||
$prefix = call_user_func_array(
|
|
||||||
'sprintf',
|
|
||||||
array_merge(array($prefix), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
self :: error(
|
|
||||||
"%s:\n%s\n## %s:%d : %s",
|
|
||||||
($prefix?$prefix:"An exception occured"),
|
|
||||||
self::get_debug_backtrace_context(1),
|
|
||||||
$exception->getFile(), $exception->getLine(),
|
|
||||||
$exception->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*******************************************************************************
|
|
||||||
* Handle PHP error logging
|
|
||||||
*******************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert PHP error number to the corresponding label
|
|
||||||
* @param int $errno
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public static function errno2type($errno) {
|
|
||||||
$constants = get_defined_constants();
|
|
||||||
if (is_array($constants))
|
|
||||||
foreach($constants as $label => $value)
|
|
||||||
if ($value == $errno && preg_match('/^E_(.*)$/', $label, $m))
|
|
||||||
return $m[1];
|
|
||||||
return 'UNKNOWN ERROR #'.$errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a PHP error
|
|
||||||
* Note: method design to be used as callable by set_error_handler()
|
|
||||||
* @param int $errno The error number
|
|
||||||
* @param string $errstr The error message
|
|
||||||
* @param string $errfile The filename that the error was raised in
|
|
||||||
* @param int $errline The line number where the error was raised
|
|
||||||
* @return false Return false to let the normal error handler continues.
|
|
||||||
*/
|
|
||||||
public static function on_php_error($errno, $errstr, $errfile, $errline) {
|
|
||||||
self :: error(
|
|
||||||
"A PHP error occured : [%s] %s\nFile : %s (line : %d)",
|
|
||||||
self :: errno2type($errno), $errstr, $errfile, $errline
|
|
||||||
);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
|
@ -1,114 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
use Throwable;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class SentryIntegration {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sentry DSN
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected static $dsn = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Types of PHP error to log in Sentry
|
|
||||||
* @see https://www.php.net/manual/fr/errorfunc.constants.php
|
|
||||||
* @var array<int>
|
|
||||||
*/
|
|
||||||
protected static array $php_error_types = array(
|
|
||||||
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
|
|
||||||
E_RECOVERABLE_ERROR,E_DEPRECATED,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialization
|
|
||||||
* @param string|null $dsn Sentry DSN
|
|
||||||
* @param float|null $traces_sample_rate Sentry traces sample rate
|
|
||||||
* (optional, default: 0.2)
|
|
||||||
* @param array<int>|null $php_error_types Types of PHP error to log in Sentry
|
|
||||||
* (optional, default: see self::$php_error_types)
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function init($dsn=null, $traces_sample_rate=null,
|
|
||||||
$php_error_types=null) {
|
|
||||||
// Init Sentry (if its DSN is configured)
|
|
||||||
if (!$dsn) return;
|
|
||||||
|
|
||||||
\Sentry\init([
|
|
||||||
'dsn' => $dsn,
|
|
||||||
'traces_sample_rate' => (
|
|
||||||
$traces_sample_rate?
|
|
||||||
$traces_sample_rate:0.2
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
|
|
||||||
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
|
|
||||||
global $auth_user;
|
|
||||||
$scope->setUser([
|
|
||||||
'id' => isset($auth_user) && $auth_user?$auth_user['uid']:null,
|
|
||||||
'email' => isset($auth_user) && $auth_user?$auth_user['mail']:null,
|
|
||||||
'segment' => isset($auth_user) && $auth_user?$auth_user['type']:null,
|
|
||||||
'ip_address' => $_SERVER['REMOTE_ADDR'],
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (is_array($php_error_types))
|
|
||||||
self :: $php_error_types = $php_error_types;
|
|
||||||
set_error_handler(
|
|
||||||
array('EesyPHP\\SentryIntegration', 'on_php_error'),
|
|
||||||
E_ALL
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log an exception or a message in Sentry
|
|
||||||
* @param string|Throwable $message
|
|
||||||
* @param array $extra_args Extra arguments to use to compute message using sprintf
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function log($message, ...$extra_args) {
|
|
||||||
if (!self :: $dsn) {
|
|
||||||
Log :: trace('Sentry DSN not configured, do not log this error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (is_string($message)) {
|
|
||||||
// Extra arguments passed, format message using sprintf
|
|
||||||
if ($extra_args) {
|
|
||||||
$message = call_user_func_array(
|
|
||||||
'sprintf',
|
|
||||||
array_merge(array($message), $extra_args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Log :: debug('Error logged in Sentry');
|
|
||||||
\Sentry\captureMessage($message);
|
|
||||||
}
|
|
||||||
elseif ($message instanceof Exception) {
|
|
||||||
Log :: debug('Exception logged in Sentry');
|
|
||||||
\Sentry\captureException($message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log a PHP error in Sentry
|
|
||||||
* Note: method design to be used as callable by set_error_handler()
|
|
||||||
* @param int $errno The error number
|
|
||||||
* @param string $errstr The error message
|
|
||||||
* @param string $errfile The filename that the error was raised in
|
|
||||||
* @param int $errline The line number where the error was raised
|
|
||||||
* @return false Return false to let the normal error handler continues.
|
|
||||||
*/
|
|
||||||
public static function on_php_error($errno, $errstr, $errfile, $errline) {
|
|
||||||
if (in_array($errno, self :: $php_error_types))
|
|
||||||
self :: log(
|
|
||||||
"A PHP error occured : [%s] %s\nFile : %s (line : %d)",
|
|
||||||
Log :: errno2type($errno), $errstr, $errfile, $errline
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
|
@ -1,92 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal Sentry Span object implementation
|
|
||||||
* This internal implementation principally permit to keep trace of new span parent
|
|
||||||
* and list of started spans.
|
|
||||||
*/
|
|
||||||
class SentrySpan {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keep trace of started Sentry spans
|
|
||||||
* @var array<int,mixed>
|
|
||||||
*/
|
|
||||||
private static $_started_spans = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The unique ID of the Sentry span
|
|
||||||
* Note: internal ID used as key in self::$_started_spans
|
|
||||||
* @var int|null
|
|
||||||
*/
|
|
||||||
private $id = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The parent of the Sentry span
|
|
||||||
* @var mixed
|
|
||||||
*/
|
|
||||||
private $parent = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The context of the Sentry span
|
|
||||||
* @var null|\Sentry\Tracing\SpanContext
|
|
||||||
*/
|
|
||||||
private $context = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Sentry span object
|
|
||||||
* @var mixed
|
|
||||||
*/
|
|
||||||
private $span = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sentry span constructor
|
|
||||||
* @param string|null $op The operation name
|
|
||||||
* @param string|null $name The span name
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct($op, $name) {
|
|
||||||
$this -> parent = \Sentry\SentrySdk::getCurrentHub()->getSpan();
|
|
||||||
// Check if we have a parent span (this is the case if we started a transaction earlier)
|
|
||||||
if (is_null($this -> parent)) return;
|
|
||||||
|
|
||||||
while (is_null($this -> id)) {
|
|
||||||
$this -> id = rand();
|
|
||||||
if (isset(self :: $_started_spans[$this -> id]))
|
|
||||||
$this -> id = null;
|
|
||||||
}
|
|
||||||
$this -> context = new \Sentry\Tracing\SpanContext();
|
|
||||||
$this -> context->setOp($op);
|
|
||||||
$this -> context->setDescription($name);
|
|
||||||
$this -> span = $this->parent->startChild($this -> context);
|
|
||||||
|
|
||||||
// Set the current span to the span we just started
|
|
||||||
\Sentry\SentrySdk::getCurrentHub()->setSpan($this -> span);
|
|
||||||
|
|
||||||
self :: $_started_spans[$this -> id] = $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finish the span (if started)
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function finish() {
|
|
||||||
if (!$this -> span) return;
|
|
||||||
$this -> span -> finish();
|
|
||||||
unset(self::$_started_spans[$this -> id]);
|
|
||||||
\Sentry\SentrySdk::getCurrentHub()->setSpan($this -> parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finish all started spans
|
|
||||||
* @see SentryTransaction::__destruct()
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function finishAll() {
|
|
||||||
foreach (array_reverse(self :: $_started_spans) as $id => $span)
|
|
||||||
$span -> finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
|
@ -1,58 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Performance monitoring
|
|
||||||
*/
|
|
||||||
|
|
||||||
class SentryTransaction {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Sentry transaction object
|
|
||||||
* @var \Sentry\Tracing\Transaction
|
|
||||||
*/
|
|
||||||
private $transaction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Sentry transaction context object
|
|
||||||
* @var \Sentry\Tracing\TransactionContext
|
|
||||||
*/
|
|
||||||
private $context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor: start a Sentry transaction
|
|
||||||
* @param string|null $op The operation name
|
|
||||||
* @param string|null $name The transaction name
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct($op=null, $name=null) {
|
|
||||||
// Setup context for the full transaction
|
|
||||||
$this->context = new \Sentry\Tracing\TransactionContext();
|
|
||||||
$this->context->setName(
|
|
||||||
$name?$name:
|
|
||||||
(php_sapi_name()=='cli'?'CLI execution':'HTTP request')
|
|
||||||
);
|
|
||||||
$this->context->setOp(
|
|
||||||
$op?$op:
|
|
||||||
(php_sapi_name()=='cli'?'cli.command':'http.request')
|
|
||||||
);
|
|
||||||
|
|
||||||
// Start the transaction
|
|
||||||
$this->transaction = \Sentry\startTransaction($this->context);
|
|
||||||
|
|
||||||
// Set the current transaction as the current span so we can retrieve it later
|
|
||||||
\Sentry\SentrySdk::getCurrentHub()->setSpan($this->transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor: Stop the current Sentry transaction
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __destruct() {
|
|
||||||
SentrySpan :: finishAll();
|
|
||||||
$this->transaction->finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
517
src/Url.php
517
src/Url.php
|
@ -1,517 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
use EesyPHP\SentrySpan;
|
|
||||||
use EesyPHP\SentryTransaction;
|
|
||||||
use EesyPHP\UrlRequest;
|
|
||||||
|
|
||||||
use function EesyPHP\format_callable;
|
|
||||||
use function EesyPHP\vardump;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class Url {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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'),
|
|
||||||
* ),
|
|
||||||
* )
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected static $patterns = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error 404 handler
|
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
protected static $error_404_handler = array('\\EesyPHP\\Url', 'error_404');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public root URL
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected static $public_root_url = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable/disable API mode
|
|
||||||
* @see self :: initialization()
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
protected static bool $_api_mode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialization
|
|
||||||
* @param string|null $public_root_url The application public root URL
|
|
||||||
* @param bool $api_mode Enable/disable API mode
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function init($public_root_url = null, $api_mode=false) {
|
|
||||||
if ($public_root_url) {
|
|
||||||
// Check URL end
|
|
||||||
if (substr(self :: $public_root_url, -1) == '/')
|
|
||||||
$public_root_url = substr($public_root_url, 0, -1);
|
|
||||||
self :: $public_root_url = $public_root_url?$public_root_url:null;
|
|
||||||
}
|
|
||||||
self :: $_api_mode = boolval($api_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an URL pattern
|
|
||||||
*
|
|
||||||
* @param string|array $pattern The URL pattern or an array of patterns (required)
|
|
||||||
* @param callable $handler The URL pattern handler (must be callable, required)
|
|
||||||
* @param boolean $authenticated Permit to define if this URL is accessible only for
|
|
||||||
* authenticated users (optional, default: true if the
|
|
||||||
* special force_authentication function is defined,
|
|
||||||
* false otherwise)
|
|
||||||
* @param boolean $override Allow override if a command already exists with the
|
|
||||||
* same name (optional, default: false)
|
|
||||||
* @param boolean $api_mode Enable API mode (optional, default: false)
|
|
||||||
* @param array|string|null $methods HTTP method (optional, default: array('GET', 'POST'))
|
|
||||||
**/
|
|
||||||
public static function add_url_handler($pattern, $handler=null, $authenticated=null, $override=true,
|
|
||||||
$api_mode=false, $methods=null) {
|
|
||||||
$authenticated = (
|
|
||||||
is_null($authenticated)?
|
|
||||||
function_exists('force_authentication'):
|
|
||||||
(bool)$authenticated
|
|
||||||
);
|
|
||||||
if (is_null($methods))
|
|
||||||
$methods = array('GET', 'POST');
|
|
||||||
elseif (!is_array($methods))
|
|
||||||
$methods = array($methods);
|
|
||||||
if (is_array($pattern)) {
|
|
||||||
if (is_null($handler))
|
|
||||||
foreach($pattern as $p => $h)
|
|
||||||
self :: add_url_handler($p, $h, $authenticated, $override, $api_mode, $methods);
|
|
||||||
else
|
|
||||||
foreach($pattern as $p)
|
|
||||||
self :: add_url_handler($p, $handler, $authenticated, $override, $api_mode, $methods);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!isset(self :: $patterns[$pattern])) {
|
|
||||||
self :: $patterns[$pattern] = array(
|
|
||||||
'handler' => $handler,
|
|
||||||
'authenticated' => $authenticated,
|
|
||||||
'api_mode' => $api_mode,
|
|
||||||
'methods' => $methods,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
elseif ($override) {
|
|
||||||
Log :: debug(
|
|
||||||
"URL : override pattern '%s' with handler '%s' (old handler = '%s')".
|
|
||||||
$pattern, format_callable($handler), vardump(self :: $patterns[$pattern])
|
|
||||||
);
|
|
||||||
self :: $patterns[$pattern] = array(
|
|
||||||
'handler' => $handler,
|
|
||||||
'authenticated' => $authenticated,
|
|
||||||
'api_mode' => $api_mode,
|
|
||||||
'methods' => $methods,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log :: debug("URL : pattern '$pattern' already defined : do not override.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show error page
|
|
||||||
*
|
|
||||||
* @param $request UrlRequest|null The request (optional, default: null)
|
|
||||||
* @param $error_code int|null The HTTP error code (optional, default: 400)
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
public static function error_page($request=null, $error_code=null) {
|
|
||||||
global $smarty;
|
|
||||||
$http_errors = array(
|
|
||||||
400 => array(
|
|
||||||
'pagetitle' => _("Bad request"),
|
|
||||||
'message' => _("Invalid request."),
|
|
||||||
),
|
|
||||||
401 => array(
|
|
||||||
'pagetitle' => _("Authentication required"),
|
|
||||||
'message' => _("You have to be authenticated to access to this page."),
|
|
||||||
),
|
|
||||||
403 => array(
|
|
||||||
'pagetitle' => _("Access denied"),
|
|
||||||
'message' => _("You do not have access to this application. If you think this is an error, please contact support."),
|
|
||||||
),
|
|
||||||
404 => array(
|
|
||||||
'pagetitle' => _("Whoops ! Page not found"),
|
|
||||||
'message' => _("The requested page can not be found."),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
$error_code = ($error_code?intval($error_code):400);
|
|
||||||
if (array_key_exists($error_code, $http_errors))
|
|
||||||
$error = $http_errors[intval($error_code)];
|
|
||||||
else
|
|
||||||
$error = array(
|
|
||||||
'pagetitle' => _('Error'),
|
|
||||||
'message' => _('An unknown error occurred. If problem persist, please contact support.'),
|
|
||||||
);
|
|
||||||
http_response_code($error_code);
|
|
||||||
|
|
||||||
if (isset($smarty) && $smarty)
|
|
||||||
$smarty -> assign('message', $error['message']);
|
|
||||||
display_template('error_page.tpl', $error['pagetitle']);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error 404 handler
|
|
||||||
*
|
|
||||||
* @param UrlRequest|null $request The request (optional, default: null)
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
public static function error_404($request=null) {
|
|
||||||
self :: error_page($request, 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set unknown URL handler
|
|
||||||
* @param callable|null $handler
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function set_unknown_url_handler($handler=null) {
|
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
if (is_callable($handler) || is_null($handler)) {
|
|
||||||
self :: $error_404_handler = $handler;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
Log :: warning(
|
|
||||||
'Url::set_unknown_url_handler(): Invalid URL handler provided: %s',
|
|
||||||
vardump($handler));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interprets the requested URL and return the corresponding UrlRequest object
|
|
||||||
*
|
|
||||||
* @param $default_url string|null The default URL if current one does not
|
|
||||||
* match with any configured pattern.
|
|
||||||
*
|
|
||||||
* @return UrlRequest The UrlRequest object corresponding to the the requested URL.
|
|
||||||
*/
|
|
||||||
protected static function get_request($default_url=null) {
|
|
||||||
$current_url = self :: get_current_url();
|
|
||||||
if ($current_url === false) {
|
|
||||||
Log :: fatal(
|
|
||||||
_('Unable to determine the requested page. '.
|
|
||||||
'If the problem persists, please contact support.')
|
|
||||||
);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
if (!is_array(self :: $patterns)) {
|
|
||||||
Log :: fatal('URL : No URL patterns configured !');
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
Log :: debug("URL : current url = '$current_url'");
|
|
||||||
Log :: trace(
|
|
||||||
"URL : check current url with the following URL patterns :\n - ".
|
|
||||||
implode("\n - ", array_keys(self :: $patterns))
|
|
||||||
);
|
|
||||||
foreach (self :: $patterns as $pattern => $handler_infos) {
|
|
||||||
$m = self :: 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']);
|
|
||||||
Log :: trace("URL : result :\n".vardump($request));
|
|
||||||
return $request;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($default_url !== false) {
|
|
||||||
Log :: debug("Current url match with no pattern. Redirect to default url ('$default_url')");
|
|
||||||
self :: redirect($default_url);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
// Error 404
|
|
||||||
$api_mode = self :: $_api_mode || (strpos($current_url, 'api/') === 0);
|
|
||||||
Log :: debug(
|
|
||||||
"Current URL match with no pattern. Use error 404 handler (API mode=$api_mode).");
|
|
||||||
return new UrlRequest(
|
|
||||||
$current_url,
|
|
||||||
array(
|
|
||||||
'handler' => self :: $error_404_handler,
|
|
||||||
'authenticated' => false,
|
|
||||||
'api_mode' => $api_mode,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the current requested URL match with a specific pattern
|
|
||||||
*
|
|
||||||
* @param string $pattern The URL pattern
|
|
||||||
* @param string|false $current_url The current URL (optional)
|
|
||||||
* @param array|null $methods HTTP method (optional, default: no check)
|
|
||||||
*
|
|
||||||
* @return array|false The URL info if pattern matched, false otherwise.
|
|
||||||
**/
|
|
||||||
public static 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 = self :: get_current_url();
|
|
||||||
if (!$current_url) return False;
|
|
||||||
}
|
|
||||||
if (preg_match($pattern, $current_url, $m)) {
|
|
||||||
Log :: debug(
|
|
||||||
"URL : Match found with pattern '$pattern' :\n\t".
|
|
||||||
str_replace("\n", "\n\t", print_r($m, true)));
|
|
||||||
return $m;
|
|
||||||
}
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retreive current requested URL and return it
|
|
||||||
*
|
|
||||||
* @return string|false The current request URL or false if fail
|
|
||||||
**/
|
|
||||||
public static function get_current_url() {
|
|
||||||
Log :: trace("URL : request URI = '".$_SERVER['REQUEST_URI']."'");
|
|
||||||
|
|
||||||
$base = self :: get_rewrite_base();
|
|
||||||
Log :: trace("URL : rewrite base = '$base'");
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_URI'] == $base)
|
|
||||||
return '';
|
|
||||||
|
|
||||||
if (substr($_SERVER['REQUEST_URI'], 0, strlen($base)) != $base) {
|
|
||||||
Log :: 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to detect rewrite base from public root URL
|
|
||||||
*
|
|
||||||
* @return string The detected rewrite base
|
|
||||||
**/
|
|
||||||
public static function get_rewrite_base() {
|
|
||||||
if (!self :: $public_root_url) return '/';
|
|
||||||
if (preg_match('|^https?://[^/]+/(.*)$|', self :: $public_root_url, $m))
|
|
||||||
return '/'.self :: remove_trailing_slash($m[1]).'/';
|
|
||||||
if (preg_match('|^/(.*)$|', self :: $public_root_url, $m))
|
|
||||||
return '/'.self :: remove_trailing_slash($m[1]).'/';
|
|
||||||
return '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger redirect to specified URL (or homepage if omited)
|
|
||||||
*
|
|
||||||
* @param string|false $go The destination URL
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
public static function redirect($go=false) {
|
|
||||||
if ($go===false)
|
|
||||||
$go = "";
|
|
||||||
// If more than one argument passed, format URL using sprintf & urlencode parameters
|
|
||||||
elseif (func_num_args() > 1)
|
|
||||||
$go = call_user_func_array(
|
|
||||||
'sprintf',
|
|
||||||
array_merge(
|
|
||||||
array($go),
|
|
||||||
array_map('urlencode', array_slice(func_get_args(), 1))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (self :: is_absolute_url($go))
|
|
||||||
$url = $go;
|
|
||||||
elseif (self :: $public_root_url)
|
|
||||||
$url = self :: $public_root_url."/$go";
|
|
||||||
else
|
|
||||||
$url = "/$go";
|
|
||||||
|
|
||||||
// Prevent loop
|
|
||||||
if (isset($_SESSION['last_redirect']) && $_SESSION['last_redirect'] == $url)
|
|
||||||
Log :: fatal(
|
|
||||||
_('Unable to determine the requested page (loop detected). '.
|
|
||||||
'If the problem persists, please contact support.'));
|
|
||||||
else
|
|
||||||
$_SESSION['last_redirect'] = $url;
|
|
||||||
|
|
||||||
Log :: debug("redirect($go) => Redirect to : <$url>");
|
|
||||||
header("Location: $url");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the current requested URL
|
|
||||||
*
|
|
||||||
* Note: if the route required that user is authenticated, this method will
|
|
||||||
* invoke the force_authentication() special function (or trigger a fatal error
|
|
||||||
* if it's not defined).
|
|
||||||
*
|
|
||||||
* @param string|null $default_url The default URL if current one does not
|
|
||||||
* match with any configured pattern.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
public static function handle_request($default_url=null) {
|
|
||||||
global $smarty;
|
|
||||||
|
|
||||||
$sentry_span = new SentrySpan('http.handle_request', 'Handle the HTTP request');
|
|
||||||
|
|
||||||
$request = self :: get_request($default_url);
|
|
||||||
|
|
||||||
if (!is_callable($request -> handler)) {
|
|
||||||
Log :: error(
|
|
||||||
"URL handler function %s does not exists !",
|
|
||||||
format_callable($request -> handler));
|
|
||||||
Log :: fatal(_("This request cannot be processed."));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request -> api_mode)
|
|
||||||
self :: $_api_mode = true;
|
|
||||||
if (isset($smarty) && $smarty)
|
|
||||||
$smarty -> assign('request', $request);
|
|
||||||
|
|
||||||
// Check authentication (if need)
|
|
||||||
if($request -> authenticated)
|
|
||||||
if (function_exists('force_authentication'))
|
|
||||||
force_authentication();
|
|
||||||
else
|
|
||||||
Log :: fatal(_("Authentication required but force_authentication function is not defined."));
|
|
||||||
|
|
||||||
try {
|
|
||||||
call_user_func($request -> handler, $request);
|
|
||||||
}
|
|
||||||
catch (Exception $e) {
|
|
||||||
Log :: exception(
|
|
||||||
$e, "An exception occured running URL handler function %s()",
|
|
||||||
format_callable($request -> handler));
|
|
||||||
Log :: fatal(_("This request could not be processed correctly."));
|
|
||||||
}
|
|
||||||
$sentry_span->finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove trailing slash in specified URL
|
|
||||||
*
|
|
||||||
* @param string $url The URL
|
|
||||||
*
|
|
||||||
* @return string The specified URL without trailing slash
|
|
||||||
**/
|
|
||||||
public static function remove_trailing_slash($url) {
|
|
||||||
if ($url == '/')
|
|
||||||
return $url;
|
|
||||||
elseif (substr($url, -1) == '/')
|
|
||||||
return substr($url, 0, -1);
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the public absolute URL
|
|
||||||
*
|
|
||||||
* @param string|null $relative_url Relative URL to convert (Default: current URL)
|
|
||||||
*
|
|
||||||
* @return string The public absolute URL
|
|
||||||
**/
|
|
||||||
public static function get_absolute_url($relative_url=null) {
|
|
||||||
if (!is_string($relative_url))
|
|
||||||
$relative_url = self :: get_current_url();
|
|
||||||
if (self :: $public_root_url[0] == '/') {
|
|
||||||
Log :: debug(
|
|
||||||
"URL :: get_absolute_url($relative_url): configured public root URL is relative ".
|
|
||||||
"(%s) => try to detect it from current request infos.",
|
|
||||||
self :: $public_root_url);
|
|
||||||
self :: $public_root_url = (
|
|
||||||
'http'.(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'?'s':'').'://'.
|
|
||||||
$_SERVER['HTTP_HOST'].self :: $public_root_url);
|
|
||||||
Log :: debug(
|
|
||||||
"URL :: get_absolute_url(%s): detected public_root_url: %s",
|
|
||||||
$relative_url, self :: $public_root_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (substr($relative_url, 0, 1) == '/')
|
|
||||||
$relative_url = substr($relative_url, 1);
|
|
||||||
$url = self :: remove_trailing_slash(self :: $public_root_url)."/$relative_url";
|
|
||||||
Log :: debug("URL :: get_absolute_url($relative_url): result = $url");
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if specified URL is absolute
|
|
||||||
*
|
|
||||||
* @param string $url The URL to check
|
|
||||||
*
|
|
||||||
* @return boolean True if specified URL is absolute, False otherwise
|
|
||||||
**/
|
|
||||||
public static function is_absolute_url($url) {
|
|
||||||
return boolval(preg_match('#^https?://#', $url));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add parameter in specified URL
|
|
||||||
*
|
|
||||||
* @param string &$url The reference of the URL
|
|
||||||
* @param string $param The parameter name
|
|
||||||
* @param string $value The parameter value
|
|
||||||
* @param boolean $encode Set if parameter value must be URL encoded (optional, default: true)
|
|
||||||
*
|
|
||||||
* @return string The completed URL
|
|
||||||
*/
|
|
||||||
public static function add_url_parameter(&$url, $param, $value, $encode=true) {
|
|
||||||
if (strpos($url, '?') === false)
|
|
||||||
$url .= '?';
|
|
||||||
else
|
|
||||||
$url .= '&';
|
|
||||||
$url .= "$param=".($encode?urlencode($value):$value);
|
|
||||||
return $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get/set API mode
|
|
||||||
* @param bool|null $value If boolean, the current API mode will be changed
|
|
||||||
* @return bool Current API mode
|
|
||||||
*/
|
|
||||||
public static function api_mode($value=null) {
|
|
||||||
if (is_bool($value)) self :: $_api_mode = $value;
|
|
||||||
return self :: $_api_mode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
|
@ -1,143 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL request abstraction
|
|
||||||
*
|
|
||||||
* @author Benjamin Renard <brenard@easter-eggs.com>
|
|
||||||
* @property-read string|null $current_url;
|
|
||||||
* @property-read array|null $handler;
|
|
||||||
* @property-read bool $authenticated;
|
|
||||||
* @property-read bool $api_mode;
|
|
||||||
*/
|
|
||||||
class UrlRequest {
|
|
||||||
|
|
||||||
// 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 string $key The name of the info
|
|
||||||
*
|
|
||||||
* @return 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
|
|
||||||
Log :: warning(
|
|
||||||
"__get($key): invalid property requested\n%s",
|
|
||||||
Log :: get_debug_backtrace_context());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set request info
|
|
||||||
*
|
|
||||||
* @param string $key The name of the info
|
|
||||||
* @param mixed $value The value of the info
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
**/
|
|
||||||
public function __set($key, $value) {
|
|
||||||
if ($key == 'referer')
|
|
||||||
$_SERVER['HTTP_REFERER'] = $value;
|
|
||||||
elseif ($key == 'http_method')
|
|
||||||
$_SERVER['REQUEST_METHOD'] = $value;
|
|
||||||
else
|
|
||||||
$this->url_params[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check is request info is set
|
|
||||||
*
|
|
||||||
* @param string $key The name of the info
|
|
||||||
*
|
|
||||||
* @return bool True is info is set, False otherwise
|
|
||||||
**/
|
|
||||||
public function __isset($key) {
|
|
||||||
if (
|
|
||||||
in_array(
|
|
||||||
$key, array('current_url', 'handler', 'authenticated',
|
|
||||||
'api_mode', 'referer', 'http_method')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return True;
|
|
||||||
return array_key_exists($key, $this->url_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get request parameter
|
|
||||||
*
|
|
||||||
* @param string $parameter The name of the parameter
|
|
||||||
* @param bool $decode If true, the parameter value will be urldecoded
|
|
||||||
* (optional, default: true)
|
|
||||||
*
|
|
||||||
* @return 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get request referer (if known)
|
|
||||||
*
|
|
||||||
* @return 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
|
@ -1,216 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace EesyPHP;
|
|
||||||
|
|
||||||
use EesyPHP\Log;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parser/formater values helpers
|
|
||||||
*/
|
|
||||||
$_date_format = "%d/%m/%Y";
|
|
||||||
$_date_time_format = "%d/%m/%Y %H:%M:%S";
|
|
||||||
function format_time($time, $with_time=true) {
|
|
||||||
global $_date_format, $_date_time_format;
|
|
||||||
if ($with_time)
|
|
||||||
return strftime($_date_time_format, $time);
|
|
||||||
return strftime($_date_format, $time);
|
|
||||||
}
|
|
||||||
|
|
||||||
function parse_date($date, $with_time=true) {
|
|
||||||
global $_date_format, $_date_time_format;
|
|
||||||
if ($with_time)
|
|
||||||
$ptime = strptime($date, $_date_time_format);
|
|
||||||
else
|
|
||||||
$ptime = strptime($date, $_date_format);
|
|
||||||
if(is_array($ptime)) {
|
|
||||||
return mktime(
|
|
||||||
$ptime['tm_hour'],
|
|
||||||
$ptime['tm_min'],
|
|
||||||
$ptime['tm_sec'],
|
|
||||||
$ptime['tm_mon']+1,
|
|
||||||
$ptime['tm_mday'],
|
|
||||||
$ptime['tm_year']+1900
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function format_size($size, $digit=False) {
|
|
||||||
if (!$digit && $digit!==0) $digit=2;
|
|
||||||
if ($size>=1099511627776)
|
|
||||||
return number_format($size/1099511627776,$digit)."To";
|
|
||||||
elseif ($size>=1073741824)
|
|
||||||
return number_format($size/1073741824,$digit)."Go";
|
|
||||||
else if ($size>=1048576)
|
|
||||||
return number_format($size/1048576,$digit)."Mo";
|
|
||||||
else if ($size>=1024)
|
|
||||||
return number_format($size/1024,$digit)."Ko";
|
|
||||||
else
|
|
||||||
return $size."o";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generic Data/value helpers
|
|
||||||
*/
|
|
||||||
function vardump($data) {
|
|
||||||
ob_start();
|
|
||||||
var_dump($data);
|
|
||||||
$data = ob_get_contents();
|
|
||||||
ob_end_clean();
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a callable object for logging
|
|
||||||
* @param string|array $callable The callable object
|
|
||||||
* @return string The callable object string representation
|
|
||||||
*/
|
|
||||||
function format_callable($callable) {
|
|
||||||
if (is_string($callable))
|
|
||||||
return $callable."()";
|
|
||||||
if (is_array($callable))
|
|
||||||
if (is_string($callable[0]))
|
|
||||||
return $callable[0]."::".$callable[1]."()";
|
|
||||||
elseif (is_object($callable[0]))
|
|
||||||
return get_class($callable[0])."->".$callable[1]."()";
|
|
||||||
else
|
|
||||||
return "Unkown->".$callable[1]."()";
|
|
||||||
// @phpstan-ignore-next-line
|
|
||||||
return vardump($callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_is_empty($val) {
|
|
||||||
switch(gettype($val)) {
|
|
||||||
case "boolean":
|
|
||||||
case "integer":
|
|
||||||
case "double":
|
|
||||||
case "object":
|
|
||||||
case "resource":
|
|
||||||
return False;
|
|
||||||
case "array":
|
|
||||||
case "string":
|
|
||||||
if ($val == "0") return false;
|
|
||||||
return empty($val);
|
|
||||||
case "NULL":
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generic file/directory helpers
|
|
||||||
*/
|
|
||||||
function dump_file($file_path, $max_age=3600) {
|
|
||||||
if (is_file($file_path)) {
|
|
||||||
header('Content-Type: '.mime_content_type($file_path));
|
|
||||||
$last_modified_time = filemtime($file_path);
|
|
||||||
$etag = md5_file($file_path);
|
|
||||||
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");
|
|
||||||
|
|
||||||
if (
|
|
||||||
(
|
|
||||||
isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
|
|
||||||
@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time
|
|
||||||
) || (
|
|
||||||
isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
|
|
||||||
trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
header("HTTP/1.1 304 Not Modified");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Pragma: public');
|
|
||||||
header('Content-Length: ' . filesize($file_path));
|
|
||||||
readfile($file_path);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
header("HTTP/1.1 404 Not found");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
function delete_directory($dir, $recursive=true) {
|
|
||||||
$files = array_diff(scandir($dir), array('.','..'));
|
|
||||||
if ($recursive) {
|
|
||||||
foreach ($files as $file) {
|
|
||||||
if (is_dir("$dir/$file")) {
|
|
||||||
if (!delete_directory("$dir/$file", true)) {
|
|
||||||
Log :: error("delete_directory($dir) : Fail to delete sub-directory '$dir/$file'.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!unlink("$dir/$file")) {
|
|
||||||
Log :: error("delete_directory($dir) : Fail to delete '$dir/$file'.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!empty($files)) {
|
|
||||||
Log :: error("delete_directory($dir) : Directory is not empty.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return rmdir($dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run external command helper
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Run external command
|
|
||||||
*
|
|
||||||
* @param $command string|array The command. It's could be an array of the command with its
|
|
||||||
* arguments.
|
|
||||||
* @param $data_stdin string|null The command arguments (optional, default: null)
|
|
||||||
* @param $escape_command_args boolean If true, the command will be escaped
|
|
||||||
* (optional, default: true)
|
|
||||||
*
|
|
||||||
* @return false|array An array of return code, stdout and stderr result or False in case of fatal
|
|
||||||
* error
|
|
||||||
**/
|
|
||||||
function run_external_command($command, $data_stdin=null, $escape_command_args=true) {
|
|
||||||
if (is_array($command))
|
|
||||||
$command = implode(' ', $command);
|
|
||||||
if ($escape_command_args)
|
|
||||||
$command = escapeshellcmd($command);
|
|
||||||
Log :: debug("Run external command: '$command'");
|
|
||||||
$descriptorspec = array(
|
|
||||||
0 => array("pipe", "r"), // stdin
|
|
||||||
1 => array("pipe", "w"), // stdout
|
|
||||||
2 => array("pipe", "w"), // stderr
|
|
||||||
);
|
|
||||||
$process = proc_open($command, $descriptorspec, $pipes);
|
|
||||||
|
|
||||||
if (!is_resource($process)) {
|
|
||||||
Log :: error("Fail to run external command: '$command'");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_null($data_stdin)) {
|
|
||||||
fwrite($pipes[0], $data_stdin);
|
|
||||||
}
|
|
||||||
fclose($pipes[0]);
|
|
||||||
|
|
||||||
$stdout = stream_get_contents($pipes[1]);
|
|
||||||
fclose($pipes[1]);
|
|
||||||
|
|
||||||
$stderr = stream_get_contents($pipes[2]);
|
|
||||||
fclose($pipes[2]);
|
|
||||||
|
|
||||||
$return_value = proc_close($process);
|
|
||||||
|
|
||||||
$error = (!empty($stderr) || $return_value != 0);
|
|
||||||
Log :: log(
|
|
||||||
($error?'ERROR':'DEBUG'),
|
|
||||||
"External command ".($error?"error":"result").":\n".
|
|
||||||
"\tCommand : $command\n".
|
|
||||||
"\tReturn code: $return_value\n".
|
|
||||||
"\tOutput:\n".
|
|
||||||
"\t\t- Stdout :\n$stdout\n\n".
|
|
||||||
"\t\t- Stderr :\n$stderr"
|
|
||||||
);
|
|
||||||
|
|
||||||
return array($return_value, $stdout, $stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|
|
Loading…
Reference in a new issue