[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 */ 9 10 namespace Joomla\CMS\Console; 11 12 use Joomla\CMS\Factory; 13 use Joomla\CMS\Language\Text; 14 use Joomla\Console\Command\AbstractCommand; 15 use Joomla\Database\DatabaseDriver; 16 use Joomla\Registry\Registry; 17 use Symfony\Component\Console\Input\Input; 18 use Symfony\Component\Console\Input\InputArgument; 19 use Symfony\Component\Console\Input\InputInterface; 20 use Symfony\Component\Console\Output\OutputInterface; 21 use Symfony\Component\Console\Style\SymfonyStyle; 22 23 // phpcs:disable PSR1.Files.SideEffects 24 \defined('JPATH_PLATFORM') or die; 25 // phpcs:enable PSR1.Files.SideEffects 26 27 /** 28 * Console command Setting Configuration options 29 * 30 * @since 4.0.0 31 */ 32 class SetConfigurationCommand extends AbstractCommand 33 { 34 /** 35 * The default command name 36 * 37 * @var string 38 * @since 4.0.0 39 */ 40 protected static $defaultName = 'config:set'; 41 42 /** 43 * Stores the Input Object 44 * @var Input 45 * @since 4.0.0 46 */ 47 private $cliInput; 48 49 /** 50 * SymfonyStyle Object 51 * @var SymfonyStyle 52 * @since 4.0.0 53 */ 54 private $ioStyle; 55 56 /** 57 * Options Array 58 * @var array 59 * @since 4.0.0 60 */ 61 private $options; 62 63 64 /** 65 * Return code if configuration is set successfully 66 * @since 4.0.0 67 */ 68 public const CONFIG_SET_SUCCESSFUL = 0; 69 70 /** 71 * Return code if configuration set failed 72 * @since 4.0.0 73 */ 74 public const CONFIG_SET_FAILED = 1; 75 76 /** 77 * Return code if config validation failed 78 * @since 4.0.0 79 */ 80 public const CONFIG_VALIDATION_FAILED = 2; 81 82 /** 83 * Return code if options are wrong 84 * @since 4.0.0 85 */ 86 public const CONFIG_OPTIONS_WRONG = 3; 87 88 /** 89 * Return code if database validation failed 90 * @since 4.0.0 91 */ 92 public const DB_VALIDATION_FAILED = 4; 93 94 /** 95 * Configures the IO 96 * 97 * @param InputInterface $input Console Input 98 * @param OutputInterface $output Console Output 99 * 100 * @return void 101 * 102 * @since 4.0.0 103 * 104 */ 105 private function configureIO(InputInterface $input, OutputInterface $output) 106 { 107 $language = Factory::getLanguage(); 108 $language->load('', JPATH_INSTALLATION, null, false, false) || 109 $language->load('', JPATH_INSTALLATION, null, true); 110 $language->load('com_config', JPATH_ADMINISTRATOR, null, false, false) || 111 $language->load('com_config', JPATH_ADMINISTRATOR, null, true); 112 $this->cliInput = $input; 113 $this->ioStyle = new SymfonyStyle($input, $output); 114 } 115 116 /** 117 * Collects options from user input 118 * 119 * @param array $options Options input by users 120 * 121 * @return boolean 122 * 123 * @since 4.0.0 124 */ 125 private function retrieveOptionsFromInput(array $options): bool 126 { 127 $collected = []; 128 129 foreach ($options as $option) { 130 if (strpos($option, '=') === false) { 131 $this->ioStyle->error('Options and values should be separated by "="'); 132 133 return false; 134 } 135 136 list($option, $value) = explode('=', $option); 137 138 $collected[$option] = $value; 139 } 140 141 $this->options = $collected; 142 143 return true; 144 } 145 146 /** 147 * Validates the options provided 148 * 149 * @return boolean 150 * 151 * @since 4.0.0 152 */ 153 private function validateOptions(): bool 154 { 155 $config = $this->getInitialConfigurationOptions(); 156 157 $configs = $config->toArray(); 158 159 $valid = true; 160 array_walk( 161 $this->options, 162 function ($value, $key) use ($configs, &$valid) { 163 if (!array_key_exists($key, $configs)) { 164 $this->ioStyle->error("Can't find option *$key* in configuration list"); 165 $valid = false; 166 } 167 } 168 ); 169 170 return $valid; 171 } 172 173 /** 174 * Sets the options array 175 * 176 * @param string $options Options string 177 * 178 * @since 4.0.0 179 * 180 * @return void 181 */ 182 public function setOptions($options) 183 { 184 $this->options = explode(' ', $options); 185 } 186 187 /** 188 * Collects the options array 189 * 190 * @return array|mixed 191 * 192 * @since 4.0.0 193 */ 194 public function getOptions() 195 { 196 return $this->cliInput->getArgument('options'); 197 } 198 199 /** 200 * Returns Default configuration Object 201 * 202 * @return Registry 203 * 204 * @since 4.0.0 205 */ 206 public function getInitialConfigurationOptions(): Registry 207 { 208 return (new Registry(new \JConfig())); 209 } 210 211 212 /** 213 * Save the configuration file 214 * 215 * @param array $options Options array 216 * 217 * @return boolean 218 * 219 * @since 4.0.0 220 */ 221 public function saveConfiguration($options): bool 222 { 223 $app = $this->getApplication(); 224 225 // Check db connection encryption properties 226 $model = $app->bootComponent('com_config')->getMVCFactory($app)->createModel('Application', 'Administrator'); 227 228 if (!$model->save($options)) { 229 $this->ioStyle->error(Text::_('Failed to save properties')); 230 231 return false; 232 } 233 234 return true; 235 } 236 237 /** 238 * Initialise the command. 239 * 240 * @return void 241 * 242 * @since 4.0.0 243 */ 244 protected function configure(): void 245 { 246 $this->addArgument( 247 'options', 248 InputArgument::REQUIRED | InputArgument::IS_ARRAY, 249 'All the options you want to set' 250 ); 251 252 $help = "<info>%command.name%</info> sets the value for a configuration option 253 \nUsage: <info>php %command.full_name%</info> <option>=<value>"; 254 255 $this->setDescription('Set a value for a configuration option'); 256 $this->setHelp($help); 257 } 258 259 /** 260 * Verifies database connection 261 * 262 * @param array $options Options array 263 * 264 * @return boolean|\Joomla\Database\DatabaseInterface 265 * 266 * @since 4.0.0 267 * @throws \Exception 268 */ 269 public function checkDb($options): bool 270 { 271 // Ensure a database type was selected. 272 if (empty($options['dbtype'])) { 273 $this->ioStyle->error(Text::_('INSTL_DATABASE_INVALID_TYPE')); 274 275 return false; 276 } 277 278 // Ensure that a hostname and user name were input. 279 if (empty($options['host']) || empty($options['user'])) { 280 $this->ioStyle->error(Text::_('INSTL_DATABASE_INVALID_DB_DETAILS')); 281 282 return false; 283 } 284 285 // Validate database table prefix. 286 if (isset($options['dbprefix']) && !preg_match('#^[a-zA-Z]+[a-zA-Z0-9_]*$#', $options['dbprefix'])) { 287 $this->ioStyle->error(Text::_('INSTL_DATABASE_PREFIX_MSG')); 288 289 return false; 290 } 291 292 // Validate length of database table prefix. 293 if (isset($options['dbprefix']) && strlen($options['dbprefix']) > 15) { 294 $this->ioStyle->error(Text::_('INSTL_DATABASE_FIX_TOO_LONG'), 'warning'); 295 296 return false; 297 } 298 299 // Validate length of database name. 300 if (strlen($options['db']) > 64) { 301 $this->ioStyle->error(Text::_('INSTL_DATABASE_NAME_TOO_LONG')); 302 303 return false; 304 } 305 306 // Validate database name. 307 if (in_array($options['dbtype'], ['pgsql', 'postgresql'], true) && !preg_match('#^[a-zA-Z_][0-9a-zA-Z_$]*$#', $options['db'])) { 308 $this->ioStyle->error(Text::_('INSTL_DATABASE_NAME_MSG_POSTGRES')); 309 310 return false; 311 } 312 313 if (in_array($options['dbtype'], ['mysql', 'mysqli']) && preg_match('#[\\\\\/]#', $options['db'])) { 314 $this->ioStyle->error(Text::_('INSTL_DATABASE_NAME_MSG_MYSQL')); 315 316 return false; 317 } 318 319 // Workaround for UPPERCASE table prefix for PostgreSQL 320 if (in_array($options['dbtype'], ['pgsql', 'postgresql'])) { 321 if (isset($options['dbprefix']) && strtolower($options['dbprefix']) !== $options['dbprefix']) { 322 $this->ioStyle->error(Text::_('INSTL_DATABASE_FIX_LOWERCASE')); 323 324 return false; 325 } 326 } 327 328 $app = $this->getApplication(); 329 330 // Check db connection encryption properties 331 $model = $app->bootComponent('com_config')->getMVCFactory($app)->createModel('Application', 'Administrator'); 332 333 if (!$model->validateDbConnection($options)) { 334 $this->ioStyle->error(Text::_('Failed to validate the db connection encryption properties')); 335 336 return false; 337 } 338 339 // Build the connection options array. 340 $settings = [ 341 'driver' => $options['dbtype'], 342 'host' => $options['host'], 343 'user' => $options['user'], 344 'password' => $options['password'], 345 'database' => $options['db'], 346 'prefix' => $options['dbprefix'], 347 ]; 348 349 if ((int) $options['dbencryption'] !== 0) { 350 $settings['ssl'] = [ 351 'enable' => true, 352 'verify_server_cert' => (bool) $options['dbsslverifyservercert'], 353 ]; 354 355 foreach (['cipher', 'ca', 'key', 'cert'] as $value) { 356 $confVal = trim($options['dbssl' . $value]); 357 358 if ($confVal !== '') { 359 $settings['ssl'][$value] = $confVal; 360 } 361 } 362 } 363 364 // Get a database object. 365 try { 366 $db = DatabaseDriver::getInstance($settings); 367 $db->getVersion(); 368 } catch (\Exception $e) { 369 $this->ioStyle->error( 370 Text::sprintf( 371 'Cannot connect to database, verify that you specified the correct database details %s', 372 $e->getMessage() 373 ) 374 ); 375 376 return false; 377 } 378 379 if ((int) $options['dbencryption'] !== 0 && empty($db->getConnectionEncryption())) { 380 if ($db->isConnectionEncryptionSupported()) { 381 $this->ioStyle->error(Text::_('COM_CONFIG_ERROR_DATABASE_ENCRYPTION_CONN_NOT_ENCRYPT')); 382 } else { 383 $this->ioStyle->error(Text::_('COM_CONFIG_ERROR_DATABASE_ENCRYPTION_SRV_NOT_SUPPORTS')); 384 } 385 386 return false; 387 } 388 389 return true; 390 } 391 392 /** 393 * Internal function to execute the command. 394 * 395 * @param InputInterface $input The input to inject into the command. 396 * @param OutputInterface $output The output to inject into the command. 397 * 398 * @return integer The command exit code 399 * 400 * @since 4.0.0 401 * @throws \Exception 402 */ 403 protected function doExecute(InputInterface $input, OutputInterface $output): int 404 { 405 $this->configureIO($input, $output); 406 407 $options = $this->getOptions(); 408 409 if (!$this->retrieveOptionsFromInput($options)) { 410 return self::CONFIG_OPTIONS_WRONG; 411 } 412 413 if (!$this->validateOptions()) { 414 return self::CONFIG_VALIDATION_FAILED; 415 } 416 417 $initialOptions = $this->getInitialConfigurationOptions()->toArray(); 418 419 $combinedOptions = $this->sanitizeOptions(array_merge($initialOptions, $this->options)); 420 421 if (!$this->checkDb($combinedOptions)) { 422 return self::DB_VALIDATION_FAILED; 423 } 424 425 if ($this->saveConfiguration($combinedOptions)) { 426 $this->ioStyle->success('Configuration set'); 427 428 return self::CONFIG_SET_SUCCESSFUL; 429 } 430 431 return self::CONFIG_SET_FAILED; 432 } 433 434 /** 435 * Sanitize the options array for boolean 436 * 437 * @param array $options Options array 438 * 439 * @return array 440 * 441 * @since 4.0.0 442 */ 443 public function sanitizeOptions(array $options): array 444 { 445 foreach ($options as $key => $value) { 446 $value = $value === 'false' ? false : $value; 447 $value = $value === 'true' ? true : $value; 448 449 $options[$key] = $value; 450 } 451 452 return $options; 453 } 454 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |