diff --git a/Neos.Flow/Classes/Cli/RequestBuilder.php b/Neos.Flow/Classes/Cli/RequestBuilder.php index f017f23677..df1ee24411 100644 --- a/Neos.Flow/Classes/Cli/RequestBuilder.php +++ b/Neos.Flow/Classes/Cli/RequestBuilder.php @@ -140,14 +140,23 @@ public function build($commandLine): Request } } } - if (count($rawCommandLineArguments) === 0) { + $firstArgument = count($rawCommandLineArguments) ? trim(array_shift($rawCommandLineArguments)) : null; + if ( + $firstArgument === null + || $firstArgument === '--help' + ) { $request->setControllerCommandName('helpStub'); return $request; } - $commandIdentifier = trim(array_shift($rawCommandLineArguments)); + if (in_array('--help', $rawCommandLineArguments, true)) { + $request->setControllerCommandName('help'); + $request->setArguments(['commandIdentifier' => $firstArgument]); + return $request; + } + try { - $command = $this->commandManager->getCommandByIdentifier($commandIdentifier); + $command = $this->commandManager->getCommandByIdentifier($firstArgument); } catch (CommandException $exception) { $request->setArgument('exception', $exception); $request->setControllerCommandName('error'); @@ -188,6 +197,9 @@ protected function parseRawCommandLineArguments(array $rawCommandLineArguments, $requiredArguments = []; $optionalArguments = []; foreach ($commandMethodParameters as $parameterName => $parameterInfo) { + if ($parameterName === 'help') { + throw new \RuntimeException(sprintf('The option --help is reserved in %s::%s', $controllerObjectName, $commandMethodName), 1730715152); + } if ($parameterInfo['optional'] === false) { $requiredArguments[strtolower($parameterName)] = [ 'parameterName' => $parameterName, diff --git a/Neos.Flow/Classes/Command/HelpCommandController.php b/Neos.Flow/Classes/Command/HelpCommandController.php index 924c6670a8..e3eeadbdd3 100644 --- a/Neos.Flow/Classes/Command/HelpCommandController.php +++ b/Neos.Flow/Classes/Command/HelpCommandController.php @@ -124,7 +124,7 @@ protected function displayHelpIndex() $this->outputLine('* = compile time command'); $this->outputLine(); - $this->outputLine('See "%s help " for more information about a specific command.', [$this->getFlowInvocationString()]); + $this->outputLine('Use "%s [command] --help" for more information about a command.', [$this->getFlowInvocationString()]); $this->outputLine(); } @@ -212,6 +212,7 @@ protected function displayHelpForCommand(Command $command) if (count($optionDescriptions) > 0) { $this->outputLine(); $this->outputLine('OPTIONS:'); + $optionDescriptions[] = vsprintf(' %-20s %s', ['--help', 'Shows detailed information about this command']); foreach ($optionDescriptions as $optionDescription) { $this->outputLine($optionDescription); } @@ -260,7 +261,7 @@ public function errorCommand(CommandException $exception) } $this->outputLine(); $this->outputLine('Enter "%s help" for an overview of all available commands', [$this->getFlowInvocationString()]); - $this->outputLine('or "%s help " for a detailed description of the corresponding command.', [$this->getFlowInvocationString()]); + $this->outputLine('or "%s --help" for a detailed description of the corresponding command.', [$this->getFlowInvocationString()]); $this->quit(1); } diff --git a/Neos.Flow/Classes/Error/Debugger.php b/Neos.Flow/Classes/Error/Debugger.php index de5eb8b560..f74a139eee 100644 --- a/Neos.Flow/Classes/Error/Debugger.php +++ b/Neos.Flow/Classes/Error/Debugger.php @@ -335,36 +335,7 @@ public static function getBacktraceCode(array $trace, bool $includeCode = true, $backtraceCode .= '
  • '; $class = isset($step['class']) ? $step['class'] . '::' : ''; - $arguments = ''; - if (isset($step['args']) && is_array($step['args'])) { - foreach ($step['args'] as $argument) { - $arguments .= (strlen($arguments) === 0) ? '' : ', '; - $arguments .= ''; - if (is_object($argument)) { - $arguments .= '' . self::getObjectSnippetPlaintext($argument) . ''; - } elseif (is_string($argument)) { - $preparedArgument = (strlen($argument) < 100) ? $argument : substr($argument, 0, 50) . '…' . substr($argument, -50); - $preparedArgument = htmlspecialchars($preparedArgument); - $preparedArgument = str_replace('…', '', $preparedArgument); - $preparedArgument = str_replace("\n", '', $preparedArgument); - $arguments .= '"' . $preparedArgument . '"'; - } elseif (is_numeric($argument)) { - $arguments .= (string)$argument; - } elseif (is_bool($argument)) { - $arguments .= ($argument === true ? 'true' : 'false'); - } elseif (is_array($argument)) { - $arguments .= sprintf( - 'array|%d|', - htmlspecialchars(self::renderArrayDump($argument, 0, true)), - count($argument) - ); - } else { - $arguments .= '' . gettype($argument) . ''; - } - $arguments .= ''; - } - } - + $arguments = (isset($step['args']) && is_array($step['args'])) ? self::renderCallArgumentsHtml($step['args']) : ''; $backtraceCode .= '
    ';
                 $backtraceCode .= $class . $step['function'] . '(' . $arguments . ')';
                 $backtraceCode .= '
    '; @@ -378,6 +349,49 @@ public static function getBacktraceCode(array $trace, bool $includeCode = true, return $backtraceCode; } + /** + * @param array $callArguments + */ + protected static function renderCallArgumentsHtml(array $callArguments): string + { + $arguments = ''; + foreach ($callArguments as $argument) { + $arguments .= ($arguments === '') ? '' : ', '; + $arguments .= ''; + try { + if (is_object($argument)) { + $arguments .= '' . self::getObjectSnippetPlaintext($argument) . ''; + } elseif (is_string($argument)) { + $preparedArgument = (strlen($argument) < 100) ? $argument : substr($argument, 0, 50) . '…' . substr($argument, -50); + $preparedArgument = htmlspecialchars($preparedArgument); + $preparedArgument = str_replace(['…', "\n"], [ + '', + '' + ], $preparedArgument); + $arguments .= '"' . $preparedArgument . '"'; + } elseif (is_numeric($argument)) { + $arguments .= (string)$argument; + } elseif (is_bool($argument)) { + $arguments .= ($argument === true ? 'true' : 'false'); + } elseif (is_array($argument)) { + $arguments .= sprintf( + 'array|%d|', + htmlspecialchars(self::renderArrayDump($argument, 0, true)), + count($argument) + ); + } else { + $arguments .= '' . get_debug_type($argument) . ''; + } + } catch (\Throwable $_) { + $arguments .= '' . get_debug_type($argument) . ''; + } + + $arguments .= ''; + } + + return $arguments; + } + /** * @param array $trace * @param bool $includeCode @@ -389,27 +403,7 @@ protected static function getBacktraceCodePlaintext(array $trace, bool $includeC foreach ($trace as $index => $step) { $class = isset($step['class']) ? $step['class'] . '::' : ''; - $arguments = ''; - if (isset($step['args']) && is_array($step['args'])) { - foreach ($step['args'] as $argument) { - $arguments .= (strlen($arguments) === 0) ? '' : ', '; - if (is_object($argument)) { - $arguments .= self::getObjectSnippetPlaintext($argument); - } elseif (is_string($argument)) { - $preparedArgument = (strlen($argument) < 100) ? $argument : substr($argument, 0, 50) . '…' . substr($argument, -50); - $arguments .= '"' . $preparedArgument . '"'; - } elseif (is_numeric($argument)) { - $arguments .= (string)$argument; - } elseif (is_bool($argument)) { - $arguments .= ($argument === true ? 'true' : 'false'); - } elseif (is_array($argument)) { - $arguments .= 'array|' . count($argument) . '|'; - } else { - $arguments .= gettype($argument); - } - } - } - + $arguments = (isset($step['args']) && is_array($step['args'])) ? self::renderCallArgumentsPlaintext($step['args']) : ''; $backtraceCode .= (count($trace) - $index) . ' ' . $class . $step['function'] . '(' . $arguments . ')'; if (isset($step['file']) && $includeCode) { @@ -421,6 +415,37 @@ protected static function getBacktraceCodePlaintext(array $trace, bool $includeC return $backtraceCode; } + /** + * @param array $callArguments + */ + protected static function renderCallArgumentsPlaintext(array $callArguments): string + { + $arguments = ''; + foreach ($callArguments as $argument) { + $arguments .= (strlen($arguments) === 0) ? '' : ', '; + try { + if (is_object($argument)) { + $arguments .= self::getObjectSnippetPlaintext($argument); + } elseif (is_string($argument)) { + $preparedArgument = (strlen($argument) < 100) ? $argument : substr($argument, 0, 50) . '…' . substr($argument, -50); + $arguments .= '"' . $preparedArgument . '"'; + } elseif (is_numeric($argument)) { + $arguments .= (string)$argument; + } elseif (is_bool($argument)) { + $arguments .= ($argument === true ? 'true' : 'false'); + } elseif (is_array($argument)) { + $arguments .= 'array|' . count($argument) . '|'; + } else { + $arguments .= get_debug_type($argument); + } + } catch (\Throwable $_) { + $arguments .= get_debug_type($argument); + } + } + + return $arguments; + } + /** * Returns a code snippet from the specified file. * @@ -470,20 +495,16 @@ public static function getCodeSnippet(string $filePathAndName, int $lineNumber, protected static function getObjectSnippetPlaintext(object $object): string { if (method_exists($object, '__toString')) { - try { - $string = (string)$object; - return self::getObjectShortName($object) . '|' . self::truncateObjectOutput($string) . '|'; - } catch (\Throwable $_) {/* This can happen if what was callable was not actually __toString (a magic __call() will do that) we can try other ways to get information. */ - } + return self::getObjectShortName($object) . '|' . self::truncateObjectOutput((string)$object) . '|'; } if ($object instanceof \JsonSerializable) { - return self::getObjectShortName($object) . '|' . self::truncateObjectOutput(json_encode($object, JSON_PARTIAL_OUTPUT_ON_ERROR, 1)) . '|'; + return self::getObjectShortName($object) . '|' . self::truncateObjectOutput(json_encode($object, JSON_THROW_ON_ERROR, 1)) . '|'; } $publicProperties = get_object_vars($object); if (!empty($publicProperties)) { - return self::getObjectShortName($object) . '|' . self::truncateObjectOutput(json_encode($publicProperties, JSON_PARTIAL_OUTPUT_ON_ERROR, 1)) . '|'; + return self::getObjectShortName($object) . '|' . self::truncateObjectOutput(json_encode($publicProperties, JSON_THROW_ON_ERROR, 1)) . '|'; } return get_class($object); diff --git a/Neos.Flow/Classes/Security/Aspect/LoggingAspect.php b/Neos.Flow/Classes/Security/Aspect/LoggingAspect.php index 25c525ae81..e85afc9ac1 100644 --- a/Neos.Flow/Classes/Security/Aspect/LoggingAspect.php +++ b/Neos.Flow/Classes/Security/Aspect/LoggingAspect.php @@ -127,14 +127,14 @@ public function logPersistedUsernamePasswordProviderAuthenticate(JoinPointInterf switch ($token->getAuthenticationStatus()) { case TokenInterface::AUTHENTICATION_SUCCESSFUL: - $this->securityLogger->notice(sprintf('Successfully authenticated token: %s', $token), $this->getLogEnvironmentFromJoinPoint($joinPoint)); + $this->securityLogger->info(sprintf('Successfully authenticated token: %s', $token), $this->getLogEnvironmentFromJoinPoint($joinPoint)); $this->alreadyLoggedAuthenticateCall = true; break; case TokenInterface::WRONG_CREDENTIALS: - $this->securityLogger->warning(sprintf('Wrong credentials given for token: %s', $token), $this->getLogEnvironmentFromJoinPoint($joinPoint)); + $this->securityLogger->notice(sprintf('Wrong credentials given for token: %s', $token), $this->getLogEnvironmentFromJoinPoint($joinPoint)); break; case TokenInterface::NO_CREDENTIALS_GIVEN: - $this->securityLogger->warning(sprintf('No credentials given or no account found for token: %s', $token), $this->getLogEnvironmentFromJoinPoint($joinPoint)); + $this->securityLogger->notice(sprintf('No credentials given or no account found for token: %s', $token), $this->getLogEnvironmentFromJoinPoint($joinPoint)); break; } }