$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', sprint( "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']) ); remove_item_attachments($item['id']); } 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)"), ) );