[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/administrator/components/com_installer/src/Model/ -> InstallModel.php (source)

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Administrator
   5   * @subpackage  com_installer
   6   *
   7   * @copyright   (C) 2006 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\Installer\Administrator\Model;
  12  
  13  use Joomla\CMS\Factory;
  14  use Joomla\CMS\Filesystem\File;
  15  use Joomla\CMS\Filesystem\Path;
  16  use Joomla\CMS\Installer\Installer;
  17  use Joomla\CMS\Installer\InstallerHelper;
  18  use Joomla\CMS\Language\Text;
  19  use Joomla\CMS\MVC\Model\BaseDatabaseModel;
  20  use Joomla\CMS\Plugin\PluginHelper;
  21  use Joomla\CMS\Router\Route;
  22  use Joomla\CMS\Updater\Update;
  23  use Joomla\CMS\Uri\Uri;
  24  
  25  // phpcs:disable PSR1.Files.SideEffects
  26  \defined('_JEXEC') or die;
  27  // phpcs:enable PSR1.Files.SideEffects
  28  
  29  /**
  30   * Extension Manager Install Model
  31   *
  32   * @since  1.5
  33   */
  34  class InstallModel extends BaseDatabaseModel
  35  {
  36      /**
  37       * @var \Joomla\CMS\Table\Table Table object
  38       */
  39      protected $_table = null;
  40  
  41      /**
  42       * @var string URL
  43       */
  44      protected $_url = null;
  45  
  46      /**
  47       * Model context string.
  48       *
  49       * @var     string
  50       */
  51      protected $_context = 'com_installer.install';
  52  
  53      /**
  54       * Method to auto-populate the model state.
  55       *
  56       * Note. Calling getState in this method will result in recursion.
  57       *
  58       * @return  void
  59       *
  60       * @since   1.6
  61       */
  62      protected function populateState()
  63      {
  64          $app = Factory::getApplication();
  65  
  66          $this->setState('message', $app->getUserState('com_installer.message'));
  67          $this->setState('extension_message', $app->getUserState('com_installer.extension_message'));
  68          $app->setUserState('com_installer.message', '');
  69          $app->setUserState('com_installer.extension_message', '');
  70  
  71          parent::populateState();
  72      }
  73  
  74      /**
  75       * Install an extension from either folder, URL or upload.
  76       *
  77       * @return  boolean
  78       *
  79       * @since   1.5
  80       */
  81      public function install()
  82      {
  83          $this->setState('action', 'install');
  84  
  85          $app = Factory::getApplication();
  86  
  87          // Load installer plugins for assistance if required:
  88          PluginHelper::importPlugin('installer');
  89  
  90          $package = null;
  91  
  92          // This event allows an input pre-treatment, a custom pre-packing or custom installation.
  93          // (e.g. from a \JSON description).
  94          $results = $app->triggerEvent('onInstallerBeforeInstallation', array($this, &$package));
  95  
  96          if (in_array(true, $results, true)) {
  97              return true;
  98          }
  99  
 100          if (in_array(false, $results, true)) {
 101              return false;
 102          }
 103  
 104          $installType = $app->input->getWord('installtype');
 105          $installLang = $app->input->getWord('package');
 106  
 107          if ($package === null) {
 108              switch ($installType) {
 109                  case 'folder':
 110                      // Remember the 'Install from Directory' path.
 111                      $app->getUserStateFromRequest($this->_context . '.install_directory', 'install_directory');
 112                      $package = $this->_getPackageFromFolder();
 113                      break;
 114  
 115                  case 'upload':
 116                      $package = $this->_getPackageFromUpload();
 117                      break;
 118  
 119                  case 'url':
 120                      $package = $this->_getPackageFromUrl();
 121                      break;
 122  
 123                  default:
 124                      $app->setUserState('com_installer.message', Text::_('COM_INSTALLER_NO_INSTALL_TYPE_FOUND'));
 125  
 126                      return false;
 127              }
 128          }
 129  
 130          // This event allows a custom installation of the package or a customization of the package:
 131          $results = $app->triggerEvent('onInstallerBeforeInstaller', array($this, &$package));
 132  
 133          if (in_array(true, $results, true)) {
 134              return true;
 135          }
 136  
 137          if (in_array(false, $results, true)) {
 138              if (in_array($installType, array('upload', 'url'))) {
 139                  InstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']);
 140              }
 141  
 142              return false;
 143          }
 144  
 145          // Check if package was uploaded successfully.
 146          if (!\is_array($package)) {
 147              $app->enqueueMessage(Text::_('COM_INSTALLER_UNABLE_TO_FIND_INSTALL_PACKAGE'), 'error');
 148  
 149              return false;
 150          }
 151  
 152          // Get an installer instance.
 153          $installer = Installer::getInstance();
 154  
 155          /*
 156           * Check for a Joomla core package.
 157           * To do this we need to set the source path to find the manifest (the same first step as Installer::install())
 158           *
 159           * This must be done before the unpacked check because InstallerHelper::detectType() returns a boolean false since the manifest
 160           * can't be found in the expected location.
 161           */
 162          if (isset($package['dir']) && is_dir($package['dir'])) {
 163              $installer->setPath('source', $package['dir']);
 164  
 165              if (!$installer->findManifest()) {
 166                  // If a manifest isn't found at the source, this may be a Joomla package; check the package directory for the Joomla manifest
 167                  if (file_exists($package['dir'] . '/administrator/manifests/files/joomla.xml')) {
 168                      // We have a Joomla package
 169                      if (in_array($installType, array('upload', 'url'))) {
 170                          InstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']);
 171                      }
 172  
 173                      $app->enqueueMessage(
 174                          Text::sprintf('COM_INSTALLER_UNABLE_TO_INSTALL_JOOMLA_PACKAGE', Route::_('index.php?option=com_joomlaupdate')),
 175                          'warning'
 176                      );
 177  
 178                      return false;
 179                  }
 180              }
 181          }
 182  
 183          // Was the package unpacked?
 184          if (empty($package['type'])) {
 185              if (in_array($installType, array('upload', 'url'))) {
 186                  InstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']);
 187              }
 188  
 189              $app->enqueueMessage(Text::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST'), 'error');
 190  
 191              return false;
 192          }
 193  
 194          // Install the package.
 195          if (!$installer->install($package['dir'])) {
 196              // There was an error installing the package.
 197              $msg = Text::sprintf('COM_INSTALLER_INSTALL_ERROR', Text::_('COM_INSTALLER_TYPE_TYPE_' . strtoupper($package['type'])));
 198              $result = false;
 199              $msgType = 'error';
 200          } else {
 201              // Package installed successfully.
 202              $msg = Text::sprintf('COM_INSTALLER_INSTALL_SUCCESS', Text::_('COM_INSTALLER_TYPE_TYPE_' . strtoupper($installLang . $package['type'])));
 203              $result = true;
 204              $msgType = 'message';
 205          }
 206  
 207          // This event allows a custom a post-flight:
 208          $app->triggerEvent('onInstallerAfterInstaller', array($this, &$package, $installer, &$result, &$msg));
 209  
 210          // Set some model state values.
 211          $app->enqueueMessage($msg, $msgType);
 212          $this->setState('name', $installer->get('name'));
 213          $this->setState('result', $result);
 214          $app->setUserState('com_installer.message', $installer->message);
 215          $app->setUserState('com_installer.extension_message', $installer->get('extension_message'));
 216          $app->setUserState('com_installer.redirect_url', $installer->get('redirect_url'));
 217  
 218          // Cleanup the install files.
 219          if (!is_file($package['packagefile'])) {
 220              $package['packagefile'] = $app->get('tmp_path') . '/' . $package['packagefile'];
 221          }
 222  
 223          InstallerHelper::cleanupInstall($package['packagefile'], $package['extractdir']);
 224  
 225          // Clear the cached extension data and menu cache
 226          $this->cleanCache('_system');
 227          $this->cleanCache('com_modules');
 228          $this->cleanCache('com_plugins');
 229          $this->cleanCache('mod_menu');
 230  
 231          return $result;
 232      }
 233  
 234      /**
 235       * Works out an installation package from a HTTP upload.
 236       *
 237       * @return  mixed   Package definition or false on failure.
 238       */
 239      protected function _getPackageFromUpload()
 240      {
 241          // Get the uploaded file information.
 242          $input    = Factory::getApplication()->input;
 243  
 244          // Do not change the filter type 'raw'. We need this to let files containing PHP code to upload. See \JInputFiles::get.
 245          $userfile = $input->files->get('install_package', null, 'raw');
 246  
 247          // Make sure that file uploads are enabled in php.
 248          if (!(bool) ini_get('file_uploads')) {
 249              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLFILE'), 'error');
 250  
 251              return false;
 252          }
 253  
 254          // Make sure that zlib is loaded so that the package can be unpacked.
 255          if (!extension_loaded('zlib')) {
 256              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLZLIB'), 'error');
 257  
 258              return false;
 259          }
 260  
 261          // If there is no uploaded file, we have a problem...
 262          if (!is_array($userfile)) {
 263              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_NO_FILE_SELECTED'), 'error');
 264  
 265              return false;
 266          }
 267  
 268          // Is the PHP tmp directory missing?
 269          if ($userfile['error'] && ($userfile['error'] == UPLOAD_ERR_NO_TMP_DIR)) {
 270              Factory::getApplication()->enqueueMessage(
 271                  Text::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLUPLOADERROR') . '<br>' . Text::_('COM_INSTALLER_MSG_WARNINGS_PHPUPLOADNOTSET'),
 272                  'error'
 273              );
 274  
 275              return false;
 276          }
 277  
 278          // Is the max upload size too small in php.ini?
 279          if ($userfile['error'] && ($userfile['error'] == UPLOAD_ERR_INI_SIZE)) {
 280              Factory::getApplication()->enqueueMessage(
 281                  Text::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLUPLOADERROR') . '<br>' . Text::_('COM_INSTALLER_MSG_WARNINGS_SMALLUPLOADSIZE'),
 282                  'error'
 283              );
 284  
 285              return false;
 286          }
 287  
 288          // Check if there was a different problem uploading the file.
 289          if ($userfile['error'] || $userfile['size'] < 1) {
 290              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_WARNINSTALLUPLOADERROR'), 'error');
 291  
 292              return false;
 293          }
 294  
 295          // Build the appropriate paths.
 296          $config   = Factory::getApplication()->getConfig();
 297          $tmp_dest = $config->get('tmp_path') . '/' . $userfile['name'];
 298          $tmp_src  = $userfile['tmp_name'];
 299  
 300          // Move uploaded file.
 301          File::upload($tmp_src, $tmp_dest, false, true);
 302  
 303          // Unpack the downloaded package file.
 304          $package = InstallerHelper::unpack($tmp_dest, true);
 305  
 306          return $package;
 307      }
 308  
 309      /**
 310       * Install an extension from a directory
 311       *
 312       * @return  array  Package details or false on failure
 313       *
 314       * @since   1.5
 315       */
 316      protected function _getPackageFromFolder()
 317      {
 318          $input = Factory::getApplication()->input;
 319  
 320          // Get the path to the package to install.
 321          $p_dir = $input->getString('install_directory');
 322          $p_dir = Path::clean($p_dir);
 323  
 324          // Did you give us a valid directory?
 325          if (!is_dir($p_dir)) {
 326              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_PLEASE_ENTER_A_PACKAGE_DIRECTORY'), 'error');
 327  
 328              return false;
 329          }
 330  
 331          // Detect the package type
 332          $type = InstallerHelper::detectType($p_dir);
 333  
 334          // Did you give us a valid package?
 335          if (!$type) {
 336              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_PATH_DOES_NOT_HAVE_A_VALID_PACKAGE'), 'error');
 337          }
 338  
 339          $package['packagefile'] = null;
 340          $package['extractdir'] = null;
 341          $package['dir'] = $p_dir;
 342          $package['type'] = $type;
 343  
 344          return $package;
 345      }
 346  
 347      /**
 348       * Install an extension from a URL.
 349       *
 350       * @return  bool|array  Package details or false on failure.
 351       *
 352       * @since   1.5
 353       */
 354      protected function _getPackageFromUrl()
 355      {
 356          $input = Factory::getApplication()->input;
 357  
 358          // Get the URL of the package to install.
 359          $url = $input->getString('install_url');
 360  
 361          // Did you give us a URL?
 362          if (!$url) {
 363              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_ENTER_A_URL'), 'error');
 364  
 365              return false;
 366          }
 367  
 368          // We only allow http & https here
 369          $uri = new Uri($url);
 370  
 371          if (!in_array($uri->getScheme(), ['http', 'https'])) {
 372              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_INVALID_URL_SCHEME'), 'error');
 373  
 374              return false;
 375          }
 376  
 377          // Handle updater XML file case:
 378          if (preg_match('/\.xml\s*$/', $url)) {
 379              $update = new Update();
 380              $update->loadFromXml($url);
 381              $package_url = trim($update->get('downloadurl', false)->_data);
 382  
 383              if ($package_url) {
 384                  $url = $package_url;
 385              }
 386  
 387              unset($update);
 388          }
 389  
 390          // Download the package at the URL given.
 391          $p_file = InstallerHelper::downloadPackage($url);
 392  
 393          // Was the package downloaded?
 394          if (!$p_file) {
 395              Factory::getApplication()->enqueueMessage(Text::_('COM_INSTALLER_MSG_INSTALL_INVALID_URL'), 'error');
 396  
 397              return false;
 398          }
 399  
 400          $tmp_dest = Factory::getApplication()->get('tmp_path');
 401  
 402          // Unpack the downloaded package file.
 403          $package = InstallerHelper::unpack($tmp_dest . '/' . $p_file, true);
 404  
 405          return $package;
 406      }
 407  }


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