[!!!][TASK] Remove legacy CLI-related constants and variables
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Console / CliRequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Backend\Console;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Symfony\Component\Console\Input\InputInterface;
18 use Symfony\Component\Console\Output\ConsoleOutput;
19 use TYPO3\CMS\Core\Console\RequestHandlerInterface;
20 use TYPO3\CMS\Core\Core\Bootstrap;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23 /**
24 * Command Line Interface Request Handler dealing with "cliKey"-based Commands from the cli_dispatch.phpsh script.
25 * Picks up requests only when coming from the CLI mode.
26 * Resolves the "cliKey" which is registered inside $TYPO3_CONF_VARS[SC_OPTIONS][GLOBAL][cliKeys]
27 * and includes the CLI-based script or exits if no valid "cliKey" is found.
28 * Also logs into the system as a backend user which needs to be added to the database called _CLI_mymodule
29 */
30 class CliRequestHandler implements RequestHandlerInterface
31 {
32 /**
33 * Instance of the current TYPO3 bootstrap
34 * @var Bootstrap
35 */
36 protected $bootstrap;
37
38 /**
39 * Constructor handing over the bootstrap
40 *
41 * @param Bootstrap $bootstrap
42 */
43 public function __construct(Bootstrap $bootstrap)
44 {
45 $this->bootstrap = $bootstrap;
46 }
47
48 /**
49 * Handles any commandline request
50 *
51 * @param InputInterface $input
52 * @return void
53 */
54 public function handleRequest(InputInterface $input)
55 {
56 $output = GeneralUtility::makeInstance(ConsoleOutput::class);
57 $exitCode = 0;
58
59 try {
60 $command = $this->validateCommandLineKeyFromInput($input);
61
62 // try and look up if the CLI command user exists, throws an exception if the CLI
63 // user cannot be found
64 list($commandLineScript, $commandLineName) = $this->getIncludeScriptByCommandLineKey($command);
65 $this->boot($commandLineName);
66
67 if (is_callable($commandLineScript)) {
68 call_user_func($commandLineScript);
69 } else {
70 // include the CLI script
71 include($commandLineScript);
72 }
73 } catch (\InvalidArgumentException $e) {
74 $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
75 $output->writeln('');
76 $output->writeln('Valid keys are:');
77 $output->writeln('');
78 $cliKeys = array_keys($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys']);
79 asort($cliKeys);
80 foreach ($cliKeys as $key => $value) {
81 $output->writeln(' ' . $value);
82 }
83 $exitCode = $e->getCode();
84 } catch (\RuntimeException $e) {
85 $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
86 $exitCode = $e->getCode();
87 } catch (\Throwable $e) {
88 $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
89 $exitCode = $e->getCode();
90 }
91
92 exit($exitCode);
93 }
94
95 /**
96 * Execute TYPO3 bootstrap
97 *
98 * @throws \RuntimeException when the _CLI_ user cannot be authenticated properly
99 */
100 protected function boot($commandLineName)
101 {
102 $this->bootstrap
103 ->loadExtensionTables()
104 ->initializeBackendUser();
105
106 // Checks for a user called starting with _CLI_ e.g. "_CLI_lowlevel"
107 $this->loadCommandLineBackendUser($commandLineName);
108
109 $this->bootstrap
110 ->initializeBackendAuthentication()
111 ->initializeLanguageObject()
112 // Make sure output is not buffered, so command-line output and interaction can take place
113 ->endOutputBufferingAndCleanPreviousOutput();
114 }
115
116 /**
117 * Check CLI parameters.
118 * First argument is a key that points to the script configuration.
119 * If it is not set or not valid, the script exits with an error message.
120 *
121 * @param InputInterface $input an instance of the input given to the CLI call
122 * @return string the CLI key in use
123 * @throws \InvalidArgumentException
124 */
125 protected function validateCommandLineKeyFromInput(InputInterface $input)
126 {
127 $cliKey = $input->getFirstArgument();
128 if (empty($cliKey)) {
129 throw new \InvalidArgumentException('This script must have a command as first argument.', 1476107418);
130 } elseif (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys'][$cliKey])) {
131 throw new \InvalidArgumentException('This supplied command is not valid.', 1476107480);
132 }
133 return $cliKey;
134 }
135
136 /**
137 * Define cli-related parameters and return the include script as well as the command line name. Used for
138 * authentication against the backend user in the "loadCommandLineBackendUser()" action.
139 *
140 * @param string $cliKey the CLI key
141 * @return array the absolute path to the include script and the command line name
142 */
143 protected function getIncludeScriptByCommandLineKey($cliKey)
144 {
145 list($commandLineScript, $commandLineName) = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys'][$cliKey];
146 if (!is_callable($commandLineScript)) {
147 $commandLineScript = GeneralUtility::getFileAbsFileName($commandLineScript);
148 }
149
150 // the CLI key (e.g. "extbase" or "lowlevel"), is removed from the argv, but the script path is kept
151 $cliScriptPath = array_shift($_SERVER['argv']);
152 array_shift($_SERVER['argv']);
153 array_unshift($_SERVER['argv'], $cliScriptPath);
154 return [$commandLineScript, $commandLineName];
155 }
156
157 /**
158 * If the backend script is in CLI mode, it will try to load a backend user named by the CLI module name (in lowercase)
159 *
160 * @param string $commandLineName the name of the module registered inside $TYPO3_CONF_VARS[SC_OPTIONS][GLOBAL][cliKeys] as second parameter
161 * @throws \RuntimeException if a non-admin Backend user could not be loaded
162 */
163 protected function loadCommandLineBackendUser($commandLineName)
164 {
165 if ($GLOBALS['BE_USER']->user['uid']) {
166 throw new \RuntimeException('Another user was already loaded which is impossible in CLI mode!', 1476107444);
167 }
168 if (strpos($commandLineName, '_CLI_') !== 0) {
169 throw new \RuntimeException('Module name, "' . $commandLineName . '", was not prefixed with "_CLI_"', 1476107445);
170 }
171 $userName = strtolower($commandLineName);
172 $GLOBALS['BE_USER']->setBeUserByName($userName);
173 if (!$GLOBALS['BE_USER']->user['uid']) {
174 throw new \RuntimeException('No backend user named "' . $userName . '" was found!', 1476107195);
175 }
176 if ($GLOBALS['BE_USER']->isAdmin()) {
177 throw new \RuntimeException('CLI backend user "' . $userName . '" was ADMIN which is not allowed!', 1476107446);
178 }
179 }
180
181 /**
182 * This request handler can handle any CLI request.
183 *
184 * @param InputInterface $input
185 * @return bool Always TRUE
186 */
187 public function canHandleRequest(InputInterface $input)
188 {
189 return true;
190 }
191
192 /**
193 * Returns the priority - how eager the handler is to actually handle the request.
194 *
195 * @return int The priority of the request handler.
196 */
197 public function getPriority()
198 {
199 return 20;
200 }
201 }