Benjamin Renard
6fdc5447f1
* Code cleaning and fix some small errors using Phpstan * Configure pre-commit to run Phpstan before each commit * Some little improvments and logging, mail, smarty & URL libs * Add Sentry integration * Add Webstat JS code inclusion * Install Smarty dependency using composer Breaking changes: * Rename Event class as HookEvent to avoid conflict with PECL event * URL with refresh GET parameter now automatically trigger redirection without it after page loading to avoid to keep it in URL
419 lines
11 KiB
PHP
419 lines
11 KiB
PHP
<?php
|
|
|
|
$cli_commands=array();
|
|
function add_cli_command($command, $handler, $short_desc, $usage_args=false, $long_desc=false,
|
|
$override=false) {
|
|
global $cli_commands;
|
|
if (array_key_exists($command, $cli_commands) && !$override) {
|
|
logging('ERROR', _("The CLI command '%s' already exists."), $command);
|
|
return False;
|
|
}
|
|
|
|
if (!is_callable($handler)) {
|
|
logging('ERROR', _("The CLI command '%s' handler is not callable !"), $command);
|
|
return False;
|
|
}
|
|
|
|
$cli_commands[$command] = array (
|
|
'handler' => $handler,
|
|
'short_desc' => $short_desc,
|
|
'usage_args' => $usage_args,
|
|
'long_desc' => $long_desc,
|
|
);
|
|
return True;
|
|
}
|
|
|
|
/*
|
|
*************************************************************************************************
|
|
* /!\ Code after this message will only be execute on CLI context /!\
|
|
*************************************************************************************************
|
|
*/
|
|
if (php_sapi_name() != "cli")
|
|
return true;
|
|
|
|
// Store current CLI command
|
|
$cli_command = null;
|
|
|
|
/**
|
|
* CLI Helpers
|
|
**/
|
|
|
|
function usage($error=false) {
|
|
global $cli_commands, $cli_command, $argv;
|
|
|
|
// If more than 1 arguments passed, format error message using sprintf
|
|
if (func_num_args() > 1) {
|
|
$error = call_user_func_array(
|
|
'sprintf',
|
|
array_merge(array($error), array_slice(func_get_args(), 1))
|
|
);
|
|
}
|
|
|
|
if ($error)
|
|
echo "$error\n\n";
|
|
printf(_("Usage: %s [-h] [-qd] command\n"), basename($argv[0]));
|
|
echo _(" -h Show this message\n");
|
|
echo _(" -q / -d Quiet/Debug mode\n");
|
|
echo _(" --trace Trace mode (the most verbose)\n");
|
|
echo _(" command Command to run\n");
|
|
echo "\n";
|
|
echo _("Available commands:\n");
|
|
|
|
foreach ($cli_commands as $command => $info) {
|
|
if ($cli_command && $command != $cli_command)
|
|
continue;
|
|
echo (
|
|
" ".str_replace(
|
|
"\n", "\n ",
|
|
wordwrap("$command : "._($info['short_desc'])))
|
|
."\n\n");
|
|
echo (
|
|
" ".basename($argv[0])." $command ".
|
|
($info['usage_args']?_($info['usage_args']):'').
|
|
"\n");
|
|
if ($info['long_desc']) {
|
|
if (is_array($info['long_desc'])) {
|
|
$lines = array();
|
|
foreach ($info['long_desc'] as $line)
|
|
$lines[] = _($line);
|
|
$info['long_desc'] = implode("\n", $lines);
|
|
}
|
|
else
|
|
$info['long_desc'] = _($info['long_desc']);
|
|
|
|
echo "\n ".str_replace("\n", "\n ", wordwrap($info['long_desc']))."\n";
|
|
}
|
|
echo "\n";
|
|
}
|
|
|
|
exit(($error?1:0));
|
|
}
|
|
|
|
function handle_cli_args() {
|
|
global $log_level, $cli_commands, $cli_command, $argv;
|
|
$log_level = 'INFO';
|
|
$cli_command = false;
|
|
$command_args = array();
|
|
for ($i=1; $i < count($argv); $i++) {
|
|
if (array_key_exists($argv[$i], $cli_commands)) {
|
|
if (!$cli_command)
|
|
$cli_command = $argv[$i];
|
|
else
|
|
usage(_("Only one command could be executed !"));
|
|
}
|
|
else {
|
|
switch($argv[$i]) {
|
|
case '-h':
|
|
case '--help':
|
|
usage();
|
|
break;
|
|
case '-d':
|
|
case '--debug':
|
|
$log_level = 'DEBUG';
|
|
break;
|
|
case '-q':
|
|
case '--quiet':
|
|
$log_level = 'WARNING';
|
|
break;
|
|
case '--trace':
|
|
$log_level = 'TRACE';
|
|
break;
|
|
default:
|
|
if ($cli_command)
|
|
$command_args[] = $argv[$i];
|
|
else
|
|
usage(
|
|
_(
|
|
"Invalid parameter \"%s\".\nNote: Command's parameter/argument must be place ".
|
|
"after the command."
|
|
), $argv[$i]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!$cli_command)
|
|
usage();
|
|
|
|
logging(
|
|
'DEBUG', "Run %s command %s with argument(s) '%s'.",
|
|
basename($argv[0]), $cli_command, implode("', '", $command_args)
|
|
);
|
|
|
|
try {
|
|
$result = call_user_func($cli_commands[$cli_command]['handler'], $command_args);
|
|
|
|
exit($result?0:1);
|
|
}
|
|
catch(Exception $e) {
|
|
log_exception($e, _("An exception occured running command %s"), $cli_command);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
function print_item_info($item) {
|
|
printf(_("Item #%s:\n"), $item['id']);
|
|
printf("\t"._("ID: %s")."\n", $item['id']);
|
|
printf("\t"._("Name: '%s'")."\n", $item['name']);
|
|
printf("\t"._("Date: %s")."\n", format_time($item['date']));
|
|
printf(
|
|
"\t"._("Description: %s")."\n",
|
|
($item['description']?"'".$item['description']."'":_("Not set"))
|
|
);
|
|
printf("\t"._("Status: %s")."\n", $item['status']);
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Common CLI commands
|
|
**/
|
|
|
|
$orderbys = array('id', 'name', 'date', 'status', 'description');
|
|
function cli_list($command_args) {
|
|
global $orderbys;
|
|
$params = array(
|
|
'order' => $orderbys[0],
|
|
'order_direction' => 'ASC',
|
|
'all' => true,
|
|
);
|
|
$patterns = array();
|
|
for($i=0; $i < count($command_args); $i++) {
|
|
switch($command_args[$i]) {
|
|
case '-o':
|
|
case '--orderby':
|
|
$i++;
|
|
if(!in_array($command_args[$i], $orderbys))
|
|
usage('Invalid --orderby clause');
|
|
$params['order'] = $command_args[$i];
|
|
break;
|
|
case '-r':
|
|
case '--reverse':
|
|
$params['order_direction'] = 'DESC';
|
|
break;
|
|
case '-s':
|
|
case '--status':
|
|
$i++;
|
|
if(!check_status($command_args[$i]))
|
|
usage('Invalid -s/--status clause');
|
|
$params['status'] = $command_args[$i];
|
|
break;
|
|
default:
|
|
$patterns[] = $command_args[$i];
|
|
}
|
|
}
|
|
|
|
if (!empty($patterns))
|
|
$params['pattern'] = implode(' ', $patterns);
|
|
|
|
$items = search_items($params);
|
|
if (!is_array($items)) {
|
|
logging("ERROR", "Invalid DB info return.\n");
|
|
return False;
|
|
}
|
|
|
|
if ($items['count'] == 0){
|
|
echo _("No item.\n");
|
|
return True;
|
|
}
|
|
|
|
$tbl = new Console_Table();
|
|
$tbl->setHeaders(
|
|
array(
|
|
'ID',
|
|
'Name',
|
|
'Date',
|
|
'Status',
|
|
'Description',
|
|
)
|
|
);
|
|
foreach($items['items'] as $info) {
|
|
$tbl->addRow(
|
|
array(
|
|
$info['id'],
|
|
$info['name'],
|
|
format_time($info['date']),
|
|
$info['status'],
|
|
($info['description']?$info['description']:''),
|
|
)
|
|
);
|
|
}
|
|
echo $tbl->getTable();
|
|
echo "\n".sprintf(_("%d item(s)"), $items['count'])."\n";
|
|
return True;
|
|
}
|
|
add_cli_command(
|
|
'list',
|
|
'cli_list',
|
|
___("List/search items"),
|
|
___("[patterns]"),
|
|
array(
|
|
___("-o|--orderby Ordering list criterion. Possible values:"),
|
|
" - ".implode("\n - ", $orderbys),
|
|
___("-r|--reverse Reverse order"),
|
|
___("-s|--status Filter on status. Possible values:"),
|
|
" - ".implode("\n - ", array_keys($status_list)),
|
|
)
|
|
);
|
|
|
|
function cli_show($command_args) {
|
|
if (count($command_args) != 1 || !check_id($command_args[0]))
|
|
usage(_('You must provide a valid ID.'));
|
|
|
|
$item_id = $command_args[0];
|
|
$item = get_item($item_id);
|
|
|
|
if (!$item)
|
|
logging('FATAL', _("Item #%s not found."), $item_id);
|
|
|
|
print_item_info($item);
|
|
return True;
|
|
}
|
|
add_cli_command(
|
|
'show',
|
|
'cli_show',
|
|
___("Show item"),
|
|
___("[ID]")
|
|
);
|
|
|
|
function cli_delete($command_args) {
|
|
if (count($command_args) != 1)
|
|
usage(_('You must provide item ID.'));
|
|
|
|
// Check URI
|
|
if (!check_id($command_args[0]))
|
|
logging('FATAL', _("Invalid item ID"));
|
|
|
|
// Check exist
|
|
$item_id = $command_args[0];
|
|
$item = get_item($item_id);
|
|
if (!$item)
|
|
logging('FATAL', _("Item #%s not found."), $item_id);
|
|
|
|
print_item_info($item);
|
|
|
|
// Sure ?
|
|
echo _("Are you sure you want to delete this item? Type 'yes' to continue: ");
|
|
$handle = fopen ("php://stdin","r");
|
|
$line = fgets($handle);
|
|
if(trim($line) != 'yes'){
|
|
logging('WARNING', _("User cancel"));
|
|
exit;
|
|
}
|
|
echo "\n";
|
|
|
|
if (!delete_item($item['id']))
|
|
logging('FATAL', _("An error occured deleting item #%d."), $item_id);
|
|
|
|
return True;
|
|
}
|
|
add_cli_command(
|
|
'delete',
|
|
'cli_delete',
|
|
___("Delete item"),
|
|
___("[item ID]")
|
|
);
|
|
|
|
function cli_export($command_args) {
|
|
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://output'), 'w');
|
|
export_items($fd);
|
|
fclose($fd);
|
|
logging('INFO', "Items export to '".(count($command_args) >= 1?$command_args[0]:'STDOUT')."'.");
|
|
}
|
|
add_cli_command(
|
|
'export',
|
|
'cli_export',
|
|
___("Export items (as CSV)"),
|
|
___("[output file path]")
|
|
);
|
|
|
|
function cli_restore($command_args) {
|
|
$fd = fopen((count($command_args) >= 1?$command_args[0]:'php://stdin'), 'r');
|
|
restore_items($fd);
|
|
fclose($fd);
|
|
logging(
|
|
'INFO', "Items restored from '%s'",
|
|
(count($command_args) >= 1?$command_args[0]:'STDIN')
|
|
);
|
|
}
|
|
add_cli_command(
|
|
'restore',
|
|
'cli_restore',
|
|
___("Restore items (from CSV)"),
|
|
___("[input file path]")
|
|
);
|
|
|
|
function cli_cron($command_args) {
|
|
global $item_max_age;
|
|
if (!isset($item_max_age))
|
|
$item_max_age = 30;
|
|
|
|
$just_try = false;
|
|
for($i=0; $i < count($command_args); $i++) {
|
|
switch($command_args[$i]) {
|
|
case '-m':
|
|
case '--max-age':
|
|
$i++;
|
|
if(!check_id($command_args[$i]))
|
|
usage('Invalid -m|--max-age clause');
|
|
$item_max_age = $command_args[$i];
|
|
break;
|
|
case '-j':
|
|
case '--just-try':
|
|
$just_try = true;
|
|
break;
|
|
default:
|
|
usage('Invalid parameter '.$command_args[$i]);
|
|
}
|
|
}
|
|
|
|
if (!is_int($item_max_age) || $item_max_age <= 0)
|
|
logging(
|
|
'FATAL',
|
|
'Invalid $item_max_age value set in configuration: it\'s must be a positive integer.');
|
|
logging('DEBUG', "cli_cron(): item max age = $item_max_age day(s)");
|
|
|
|
$limit = time() - ($item_max_age * 86400);
|
|
logging('DEBUG', "Handle items expiration with creation date limit ".format_time($limit).".");
|
|
|
|
$items = search_items(array('all' => true));
|
|
$error = false;
|
|
foreach($items['items'] as $item) {
|
|
if ($item['date'] < $limit) {
|
|
if ($just_try) {
|
|
logging('DEBUG', 'Just-try mode: do not really delete item #%s (%s, creation date: %s)',
|
|
$item['id'], $item['name'], format_time($item['date'])
|
|
);
|
|
}
|
|
else if (delete_item($item['id'])) {
|
|
logging('INFO', 'Item #%s (%s) deleted (creation date: %s)',
|
|
$item['id'], $item['name'], format_time($item['date'])
|
|
);
|
|
}
|
|
else {
|
|
logging('ERROR', 'Fail to delete item "%s" (%s, creation date: %s)',
|
|
$item['id'], $item['name'], format_time($item['date'])
|
|
);
|
|
$error = true;
|
|
}
|
|
}
|
|
else {
|
|
logging('DEBUG', 'Item "%s" (%s) still valid (creation date: %s)',
|
|
$item['id'], $item['name'], format_time($item['date'])
|
|
);
|
|
}
|
|
}
|
|
exit($error?1:0);
|
|
}
|
|
add_cli_command(
|
|
'cron',
|
|
'cli_cron',
|
|
___("Cron to handle item expiration"),
|
|
false,
|
|
array (
|
|
___("-j/--just-try Just-try mode : do not really removed expired item(s)"),
|
|
___("-m/--max-age Item expiration limit (in days, optional)"),
|
|
)
|
|
);
|
|
|
|
# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
|