[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package Joomla.Administrator 5 * @subpackage com_admin 6 * 7 * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> 8 * @license GNU General Public License version 2 or later; see LICENSE.txt 9 */ 10 11 namespace Joomla\Component\Admin\Administrator\Model; 12 13 use Joomla\CMS\Component\ComponentHelper; 14 use Joomla\CMS\Factory; 15 use Joomla\CMS\Language\Text; 16 use Joomla\CMS\Log\Log; 17 use Joomla\CMS\MVC\Model\BaseDatabaseModel; 18 use Joomla\CMS\Version; 19 use Joomla\Registry\Registry; 20 21 // phpcs:disable PSR1.Files.SideEffects 22 \defined('_JEXEC') or die; 23 // phpcs:enable PSR1.Files.SideEffects 24 25 /** 26 * Model for the display of system information. 27 * 28 * @since 1.6 29 */ 30 class SysinfoModel extends BaseDatabaseModel 31 { 32 /** 33 * Some PHP settings 34 * 35 * @var array 36 * @since 1.6 37 */ 38 protected $php_settings = []; 39 40 /** 41 * Config values 42 * 43 * @var array 44 * @since 1.6 45 */ 46 protected $config = []; 47 48 /** 49 * Some system values 50 * 51 * @var array 52 * @since 1.6 53 */ 54 protected $info = []; 55 56 /** 57 * PHP info 58 * 59 * @var string 60 * @since 1.6 61 */ 62 protected $php_info = null; 63 64 /** 65 * Array containing the phpinfo() data. 66 * 67 * @var array 68 * 69 * @since 3.5 70 */ 71 protected $phpInfoArray; 72 73 /** 74 * Private/critical data that we don't want to share 75 * 76 * @var array 77 * 78 * @since 3.5 79 */ 80 protected $privateSettings = [ 81 'phpInfoArray' => [ 82 'CONTEXT_DOCUMENT_ROOT', 83 'Cookie', 84 'DOCUMENT_ROOT', 85 'extension_dir', 86 'error_log', 87 'Host', 88 'HTTP_COOKIE', 89 'HTTP_HOST', 90 'HTTP_ORIGIN', 91 'HTTP_REFERER', 92 'HTTP Request', 93 'include_path', 94 'mysql.default_socket', 95 'MYSQL_SOCKET', 96 'MYSQL_INCLUDE', 97 'MYSQL_LIBS', 98 'mysqli.default_socket', 99 'MYSQLI_SOCKET', 100 'PATH', 101 'Path to sendmail', 102 'pdo_mysql.default_socket', 103 'Referer', 104 'REMOTE_ADDR', 105 'SCRIPT_FILENAME', 106 'sendmail_path', 107 'SERVER_ADDR', 108 'SERVER_ADMIN', 109 'Server Administrator', 110 'SERVER_NAME', 111 'Server Root', 112 'session.name', 113 'session.save_path', 114 'upload_tmp_dir', 115 'User/Group', 116 'open_basedir', 117 ], 118 'other' => [ 119 'db', 120 'dbprefix', 121 'fromname', 122 'live_site', 123 'log_path', 124 'mailfrom', 125 'memcached_server_host', 126 'open_basedir', 127 'Origin', 128 'proxy_host', 129 'proxy_user', 130 'proxy_pass', 131 'redis_server_host', 132 'redis_server_auth', 133 'secret', 134 'sendmail', 135 'session.save_path', 136 'session_memcached_server_host', 137 'session_redis_server_host', 138 'session_redis_server_auth', 139 'sitename', 140 'smtphost', 141 'tmp_path', 142 'open_basedir', 143 ] 144 ]; 145 146 /** 147 * System values that can be "safely" shared 148 * 149 * @var array 150 * 151 * @since 3.5 152 */ 153 protected $safeData; 154 155 /** 156 * Information about writable state of directories 157 * 158 * @var array 159 * @since 1.6 160 */ 161 protected $directories = []; 162 163 /** 164 * The current editor. 165 * 166 * @var string 167 * @since 1.6 168 */ 169 protected $editor = null; 170 171 /** 172 * Remove sections of data marked as private in the privateSettings 173 * 174 * @param array $dataArray Array with data that may contain private information 175 * @param string $dataType Type of data to search for a specific section in the privateSettings array 176 * 177 * @return array 178 * 179 * @since 3.5 180 */ 181 protected function cleanPrivateData(array $dataArray, string $dataType = 'other'): array 182 { 183 $dataType = isset($this->privateSettings[$dataType]) ? $dataType : 'other'; 184 185 $privateSettings = $this->privateSettings[$dataType]; 186 187 if (!$privateSettings) { 188 return $dataArray; 189 } 190 191 foreach ($dataArray as $section => $values) { 192 if (\is_array($values)) { 193 $dataArray[$section] = $this->cleanPrivateData($values, $dataType); 194 } 195 196 if (\in_array($section, $privateSettings, true)) { 197 $dataArray[$section] = $this->cleanSectionPrivateData($values); 198 } 199 } 200 201 return $dataArray; 202 } 203 204 /** 205 * Obfuscate section values 206 * 207 * @param mixed $sectionValues Section data 208 * 209 * @return string|array 210 * 211 * @since 3.5 212 */ 213 protected function cleanSectionPrivateData($sectionValues) 214 { 215 if (!\is_array($sectionValues)) { 216 if (strstr($sectionValues, JPATH_ROOT)) { 217 $sectionValues = 'xxxxxx'; 218 } 219 220 return \strlen($sectionValues) ? 'xxxxxx' : ''; 221 } 222 223 foreach ($sectionValues as $setting => $value) { 224 $sectionValues[$setting] = \strlen($value) ? 'xxxxxx' : ''; 225 } 226 227 return $sectionValues; 228 } 229 230 /** 231 * Method to get the PHP settings 232 * 233 * @return array Some PHP settings 234 * 235 * @since 1.6 236 */ 237 public function &getPhpSettings(): array 238 { 239 if (!empty($this->php_settings)) { 240 return $this->php_settings; 241 } 242 243 $this->php_settings = [ 244 'memory_limit' => ini_get('memory_limit'), 245 'upload_max_filesize' => ini_get('upload_max_filesize'), 246 'post_max_size' => ini_get('post_max_size'), 247 'display_errors' => ini_get('display_errors') == '1', 248 'short_open_tag' => ini_get('short_open_tag') == '1', 249 'file_uploads' => ini_get('file_uploads') == '1', 250 'output_buffering' => (int) ini_get('output_buffering') !== 0, 251 'open_basedir' => ini_get('open_basedir'), 252 'session.save_path' => ini_get('session.save_path'), 253 'session.auto_start' => ini_get('session.auto_start'), 254 'disable_functions' => ini_get('disable_functions'), 255 'xml' => \extension_loaded('xml'), 256 'zlib' => \extension_loaded('zlib'), 257 'zip' => \function_exists('zip_open') && \function_exists('zip_read'), 258 'mbstring' => \extension_loaded('mbstring'), 259 'fileinfo' => \extension_loaded('fileinfo'), 260 'gd' => \extension_loaded('gd'), 261 'iconv' => \function_exists('iconv'), 262 'intl' => \function_exists('transliterator_transliterate'), 263 'max_input_vars' => ini_get('max_input_vars'), 264 ]; 265 266 return $this->php_settings; 267 } 268 269 /** 270 * Method to get the config 271 * 272 * @return array config values 273 * 274 * @since 1.6 275 */ 276 public function &getConfig(): array 277 { 278 if (!empty($this->config)) { 279 return $this->config; 280 } 281 282 $registry = new Registry(new \JConfig()); 283 $this->config = $registry->toArray(); 284 $hidden = [ 285 'host', 'user', 'password', 'ftp_user', 'ftp_pass', 286 'smtpuser', 'smtppass', 'redis_server_auth', 'session_redis_server_auth', 287 'proxy_user', 'proxy_pass', 'secret' 288 ]; 289 290 foreach ($hidden as $key) { 291 $this->config[$key] = 'xxxxxx'; 292 } 293 294 return $this->config; 295 } 296 297 /** 298 * Method to get the system information 299 * 300 * @return array System information values 301 * 302 * @since 1.6 303 */ 304 public function &getInfo(): array 305 { 306 if (!empty($this->info)) { 307 return $this->info; 308 } 309 310 $db = $this->getDatabase(); 311 312 $this->info = [ 313 'php' => php_uname(), 314 'dbserver' => $db->getServerType(), 315 'dbversion' => $db->getVersion(), 316 'dbcollation' => $db->getCollation(), 317 'dbconnectioncollation' => $db->getConnectionCollation(), 318 'dbconnectionencryption' => $db->getConnectionEncryption(), 319 'dbconnencryptsupported' => $db->isConnectionEncryptionSupported(), 320 'phpversion' => PHP_VERSION, 321 'server' => $_SERVER['SERVER_SOFTWARE'] ?? getenv('SERVER_SOFTWARE'), 322 'sapi_name' => PHP_SAPI, 323 'version' => (new Version())->getLongVersion(), 324 'useragent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 325 ]; 326 327 return $this->info; 328 } 329 330 /** 331 * Check if the phpinfo function is enabled 332 * 333 * @return boolean True if enabled 334 * 335 * @since 3.4.1 336 */ 337 public function phpinfoEnabled(): bool 338 { 339 return !\in_array('phpinfo', explode(',', ini_get('disable_functions'))); 340 } 341 342 /** 343 * Method to get filter data from the model 344 * 345 * @param string $dataType Type of data to get safely 346 * @param bool $public If true no sensitive information will be removed 347 * 348 * @return array 349 * 350 * @since 3.5 351 */ 352 public function getSafeData(string $dataType, bool $public = true): array 353 { 354 if (isset($this->safeData[$dataType])) { 355 return $this->safeData[$dataType]; 356 } 357 358 $methodName = 'get' . ucfirst($dataType); 359 360 if (!method_exists($this, $methodName)) { 361 return []; 362 } 363 364 $data = $this->$methodName($public); 365 366 $this->safeData[$dataType] = $this->cleanPrivateData($data, $dataType); 367 368 return $this->safeData[$dataType]; 369 } 370 371 /** 372 * Method to get the PHP info 373 * 374 * @return string PHP info 375 * 376 * @since 1.6 377 */ 378 public function &getPHPInfo(): string 379 { 380 if (!$this->phpinfoEnabled()) { 381 $this->php_info = Text::_('COM_ADMIN_PHPINFO_DISABLED'); 382 383 return $this->php_info; 384 } 385 386 if (!\is_null($this->php_info)) { 387 return $this->php_info; 388 } 389 390 ob_start(); 391 date_default_timezone_set('UTC'); 392 phpinfo(INFO_GENERAL | INFO_CONFIGURATION | INFO_MODULES); 393 $phpInfo = ob_get_contents(); 394 ob_end_clean(); 395 preg_match_all('#<body[^>]*>(.*)</body>#siU', $phpInfo, $output); 396 $output = preg_replace('#<table[^>]*>#', '<table class="table">', $output[1][0]); 397 $output = preg_replace('#(\w),(\w)#', '\1, \2', $output); 398 $output = preg_replace('#<hr />#', '', $output); 399 $output = str_replace('<div class="text-center">', '', $output); 400 $output = preg_replace('#<tr class="h">(.*)</tr>#', '<thead><tr class="h">$1</tr></thead><tbody>', $output); 401 $output = str_replace('</table>', '</tbody></table>', $output); 402 $output = str_replace('</div>', '', $output); 403 $this->php_info = $output; 404 405 return $this->php_info; 406 } 407 408 /** 409 * Get phpinfo() output as array 410 * 411 * @return array 412 * 413 * @since 3.5 414 */ 415 public function getPhpInfoArray(): array 416 { 417 // Already cached 418 if (null !== $this->phpInfoArray) { 419 return $this->phpInfoArray; 420 } 421 422 $phpInfo = $this->getPHPInfo(); 423 424 $this->phpInfoArray = $this->parsePhpInfo($phpInfo); 425 426 return $this->phpInfoArray; 427 } 428 429 /** 430 * Method to get a list of installed extensions 431 * 432 * @return array installed extensions 433 * 434 * @since 3.5 435 */ 436 public function getExtensions(): array 437 { 438 $installed = []; 439 $db = Factory::getContainer()->get('DatabaseDriver'); 440 $query = $db->getQuery(true) 441 ->select('*') 442 ->from($db->quoteName('#__extensions')); 443 $db->setQuery($query); 444 445 try { 446 $extensions = $db->loadObjectList(); 447 } catch (\Exception $e) { 448 try { 449 Log::add(Text::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $e->getCode(), $e->getMessage()), Log::WARNING, 'jerror'); 450 } catch (\RuntimeException $exception) { 451 Factory::getApplication()->enqueueMessage( 452 Text::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $e->getCode(), $e->getMessage()), 453 'warning' 454 ); 455 } 456 457 return $installed; 458 } 459 460 if (empty($extensions)) { 461 return $installed; 462 } 463 464 foreach ($extensions as $extension) { 465 if (\strlen($extension->name) == 0) { 466 continue; 467 } 468 469 $installed[$extension->name] = [ 470 'name' => $extension->name, 471 'type' => $extension->type, 472 'state' => $extension->enabled ? Text::_('JENABLED') : Text::_('JDISABLED'), 473 'author' => 'unknown', 474 'version' => 'unknown', 475 'creationDate' => 'unknown', 476 'authorUrl' => 'unknown', 477 ]; 478 479 $manifest = new Registry($extension->manifest_cache); 480 481 $extraData = [ 482 'author' => $manifest->get('author', ''), 483 'version' => $manifest->get('version', ''), 484 'creationDate' => $manifest->get('creationDate', ''), 485 'authorUrl' => $manifest->get('authorUrl', '') 486 ]; 487 488 $installed[$extension->name] = array_merge($installed[$extension->name], $extraData); 489 } 490 491 return $installed; 492 } 493 494 /** 495 * Method to get the directory states 496 * 497 * @param bool $public If true no information is going to be removed 498 * 499 * @return array States of directories 500 * 501 * @throws \Exception 502 * @since 1.6 503 */ 504 public function getDirectory(bool $public = false): array 505 { 506 if (!empty($this->directories)) { 507 return $this->directories; 508 } 509 510 $this->directories = []; 511 512 $registry = Factory::getApplication()->getConfig(); 513 $cparams = ComponentHelper::getParams('com_media'); 514 515 $this->addDirectory('administrator/components', JPATH_ADMINISTRATOR . '/components'); 516 $this->addDirectory('administrator/components/com_joomlaupdate', JPATH_ADMINISTRATOR . '/components/com_joomlaupdate'); 517 $this->addDirectory('administrator/language', JPATH_ADMINISTRATOR . '/language'); 518 519 // List all admin languages 520 $admin_langs = new \DirectoryIterator(JPATH_ADMINISTRATOR . '/language'); 521 522 foreach ($admin_langs as $folder) { 523 if ($folder->isDot() || !$folder->isDir()) { 524 continue; 525 } 526 527 $this->addDirectory( 528 'administrator/language/' . $folder->getFilename(), 529 JPATH_ADMINISTRATOR . '/language/' . $folder->getFilename() 530 ); 531 } 532 533 // List all manifests folders 534 $manifests = new \DirectoryIterator(JPATH_ADMINISTRATOR . '/manifests'); 535 536 foreach ($manifests as $folder) { 537 if ($folder->isDot() || !$folder->isDir()) { 538 continue; 539 } 540 541 $this->addDirectory( 542 'administrator/manifests/' . $folder->getFilename(), 543 JPATH_ADMINISTRATOR . '/manifests/' . $folder->getFilename() 544 ); 545 } 546 547 $this->addDirectory('administrator/modules', JPATH_ADMINISTRATOR . '/modules'); 548 $this->addDirectory('administrator/templates', JPATH_THEMES); 549 550 $this->addDirectory('components', JPATH_SITE . '/components'); 551 552 $this->addDirectory($cparams->get('image_path'), JPATH_SITE . '/' . $cparams->get('image_path')); 553 554 // List all images folders 555 $image_folders = new \DirectoryIterator(JPATH_SITE . '/' . $cparams->get('image_path')); 556 557 foreach ($image_folders as $folder) { 558 if ($folder->isDot() || !$folder->isDir()) { 559 continue; 560 } 561 562 $this->addDirectory( 563 'images/' . $folder->getFilename(), 564 JPATH_SITE . '/' . $cparams->get('image_path') . '/' . $folder->getFilename() 565 ); 566 } 567 568 $this->addDirectory('language', JPATH_SITE . '/language'); 569 570 // List all site languages 571 $site_langs = new \DirectoryIterator(JPATH_SITE . '/language'); 572 573 foreach ($site_langs as $folder) { 574 if ($folder->isDot() || !$folder->isDir()) { 575 continue; 576 } 577 578 $this->addDirectory('language/' . $folder->getFilename(), JPATH_SITE . '/language/' . $folder->getFilename()); 579 } 580 581 $this->addDirectory('libraries', JPATH_LIBRARIES); 582 583 $this->addDirectory('media', JPATH_SITE . '/media'); 584 $this->addDirectory('modules', JPATH_SITE . '/modules'); 585 $this->addDirectory('plugins', JPATH_PLUGINS); 586 587 $plugin_groups = new \DirectoryIterator(JPATH_SITE . '/plugins'); 588 589 foreach ($plugin_groups as $folder) { 590 if ($folder->isDot() || !$folder->isDir()) { 591 continue; 592 } 593 594 $this->addDirectory('plugins/' . $folder->getFilename(), JPATH_PLUGINS . '/' . $folder->getFilename()); 595 } 596 597 $this->addDirectory('templates', JPATH_SITE . '/templates'); 598 $this->addDirectory('configuration.php', JPATH_CONFIGURATION . '/configuration.php'); 599 600 // Is there a cache path in configuration.php? 601 if ($cache_path = trim($registry->get('cache_path', ''))) { 602 // Frontend and backend use same directory for caching. 603 $this->addDirectory($cache_path, $cache_path, 'COM_ADMIN_CACHE_DIRECTORY'); 604 } else { 605 $this->addDirectory('administrator/cache', JPATH_CACHE, 'COM_ADMIN_CACHE_DIRECTORY'); 606 } 607 608 $this->addDirectory('media/cache', JPATH_ROOT . '/media/cache', 'COM_ADMIN_MEDIA_CACHE_DIRECTORY'); 609 610 if ($public) { 611 $this->addDirectory( 612 'log', 613 $registry->get('log_path', JPATH_ADMINISTRATOR . '/logs'), 614 'COM_ADMIN_LOG_DIRECTORY' 615 ); 616 $this->addDirectory( 617 'tmp', 618 $registry->get('tmp_path', JPATH_ROOT . '/tmp'), 619 'COM_ADMIN_TEMP_DIRECTORY' 620 ); 621 } else { 622 $this->addDirectory( 623 $registry->get('log_path', JPATH_ADMINISTRATOR . '/logs'), 624 $registry->get('log_path', JPATH_ADMINISTRATOR . '/logs'), 625 'COM_ADMIN_LOG_DIRECTORY' 626 ); 627 $this->addDirectory( 628 $registry->get('tmp_path', JPATH_ROOT . '/tmp'), 629 $registry->get('tmp_path', JPATH_ROOT . '/tmp'), 630 'COM_ADMIN_TEMP_DIRECTORY' 631 ); 632 } 633 634 return $this->directories; 635 } 636 637 /** 638 * Method to add a directory 639 * 640 * @param string $name Directory Name 641 * @param string $path Directory path 642 * @param string $message Message 643 * 644 * @return void 645 * 646 * @since 1.6 647 */ 648 private function addDirectory(string $name, string $path, string $message = ''): void 649 { 650 $this->directories[$name] = ['writable' => is_writable($path), 'message' => $message,]; 651 } 652 653 /** 654 * Method to get the editor 655 * 656 * @return string The default editor 657 * 658 * @note Has to be removed (it is present in the config...) 659 * @since 1.6 660 */ 661 public function &getEditor(): string 662 { 663 if (!is_null($this->editor)) { 664 return $this->editor; 665 } 666 667 $this->editor = Factory::getApplication()->get('editor'); 668 669 return $this->editor; 670 } 671 672 /** 673 * Parse phpinfo output into an array 674 * Source https://gist.github.com/sbmzhcn/6255314 675 * 676 * @param string $html Output of phpinfo() 677 * 678 * @return array 679 * 680 * @since 3.5 681 */ 682 protected function parsePhpInfo(string $html): array 683 { 684 $html = strip_tags($html, '<h2><th><td>'); 685 $html = preg_replace('/<th[^>]*>([^<]+)<\/th>/', '<info>\1</info>', $html); 686 $html = preg_replace('/<td[^>]*>([^<]+)<\/td>/', '<info>\1</info>', $html); 687 $t = preg_split('/(<h2[^>]*>[^<]+<\/h2>)/', $html, -1, PREG_SPLIT_DELIM_CAPTURE); 688 $r = []; 689 $count = \count($t); 690 $p1 = '<info>([^<]+)<\/info>'; 691 $p2 = '/' . $p1 . '\s*' . $p1 . '\s*' . $p1 . '/'; 692 $p3 = '/' . $p1 . '\s*' . $p1 . '/'; 693 694 for ($i = 1; $i < $count; $i++) { 695 if (preg_match('/<h2[^>]*>([^<]+)<\/h2>/', $t[$i], $matches)) { 696 $name = trim($matches[1]); 697 $vals = explode("\n", $t[$i + 1]); 698 699 foreach ($vals as $val) { 700 // 3cols 701 if (preg_match($p2, $val, $matches)) { 702 $r[$name][trim($matches[1])] = [trim($matches[2]), trim($matches[3]),]; 703 } elseif (preg_match($p3, $val, $matches)) { 704 // 2cols 705 $r[$name][trim($matches[1])] = trim($matches[2]); 706 } 707 } 708 } 709 } 710 711 return $r; 712 } 713 }
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 |