[ Index ]

PHP Cross Reference of Joomla 2.5.4 DE

title

Body

[close]

/libraries/joomla/installer/ -> installer.php (source)

   1  <?php
   2  /**
   3   * @package     Joomla.Platform
   4   * @subpackage  Installer
   5   *
   6   * @copyright   Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
   7   * @license     GNU General Public License version 2 or later; see LICENSE
   8   */
   9  
  10  defined('JPATH_PLATFORM') or die;
  11  
  12  jimport('joomla.filesystem.file');
  13  jimport('joomla.filesystem.folder');
  14  jimport('joomla.filesystem.archive');
  15  jimport('joomla.filesystem.path');
  16  jimport('joomla.base.adapter');
  17  
  18  /**
  19   * Joomla base installer class
  20   *
  21   * @package     Joomla.Platform
  22   * @subpackage  Installer
  23   * @since       11.1
  24   */
  25  class JInstaller extends JAdapter
  26  {
  27      /**
  28       * Array of paths needed by the installer
  29       *
  30       * @var    array
  31       * @since  11.1
  32       */
  33      protected $_paths = array();
  34  
  35      /**
  36       * True if package is an upgrade
  37       *
  38       * @var    boolean
  39       * @since  11.1
  40       */
  41      protected $_upgrade = null;
  42  
  43      /**
  44       * The manifest trigger class
  45       *
  46       * @var    object
  47       * @since  11.1
  48       */
  49      public $manifestClass = null;
  50  
  51      /**
  52       * True if existing files can be overwritten
  53       * @var    boolean
  54       * @since  11.1
  55       */
  56      protected $_overwrite = false;
  57  
  58      /**
  59       * Stack of installation steps
  60       * - Used for installation rollback
  61       *
  62       * @var    array
  63       * @since  11.1
  64       */
  65      protected $_stepStack = array();
  66  
  67      /**
  68       * Extension Table Entry
  69       *
  70       * @var    JTableExtension
  71       * @since  11.1
  72       */
  73      public $extension = null;
  74  
  75      /**
  76       * The output from the install/uninstall scripts
  77       *
  78       * @var    string
  79       * @since  11.1
  80       * */
  81      public $message = null;
  82  
  83      /**
  84       * The installation manifest XML object
  85       *
  86       * @var    object
  87       * @since  11.1
  88       */
  89      public $manifest = null;
  90  
  91      /**
  92       * The extension message that appears
  93       *
  94       * @var    string
  95       * @since  11.1
  96       */
  97      protected $extension_message = null;
  98  
  99      /**
 100       * The redirect URL if this extension (can be null if no redirect)
 101       *
 102       * @var    string
 103       * @since  11.1
 104       */
 105      protected $redirect_url = null;
 106  
 107      /**
 108       * @var    JInstaller  JInstaller instance container.
 109       * @since  11.3
 110       */
 111      protected static $instance;
 112  
 113      /**
 114       * Constructor
 115       *
 116       * @since   11.1
 117       */
 118  	public function __construct()
 119      {
 120          parent::__construct(dirname(__FILE__), 'JInstaller');
 121      }
 122  
 123      /**
 124       * Returns the global Installer object, only creating it
 125       * if it doesn't already exist.
 126       *
 127       * @return  object  An installer object
 128       *
 129       * @since   11.1
 130       */
 131  	public static function getInstance()
 132      {
 133          if (!isset(self::$instance))
 134          {
 135              self::$instance = new JInstaller;
 136          }
 137          return self::$instance;
 138      }
 139  
 140      /**
 141       * Get the allow overwrite switch
 142       *
 143       * @return  boolean  Allow overwrite switch
 144       *
 145       * @since   11.1
 146       * @deprecated 12.1 Use JInstaller::isOverwrite()
 147       */
 148  	public function getOverwrite()
 149      {
 150          JLog::add('JInstaller::getOverwrite() is deprecated. Please use JInstaller::isOverwrite() instead', JLog::WARNING, 'deprecated');
 151          return $this->isOverwrite();
 152      }
 153  
 154      /**
 155       * Get the allow overwrite switch
 156       *
 157       * @return  boolean  Allow overwrite switch
 158       *
 159       * @since   11.4
 160       */
 161  	public function isOverwrite()
 162      {
 163          return $this->_overwrite;
 164      }
 165  
 166      /**
 167       * Set the allow overwrite switch
 168       *
 169       * @param   boolean  $state  Overwrite switch state
 170       *
 171       * @return  boolean  True it state is set, false if it is not
 172       *
 173       * @since   11.1
 174       */
 175  	public function setOverwrite($state = false)
 176      {
 177          $tmp = $this->_overwrite;
 178  
 179          if ($state)
 180          {
 181              $this->_overwrite = true;
 182          }
 183          else
 184          {
 185              $this->_overwrite = false;
 186          }
 187  
 188          return $tmp;
 189      }
 190  
 191      /**
 192       * Get the redirect location
 193       *
 194       * @return  string  Redirect location (or null)
 195       *
 196       * @since   11.1
 197       */
 198  	public function getRedirectURL()
 199      {
 200          return $this->redirect_url;
 201      }
 202  
 203      /**
 204       * Set the redirect location
 205       *
 206       * @param   string  $newurl  New redirect location
 207       *
 208       * @return  void
 209       *
 210       * @since   11.1
 211       */
 212  	public function setRedirectURL($newurl)
 213      {
 214          $this->redirect_url = $newurl;
 215      }
 216  
 217      /**
 218       * Get the upgrade switch
 219       *
 220       * @return  boolean
 221       *
 222       * @since   11.1
 223       * @deprecated 12.1 Use JInstaller::isUpgrade()
 224       */
 225  	public function getUpgrade()
 226      {
 227          JLog::add('JInstaller::getUpgrade() is deprecated. Please use JInstaller::isUpgrade() instead', JLog::WARNING, 'deprecated');
 228          return $this->isUpgrade();
 229      }
 230  
 231      /**
 232       * Get the upgrade switch
 233       *
 234       * @return  boolean
 235       *
 236       * @since   11.4
 237       */
 238  	public function isUpgrade()
 239      {
 240          return $this->_upgrade;
 241      }
 242  
 243      /**
 244       * Set the upgrade switch
 245       *
 246       * @param   boolean  $state  Upgrade switch state
 247       *
 248       * @return  boolean  True if upgrade, false otherwise
 249       *
 250       * @since   11.1
 251       */
 252  	public function setUpgrade($state = false)
 253      {
 254          $tmp = $this->_upgrade;
 255  
 256          if ($state)
 257          {
 258              $this->_upgrade = true;
 259          }
 260          else
 261          {
 262              $this->_upgrade = false;
 263          }
 264  
 265          return $tmp;
 266      }
 267  
 268      /**
 269       * Get the installation manifest object
 270       *
 271       * @return  object  Manifest object
 272       *
 273       * @since   11.1
 274       */
 275  	public function getManifest()
 276      {
 277          if (!is_object($this->manifest))
 278          {
 279              $this->findManifest();
 280          }
 281  
 282          return $this->manifest;
 283      }
 284  
 285      /**
 286       * Get an installer path by name
 287       *
 288       * @param   string  $name     Path name
 289       * @param   string  $default  Default value
 290       *
 291       * @return  string  Path
 292       *
 293       * @since   11.1
 294       */
 295  	public function getPath($name, $default = null)
 296      {
 297          return (!empty($this->_paths[$name])) ? $this->_paths[$name] : $default;
 298      }
 299  
 300      /**
 301       * Sets an installer path by name
 302       *
 303       * @param   string  $name   Path name
 304       * @param   string  $value  Path
 305       *
 306       * @return  void
 307       *
 308       * @since   11.1
 309       */
 310  	public function setPath($name, $value)
 311      {
 312          $this->_paths[$name] = $value;
 313      }
 314  
 315      /**
 316       * Pushes a step onto the installer stack for rolling back steps
 317       *
 318       * @param   array  $step  Installer step
 319       *
 320       * @return  void
 321       *
 322       * @since   11.1
 323       */
 324  	public function pushStep($step)
 325      {
 326          $this->_stepStack[] = $step;
 327      }
 328  
 329      /**
 330       * Installation abort method
 331       *
 332       * @param   string  $msg   Abort message from the installer
 333       * @param   string  $type  Package type if defined
 334       *
 335       * @return  boolean  True if successful
 336       *
 337       * @since   11.1
 338       */
 339  	public function abort($msg = null, $type = null)
 340      {
 341          // Initialise variables.
 342          $retval = true;
 343          $step = array_pop($this->_stepStack);
 344  
 345          // Raise abort warning
 346          if ($msg)
 347          {
 348              JError::raiseWarning(100, $msg);
 349          }
 350  
 351          while ($step != null)
 352          {
 353              switch ($step['type'])
 354              {
 355                  case 'file':
 356                      // Remove the file
 357                      $stepval = JFile::delete($step['path']);
 358                      break;
 359  
 360                  case 'folder':
 361                      // Remove the folder
 362                      $stepval = JFolder::delete($step['path']);
 363                      break;
 364  
 365                  case 'query':
 366                      // Placeholder in case this is necessary in the future
 367                      // $stepval is always false because if this step was called it invariably failed
 368                      $stepval = false;
 369                      break;
 370  
 371                  case 'extension':
 372                      // Get database connector object
 373                      $db = $this->getDBO();
 374                      $query = $db->getQuery(true);
 375  
 376                      // Remove the entry from the #__extensions table
 377                      $query->delete($db->quoteName('#__extensions'));
 378                      $query->where($db->quoteName('extension_id') . ' = ' . (int) $step['id']);
 379                      $db->setQuery($query);
 380                      $stepval = $db->query();
 381  
 382                      break;
 383  
 384                  default:
 385                      if ($type && is_object($this->_adapters[$type]))
 386                      {
 387                          // Build the name of the custom rollback method for the type
 388                          $method = '_rollback_' . $step['type'];
 389                          // Custom rollback method handler
 390                          if (method_exists($this->_adapters[$type], $method))
 391                          {
 392                              $stepval = $this->_adapters[$type]->$method($step);
 393                          }
 394                      }
 395                      else
 396                      {
 397                          $stepval = false; // set it to false
 398                      }
 399                      break;
 400              }
 401  
 402              // Only set the return value if it is false
 403              if ($stepval === false)
 404              {
 405                  $retval = false;
 406              }
 407  
 408              // Get the next step and continue
 409              $step = array_pop($this->_stepStack);
 410          }
 411  
 412          $conf = JFactory::getConfig();
 413          $debug = $conf->get('debug');
 414  
 415          if ($debug)
 416          {
 417              JError::raiseError(500, JText::_('JLIB_INSTALLER_ABORT_DEBUG') . $msg);
 418          }
 419  
 420          return $retval;
 421      }
 422  
 423      // Adapter functions
 424  
 425      /**
 426       * Package installation method
 427       *
 428       * @param   string  $path  Path to package source folder
 429       *
 430       * @return  boolean  True if successful
 431       *
 432       * @since   11.1
 433       */
 434  	public function install($path = null)
 435      {
 436          if ($path && JFolder::exists($path))
 437          {
 438              $this->setPath('source', $path);
 439          }
 440          else
 441          {
 442              $this->abort(JText::_('JLIB_INSTALLER_ABORT_NOINSTALLPATH'));
 443              return false;
 444          }
 445  
 446          if (!$this->setupInstall())
 447          {
 448              $this->abort(JText::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST'));
 449  
 450              return false;
 451          }
 452  
 453          $type = (string) $this->manifest->attributes()->type;
 454  
 455          if (is_object($this->_adapters[$type]))
 456          {
 457              // Add the languages from the package itself
 458              if (method_exists($this->_adapters[$type], 'loadLanguage'))
 459              {
 460                  $this->_adapters[$type]->loadLanguage($path);
 461              }
 462  
 463              // Fire the onExtensionBeforeInstall event.
 464              JPluginHelper::importPlugin('extension');
 465              $dispatcher = JDispatcher::getInstance();
 466              $dispatcher->trigger(
 467                  'onExtensionBeforeInstall',
 468                  array('method' => 'install', 'type' => $type, 'manifest' => $this->manifest, 'extension' => 0)
 469              );
 470  
 471              // Run the install
 472              $result = $this->_adapters[$type]->install();
 473  
 474              // Fire the onExtensionAfterInstall
 475              $dispatcher->trigger(
 476                  'onExtensionAfterInstall',
 477                  array('installer' => clone $this, 'eid' => $result)
 478              );
 479  
 480              if ($result !== false)
 481              {
 482                  return true;
 483              }
 484              else
 485              {
 486                  return false;
 487              }
 488          }
 489  
 490          return false;
 491      }
 492  
 493      /**
 494       * Discovered package installation method
 495       *
 496       * @param   integer  $eid  Extension ID
 497       *
 498       * @return  boolean  True if successful
 499       *
 500       * @since   11.1
 501       */
 502  	public function discover_install($eid = null)
 503      {
 504          if ($eid)
 505          {
 506              $this->extension = JTable::getInstance('extension');
 507  
 508              if (!$this->extension->load($eid))
 509              {
 510                  $this->abort(JText::_('JLIB_INSTALLER_ABORT_LOAD_DETAILS'));
 511  
 512                  return false;
 513              }
 514  
 515              if ($this->extension->state != -1)
 516              {
 517                  $this->abort(JText::_('JLIB_INSTALLER_ABORT_ALREADYINSTALLED'));
 518  
 519                  return false;
 520              }
 521  
 522              // Lazy load the adapter
 523              if (!isset($this->_adapters[$this->extension->type]) || !is_object($this->_adapters[$this->extension->type]))
 524              {
 525                  if (!$this->setAdapter($this->extension->type))
 526                  {
 527                      return false;
 528                  }
 529              }
 530  
 531              if (is_object($this->_adapters[$this->extension->type]))
 532              {
 533                  if (method_exists($this->_adapters[$this->extension->type], 'discover_install'))
 534                  {
 535                      // Add the languages from the package itself
 536                      if (method_exists($this->_adapters[$this->extension->type], 'loadLanguage'))
 537                      {
 538                          $this->_adapters[$this->extension->type]->loadLanguage();
 539                      }
 540  
 541                      // Fire the onExtensionBeforeInstall event.
 542                      JPluginHelper::importPlugin('extension');
 543                      $dispatcher = JDispatcher::getInstance();
 544                      $dispatcher->trigger(
 545                          'onExtensionBeforeInstall',
 546                          array(
 547                              'method' => 'discover_install',
 548                              'type' => $this->extension->get('type'),
 549                              'manifest' => null,
 550                              'extension' => $this->extension->get('extension_id')
 551                          )
 552                      );
 553  
 554                      // Run the install
 555                      $result = $this->_adapters[$this->extension->type]->discover_install();
 556                      // Fire the onExtensionAfterInstall
 557                      $dispatcher->trigger(
 558                          'onExtensionAfterInstall',
 559                          array('installer' => clone $this, 'eid' => $result)
 560                      );
 561                      if ($result !== false)
 562                      {
 563                          return true;
 564                      }
 565                      else
 566                      {
 567                          return false;
 568                      }
 569                  }
 570                  else
 571                  {
 572                      $this->abort(JText::_('JLIB_INSTALLER_ABORT_METHODNOTSUPPORTED'));
 573  
 574                      return false;
 575                  }
 576              }
 577  
 578              return false;
 579          }
 580          else
 581          {
 582              $this->abort(JText::_('JLIB_INSTALLER_ABORT_EXTENSIONNOTVALID'));
 583  
 584              return false;
 585          }
 586      }
 587  
 588      /**
 589       * Extension discover method
 590       * Asks each adapter to find extensions
 591       *
 592       * @return  array  JExtension
 593       *
 594       * @since   11.1
 595       */
 596  	public function discover()
 597      {
 598          $this->loadAllAdapters();
 599          $results = array();
 600  
 601          foreach ($this->_adapters as $adapter)
 602          {
 603              // Joomla! 1.5 installation adapter legacy support
 604              if (method_exists($adapter, 'discover'))
 605              {
 606                  $tmp = $adapter->discover();
 607  
 608                  // if its an array and has entries
 609                  if (is_array($tmp) && count($tmp))
 610                  {
 611                      // merge it into the system
 612                      $results = array_merge($results, $tmp);
 613                  }
 614              }
 615          }
 616  
 617          return $results;
 618      }
 619  
 620      /**
 621       * Package update method
 622       *
 623       * @param   string  $path  Path to package source folder
 624       *
 625       * @return  boolean  True if successful
 626       *
 627       * @since   11.1
 628       */
 629  	public function update($path = null)
 630      {
 631          if ($path && JFolder::exists($path))
 632          {
 633              $this->setPath('source', $path);
 634          }
 635          else
 636          {
 637              $this->abort(JText::_('JLIB_INSTALLER_ABORT_NOUPDATEPATH'));
 638          }
 639  
 640          if (!$this->setupInstall())
 641          {
 642              return $this->abort(JText::_('JLIB_INSTALLER_ABORT_DETECTMANIFEST'));
 643          }
 644  
 645          $type = (string) $this->manifest->attributes()->type;
 646  
 647          if (is_object($this->_adapters[$type]))
 648          {
 649              // Add the languages from the package itself
 650              if (method_exists($this->_adapters[$type], 'loadLanguage'))
 651              {
 652                  $this->_adapters[$type]->loadLanguage($path);
 653              }
 654  
 655              // Fire the onExtensionBeforeUpdate event.
 656              JPluginHelper::importPlugin('extension');
 657              $dispatcher = JDispatcher::getInstance();
 658              $dispatcher->trigger('onExtensionBeforeUpdate', array('type' => $type, 'manifest' => $this->manifest));
 659  
 660              // Run the update
 661              $result = $this->_adapters[$type]->update();
 662  
 663              // Fire the onExtensionAfterUpdate
 664              $dispatcher->trigger(
 665                  'onExtensionAfterUpdate',
 666                  array('installer' => clone $this, 'eid' => $result)
 667              );
 668  
 669              if ($result !== false)
 670              {
 671                  return true;
 672              }
 673              else
 674              {
 675                  return false;
 676              }
 677          }
 678  
 679          return false;
 680      }
 681  
 682      /**
 683       * Package uninstallation method
 684       *
 685       * @param   string   $type        Package type
 686       * @param   mixed    $identifier  Package identifier for adapter
 687       * @param   integer  $cid         Application ID; deprecated in 1.6
 688       *
 689       * @return  boolean  True if successful
 690       *
 691       * @since   11.1
 692       */
 693  	public function uninstall($type, $identifier, $cid = 0)
 694      {
 695          if (!isset($this->_adapters[$type]) || !is_object($this->_adapters[$type]))
 696          {
 697              if (!$this->setAdapter($type))
 698              {
 699                  // We failed to get the right adapter
 700                  return false;
 701              }
 702          }
 703  
 704          if (is_object($this->_adapters[$type]))
 705          {
 706              // We don't load languages here, we get the extension adapter to work it out
 707              // Fire the onExtensionBeforeUninstall event.
 708              JPluginHelper::importPlugin('extension');
 709              $dispatcher = JDispatcher::getInstance();
 710              $dispatcher->trigger('onExtensionBeforeUninstall', array('eid' => $identifier));
 711              // Run the uninstall
 712              $result = $this->_adapters[$type]->uninstall($identifier);
 713              // Fire the onExtensionAfterInstall
 714              $dispatcher->trigger(
 715                  'onExtensionAfterUninstall',
 716                  array('installer' => clone $this, 'eid' => $identifier, 'result' => $result)
 717              );
 718  
 719              return $result;
 720          }
 721  
 722          return false;
 723      }
 724  
 725      /**
 726       * Refreshes the manifest cache stored in #__extensions
 727       *
 728       * @param   integer  $eid  Extension ID
 729       *
 730       * @return  mixed  void on success, false on error @todo missing return value ?
 731       *
 732       * @since   11.1
 733       */
 734  	public function refreshManifestCache($eid)
 735      {
 736          if ($eid)
 737          {
 738              $this->extension = JTable::getInstance('extension');
 739  
 740              if (!$this->extension->load($eid))
 741              {
 742                  $this->abort(JText::_('JLIB_INSTALLER_ABORT_LOAD_DETAILS'));
 743                  return false;
 744              }
 745  
 746              if ($this->extension->state == -1)
 747              {
 748                  $this->abort(JText::_('JLIB_INSTALLER_ABORT_REFRESH_MANIFEST_CACHE'));
 749                  return false;
 750              }
 751  
 752              // Lazy load the adapter
 753              if (!isset($this->_adapters[$this->extension->type]) || !is_object($this->_adapters[$this->extension->type]))
 754              {
 755                  if (!$this->setAdapter($this->extension->type))
 756                  {
 757                      return false;
 758                  }
 759              }
 760  
 761              if (is_object($this->_adapters[$this->extension->type]))
 762              {
 763                  if (method_exists($this->_adapters[$this->extension->type], 'refreshManifestCache'))
 764                  {
 765                      $result = $this->_adapters[$this->extension->type]->refreshManifestCache();
 766  
 767                      if ($result !== false)
 768                      {
 769                          return true;
 770                      }
 771                      else
 772                      {
 773                          return false;
 774                      }
 775                  }
 776                  else
 777                  {
 778                      $this->abort(JText::sprintf('JLIB_INSTALLER_ABORT_METHODNOTSUPPORTED_TYPE', $this->extension->type));
 779  
 780                      return false;
 781                  }
 782              }
 783  
 784              return false;
 785          }
 786          else
 787          {
 788              $this->abort(JText::_('JLIB_INSTALLER_ABORT_REFRESH_MANIFEST_CACHE_VALID'));
 789  
 790              return false;
 791          }
 792      }
 793  
 794      // Utility functions
 795  
 796      /**
 797       * Prepare for installation: this method sets the installation directory, finds
 798       * and checks the installation file and verifies the installation type.
 799       *
 800       * @return  boolean  True on success
 801       *
 802       * @since   11.1
 803       */
 804  	public function setupInstall()
 805      {
 806          // We need to find the installation manifest file
 807          if (!$this->findManifest())
 808          {
 809              return false;
 810          }
 811  
 812          // Load the adapter(s) for the install manifest
 813          $type = (string) $this->manifest->attributes()->type;
 814  
 815          // Lazy load the adapter
 816          if (!isset($this->_adapters[$type]) || !is_object($this->_adapters[$type]))
 817          {
 818              if (!$this->setAdapter($type))
 819              {
 820                  return false;
 821              }
 822          }
 823  
 824          return true;
 825      }
 826  
 827      /**
 828       * Backward compatible method to parse through a queries element of the
 829       * installation manifest file and take appropriate action.
 830       *
 831       * @param   JXMLElement  $element  The XML node to process
 832       *
 833       * @return  mixed  Number of queries processed or False on error
 834       *
 835       * @since   11.1
 836       */
 837  	public function parseQueries($element)
 838      {
 839          // Get the database connector object
 840          $db = & $this->_db;
 841  
 842          if (!$element || !count($element->children()))
 843          {
 844              // Either the tag does not exist or has no children therefore we return zero files processed.
 845              return 0;
 846          }
 847  
 848          // Get the array of query nodes to process
 849          $queries = $element->children();
 850  
 851          if (count($queries) == 0)
 852          {
 853              // No queries to process
 854              return 0;
 855          }
 856  
 857          // Process each query in the $queries array (children of $tagName).
 858          foreach ($queries as $query)
 859          {
 860              $db->setQuery($query->data());
 861  
 862              if (!$db->query())
 863              {
 864                  JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $db->stderr(true)));
 865  
 866                  return false;
 867              }
 868          }
 869  
 870          return (int) count($queries);
 871      }
 872  
 873      /**
 874       * Method to extract the name of a discreet installation sql file from the installation manifest file.
 875       *
 876       * @param   object  $element  The XML node to process
 877       *
 878       * @return  mixed  Number of queries processed or False on error
 879       *
 880       * @since   11.1
 881       */
 882  	public function parseSQLFiles($element)
 883      {
 884          if (!$element || !count($element->children()))
 885          {
 886              // The tag does not exist.
 887              return 0;
 888          }
 889  
 890          // Initialise variables.
 891          $queries = array();
 892          $db = & $this->_db;
 893          $dbDriver = strtolower($db->name);
 894  
 895          if ($dbDriver == 'mysqli')
 896          {
 897              $dbDriver = 'mysql';
 898          }
 899          elseif($dbDriver == 'sqlsrv')
 900          {
 901              $dbDriver = 'sqlazure';
 902          }
 903  
 904          // Get the name of the sql file to process
 905          $sqlfile = '';
 906  
 907          foreach ($element->children() as $file)
 908          {
 909              $fCharset = (strtolower($file->attributes()->charset) == 'utf8') ? 'utf8' : '';
 910              $fDriver = strtolower($file->attributes()->driver);
 911  
 912              if ($fDriver == 'mysqli')
 913              {
 914                  $fDriver = 'mysql';
 915              }
 916              elseif($fDriver == 'sqlsrv')
 917              {
 918                  $fDriver = 'sqlazure';
 919              }
 920  
 921              if ($fCharset == 'utf8' && $fDriver == $dbDriver)
 922              {
 923                  $sqlfile = $this->getPath('extension_root') . '/' . $file;
 924  
 925                  // Check that sql files exists before reading. Otherwise raise error for rollback
 926                  if (!file_exists($sqlfile))
 927                  {
 928                      JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_FILENOTFOUND', $sqlfile));
 929  
 930                      return false;
 931                  }
 932  
 933                  $buffer = file_get_contents($sqlfile);
 934  
 935                  // Graceful exit and rollback if read not successful
 936                  if ($buffer === false)
 937                  {
 938                      JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_SQL_READBUFFER'));
 939  
 940                      return false;
 941                  }
 942  
 943                  // Create an array of queries from the sql file
 944                  $queries = JInstallerHelper::splitSql($buffer);
 945  
 946                  if (count($queries) == 0)
 947                  {
 948                      // No queries to process
 949                      return 0;
 950                  }
 951  
 952                  // Process each query in the $queries array (split out of sql file).
 953                  foreach ($queries as $query)
 954                  {
 955                      $query = trim($query);
 956  
 957                      if ($query != '' && $query{0} != '#')
 958                      {
 959                          $db->setQuery($query);
 960  
 961                          if (!$db->query())
 962                          {
 963                              JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $db->stderr(true)));
 964  
 965                              return false;
 966                          }
 967                      }
 968                  }
 969              }
 970          }
 971  
 972          return (int) count($queries);
 973      }
 974  
 975      /**
 976       * Set the schema version for an extension by looking at its latest update
 977       *
 978       * @param   JXMLElement  $schema  Schema Tag
 979       * @param   integer      $eid     Extension ID
 980       *
 981       * @return  void
 982       *
 983       * @since   11.1
 984       */
 985  	public function setSchemaVersion($schema, $eid)
 986      {
 987          if ($eid && $schema)
 988          {
 989              $db = JFactory::getDBO();
 990              $schemapaths = $schema->children();
 991  
 992              if (!$schemapaths)
 993              {
 994                  return;
 995              }
 996  
 997              if (count($schemapaths))
 998              {
 999                  $dbDriver = strtolower($db->name);
1000                  if ($dbDriver == 'mysqli')
1001                  {
1002                      $dbDriver = 'mysql';
1003                  }
1004                  elseif ($dbDriver == 'sqlsrv')
1005                  {
1006                      $dbDriver = 'sqlazure';
1007                  }
1008                  
1009  
1010                  $schemapath = '';
1011  
1012                  foreach ($schemapaths as $entry)
1013                  {
1014                      $attrs = $entry->attributes();
1015                      if ($attrs['type'] == $dbDriver)
1016                      {
1017                          $schemapath = $entry;
1018                          break;
1019                      }
1020                  }
1021  
1022                  if (strlen($schemapath))
1023                  {
1024                      $files = str_replace('.sql', '', JFolder::files($this->getPath('extension_root') . '/' . $schemapath, '\.sql$'));
1025                      usort($files, 'version_compare');
1026                      // Update the database
1027                      $query = $db->getQuery(true);
1028                      $query->delete()
1029                          ->from('#__schemas')
1030                          ->where('extension_id = ' . $eid);
1031                      $db->setQuery($query);
1032  
1033                      if ($db->query())
1034                      {
1035                          $query->clear();
1036                          $query->insert($db->quoteName('#__schemas'));
1037                          $query->columns(array($db->quoteName('extension_id'), $db->quoteName('version_id')));
1038                          $query->values($eid . ', ' . $db->quote(end($files)));
1039                          $db->setQuery($query);
1040                          $db->query();
1041                      }
1042                  }
1043              }
1044          }
1045      }
1046  
1047      /**
1048       * Method to process the updates for an item
1049       *
1050       * @param   JXMLElement  $schema  The XML node to process
1051       * @param   integer      $eid     Extension Identifier
1052       *
1053       * @return  boolean      Result of the operations
1054       *
1055       * @since   11.1
1056       */
1057  	public function parseSchemaUpdates($schema, $eid)
1058      {
1059          $files = array();
1060          $update_count = 0;
1061  
1062          // Ensure we have an XML element and a valid extension id
1063          if ($eid && $schema)
1064          {
1065              $db = JFactory::getDBO();
1066              $schemapaths = $schema->children();
1067  
1068              if (count($schemapaths))
1069              {
1070                  $dbDriver = strtolower($db->name);
1071  
1072                  if ($dbDriver == 'mysqli')
1073                  {
1074                      $dbDriver = 'mysql';
1075                  }
1076                  elseif ($dbDriver == 'sqlsrv')
1077                  {
1078                      $dbDriver = 'sqlazure';
1079                  }
1080  
1081                  $schemapath = '';
1082                  foreach ($schemapaths as $entry)
1083                  {
1084                      $attrs = $entry->attributes();
1085                      if ($attrs['type'] == $dbDriver)
1086                      {
1087                          $schemapath = $entry;
1088                          break;
1089                      }
1090                  }
1091  
1092                  if (strlen($schemapath))
1093                  {
1094                      $files = str_replace('.sql', '', JFolder::files($this->getPath('extension_root') . '/' . $schemapath, '\.sql$'));
1095                      usort($files, 'version_compare');
1096  
1097                      if (!count($files))
1098                      {
1099                          return false;
1100                      }
1101  
1102                      $query = $db->getQuery(true);
1103                      $query->select('version_id')
1104                          ->from('#__schemas')
1105                          ->where('extension_id = ' . $eid);
1106                      $db->setQuery($query);
1107                      $version = $db->loadResult();
1108  
1109                      if ($version)
1110                      {
1111                          // We have a version!
1112                          foreach ($files as $file)
1113                          {
1114                              if (version_compare($file, $version) > 0)
1115                              {
1116                                  $buffer = file_get_contents($this->getPath('extension_root') . '/' . $schemapath . '/' . $file . '.sql');
1117  
1118                                  // Graceful exit and rollback if read not successful
1119                                  if ($buffer === false)
1120                                  {
1121                                      JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_SQL_READBUFFER'));
1122  
1123                                      return false;
1124                                  }
1125  
1126                                  // Create an array of queries from the sql file
1127                                  $queries = JInstallerHelper::splitSql($buffer);
1128  
1129                                  if (count($queries) == 0)
1130                                  {
1131                                      // No queries to process
1132                                      continue;
1133                                  }
1134  
1135                                  // Process each query in the $queries array (split out of sql file).
1136                                  foreach ($queries as $query)
1137                                  {
1138                                      $query = trim($query);
1139                                      if ($query != '' && $query{0} != '#')
1140                                      {
1141                                          $db->setQuery($query);
1142  
1143                                          if (!$db->query())
1144                                          {
1145                                              JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $db->stderr(true)));
1146  
1147                                              return false;
1148                                          }
1149  
1150                                          $update_count++;
1151                                      }
1152                                  }
1153                              }
1154                          }
1155                      }
1156  
1157                      // Update the database
1158                      $query = $db->getQuery(true);
1159                      $query->delete()
1160                          ->from('#__schemas')
1161                          ->where('extension_id = ' . $eid);
1162                      $db->setQuery($query);
1163  
1164                      if ($db->Query())
1165                      {
1166                          $query->clear();
1167                          $query->insert($db->quoteName('#__schemas'));
1168                          $query->columns(array($db->quoteName('extension_id'), $db->quoteName('version_id')));
1169                          $query->values($eid . ', ' . $db->quote(end($files)));
1170                          $db->setQuery($query);
1171                          $db->Query();
1172                      }
1173                  }
1174              }
1175          }
1176  
1177          return $update_count;
1178      }
1179  
1180      /**
1181       * Method to parse through a files element of the installation manifest and take appropriate
1182       * action.
1183       *
1184       * @param   JXMLElement  $element   The XML node to process
1185       * @param   integer      $cid       Application ID of application to install to
1186       * @param   array        $oldFiles  List of old files (JXMLElement's)
1187       * @param   array        $oldMD5    List of old MD5 sums (indexed by filename with value as MD5)
1188       *
1189       * @return  boolean      True on success
1190       *
1191       * @since   11.1
1192       */
1193  	public function parseFiles($element, $cid = 0, $oldFiles = null, $oldMD5 = null)
1194      {
1195          // Get the array of file nodes to process; we checked whether this had children above.
1196          if (!$element || !count($element->children()))
1197          {
1198              // Either the tag does not exist or has no children (hence no files to process) therefore we return zero files processed.
1199              return 0;
1200          }
1201  
1202          // Initialise variables.
1203          $copyfiles = array();
1204  
1205          // Get the client info
1206          $client = JApplicationHelper::getClientInfo($cid);
1207  
1208          /*
1209           * Here we set the folder we are going to remove the files from.
1210           */
1211          if ($client)
1212          {
1213              $pathname = 'extension_' . $client->name;
1214              $destination = $this->getPath($pathname);
1215          }
1216          else
1217          {
1218              $pathname = 'extension_root';
1219              $destination = $this->getPath($pathname);
1220          }
1221  
1222          // Here we set the folder we are going to copy the files from.
1223  
1224          // Does the element have a folder attribute?
1225          //
1226          // If so this indicates that the files are in a subdirectory of the source
1227          // folder and we should append the folder attribute to the source path when
1228          // copying files.
1229  
1230          $folder = (string) $element->attributes()->folder;
1231  
1232          if ($folder && file_exists($this->getPath('source') . '/' . $folder))
1233          {
1234              $source = $this->getPath('source') . '/' . $folder;
1235          }
1236          else
1237          {
1238              $source = $this->getPath('source');
1239          }
1240  
1241          // Work out what files have been deleted
1242          if ($oldFiles && ($oldFiles instanceof JXMLElement))
1243          {
1244              $oldEntries = $oldFiles->children();
1245  
1246              if (count($oldEntries))
1247              {
1248                  $deletions = $this->findDeletedFiles($oldEntries, $element->children());
1249  
1250                  foreach ($deletions['folders'] as $deleted_folder)
1251                  {
1252                      JFolder::delete($destination . '/' . $deleted_folder);
1253                  }
1254  
1255                  foreach ($deletions['files'] as $deleted_file)
1256                  {
1257                      JFile::delete($destination . '/' . $deleted_file);
1258                  }
1259              }
1260          }
1261  
1262          // Copy the MD5SUMS file if it exists
1263          if (file_exists($source . '/MD5SUMS'))
1264          {
1265              $path['src'] = $source . '/MD5SUMS';
1266              $path['dest'] = $destination . '/MD5SUMS';
1267              $path['type'] = 'file';
1268              $copyfiles[] = $path;
1269          }
1270  
1271          // Process each file in the $files array (children of $tagName).
1272          foreach ($element->children() as $file)
1273          {
1274              $path['src'] = $source . '/' . $file;
1275              $path['dest'] = $destination . '/' . $file;
1276  
1277              // Is this path a file or folder?
1278              $path['type'] = ($file->getName() == 'folder') ? 'folder' : 'file';
1279  
1280              // Before we can add a file to the copyfiles array we need to ensure
1281              // that the folder we are copying our file to exits and if it doesn't,
1282              // we need to create it.
1283  
1284              if (basename($path['dest']) != $path['dest'])
1285              {
1286                  $newdir = dirname($path['dest']);
1287  
1288                  if (!JFolder::create($newdir))
1289                  {
1290                      JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir));
1291                      return false;
1292                  }
1293              }
1294  
1295              // Add the file to the copyfiles array
1296              $copyfiles[] = $path;
1297          }
1298  
1299          return $this->copyFiles($copyfiles);
1300      }
1301  
1302      /**
1303       * Method to parse through a languages element of the installation manifest and take appropriate
1304       * action.
1305       *
1306       * @param   JXMLElement  $element  The XML node to process
1307       * @param   integer      $cid      Application ID of application to install to
1308       *
1309       * @return  boolean  True on success
1310       *
1311       * @since   11.1
1312       */
1313  	public function parseLanguages($element, $cid = 0)
1314      {
1315          // TODO: work out why the below line triggers 'node no longer exists' errors with files
1316          if (!$element || !count($element->children()))
1317          {
1318              // Either the tag does not exist or has no children therefore we return zero files processed.
1319              return 0;
1320          }
1321  
1322          // Initialise variables.
1323          $copyfiles = array();
1324  
1325          // Get the client info
1326          $client = JApplicationHelper::getClientInfo($cid);
1327  
1328          // Here we set the folder we are going to copy the files to.
1329          // 'languages' Files are copied to JPATH_BASE/language/ folder
1330  
1331          $destination = $client->path . '/language';
1332  
1333          // Here we set the folder we are going to copy the files from.
1334  
1335          // Does the element have a folder attribute?
1336  
1337          // If so this indicates that the files are in a subdirectory of the source
1338          // folder and we should append the folder attribute to the source path when
1339          // copying files.
1340  
1341          $folder = (string) $element->attributes()->folder;
1342  
1343          if ($folder && file_exists($this->getPath('source') . '/' . $folder))
1344          {
1345              $source = $this->getPath('source') . '/' . $folder;
1346          }
1347          else
1348          {
1349              $source = $this->getPath('source');
1350          }
1351  
1352          // Process each file in the $files array (children of $tagName).
1353          foreach ($element->children() as $file)
1354          {
1355              // Language files go in a subfolder based on the language code, ie.
1356              // <language tag="en-US">en-US.mycomponent.ini</language>
1357              // would go in the en-US subdirectory of the language folder.
1358  
1359              // We will only install language files where a core language pack
1360              // already exists.
1361  
1362              if ((string) $file->attributes()->tag != '')
1363              {
1364                  $path['src'] = $source . '/' . $file;
1365  
1366                  if ((string) $file->attributes()->client != '')
1367                  {
1368                      // Override the client
1369                      $langclient = JApplicationHelper::getClientInfo((string) $file->attributes()->client, true);
1370                      $path['dest'] = $langclient->path . '/language/' . $file->attributes()->tag . '/' . basename((string) $file);
1371                  }
1372                  else
1373                  {
1374                      // Use the default client
1375                      $path['dest'] = $destination . '/' . $file->attributes()->tag . '/' . basename((string) $file);
1376                  }
1377  
1378                  // If the language folder is not present, then the core pack hasn't been installed... ignore
1379                  if (!JFolder::exists(dirname($path['dest'])))
1380                  {
1381                      continue;
1382                  }
1383              }
1384              else
1385              {
1386                  $path['src'] = $source . '/' . $file;
1387                  $path['dest'] = $destination . '/' . $file;
1388              }
1389  
1390              //
1391              // Before we can add a file to the copyfiles array we need to ensure
1392              // that the folder we are copying our file to exits and if it doesn't,
1393              // we need to create it.
1394  
1395              if (basename($path['dest']) != $path['dest'])
1396              {
1397                  $newdir = dirname($path['dest']);
1398  
1399                  if (!JFolder::create($newdir))
1400                  {
1401                      JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir));
1402  
1403                      return false;
1404                  }
1405              }
1406  
1407              // Add the file to the copyfiles array
1408              $copyfiles[] = $path;
1409          }
1410  
1411          return $this->copyFiles($copyfiles);
1412      }
1413  
1414      /**
1415       * Method to parse through a media element of the installation manifest and take appropriate
1416       * action.
1417       *
1418       * @param   JXMLElement  $element  The XML node to process
1419       * @param   integer      $cid      Application ID of application to install to
1420       *
1421       * @return  boolean     True on success
1422       *
1423       * @since   11.1
1424       */
1425  	public function parseMedia($element, $cid = 0)
1426      {
1427          if (!$element || !count($element->children()))
1428          {
1429              // Either the tag does not exist or has no children therefore we return zero files processed.
1430              return 0;
1431          }
1432  
1433          // Initialise variables.
1434          $copyfiles = array();
1435  
1436          // Get the client info
1437          $client = JApplicationHelper::getClientInfo($cid);
1438  
1439          // Here we set the folder we are going to copy the files to.
1440          //    Default 'media' Files are copied to the JPATH_BASE/media folder
1441  
1442          $folder = ((string) $element->attributes()->destination) ? '/' . $element->attributes()->destination : null;
1443          $destination = JPath::clean(JPATH_ROOT . '/media' . $folder);
1444  
1445          // Here we set the folder we are going to copy the files from.
1446  
1447          // Does the element have a folder attribute?
1448          // If so this indicates that the files are in a subdirectory of the source
1449          // folder and we should append the folder attribute to the source path when
1450          // copying files.
1451  
1452          $folder = (string) $element->attributes()->folder;
1453  
1454          if ($folder && file_exists($this->getPath('source') . '/' . $folder))
1455          {
1456              $source = $this->getPath('source') . '/' . $folder;
1457          }
1458          else
1459          {
1460              $source = $this->getPath('source');
1461          }
1462  
1463          // Process each file in the $files array (children of $tagName).
1464          foreach ($element->children() as $file)
1465          {
1466              $path['src'] = $source . '/' . $file;
1467              $path['dest'] = $destination . '/' . $file;
1468  
1469              // Is this path a file or folder?
1470              $path['type'] = ($file->getName() == 'folder') ? 'folder' : 'file';
1471  
1472              // Before we can add a file to the copyfiles array we need to ensure
1473              // that the folder we are copying our file to exits and if it doesn't,
1474              // we need to create it.
1475  
1476              if (basename($path['dest']) != $path['dest'])
1477              {
1478                  $newdir = dirname($path['dest']);
1479  
1480                  if (!JFolder::create($newdir))
1481                  {
1482                      JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir));
1483  
1484                      return false;
1485                  }
1486              }
1487  
1488              // Add the file to the copyfiles array
1489              $copyfiles[] = $path;
1490          }
1491  
1492          return $this->copyFiles($copyfiles);
1493      }
1494  
1495      /**
1496       * Method to parse the parameters of an extension, build the INI
1497       * string for its default parameters, and return the INI string.
1498       *
1499       * @return  string   INI string of parameter values
1500       *
1501       * @since   11.1
1502       */
1503  	public function getParams()
1504      {
1505          // Validate that we have a fieldset to use
1506          if (!isset($this->manifest->config->fields->fieldset))
1507          {
1508              return '{}';
1509          }
1510          // Getting the fieldset tags
1511          $fieldsets = $this->manifest->config->fields->fieldset;
1512  
1513          // Creating the data collection variable:
1514          $ini = array();
1515  
1516          // Iterating through the fieldsets:
1517          foreach ($fieldsets as $fieldset)
1518          {
1519              if (!count($fieldset->children()))
1520              {
1521                  // Either the tag does not exist or has no children therefore we return zero files processed.
1522                  return null;
1523              }
1524  
1525              // Iterating through the fields and collecting the name/default values:
1526              foreach ($fieldset as $field)
1527              {
1528                  // Check against the null value since otherwise default values like "0"
1529                  // cause entire parameters to be skipped.
1530  
1531                  if (($name = $field->attributes()->name) === null)
1532                  {
1533                      continue;
1534                  }
1535  
1536                  if (($value = $field->attributes()->default) === null)
1537                  {
1538                      continue;
1539                  }
1540  
1541                  $ini[(string) $name] = (string) $value;
1542              }
1543          }
1544  
1545          return json_encode($ini);
1546      }
1547  
1548      /**
1549       * Copyfiles
1550       *
1551       * Copy files from source directory to the target directory
1552       *
1553       * @param   array    $files      Array with filenames
1554       * @param   boolean  $overwrite  True if existing files can be replaced
1555       *
1556       * @return  boolean  True on success
1557       *
1558       * @since   11.1
1559       */
1560  	public function copyFiles($files, $overwrite = null)
1561      {
1562          // To allow for manual override on the overwriting flag, we check to see if
1563          // the $overwrite flag was set and is a boolean value.  If not, use the object
1564          // allowOverwrite flag.
1565  
1566          if (is_null($overwrite) || !is_bool($overwrite))
1567          {
1568              $overwrite = $this->_overwrite;
1569          }
1570  
1571          /*
1572           * $files must be an array of filenames.  Verify that it is an array with
1573           * at least one file to copy.
1574           */
1575          if (is_array($files) && count($files) > 0)
1576          {
1577  
1578              foreach ($files as $file)
1579              {
1580                  // Get the source and destination paths
1581                  $filesource = JPath::clean($file['src']);
1582                  $filedest = JPath::clean($file['dest']);
1583                  $filetype = array_key_exists('type', $file) ? $file['type'] : 'file';
1584  
1585                  if (!file_exists($filesource))
1586                  {
1587                      /*
1588                       * The source file does not exist.  Nothing to copy so set an error
1589                       * and return false.
1590                       */
1591                      JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_NO_FILE', $filesource));
1592  
1593                      return false;
1594                  }
1595                  elseif (($exists = file_exists($filedest)) && !$overwrite)
1596                  {
1597  
1598                      // It's okay if the manifest already exists
1599                      if ($this->getPath('manifest') == $filesource)
1600                      {
1601                          continue;
1602                      }
1603  
1604                      // The destination file already exists and the overwrite flag is false.
1605                      // Set an error and return false.
1606  
1607                      JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_FILE_EXISTS', $filedest));
1608  
1609                      return false;
1610                  }
1611                  else
1612                  {
1613                      // Copy the folder or file to the new location.
1614                      if ($filetype == 'folder')
1615                      {
1616                          if (!(JFolder::copy($filesource, $filedest, null, $overwrite)))
1617                          {
1618                              JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_FAIL_COPY_FOLDER', $filesource, $filedest));
1619                              return false;
1620                          }
1621  
1622                          $step = array('type' => 'folder', 'path' => $filedest);
1623                      }
1624                      else
1625                      {
1626                          if (!(JFile::copy($filesource, $filedest, null)))
1627                          {
1628                              JError::raiseWarning(1, JText::sprintf('JLIB_INSTALLER_ERROR_FAIL_COPY_FILE', $filesource, $filedest));
1629  
1630                              return false;
1631                          }
1632  
1633                          $step = array('type' => 'file', 'path' => $filedest);
1634                      }
1635  
1636                      /*
1637                       * Since we copied a file/folder, we want to add it to the installation step stack so that
1638                       * in case we have to roll back the installation we can remove the files copied.
1639                       */
1640                      if (!$exists)
1641                      {
1642                          $this->_stepStack[] = $step;
1643                      }
1644                  }
1645              }
1646          }
1647          else
1648          {
1649              // The $files variable was either not an array or an empty array
1650              return false;
1651          }
1652  
1653          return count($files);
1654      }
1655  
1656      /**
1657       * Method to parse through a files element of the installation manifest and remove
1658       * the files that were installed
1659       *
1660       * @param   object   $element  The XML node to process
1661       * @param   integer  $cid      Application ID of application to remove from
1662       *
1663       * @return  boolean  True on success
1664       *
1665       * @since   11.1
1666       */
1667  	public function removeFiles($element, $cid = 0)
1668      {
1669          if (!$element || !count($element->children()))
1670          {
1671              // Either the tag does not exist or has no children therefore we return zero files processed.
1672              return true;
1673          }
1674  
1675          // Initialise variables.
1676          $removefiles = array();
1677          $retval = true;
1678  
1679          $debug = false;
1680          if (isset($GLOBALS['installerdebug']) && $GLOBALS['installerdebug'])
1681          {
1682              $debug = true;
1683          }
1684  
1685          // Get the client info if we're using a specific client
1686          if ($cid > -1)
1687          {
1688              $client = JApplicationHelper::getClientInfo($cid);
1689          }
1690          else
1691          {
1692              $client = null;
1693          }
1694  
1695          // Get the array of file nodes to process
1696          $files = $element->children();
1697  
1698          if (count($files) == 0)
1699          {
1700              // No files to process
1701              return true;
1702          }
1703  
1704          $folder = '';
1705  
1706          /*
1707           * Here we set the folder we are going to remove the files from.  There are a few
1708           * special cases that need to be considered for certain reserved tags.
1709           */
1710          switch ($element->getName())
1711          {
1712              case 'media':
1713                  if ((string) $element->attributes()->destination)
1714                  {
1715                      $folder = (string) $element->attributes()->destination;
1716                  }
1717                  else
1718                  {
1719                      $folder = '';
1720                  }
1721  
1722                  $source = $client->path . '/media/' . $folder;
1723  
1724                  break;
1725  
1726              case 'languages':
1727                  $lang_client = (string) $element->attributes()->client;
1728  
1729                  if ($lang_client)
1730                  {
1731                      $client = JApplicationHelper::getClientInfo($lang_client, true);
1732                      $source = $client->path . '/language';
1733                  }
1734                  else
1735                  {
1736                      if ($client)
1737                      {
1738                          $source = $client->path . '/language';
1739                      }
1740                      else
1741                      {
1742                          $source = '';
1743                      }
1744                  }
1745  
1746                  break;
1747  
1748              default:
1749                  if ($client)
1750                  {
1751                      $pathname = 'extension_' . $client->name;
1752                      $source = $this->getPath($pathname);
1753                  }
1754                  else
1755                  {
1756                      $pathname = 'extension_root';
1757                      $source = $this->getPath($pathname);
1758                  }
1759  
1760                  break;
1761          }
1762  
1763          // Process each file in the $files array (children of $tagName).
1764          foreach ($files as $file)
1765          {
1766              // If the file is a language, we must handle it differently.  Language files
1767              // go in a subdirectory based on the language code, ie.
1768              //        <language tag="en_US">en_US.mycomponent.ini</language>
1769              // would go in the en_US subdirectory of the languages directory.
1770  
1771              if ($file->getName() == 'language' && (string) $file->attributes()->tag != '')
1772              {
1773                  if ($source)
1774                  {
1775                      $path = $source . '/' . $file->attributes()->tag . '/' . basename((string) $file);
1776                  }
1777                  else
1778                  {
1779                      $target_client = JApplicationHelper::getClientInfo((string) $file->attributes()->client, true);
1780                      $path = $target_client->path . '/language/' . $file->attributes()->tag . '/' . basename((string) $file);
1781                  }
1782  
1783                  // If the language folder is not present, then the core pack hasn't been installed... ignore
1784                  if (!JFolder::exists(dirname($path)))
1785                  {
1786                      continue;
1787                  }
1788              }
1789              else
1790              {
1791                  $path = $source . '/' . $file;
1792              }
1793  
1794              // Actually delete the files/folders
1795  
1796              if (is_dir($path))
1797              {
1798                  $val = JFolder::delete($path);
1799              }
1800              else
1801              {
1802                  $val = JFile::delete($path);
1803              }
1804  
1805              if ($val === false)
1806              {
1807                  JError::raiseWarning(43, 'Failed to delete ' . $path);
1808                  $retval = false;
1809              }
1810          }
1811  
1812          if (!empty($folder))
1813          {
1814              $val = JFolder::delete($source);
1815          }
1816  
1817          return $retval;
1818      }
1819  
1820      /**
1821       * Copies the installation manifest file to the extension folder in the given client
1822       *
1823       * @param   integer  $cid  Where to copy the installfile [optional: defaults to 1 (admin)]
1824       *
1825       * @return  boolean  True on success, False on error
1826       *
1827       * @since   11.1
1828       */
1829  	public function copyManifest($cid = 1)
1830      {
1831          // Get the client info
1832          $client = JApplicationHelper::getClientInfo($cid);
1833  
1834          $path['src'] = $this->getPath('manifest');
1835  
1836          if ($client)
1837          {
1838              $pathname = 'extension_' . $client->name;
1839              $path['dest'] = $this->getPath($pathname) . '/' . basename($this->getPath('manifest'));
1840          }
1841          else
1842          {
1843              $pathname = 'extension_root';
1844              $path['dest'] = $this->getPath($pathname) . '/' . basename($this->getPath('manifest'));
1845          }
1846  
1847          return $this->copyFiles(array($path), true);
1848      }
1849  
1850      /**
1851       * Tries to find the package manifest file
1852       *
1853       * @return  boolean  True on success, False on error
1854       *
1855       * @since 1.0
1856       */
1857  	public function findManifest()
1858      {
1859          // Get an array of all the XML files from the installation directory
1860          $xmlfiles = JFolder::files($this->getPath('source'), '.xml$', 1, true);
1861          // If at least one XML file exists
1862          if (!empty($xmlfiles))
1863          {
1864  
1865              foreach ($xmlfiles as $file)
1866              {
1867                  // Is it a valid Joomla installation manifest file?
1868                  $manifest = $this->isManifest($file);
1869  
1870                  if (!is_null($manifest))
1871                  {
1872                      // If the root method attribute is set to upgrade, allow file overwrite
1873                      if ((string) $manifest->attributes()->method == 'upgrade')
1874                      {
1875                          $this->_upgrade = true;
1876                          $this->_overwrite = true;
1877                      }
1878  
1879                      // If the overwrite option is set, allow file overwriting
1880                      if ((string) $manifest->attributes()->overwrite == 'true')
1881                      {
1882                          $this->_overwrite = true;
1883                      }
1884  
1885                      // Set the manifest object and path
1886                      $this->manifest = $manifest;
1887                      $this->setPath('manifest', $file);
1888  
1889                      // Set the installation source path to that of the manifest file
1890                      $this->setPath('source', dirname($file));
1891  
1892                      return true;
1893                  }
1894              }
1895  
1896              // None of the XML files found were valid install files
1897              JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_NOTFINDJOOMLAXMLSETUPFILE'));
1898  
1899              return false;
1900          }
1901          else
1902          {
1903              // No XML files were found in the install folder
1904              JError::raiseWarning(1, JText::_('JLIB_INSTALLER_ERROR_NOTFINDXMLSETUPFILE'));
1905              return false;
1906          }
1907      }
1908  
1909      /**
1910       * Is the XML file a valid Joomla installation manifest file.
1911       *
1912       * @param   string  $file  An xmlfile path to check
1913       *
1914       * @return  mixed  A JXMLElement, or null if the file failed to parse
1915       *
1916       * @since   11.1
1917       */
1918  	public function isManifest($file)
1919      {
1920          // Initialise variables.
1921          $xml = JFactory::getXML($file);
1922  
1923          // If we cannot load the XML file return null
1924          if (!$xml)
1925          {
1926              return null;
1927          }
1928  
1929          // Check for a valid XML root tag.
1930          // @todo: Remove backwards compatibility in a future version
1931          // Should be 'extension', but for backward compatibility we will accept 'extension' or 'install'.
1932  
1933          // 1.5 uses 'install'
1934          // 1.6 uses 'extension'
1935          if ($xml->getName() != 'install' && $xml->getName() != 'extension')
1936          {
1937              return null;
1938          }
1939  
1940          // Valid manifest file return the object
1941          return $xml;
1942      }
1943  
1944      /**
1945       * Generates a manifest cache
1946       *
1947       * @return string serialised manifest data
1948       *
1949       * @since   11.1
1950       */
1951  	public function generateManifestCache()
1952      {
1953          return json_encode(JApplicationHelper::parseXMLInstallFile($this->getPath('manifest')));
1954      }
1955  
1956      /**
1957       * Cleans up discovered extensions if they're being installed some other way
1958       *
1959       * @param   string   $type     The type of extension (component, etc)
1960       * @param   string   $element  Unique element identifier (e.g. com_content)
1961       * @param   string   $folder   The folder of the extension (plugins; e.g. system)
1962       * @param   integer  $client   The client application (administrator or site)
1963       *
1964       * @return  object    Result of query
1965       *
1966       * @since   11.1
1967       */
1968  	public function cleanDiscoveredExtension($type, $element, $folder = '', $client = 0)
1969      {
1970          $dbo = JFactory::getDBO();
1971          $query = $dbo->getQuery(true);
1972          $query->delete($dbo->quoteName('#__extensions'));
1973          $query->where('type = ' . $dbo->Quote($type));
1974          $query->where('element = ' . $dbo->Quote($element));
1975          $query->where('folder = ' . $dbo->Quote($folder));
1976          $query->where('client_id = ' . intval($client));
1977          $query->where('state = -1');
1978  
1979          return $dbo->Query();
1980      }
1981  
1982      /**
1983       * Compares two "files" entries to find deleted files/folders
1984       *
1985       * @param   array  $old_files  An array of JXMLElement objects that are the old files
1986       * @param   array  $new_files  An array of JXMLElement objects that are the new files
1987       *
1988       * @return  array  An array with the delete files and folders in findDeletedFiles[files] and findDeletedFiles[folders] respectively
1989       *
1990       * @since   11.1
1991       */
1992  	public function findDeletedFiles($old_files, $new_files)
1993      {
1994          // The magic find deleted files function!
1995          // The files that are new
1996          $files = array();
1997          // The folders that are new
1998          $folders = array();
1999          // The folders of the files that are new
2000          $containers = array();
2001          // A list of files to delete
2002          $files_deleted = array();
2003          // A list of folders to delete
2004          $folders_deleted = array();
2005  
2006          foreach ($new_files as $file)
2007          {
2008              switch ($file->getName())
2009              {
2010                  case 'folder':
2011                      // Add any folders to the list
2012                      $folders[] = (string) $file; // add any folders to the list
2013                      break;
2014  
2015                  case 'file':
2016                  default:
2017                      // Add any files to the list
2018                      $files[] = (string) $file;
2019                      // Now handle the folder part of the file to ensure we get any containers
2020                      // Break up the parts of the directory
2021                      $container_parts = explode('/', dirname((string) $file));
2022                      // Make sure this is clean and empty
2023                      $container = '';
2024  
2025                      foreach ($container_parts as $part)
2026                      {
2027                          // Iterate through each part
2028                          // Add a slash if its not empty
2029                          if (!empty($container))
2030                          {
2031                              $container .= '/';
2032                          }
2033                          $container .= $part; // append the folder part
2034                          if (!in_array($container, $containers))
2035                          {
2036                              $containers[] = $container; // add the container if it doesn't already exist
2037                          }
2038                      }
2039                      break;
2040              }
2041          }
2042  
2043          foreach ($old_files as $file)
2044          {
2045              switch ($file->getName())
2046              {
2047                  case 'folder':
2048                      if (!in_array((string) $file, $folders))
2049                      {
2050                          // See whether the folder exists in the new list
2051                          if (!in_array((string) $file, $containers))
2052                          {
2053                              // Check if the folder exists as a container in the new list
2054                              // If it's not in the new list or a container then delete it
2055                              $folders_deleted[] = (string) $file;
2056                          }
2057                      }
2058                      break;
2059  
2060                  case 'file':
2061                  default:
2062                      if (!in_array((string) $file, $files))
2063                      {
2064                          // look if the file exists in the new list
2065                          if (!in_array(dirname((string) $file), $folders))
2066                          {
2067                              // look if the file is now potentially in a folder
2068                              $files_deleted[] = (string) $file; // not in a folder, doesn't exist, wipe it out!
2069                          }
2070                      }
2071                      break;
2072              }
2073          }
2074  
2075          return array('files' => $files_deleted, 'folders' => $folders_deleted);
2076      }
2077  
2078      /**
2079       * Loads an MD5SUMS file into an associative array
2080       *
2081       * @param   string  $filename  Filename to load
2082       *
2083       * @return  array  Associative array with filenames as the index and the MD5 as the value
2084       *
2085       * @since   11.1
2086       */
2087  	public function loadMD5Sum($filename)
2088      {
2089          if (!file_exists($filename))
2090          {
2091              // Bail if the file doesn't exist
2092              return false;
2093          }
2094  
2095          $data = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2096          $retval = array();
2097  
2098          foreach ($data as $row)
2099          {
2100              $results = explode('  ', $row); // split up the data
2101              $results[1] = str_replace('./', '', $results[1]); // cull any potential prefix
2102              $retval[$results[1]] = $results[0]; // throw into the array
2103          }
2104  
2105          return $retval;
2106      }
2107  }


Generated: Tue Apr 3 11:40:28 2012 Cross-referenced by PHPXref 0.7.1