[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/components/com_admin/src/Model/ -> SysinfoModel.php (source)

   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  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer