6f25a655060665e0b9153ccf838fd078ef9edcda
[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\Authentication\CommandLineUserAuthentication;
20 use TYPO3\CMS\Core\Console\RequestHandlerInterface;
21 use TYPO3\CMS\Core\Core\Bootstrap;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23
24 /**
25 * Command Line Interface Request Handler dealing with "cliKey"-based Commands from the cli_dispatch.phpsh script.
26 * Picks up requests only when coming from the CLI mode.
27 * Resolves the "cliKey" which is registered inside $TYPO3_CONF_VARS[SC_OPTIONS][GLOBAL][cliKeys]
28 * and includes the CLI-based script or exits if no valid "cliKey" is found.
29 * Also logs into the system as a backend user which needs to be added to the database called _CLI_mymodule
30 *
31 * This class is deprecated in favor of the Core-based CommandRequestHandler, which uses Symfony Commands.
32 */
33 class CliRequestHandler implements RequestHandlerInterface
34 {
35 /**
36 * Instance of the current TYPO3 bootstrap
37 * @var Bootstrap
38 */
39 protected $bootstrap;
40
41 /**
42 * Constructor handing over the bootstrap
43 *
44 * @param Bootstrap $bootstrap
45 */
46 public function __construct(Bootstrap $bootstrap)
47 {
48 $this->bootstrap = $bootstrap;
49 }
50
51 /**
52 * Handles any commandline request
53 *
54 * @param InputInterface $input
55 */
56 public function handleRequest(InputInterface $input)
57 {
58 GeneralUtility::deprecationLog('Using cli_dispatch.phpsh as entry point for CLI commands has been marked '
59 . 'as deprecated and will be removed in TYPO3 v9. Please use the new CLI entrypoint via /typo3/sysext/core/bin/typo3 instead.');
60 $output = GeneralUtility::makeInstance(ConsoleOutput::class);
61 $exitCode = 0;
62
63 try {
64 $command = $this->validateCommandLineKeyFromInput($input);
65
66 // try and look up if the CLI command exists
67 $commandLineScript = $this->getIncludeScriptByCommandLineKey($command);
68 $this->boot();
69
70 if (is_callable($commandLineScript)) {
71 call_user_func($commandLineScript, $input, $output);
72 } else {
73 // include the CLI script
74 include($commandLineScript);
75 }
76 } catch (\InvalidArgumentException $e) {
77 $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
78 $output->writeln('');
79 $output->writeln('Valid keys are:');
80 $output->writeln('');
81 $cliKeys = array_keys($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys']);
82 asort($cliKeys);
83 foreach ($cliKeys as $key => $value) {
84 $output->writeln(' ' . $value);
85 }
86 $exitCode = $e->getCode();
87 } catch (\RuntimeException $e) {
88 $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
89 $exitCode = $e->getCode();
90 } catch (\Throwable $e) {
91 $output->writeln('<error>Oops, an error occurred: ' . $e->getMessage() . '</error>');
92 $exitCode = $e->getCode();
93 }
94
95 exit($exitCode);
96 }
97
98 /**
99 * Execute TYPO3 bootstrap
100 *
101 * @throws \RuntimeException when the _CLI_ user cannot be authenticated properly
102 */
103 protected function boot()
104 {
105 $this->bootstrap
106 ->loadBaseTca()
107 ->loadExtTables()
108 ->initializeBackendUser(CommandLineUserAuthentication::class);
109
110 // Checks for a user _CLI_, if non exists, will create one
111 $this->loadCommandLineBackendUser();
112
113 $this->bootstrap
114 ->initializeLanguageObject()
115 // Make sure output is not buffered, so command-line output and interaction can take place
116 ->endOutputBufferingAndCleanPreviousOutput();
117 }
118
119 /**
120 * Check CLI parameters.
121 * First argument is a key that points to the script configuration.
122 * If it is not set or not valid, the script exits with an error message.
123 *
124 * @param InputInterface $input an instance of the input given to the CLI call
125 * @return string the CLI key in use
126 * @throws \InvalidArgumentException
127 */
128 protected function validateCommandLineKeyFromInput(InputInterface $input)
129 {
130 $cliKey = $input->getFirstArgument();
131 if (empty($cliKey)) {
132 throw new \InvalidArgumentException('This script must have a command as first argument.', 1476107418);
133 } elseif (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys'][$cliKey])) {
134 throw new \InvalidArgumentException('This supplied command is not valid.', 1476107480);
135 }
136 return $cliKey;
137 }
138
139 /**
140 * Define cli-related parameters and return the include script.
141 *
142 * @param string $cliKey the CLI key
143 * @return string the absolute path to the include script
144 */
145 protected function getIncludeScriptByCommandLineKey($cliKey)
146 {
147 $commandLineScript = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['cliKeys'][$cliKey][0];
148 if (!is_callable($commandLineScript)) {
149 $commandLineScript = GeneralUtility::getFileAbsFileName($commandLineScript);
150 }
151
152 // the CLI key (e.g. "extbase" or "lowlevel"), is removed from the argv, but the script path is kept
153 $cliScriptPath = array_shift($_SERVER['argv']);
154 array_shift($_SERVER['argv']);
155 array_unshift($_SERVER['argv'], $cliScriptPath);
156 return $commandLineScript;
157 }
158
159 /**
160 * If the backend script is in CLI mode, it will try to load a backend user named _cli_
161 *
162 * @throws \RuntimeException if a non-admin Backend user could not be loaded
163 */
164 protected function loadCommandLineBackendUser()
165 {
166 if ($GLOBALS['BE_USER']->user['uid']) {
167 throw new \RuntimeException('Another user was already loaded which is impossible in CLI mode!', 1476107444);
168 }
169 $GLOBALS['BE_USER']->authenticate();
170 }
171
172 /**
173 * This request handler can handle any CLI request.
174 *
175 * @param InputInterface $input
176 * @return bool Always TRUE
177 */
178 public function canHandleRequest(InputInterface $input)
179 {
180 return true;
181 }
182
183 /**
184 * Returns the priority - how eager the handler is to actually handle the request.
185 *
186 * @return int The priority of the request handler.
187 */
188 public function getPriority()
189 {
190 return 20;
191 }
192 }