diff options
Diffstat (limited to 'cli')
| -rw-r--r-- | cli/README.md | 100 | ||||
| -rw-r--r-- | cli/_cli.php | 113 | ||||
| -rw-r--r-- | cli/_update-or-create-user.php | 15 | ||||
| -rwxr-xr-x | cli/actualize-user.php | 16 | ||||
| -rwxr-xr-x | cli/check.translation.php | 41 | ||||
| -rwxr-xr-x | cli/db-optimize.php | 16 | ||||
| -rwxr-xr-x | cli/delete-user.php | 16 | ||||
| -rwxr-xr-x | cli/do-install.php | 24 | ||||
| -rwxr-xr-x | cli/export-opml-for-user.php | 16 | ||||
| -rwxr-xr-x | cli/export-sqlite-for-user.php | 21 | ||||
| -rwxr-xr-x | cli/export-zip-for-user.php | 24 | ||||
| -rwxr-xr-x | cli/import-for-user.php | 27 | ||||
| -rwxr-xr-x | cli/import-sqlite-for-user.php | 25 | ||||
| -rwxr-xr-x | cli/manipulate.translation.php | 106 | ||||
| -rwxr-xr-x | cli/reconfigure.php | 21 | ||||
| -rwxr-xr-x | cli/user-info.php | 42 |
16 files changed, 352 insertions, 271 deletions
diff --git a/cli/README.md b/cli/README.md index 028bfbc8f..1ce70b5c1 100644 --- a/cli/README.md +++ b/cli/README.md @@ -35,22 +35,22 @@ cd /usr/share/FreshRSS # Ensure the needed directories in ./data/ ./cli/do-install.php --default-user admin [ --auth-type form --environment production --base-url https://rss.example.net --language en --title FreshRSS --allow-anonymous --allow-anonymous-refresh --api-enabled --db-type sqlite --db-host localhost:3306 --db-user freshrss --db-password dbPassword123 --db-base freshrss --db-prefix freshrss_ ] -# --default-user must be alphanumeric and not longer than 38 characters. The default user of this FreshRSS instance, used as the public user for anonymous reading -# --auth-type can be: 'form' (default), 'http_auth' (using the Web server access control), 'none' (dangerous) -# --environment can be: 'production' (default), 'development' (for additional log messages) -# --base-url should be a public (routable) URL if possible, and is used for push (WebSub), for some API functions (e.g. favicons), and external URLs in FreshRSS -# --language can be: 'en' (default), 'fr', or one of the [supported languages](../app/i18n/) -# --title web user interface title for this FreshRSS instance -# --allow-anonymous sets whether non logged-in visitors are permitted to see the default user's feeds -# --allow-anonymous-refresh sets whether to permit anonymous users to start the refresh process -# --api-enabled sets whether the API may be used for mobile apps. API passwords must be set for individual users -# --db-type can be: 'sqlite' (default), 'mysql' (MySQL or MariaDB), 'pgsql' (PostgreSQL) -# --db-host URL of the database server. Default is 'localhost' -# --db-user sets database user -# --db-password sets database password -# --db-base sets database name -# --db-prefix is an optional prefix in front of the names of the tables. We suggest using 'freshrss_' (default) -# This command does not create the default user. Do that with ./cli/create-user.php +# --default-user must be alphanumeric and not longer than 38 characters. The default user of this FreshRSS instance, used as the public user for anonymous reading. +# --auth-type can be: 'form' (default), 'http_auth' (using the Web server access control), 'none' (dangerous). +# --environment can be: 'production' (default), 'development' (for additional log messages). +# --base-url should be a public (routable) URL if possible, and is used for push (WebSub), for some API functions (e.g. favicons), and external URLs in FreshRSS. +# --language can be: 'en' (default), 'fr', or one of the [supported languages](../app/i18n/). +# --title web user interface title for this FreshRSS instance. +# --allow-anonymous sets whether non logged-in visitors are permitted to see the default user's feeds. +# --allow-anonymous-refresh sets whether to permit anonymous users to start the refresh process. +# --api-enabled sets whether the API may be used for mobile apps. API passwords must be set for individual users. +# --db-type can be: 'sqlite' (default), 'mysql' (MySQL or MariaDB), 'pgsql' (PostgreSQL). +# --db-host URL of the database server. Default is 'localhost'. +# --db-user sets database user. +# --db-password sets database password. +# --db-base sets database name. +# --db-prefix is an optional prefix in front of the names of the tables. We suggest using 'freshrss_' (default). +# This command does not create the default user. Do that with ./cli/create-user.php. ./cli/reconfigure.php # Same parameters as for do-install.php. Used to update an existing installation. @@ -64,51 +64,52 @@ cd /usr/share/FreshRSS cd /usr/share/FreshRSS ./cli/create-user.php --user username [ --password 'password' --api-password 'api_password' --language en --email user@example.net --token 'longRandomString' --no-default-feeds --purge-after-months 3 --feed-min-articles-default 50 --feed-ttl-default 3600 --since-hours-posts-per-rss 168 --max-posts-per-rss 400 ] -# --user must be alphanumeric, not longer than 38 characters. The name of the user to be created/updated -# --password sets the user's password -# --api-password sets the user's api password -# --language can be: 'en' (default), 'fr', or one of the [supported languages](../app/i18n/) -# --email sets an email for the user which will be used email validation if it forced email validation is enabled -# --no-default-feeds do not add this FreshRSS instance's default feeds to the user during creation -# --purge-after-months max age an article can reach before being archived. Default is '3' -# --feed-min-articles-default number of articles in a feed at which archiving will pause. Default is '50' -# --feed-ttl-default minimum number of seconds to elapse between feed refreshes. Default is '3600' -# --max-posts-per-rss number of articles in a feed at which an old article will be archived before a new article is added. Default is '200' +# --user must be alphanumeric, not longer than 38 characters. The name of the user to be created/updated. +# --password sets the user's password. +# --api-password sets the user's api password. +# --language can be: 'en' (default), 'fr', or one of the [supported languages](../app/i18n/). +# --email sets an email for the user which will be used email validation if it forced email validation is enabled. +# --no-default-feeds do not add this FreshRSS instance's default feeds to the user during creation. +# --purge-after-months max age an article can reach before being archived. Default is '3'. +# --feed-min-articles-default number of articles in a feed at which archiving will pause. Default is '50'. +# --feed-ttl-default minimum number of seconds to elapse between feed refreshes. Default is '3600'. +# --max-posts-per-rss number of articles in a feed at which an old article will be archived before a new article is added. Default is '200'. ./cli/update-user.php --user username [ ... ] -# Same options as create-user.php, except --no-default-feeds which is only available for create-user.php +# Same options as create-user.php, except --no-default-feeds which is only available for create-user.php. ``` > ℹ️ More options for [the configuration of users](../config-user.default.php#L3-L5) may be set in `./data/config-user.custom.php` prior to creating new users, or in `./data/users/*/config.php` for existing users. ```sh ./cli/actualize-user.php --user username -# Fetch feeds for the specified user +# Fetch feeds for the specified user. ./cli/delete-user.php --user username +# Deletes the specified user. ./cli/list-users.php -# Return a list of users, with the default/admin user first +# Return a list of users, with the default/admin user first. -./cli/user-info.php [ -h --header --json --user username1 --user username2 ... ] -# -h is to use a human-readable format -# --header outputs some columns headers -# --json JSON format (disables --header and -h but uses ISO Zulu format for dates) -# --user indicates a username, and can be repeated +./cli/user-info.php [ --human-readable --header --json --user username1 --user username2 ... ] +# -h, --human-readable display output in a human readable format +# --header outputs some columns headers. +# --json JSON format (disables --header and --human-readable but uses ISO Zulu format for dates). +# --user indicates a username, and can be repeated. # Returns: 1) a * if the user is admin, 2) the name of the user, # 3) the date/time of last user action, 4) the size occupied, # and the number of: 5) categories, 6) feeds, 7) read articles, 8) unread articles, 9) favourites, 10) tags, -# 11) language, 12) e-mail +# 11) language, 12) e-mail. ./cli/import-for-user.php --user username --filename /path/to/file.ext -# The extension of the file { .json, .opml, .xml, .zip } is used to detect the type of import +# The extension of the file { .json, .opml, .xml, .zip } is used to detect the type of import. ./cli/export-sqlite-for-user.php --user username --filename /path/to/db.sqlite # Export the user’s database to a new SQLite file. ./cli/import-sqlite-for-user.php --user username [ --force-overwrite ] --filename /path/to/db.sqlite # Import the user’s database from an SQLite file. -# --force-overwrite will clear the target user database before import (import only works on an empty user database) +# --force-overwrite will clear the target user database before import (import only works on an empty user database). ./cli/export-opml-for-user.php --user username > /path/to/file.opml.xml @@ -129,15 +130,22 @@ cd /usr/share/FreshRSS ```sh cd /usr/share/FreshRSS -./cli/manipulate.translation.php --a [-h --a --k --v --l --o] -# manipulate the i18n language files -# -h is to use a human-readable format -# --a selects the action to perform. (can be: add, delete, exist, format, and ignore. -# --k selects the key to work on. -# --v selects the value to set. -# --l selects the language to work on. -# --r revert the action (only for ignore action) -# --o selects the origin language (only for add language action) +./cli/manipulate.translation.php --action [ --help --key --value --language --revert --origin-language ] +# manipulate translation files. +# -a, --action selects the action to perform. (can be either: add, delete, exist, format, or ignore) +# -h, --help displays the commands help file. +# -k, --key selects the key to work on. +# -v, --value selects the value to set. +# -l, --language selects the language to work on. +# -r, --revert revert the action (only used with ignore action). +# -o, --origin-language selects the origin language (only used with add language action). + +./cli/check-translation.php [ ---display-result --help --language fr --display-report ] +# Check if translation files have missing keys or missing translations. +# -d, --display-result display results of check. +# -h, --help display help text and exit. +# -l, --language set the language check. +# -r, --display-report display completion report. ``` ## Note about cron diff --git a/cli/_cli.php b/cli/_cli.php index 9ba6ec006..c51dd69a3 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -6,8 +6,7 @@ if (php_sapi_name() !== 'cli') { } const EXIT_CODE_ALREADY_EXISTS = 3; -const REGEX_INPUT_OPTIONS = '/^--/'; -const REGEX_PARAM_OPTIONS = '/:*$/'; +const REGEX_INPUT_OPTIONS = '/^-{2}|^-{1}/'; require(__DIR__ . '/../constants.php'); require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader @@ -77,37 +76,43 @@ function performRequirementCheck(string $databaseType): void { /** * Parses parameters used with FreshRSS' CLI commands. - * @param array{'valid':array<string,string>,'deprecated':array<string,string>} $parameters An array of 'valid': An - * array of parameters as keys and their respective getopt() notations as values. 'deprecated' An array with - * replacement parameters as keys and their respective deprecated parameters as values. - * @return array{'valid':array<string,string|bool>,'invalid':array<string>} An array of 'valid': an array of all - * known parameters used and their respective options and 'invalid': an array of all unknown parameters used. + * @param array{'long':array<string,string>,'short':array<string,string>,'deprecated':array<string,string>} $parameters + * Matrix of 'long': map of long option names as keys and their respective getopt() notations as values, + * 'short': map of short option names as values and their equivalent long options as keys, 'deprecated': map of + * replacement option names as keys and their respective deprecated option names as values. + * @return array{'valid':array<string,string>,'invalid':array<string>} Matrix of 'valid': map of of all known + * option names used and their respective values and 'invalid': list of all unknown options used. */ function parseCliParams(array $parameters): array { global $argv; - $cliParams = []; + $longOptions = []; + $shortOptions = ''; - foreach ($parameters['valid'] as $param => $getopt_val) { - $cliParams[] = $param . $getopt_val; + foreach ($parameters['long'] as $name => $getopt_note) { + $longOptions[] = $name . $getopt_note; } - foreach ($parameters['deprecated'] as $param => $deprecatedParam) { - $cliParams[] = $deprecatedParam . $parameters['valid'][$param]; + foreach ($parameters['deprecated'] as $name => $deprecatedName) { + $longOptions[] = $deprecatedName . $parameters['long'][$name]; + } + foreach ($parameters['short'] as $name => $shortName) { + $shortOptions .= $shortName . $parameters['long'][$name]; } - $opts = getopt('', $cliParams); + $options = getopt($shortOptions, $longOptions); - /** @var array<string,string|bool> $valid */ - $valid = is_array($opts) ? $opts : []; + $valid = is_array($options) ? $options : []; - array_walk($valid, static fn(&$option) => $option = $option === false ? true : $option); + array_walk($valid, static fn(&$option) => $option = $option === false ? '' : $option); - if (checkforDeprecatedParameterUse(array_keys($valid), $parameters['deprecated'])) { - $valid = updateDeprecatedParameters($valid, $parameters['deprecated']); - } + /** @var array<string,string> $valid */ + checkForDeprecatedOptions(array_keys($valid), $parameters['deprecated']); + + $valid = replaceOptions($valid, $parameters['short']); + $valid = replaceOptions($valid, $parameters['deprecated']); $invalid = findInvalidOptions( $argv, - array_merge(array_keys($parameters['valid']), array_values($parameters['deprecated'])) + array_merge(array_keys($parameters['long']), array_values($parameters['short']), array_values($parameters['deprecated'])) ); return [ @@ -120,7 +125,7 @@ function parseCliParams(array $parameters): array { * @param array<string> $options * @return array<string> */ -function getLongOptions(array $options, string $regex): array { +function getOptions(array $options, string $regex): array { $longOptions = array_filter($options, static function (string $a) use ($regex) { return preg_match($regex, $a) === 1; }); @@ -130,30 +135,13 @@ function getLongOptions(array $options, string $regex): array { } /** - * @param array<string> $input - * @param array<string> $params - */ -function validateOptions(array $input, array $params): bool { - $sanitizeInput = getLongOptions($input, REGEX_INPUT_OPTIONS); - $sanitizeParams = getLongOptions($params, REGEX_PARAM_OPTIONS); - $unknownOptions = array_diff($sanitizeInput, $sanitizeParams); - - if (0 === count($unknownOptions)) { - return true; - } - - fwrite(STDERR, sprintf("FreshRSS error: unknown options: %s\n", implode (', ', $unknownOptions))); - return false; -} - -/** - * Checks for use of unknown parameters with FreshRSS' CLI commands. - * @param array<string> $input An array of parameters to check for validity. - * @param array<string> $params An array of valid parameters to check against. - * @return array<string> Returns an array of all unknown parameters found. + * Checks for presence of unknown options. + * @param array<string> $input List of command line arguments to check for validity. + * @param array<string> $params List of valid options to check against. + * @return array<string> Returns a list all unknown options found. */ function findInvalidOptions(array $input, array $params): array { - $sanitizeInput = getLongOptions($input, REGEX_INPUT_OPTIONS); + $sanitizeInput = getOptions($input, REGEX_INPUT_OPTIONS); $unknownOptions = array_diff($sanitizeInput, $params); if (0 === count($unknownOptions)) { @@ -165,15 +153,14 @@ function findInvalidOptions(array $input, array $params): array { } /** - * Checks for use of deprecated parameters with FreshRSS' CLI commands. - * @param array<string> $options User inputs to check for deprecated parameter use. - * @param array<string,string> $params An array with replacement parameters as keys and their respective deprecated - * parameters as values. - * @return bool Returns TRUE and generates a deprecation warning if deprecated parameters - * have been used, FALSE otherwise. + * Checks for presence of deprecated options. + * @param array<string> $optionNames Command line option names to check for deprecation. + * @param array<string,string> $params Map of replacement options as keys and their respective deprecated + * options as values. + * @return bool Returns TRUE and generates a deprecation warning if deprecated options are present, FALSE otherwise. */ -function checkforDeprecatedParameterUse(array $options, array $params): bool { - $deprecatedOptions = array_intersect($options, $params); +function checkForDeprecatedOptions(array $optionNames, array $params): bool { + $deprecatedOptions = array_intersect($optionNames, $params); $replacements = array_map(static fn($option) => array_search($option, $params, true), $deprecatedOptions); if (0 === count($deprecatedOptions)) { @@ -187,25 +174,17 @@ function checkforDeprecatedParameterUse(array $options, array $params): bool { } /** - * Switches all used deprecated parameters to their replacements if they have one. - * - * @template T - * - * @param array<string,T> $options User inputs. - * @param array<string,string> $params An array with replacement parameters as keys and their respective deprecated - * parameters as values. - * @return array<string,T> Returns $options with deprications replaced. + * Switches items in a list to their provided replacements. + * @param array<string,string> $options Map with items to check for replacement as keys. + * @param array<string,string> $replacements Map of replacement items as keys and the item they replace as their values. + * @return array<string,string> Returns $options with replacements. */ -function updateDeprecatedParameters(array $options, array $params): array { +function replaceOptions(array $options, array $replacements): array { $updatedOptions = []; - foreach ($options as $param => $option) { - $replacement = array_search($param, $params, true); - if (is_string($replacement)) { - $updatedOptions[$replacement] = $option; - } else { - $updatedOptions[$param] = $option; - } + foreach ($options as $name => $value) { + $replacement = array_search($name, $replacements, true); + $updatedOptions[$replacement ? $replacement : $name] = $value; } return $updatedOptions; diff --git a/cli/_update-or-create-user.php b/cli/_update-or-create-user.php index 23666e3ae..1cc08bd25 100644 --- a/cli/_update-or-create-user.php +++ b/cli/_update-or-create-user.php @@ -4,8 +4,8 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$parameters = array( - 'valid' => array( +$parameters = [ + 'long' => [ 'user' => ':', 'password' => ':', 'api-password' => ':', @@ -17,21 +17,22 @@ $parameters = array( 'feed-ttl-default' => ':', 'since-hours-posts-per-rss' => ':', 'max-posts-per-rss' => ':', - ), - 'deprecated' => array( + ], + 'short' => [], + 'deprecated' => [ 'api-password' => 'api_password', 'purge-after-months' => 'purge_after_months', 'feed-min-articles-default' => 'feed_min_articles_default', 'feed-ttl-default' => 'feed_ttl_default', 'since-hours-posts-per-rss' => 'since_hours_posts_per_rss', 'max-posts-per-rss' => 'max_posts_per_rss', - ), -); + ], +]; if (!isset($isUpdate)) { $isUpdate = false; } elseif (!$isUpdate) { - $parameters['valid']['no-default-feeds'] = ''; //Only for creating new users + $parameters['long']['no-default-feeds'] = ''; //Only for creating new users $parameters['deprecated']['no-default-feeds'] = 'no_default_feeds'; } diff --git a/cli/actualize-user.php b/cli/actualize-user.php index 99b48116d..f2fae116c 100755 --- a/cli/actualize-user.php +++ b/cli/actualize-user.php @@ -5,17 +5,21 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = array( - 'user:', -); +$parameters = [ + 'long' => [ + 'user' => ':' + ], + 'short' => [], + 'deprecated' => [], +]; -$options = getopt('', $params); +$options = parseCliParams($parameters); -if (!validateOptions($argv, $params) || empty($options['user']) || !is_string($options['user'])) { +if (!empty($options['invalid']) || empty($options['valid']['user']) || !is_string($options['valid']['user'])) { fail('Usage: ' . basename(__FILE__) . " --user username"); } -$username = cliInitUser($options['user']); +$username = cliInitUser($options['valid']['user']); Minz_ExtensionManager::callHookVoid('freshrss_user_maintenance'); diff --git a/cli/check.translation.php b/cli/check.translation.php index 747a35be9..10a346dee 100755 --- a/cli/check.translation.php +++ b/cli/check.translation.php @@ -1,28 +1,45 @@ #!/usr/bin/env php <?php declare(strict_types=1); +require_once __DIR__ . '/_cli.php'; require_once __DIR__ . '/i18n/I18nCompletionValidator.php'; require_once __DIR__ . '/i18n/I18nData.php'; require_once __DIR__ . '/i18n/I18nFile.php'; require_once __DIR__ . '/i18n/I18nUsageValidator.php'; +require_once __DIR__ . '/../constants.php'; $i18nFile = new I18nFile(); $i18nData = new I18nData($i18nFile->load()); -/** @var array<string,string>|false $options */ -$options = getopt('dhl:r'); - -if (!is_array($options) || array_key_exists('h', $options)) { +$parameters = [ + 'long' => [ + 'display-result' => '', + 'help' => '', + 'language' => ':', + 'display-report' => '', + ], + 'short' => [ + 'display-result' => 'd', + 'help' => 'h', + 'language' => 'l', + 'display-report' => 'r', + ], + 'deprecated' => [], +]; + +$options = parseCliParams($parameters); + +if (!empty($options['invalid']) || array_key_exists('help', $options['valid'])) { checkHelp(); } -if (array_key_exists('l', $options)) { - $languages = array($options['l']); +if (array_key_exists('language', $options['valid'])) { + $languages = [$options['valid']['language']]; } else { $languages = $i18nData->getAvailableLanguages(); } -$displayResults = array_key_exists('d', $options); -$displayReport = array_key_exists('r', $options); +$displayResults = array_key_exists('display-result', $options['valid']); +$displayReport = array_key_exists('display-report', $options['valid']); $isValidated = true; $result = []; @@ -99,10 +116,10 @@ SYNOPSIS DESCRIPTION Check if translation files have missing keys or missing translations. - -d display results. - -h display this help and exit. - -l=LANG filter by LANG. - -r display completion report. + -d, --display-result display results. + -h, --help display this help and exit. + -l, --language=LANG filter by LANG. + -r, --display-report display completion report. HELP; exit; diff --git a/cli/db-optimize.php b/cli/db-optimize.php index 82f545420..d553b64d9 100755 --- a/cli/db-optimize.php +++ b/cli/db-optimize.php @@ -5,17 +5,21 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = array( - 'user:', -); +$parameters = [ + 'long' => [ + 'user' => ':', + ], + 'short' => [], + 'deprecated' => [], +]; -$options = getopt('', $params); +$options = parseCliParams($parameters); -if (!validateOptions($argv, $params) || empty($options['user']) || !is_string($options['user'])) { +if (!empty($options['invalid']) || empty($options['valid']['user']) || !is_string($options['valid']['user'])) { fail('Usage: ' . basename(__FILE__) . " --user username"); } -$username = cliInitUser($options['user']); +$username = cliInitUser($options['valid']['user']); echo 'FreshRSS optimizing database for user “', $username, "”…\n"; diff --git a/cli/delete-user.php b/cli/delete-user.php index d8d3033cc..b4f042847 100755 --- a/cli/delete-user.php +++ b/cli/delete-user.php @@ -5,16 +5,20 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = array( - 'user:', -); +$parameters = [ + 'long' => [ + 'user' => ':', + ], + 'short' => [], + 'deprecated' => [], +]; -$options = getopt('', $params); +$options = parseCliParams($parameters); -if (!validateOptions($argv, $params) || empty($options['user']) || !is_string($options['user'])) { +if (!empty($options['invalid']) || empty($options['valid']['user']) || !is_string($options['valid']['user'])) { fail('Usage: ' . basename(__FILE__) . " --user username"); } -$username = $options['user']; +$username = $options['valid']['user']; if (!FreshRSS_user_Controller::checkUsername($username)) { fail('FreshRSS error: invalid username “' . $username . '”'); } diff --git a/cli/do-install.php b/cli/do-install.php index 3e9c59162..2d73c2e98 100755 --- a/cli/do-install.php +++ b/cli/do-install.php @@ -7,8 +7,8 @@ if (file_exists(DATA_PATH . '/applied_migrations.txt')) { fail('FreshRSS seems to be already installed!' . "\n" . 'Please use `./cli/reconfigure.php` instead.', EXIT_CODE_ALREADY_EXISTS); } -$parameters = array( - 'valid' => array( +$parameters = [ + 'long' => [ 'environment' => ':', 'base-url' => ':', 'language' => ':', @@ -26,8 +26,9 @@ $parameters = array( 'db-password' => ':', 'db-base' => ':', 'db-prefix' => '::', - ), - 'deprecated' => array( + ], + 'short' => [], + 'deprecated' => [ 'base-url' => 'base_url', 'default-user' => 'default_user', 'allow-anonymous' => 'allow_anonymous', @@ -36,10 +37,10 @@ $parameters = array( 'api-enabled' => 'api_enabled', 'allow-robots' => 'allow_robots', 'disable-update' => 'disable_update', - ), -); + ], +]; -$configParams = array( +$configParams = [ 'environment' => 'environment', 'base-url' => 'base_url', 'language' => 'language', @@ -51,16 +52,16 @@ $configParams = array( 'api-enabled' => 'api_enabled', 'allow-robots' => 'allow_robots', 'disable-update' => 'disable_update', -); +]; -$dBconfigParams = array( +$dBconfigParams = [ 'db-type' => 'type', 'db-host' => 'host', 'db-user' => 'user', 'db-password' => 'password', 'db-base' => 'base', 'db-prefix' => 'prefix', -); +]; $options = parseCliParams($parameters); @@ -89,7 +90,8 @@ if (file_exists($customConfigPath)) { foreach ($configParams as $param => $configParam) { if (isset($options['valid'][$param])) { - $config[$configParam] = $options['valid'][$param]; + $isFlag = $parameters['long'][$param] === ''; + $config[$configParam] = $isFlag ? true : $options['valid'][$param]; } } diff --git a/cli/export-opml-for-user.php b/cli/export-opml-for-user.php index 51beb12f3..7c59c65ef 100755 --- a/cli/export-opml-for-user.php +++ b/cli/export-opml-for-user.php @@ -5,17 +5,21 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = array( - 'user:', -); +$parameters = [ + 'long' => [ + 'user' => ':', + ], + 'short' => [], + 'deprecated' => [], +]; -$options = getopt('', $params); +$options = parseCliParams($parameters); -if (!validateOptions($argv, $params) || empty($options['user']) || !is_string($options['user'])) { +if (!empty($options['invalid']) || empty($options['valid']['user']) || !is_string($options['valid']['user'])) { fail('Usage: ' . basename(__FILE__) . " --user username > /path/to/file.opml.xml"); } -$username = cliInitUser($options['user']); +$username = cliInitUser($options['valid']['user']); fwrite(STDERR, 'FreshRSS exporting OPML for user “' . $username . "”…\n"); diff --git a/cli/export-sqlite-for-user.php b/cli/export-sqlite-for-user.php index ee8e183f6..e67896df9 100755 --- a/cli/export-sqlite-for-user.php +++ b/cli/export-sqlite-for-user.php @@ -5,19 +5,26 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = [ - 'user:', - 'filename:', +$parameters = [ + 'long' => [ + 'user' => ':', + 'filename' => ':', + ], + 'short' => [], + 'deprecated' => [], ]; -$options = getopt('', $params); +$options = parseCliParams($parameters); -if (!validateOptions($argv, $params) || empty($options['user']) || empty($options['filename']) || !is_string($options['user']) || !is_string($options['filename'])) { +if (!empty($options['invalid']) + || empty($options['valid']['user']) || empty($options['valid']['filename']) + || !is_string($options['valid']['user']) || !is_string($options['valid']['filename']) +) { fail('Usage: ' . basename(__FILE__) . ' --user username --filename /path/to/db.sqlite'); } -$username = cliInitUser($options['user']); -$filename = $options['filename']; +$username = cliInitUser($options['valid']['user']); +$filename = $options['valid']['filename']; if (pathinfo($filename, PATHINFO_EXTENSION) !== 'sqlite') { fail('Only *.sqlite files are supported!'); diff --git a/cli/export-zip-for-user.php b/cli/export-zip-for-user.php index 5458784bf..d818096e4 100755 --- a/cli/export-zip-for-user.php +++ b/cli/export-zip-for-user.php @@ -5,14 +5,18 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = array( - 'user:', - 'max-feed-entries:', -); - -$options = getopt('', $params); - -if (!validateOptions($argv, $params) || empty($options['user']) || !is_string($options['user'])) { +$parameters = [ + 'long' => [ + 'user' => ':', + 'max-feed-entries' => ':', + ], + 'short' => [], + 'deprecated' => [], +]; + +$options = parseCliParams($parameters); + +if (!empty($options['invalid']) || empty($options['valid']['user']) || !is_string($options['valid']['user'])) { fail('Usage: ' . basename(__FILE__) . " --user username ( --max-feed-entries 100 ) > /path/to/file.zip"); } @@ -20,12 +24,12 @@ if (!extension_loaded('zip')) { fail('FreshRSS error: Lacking php-zip extension!'); } -$username = cliInitUser($options['user']); +$username = cliInitUser($options['valid']['user']); fwrite(STDERR, 'FreshRSS exporting ZIP for user “' . $username . "”…\n"); $export_service = new FreshRSS_Export_Service($username); -$number_entries = empty($options['max-feed-entries']) ? 100 : intval($options['max-feed-entries']); +$number_entries = empty($options['valid']['max-feed-entries']) ? 100 : intval($options['valid']['max-feed-entries']); $exported_files = []; // First, we generate the OPML file diff --git a/cli/import-for-user.php b/cli/import-for-user.php index b4731b13b..6969a8946 100755 --- a/cli/import-for-user.php +++ b/cli/import-for-user.php @@ -5,20 +5,27 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = array( - 'user:', - 'filename:', -); - -$options = getopt('', $params); - -if (!validateOptions($argv, $params) || empty($options['user']) || empty($options['filename']) || !is_string($options['user']) || !is_string($options['filename'])) { +$parameters = [ + 'long' => [ + 'user' => ':', + 'filename' => ':', + ], + 'short' => [], + 'deprecated' => [], +]; + +$options = parseCliParams($parameters); + +if (!empty($options['invalid']) + || empty($options['valid']['user']) || empty($options['valid']['filename']) + || !is_string($options['valid']['user']) || !is_string($options['valid']['filename']) +) { fail('Usage: ' . basename(__FILE__) . " --user username --filename /path/to/file.ext"); } -$username = cliInitUser($options['user']); +$username = cliInitUser($options['valid']['user']); -$filename = $options['filename']; +$filename = $options['valid']['filename']; if (!is_readable($filename)) { fail('FreshRSS error: file is not readable “' . $filename . '”'); } diff --git a/cli/import-sqlite-for-user.php b/cli/import-sqlite-for-user.php index b61a73523..29b7c1b0c 100755 --- a/cli/import-sqlite-for-user.php +++ b/cli/import-sqlite-for-user.php @@ -5,20 +5,27 @@ require(__DIR__ . '/_cli.php'); performRequirementCheck(FreshRSS_Context::systemConf()->db['type'] ?? ''); -$params = [ - 'user:', - 'filename:', - 'force-overwrite', +$parameters = [ + 'long' => [ + 'user' => ':', + 'filename' => ':', + 'force-overwrite' => '', + ], + 'short' => [], + 'deprecated' => [], ]; -$options = getopt('', $params); +$options = parseCliParams($parameters); -if (!validateOptions($argv, $params) || empty($options['user']) || empty($options['filename']) || !is_string($options['user']) || !is_string($options['filename'])) { +if (!empty($options['invalid']) + || empty($options['valid']['user']) || empty($options['valid']['filename']) + || !is_string($options['valid']['user']) || !is_string($options['valid']['filename']) +) { fail('Usage: ' . basename(__FILE__) . ' --user username --force-overwrite --filename /path/to/db.sqlite'); } -$username = cliInitUser($options['user']); -$filename = $options['filename']; +$username = cliInitUser($options['valid']['user']); +$filename = $options['valid']['filename']; if (pathinfo($filename, PATHINFO_EXTENSION) !== 'sqlite') { fail('Only *.sqlite files are supported!'); @@ -27,7 +34,7 @@ if (pathinfo($filename, PATHINFO_EXTENSION) !== 'sqlite') { echo 'FreshRSS importing database from SQLite for user “', $username, "”…\n"; $databaseDAO = FreshRSS_Factory::createDatabaseDAO($username); -$clearFirst = array_key_exists('force-overwrite', $options); +$clearFirst = array_key_exists('force-overwrite', $options['valid']); $ok = $databaseDAO->dbCopy($filename, FreshRSS_DatabaseDAO::SQLITE_IMPORT, $clearFirst); if (!$ok) { echo 'If you would like to clear the user database first, use the option --force-overwrite', "\n"; diff --git a/cli/manipulate.translation.php b/cli/manipulate.translation.php index 611cdb0d5..358a3ec33 100755 --- a/cli/manipulate.translation.php +++ b/cli/manipulate.translation.php @@ -1,53 +1,75 @@ #!/usr/bin/env php <?php declare(strict_types=1); +require_once __DIR__ . '/_cli.php'; require_once __DIR__ . '/i18n/I18nData.php'; require_once __DIR__ . '/i18n/I18nFile.php'; require_once __DIR__ . '/../constants.php'; -/** @var array<string,string>|false $options */ -$options = getopt('a:hk:l:o:rv:'); - -if (!is_array($options) || array_key_exists('h', $options)) { +$parameters = [ + 'long' => [ + 'action' => ':', + 'help' => '', + 'key' => ':', + 'language' => ':', + 'origin-language' => ':', + 'revert' => '', + 'value' => ':', + ], + 'short' => [ + 'action' => 'a', + 'help' => 'h', + 'key' => 'k', + 'language' => 'l', + 'origin-language' => 'o', + 'revert' => 'r', + 'value' => 'v', + ], + 'deprecated' => [], +]; + +$options = parseCliParams($parameters); + +if (!empty($options['invalid']) || array_key_exists('help', $options['valid'])) { manipulateHelp(); exit(); } -if (!array_key_exists('a', $options)) { +if (!array_key_exists('action', $options['valid'])) { error('You need to specify the action to perform.'); } $data = new I18nFile(); $i18nData = new I18nData($data->load()); -switch ($options['a']) { +switch ($options['valid']['action']) { case 'add' : - if (array_key_exists('k', $options) && array_key_exists('v', $options) && array_key_exists('l', $options)) { - $i18nData->addValue($options['k'], $options['v'], $options['l']); - } elseif (array_key_exists('k', $options) && array_key_exists('v', $options)) { - $i18nData->addKey($options['k'], $options['v']); - } elseif (array_key_exists('l', $options)) { + if (array_key_exists('key', $options['valid']) && array_key_exists('value', $options['valid']) && array_key_exists('language', $options['valid'])) { + $i18nData->addValue($options['valid']['key'], $options['valid']['value'], $options['valid']['language']); + } elseif (array_key_exists('key', $options['valid']) && array_key_exists('value', $options['valid'])) { + $i18nData->addKey($options['valid']['key'], $options['valid']['value']); + } elseif (array_key_exists('language', $options['valid'])) { $reference = null; - if (array_key_exists('o', $options)) { - $reference = $options['o']; + if (array_key_exists('origin-language', $options['valid'])) { + $reference = $options['valid']['origin-language']; } - $i18nData->addLanguage($options['l'], $reference); + $i18nData->addLanguage($options['valid']['language'], $reference); } else { error('You need to specify a valid set of options.'); exit; } break; case 'delete' : - if (array_key_exists('k', $options)) { - $i18nData->removeKey($options['k']); + if (array_key_exists('key', $options['valid'])) { + $i18nData->removeKey($options['valid']['key']); } else { error('You need to specify the key to delete.'); exit; } break; case 'exist': - if (array_key_exists('k', $options)) { - $key = $options['k']; + if (array_key_exists('key', $options['valid'])) { + $key = $options['valid']['key']; if ($i18nData->isKnown($key)) { echo "The '{$key}' key is known.\n\n"; } else { @@ -61,16 +83,16 @@ switch ($options['a']) { case 'format' : break; case 'ignore' : - if (array_key_exists('l', $options) && array_key_exists('k', $options)) { - $i18nData->ignore($options['k'], $options['l'], array_key_exists('r', $options)); + if (array_key_exists('language', $options['valid']) && array_key_exists('key', $options['valid'])) { + $i18nData->ignore($options['valid']['key'], $options['valid']['language'], array_key_exists('revert', $options['valid'])); } else { error('You need to specify a valid set of options.'); exit; } break; case 'ignore_unmodified' : - if (array_key_exists('l', $options)) { - $i18nData->ignore_unmodified($options['l'], array_key_exists('r', $options)); + if (array_key_exists('language', $options['valid'])) { + $i18nData->ignore_unmodified($options['valid']['language'], array_key_exists('revert', $options['valid'])); } else { error('You need to specify a valid set of options.'); exit; @@ -110,46 +132,48 @@ SYNOPSIS DESCRIPTION Manipulate translation files. - -a=ACTION - select the action to perform. Available actions are add, delete, - exist, format, ignore, and ignore_unmodified. This option is mandatory. - -k=KEY select the key to work on. - -v=VAL select the value to set. - -l=LANG select the language to work on. - -h display this help and exit. - -r revert the action (only for ignore action) - -o=LANG select the origin language (only for add language action) + -a, --action=ACTION + select the action to perform. Available actions are add, delete, + exist, format, ignore, and ignore_unmodified. This option is mandatory. + -k, --key=KEY select the key to work on. + -v, --value=VAL select the value to set. + -l, --language=LANG select the language to work on. + -h, --help display this help and exit. + -r, --revert revert the action (only for ignore action) + -o, origin-language=LANG + select the origin language (only for add language action) EXAMPLES -Example 1: add a language. It adds a new language by duplicating the referential. +Example 1: add a language. It adds a new language by duplicating the referential. php $file -a add -l my_lang php $file -a add -l my_lang -o ref_lang -Example 2: add a new key. It adds the key for all supported languages. +Example 2: add a new key. It adds the key for all supported languages. php $file -a add -k my_key -v my_value -Example 3: add a new value. It adds a new value for the selected key in the selected language. +Example 3: add a new value. It adds a new value for the selected key in the selected language. php $file -a add -k my_key -v my_value -l my_lang -Example 4: delete a key. It deletes the selected key from all supported languages. +Example 4: delete a key. It deletes the selected key from all supported languages. php $file -a delete -k my_key -Example 5: format i18n files. +Example 5: format i18n files. php $file -a format -Example 6: ignore a key. It adds the key in the ignore file to mark it as translated. +Example 6: ignore a key. Adds IGNORE comment to the key in the selected language, marking it as translated. php $file -a ignore -k my_key -l my_lang -Example 7: revert ignore a key. It removes the key from the ignore file. +Example 7: revert ignore a key. Removes IGNORE comment from the key in the selected language. php $file -a ignore -r -k my_key -l my_lang -Example 8: ignore all unmodified keys. It adds all modified keys in the ignore file to mark it as translated. +Example 8: ignore all unmodified keys. Adds IGNORE comments to all unmodified keys in the selected language, marking them as translated. php $file -a ignore_unmodified -l my_lang -Example 9: revert ignore of all unmodified keys. It removes the unmodified keys from the ignore file. Warning, this will also revert keys added individually. +Example 9: revert ignore on all unmodified keys. Removes IGNORE comments from all unmodified keys in the selected language. + Warning: will also revert individually added unmodified keys. php $file -a ignore_unmodified -r -l my_lang -Example 10: check if a key exist. +Example 10: check if a key exist. php $file -a exist -k my_key\n\n HELP; diff --git a/cli/reconfigure.php b/cli/reconfigure.php index da433c1a0..fde16c921 100755 --- a/cli/reconfigure.php +++ b/cli/reconfigure.php @@ -3,8 +3,8 @@ declare(strict_types=1); require(__DIR__ . '/_cli.php'); -$parameters = array( - 'valid' => array( +$parameters = [ + 'long' => [ 'environment' => ':', 'base-url' => ':', 'language' => ':', @@ -22,8 +22,9 @@ $parameters = array( 'db-password' => ':', 'db-base' => ':', 'db-prefix' => '::', - ), - 'deprecated' => array( + ], + 'short' => [], + 'deprecated' => [ 'base-url' => 'base_url', 'default-user' => 'default_user', 'allow-anonymous' => 'allow_anonymous', @@ -32,10 +33,10 @@ $parameters = array( 'api-enabled' => 'api_enabled', 'allow-robots' => 'allow_robots', 'disable-update' => 'disable_update', - ), -); + ], +]; -$configParams = array( +$configParams = [ 'environment', 'base-url', 'language', @@ -47,16 +48,16 @@ $configParams = array( 'api-enabled', 'allow-robots', 'disable-update', -); +]; -$dBconfigParams = array( +$dBconfigParams = [ 'db-type' => 'type', 'db-host' => 'host', 'db-user' => 'user', 'db-password' => 'password', 'db-base' => 'base', 'db-prefix' => 'prefix', -); +]; $options = parseCliParams($parameters); diff --git a/cli/user-info.php b/cli/user-info.php index fbf60482a..f492d26b2 100755 --- a/cli/user-info.php +++ b/cli/user-info.php @@ -5,37 +5,45 @@ require(__DIR__ . '/_cli.php'); const DATA_FORMAT = "%-7s | %-20s | %-5s | %-7s | %-25s | %-15s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-5s | %-10s\n"; -$params = array( - 'user:', - 'header', - 'json', -); -$options = getopt('h', $params); +$parameters = [ + 'long' => [ + 'user' => ':', + 'header' => '', + 'json' => '', + 'human-readable' => '', + ], + 'short' => [ + 'human-readable' => 'h', + ], + 'deprecated' => [], +]; -if (!validateOptions($argv, $params)) { - fail('Usage: ' . basename(__FILE__) . ' (-h --header --json --user username --user username …)'); +$options = parseCliParams($parameters); + +if (!empty($options['invalid'])) { + fail('Usage: ' . basename(__FILE__) . ' (--human-readable --header --json --user username --user username …)'); } -if (empty($options['user'])) { +if (empty($options['valid']['user'])) { $users = listUsers(); -} elseif (is_array($options['user'])) { +} elseif (is_array($options['valid']['user'])) { /** @var array<string> $users */ - $users = $options['user']; + $users = $options['valid']['user']; } else { /** @var array<string> $users */ - $users = array($options['user']); + $users = [$options['valid']['user']]; } sort($users); -$formatJson = isset($options['json']); +$formatJson = isset($options['valid']['json']); $jsonOutput = []; if ($formatJson) { - unset($options['header']); - unset($options['h']); + unset($options['valid']['header']); + unset($options['valid']['human-readable']); } -if (array_key_exists('header', $options)) { +if (array_key_exists('header', $options['valid'])) { printf( DATA_FORMAT, 'default', @@ -84,7 +92,7 @@ foreach ($users as $username) { 'lang' => FreshRSS_Context::userConf()->language, 'mail_login' => FreshRSS_Context::userConf()->mail_login, ); - if (isset($options['h'])) { //Human format + if (isset($options['valid']['human-readable'])) { //Human format $data['last_user_activity'] = date('c', $data['last_user_activity']); $data['database_size'] = format_bytes($data['database_size']); } |
