[ Index ]

PHP Cross Reference of Joomla 1.5.26 DE

title

Body

[close]

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

   1  <?php
   2  /**
   3   * @version        $Id: installer.php 14401 2010-01-26 14:10:00Z louis $
   4   * @package        Joomla.Framework
   5   * @subpackage    Installer
   6   * @copyright    Copyright (C) 2005 - 2010 Open Source Matters. All rights reserved.
   7   * @license        GNU/GPL, see LICENSE.php
   8   * Joomla! is free software. This version may have been modified pursuant
   9   * to the GNU General Public License, and as distributed it includes or
  10   * is derivative of works licensed under the GNU General Public License or
  11   * other free or open source software licenses.
  12   * See COPYRIGHT.php for copyright notices and details.
  13   */
  14  
  15  // Check to ensure this file is within the rest of the framework
  16  defined('JPATH_BASE') or die();
  17  
  18  jimport('joomla.filesystem.file');
  19  jimport('joomla.filesystem.folder');
  20  jimport('joomla.filesystem.archive');
  21  jimport('joomla.filesystem.path');
  22  
  23  /**
  24   * Joomla base installer class
  25   *
  26   * @package        Joomla.Framework
  27   * @subpackage    Installer
  28   * @since        1.5
  29   */
  30  class JInstaller extends JObject
  31  {
  32      /**
  33       * Array of paths needed by the installer
  34       * @var array
  35       */
  36      var $_paths = array();
  37  
  38      /**
  39       * The installation manifest XML object
  40       * @var object
  41       */
  42      var $_manifest = null;
  43  
  44      /**
  45       * True if existing files can be overwritten
  46       * @var boolean
  47       */
  48      var $_overwrite = false;
  49  
  50      /**
  51       * A database connector object
  52       * @var object
  53       */
  54      var $_db = null;
  55  
  56      /**
  57       * Associative array of package installer handlers
  58       * @var array
  59       */
  60      var $_adapters = array();
  61  
  62      /**
  63       * Stack of installation steps
  64       *     - Used for installation rollback
  65       * @var array
  66       */
  67      var $_stepStack = array();
  68  
  69      /**
  70       * The output from the install/uninstall scripts
  71       * @var string
  72       */
  73      var $message = null;
  74  
  75      /**
  76       * Constructor
  77       *
  78       * @access protected
  79       */
  80  	function __construct()
  81      {
  82          $this->_db =& JFactory::getDBO();
  83      }
  84  
  85      /**
  86       * Returns a reference to the global Installer object, only creating it
  87       * if it doesn't already exist.
  88       *
  89       * @static
  90       * @return    object    An installer object
  91       * @since 1.5
  92       */
  93      function &getInstance()
  94      {
  95          static $instance;
  96  
  97          if (!isset ($instance)) {
  98              $instance = new JInstaller();
  99          }
 100          return $instance;
 101      }
 102  
 103      /**
 104       * Get the allow overwrite switch
 105       *
 106       * @access    public
 107       * @return    boolean    Allow overwrite switch
 108       * @since    1.5
 109       */
 110  	function getOverwrite()
 111      {
 112          return $this->_overwrite;
 113      }
 114  
 115      /**
 116       * Set the allow overwrite switch
 117       *
 118       * @access    public
 119       * @param    boolean    $state    Overwrite switch state
 120       * @return    boolean    Previous value
 121       * @since    1.5
 122       */
 123  	function setOverwrite($state=false)
 124      {
 125          $tmp = $this->_overwrite;
 126          if ($state) {
 127              $this->_overwrite = true;
 128          } else {
 129              $this->_overwrite = false;
 130          }
 131          return $tmp;
 132      }
 133  
 134      /**
 135       * Get the database connector object
 136       *
 137       * @access    public
 138       * @return    object    Database connector object
 139       * @since    1.5
 140       */
 141      function &getDBO()
 142      {
 143          return $this->_db;
 144      }
 145  
 146      /**
 147       * Get the installation manifest object
 148       *
 149       * @access    public
 150       * @return    object    Manifest object
 151       * @since    1.5
 152       */
 153      function &getManifest()
 154      {
 155          if (!is_object($this->_manifest)) {
 156              $this->_findManifest();
 157          }
 158          return $this->_manifest;
 159      }
 160  
 161      /**
 162       * Get an installer path by name
 163       *
 164       * @access    public
 165       * @param    string    $name        Path name
 166       * @param    string    $default    Default value
 167       * @return    string    Path
 168       * @since    1.5
 169       */
 170  	function getPath($name, $default=null)
 171      {
 172          return (!empty($this->_paths[$name])) ? $this->_paths[$name] : $default;
 173      }
 174  
 175      /**
 176       * Sets an installer path by name
 177       *
 178       * @access    public
 179       * @param    string    $name    Path name
 180       * @param    string    $value    Path
 181       * @return    void
 182       * @since    1.5
 183       */
 184  	function setPath($name, $value)
 185      {
 186          $this->_paths[$name] = $value;
 187      }
 188  
 189      /**
 190       * Pushes a step onto the installer stack for rolling back steps
 191       *
 192       * @access    public
 193       * @param    array    $step    Installer step
 194       * @return    void
 195       * @since    1.5
 196       */
 197  	function pushStep($step)
 198      {
 199          $this->_stepStack[] = $step;
 200      }
 201  
 202      /**
 203       * Set an installer adapter by name
 204       *
 205       * @access    public
 206       * @param    string    $name        Adapter name
 207       * @param    object    $adapter    Installer adapter object
 208       * @return    boolean True if successful
 209       * @since    1.5
 210       */
 211  	function setAdapter($name, $adapter = null)
 212      {
 213          if (!is_object($adapter))
 214          {
 215              // Try to load the adapter object
 216              require_once(dirname(__FILE__).DS.'adapters'.DS.strtolower($name).'.php');
 217              $class = 'JInstaller'.ucfirst($name);
 218              if (!class_exists($class)) {
 219                  return false;
 220              }
 221              $adapter = new $class($this);
 222              $adapter->parent =& $this;
 223          }
 224          $this->_adapters[$name] =& $adapter;
 225          return true;
 226      }
 227  
 228      /**
 229       * Installation abort method
 230       *
 231       * @access    public
 232       * @param    string    $msg    Abort message from the installer
 233       * @param    string    $type    Package type if defined
 234       * @return    boolean    True if successful
 235       * @since    1.5
 236       */
 237  	function abort($msg=null, $type=null)
 238      {
 239          // Initialize variables
 240          $retval = true;
 241          $step = array_pop($this->_stepStack);
 242  
 243          // Raise abort warning
 244          if ($msg) {
 245              JError::raiseWarning(100, $msg);
 246          }
 247  
 248          while ($step != null)
 249          {
 250              switch ($step['type'])
 251              {
 252                  case 'file' :
 253                      // remove the file
 254                      $stepval = JFile::delete($step['path']);
 255                      break;
 256  
 257                  case 'folder' :
 258                      // remove the folder
 259                      $stepval = JFolder::delete($step['path']);
 260                      break;
 261  
 262                  case 'query' :
 263                      // placeholder in case this is necessary in the future
 264                      break;
 265  
 266                  default :
 267                      if ($type && is_object($this->_adapters[$type])) {
 268                          // Build the name of the custom rollback method for the type
 269                          $method = '_rollback_'.$step['type'];
 270                          // Custom rollback method handler
 271                          if (method_exists($this->_adapters[$type], $method)) {
 272                              $stepval = $this->_adapters[$type]->$method($step);
 273                          }
 274                      }
 275                      break;
 276              }
 277  
 278              // Only set the return value if it is false
 279              if ($stepval === false) {
 280                  $retval = false;
 281              }
 282  
 283              // Get the next step and continue
 284              $step = array_pop($this->_stepStack);
 285          }
 286  
 287          return $retval;
 288      }
 289  
 290      /**
 291       * Package installation method
 292       *
 293       * @access    public
 294       * @param    string    $path    Path to package source folder
 295       * @return    boolean    True if successful
 296       * @since    1.5
 297       */
 298  	function install($path=null)
 299      {
 300          if ($path && JFolder::exists($path)) {
 301              $this->setPath('source', $path);
 302          } else {
 303              $this->abort(JText::_('Install path does not exist'));
 304              return false;
 305          }
 306  
 307          if (!$this->setupInstall()) {
 308              $this->abort(JText::_('Unable to detect manifest file'));
 309              return false;
 310          }
 311  
 312          /*
 313           * LEGACY CHECK
 314           */
 315          $root        =& $this->_manifest->document;
 316          $version    = $root->attributes('version');
 317          $rootName    = $root->name();
 318          $config        = &JFactory::getConfig();
 319          if ((version_compare($version, '1.5', '<') || $rootName == 'mosinstall') && !$config->getValue('config.legacy')) {
 320              $this->abort(JText::_('MUSTENABLELEGACY'));
 321              return false;
 322          }
 323  
 324          $type = $root->attributes('type');
 325  
 326          // Needed for legacy reasons ... to be deprecated in next minor release
 327          if ($type == 'mambot') {
 328              $type = 'plugin';
 329          }
 330  
 331          if (is_object($this->_adapters[$type])) {
 332              return $this->_adapters[$type]->install();
 333          }
 334          return false;
 335      }
 336  
 337      /**
 338       * Package update method
 339       *
 340       * @access    public
 341       * @param    string    $path    Path to package source folder
 342       * @return    boolean    True if successful
 343       * @since    1.5
 344       */
 345  	function update($path=null)
 346      {
 347          if ($path && JFolder::exists($path)) {
 348              $this->setPath('source', $path);
 349          } else {
 350              $this->abort(JText::_('Update path does not exist'));
 351          }
 352  
 353          if (!$this->setupInstall()) {
 354              return $this->abort(JText::_('Unable to detect manifest file'));
 355          }
 356  
 357          /*
 358           * LEGACY CHECK
 359           */
 360          $root        =& $this->_manifest->document;
 361          $version    = $root->attributes('version');
 362          $rootName    = $root->name();
 363          $config        = &JFactory::getConfig();
 364          if ((version_compare($version, '1.5', '<') || $rootName == 'mosinstall') && !$config->getValue('config.legacy')) {
 365              return $this->abort(JText::_('MUSTENABLELEGACY'));
 366          }
 367  
 368          $type = $root->attributes('type');
 369  
 370          // Needed for legacy reasons ... to be deprecated in next minor release
 371          if ($type == 'mambot') {
 372              $type = 'plugin';
 373          }
 374  
 375          if (is_object($this->_adapters[$type])) {
 376              return $this->_adapters[$type]->update();
 377          }
 378          return false;
 379      }
 380  
 381      /**
 382       * Package uninstallation method
 383       *
 384       * @access    public
 385       * @param    string    $type    Package type
 386       * @param    mixed    $identifier    Package identifier for adapter
 387       * @param    int        $cid    Application ID
 388       * @return    boolean    True if successful
 389       * @since    1.5
 390       */
 391  	function uninstall($type, $identifier, $cid=0)
 392      {
 393          if (!isset($this->_adapters[$type]) || !is_object($this->_adapters[$type])) {
 394              if (!$this->setAdapter($type)) {
 395                  return false;
 396              }
 397          }
 398          if (is_object($this->_adapters[$type])) {
 399              return $this->_adapters[$type]->uninstall($identifier, $cid);
 400          }
 401          return false;
 402      }
 403  
 404      /**
 405       * Prepare for installation: this method sets the installation directory, finds
 406       * and checks the installation file and verifies the installation type
 407       *
 408       * @access public
 409       * @return boolean True on success
 410       * @since 1.0
 411       */
 412  	function setupInstall()
 413      {
 414          // We need to find the installation manifest file
 415          if (!$this->_findManifest()) {
 416              return false;
 417          }
 418  
 419          // Load the adapter(s) for the install manifest
 420          $root =& $this->_manifest->document;
 421          $type = $root->attributes('type');
 422  
 423          // Needed for legacy reasons ... to be deprecated in next minor release
 424          if ($type == 'mambot') {
 425              $type = 'plugin';
 426          }
 427  
 428          // Lazy load the adapter
 429          if (!isset($this->_adapters[$type]) || !is_object($this->_adapters[$type])) {
 430              if (!$this->setAdapter($type)) {
 431                  return false;
 432              }
 433          }
 434  
 435          return true;
 436      }
 437  
 438      /**
 439       * Backward compatible Method to parse through a queries element of the
 440       * installation manifest file and take appropriate action.
 441       *
 442       * @access    public
 443       * @param    object    $element     The xml node to process
 444       * @return    mixed    Number of queries processed or False on error
 445       * @since    1.5
 446       */
 447  	function parseQueries($element)
 448      {
 449          // Get the database connector object
 450          $db = & $this->_db;
 451  
 452          if (!is_a($element, 'JSimpleXMLElement') || !count($element->children())) {
 453              // Either the tag does not exist or has no children therefore we return zero files processed.
 454              return 0;
 455          }
 456  
 457          // Get the array of query nodes to process
 458          $queries = $element->children();
 459          if (count($queries) == 0) {
 460              // No queries to process
 461              return 0;
 462          }
 463  
 464          // Process each query in the $queries array (children of $tagName).
 465          foreach ($queries as $query)
 466          {
 467              $db->setQuery($query->data());
 468              if (!$db->query()) {
 469                  JError::raiseWarning(1, 'JInstaller::install: '.JText::_('SQL Error')." ".$db->stderr(true));
 470                  return false;
 471              }
 472          }
 473          return (int) count($queries);
 474      }
 475  
 476      /**
 477       * Method to extract the name of a discreet installation sql file from the installation manifest file.
 478       *
 479       * @access    public
 480       * @param    object    $element     The xml node to process
 481       * @param    string    $version    The database connector to use
 482       * @return    mixed    Number of queries processed or False on error
 483       * @since    1.5
 484       */
 485  	function parseSQLFiles($element)
 486      {
 487          // Initialize variables
 488          $queries = array();
 489          $db = & $this->_db;
 490          $dbDriver = strtolower($db->get('name'));
 491          if ($dbDriver == 'mysqli') {
 492              $dbDriver = 'mysql';
 493          }
 494          $dbCharset = ($db->hasUTF()) ? 'utf8' : '';
 495  
 496          if (!is_a($element, 'JSimpleXMLElement')) {
 497              // The tag does not exist.
 498              return 0;
 499          }
 500  
 501          // Get the array of file nodes to process
 502          $files = $element->children();
 503          if (count($files) == 0) {
 504              // No files to process
 505              return 0;
 506          }
 507  
 508          // Get the name of the sql file to process
 509          $sqlfile = '';
 510          foreach ($files as $file)
 511          {
 512              $fCharset = (strtolower($file->attributes('charset')) == 'utf8') ? 'utf8' : '';
 513              $fDriver  = strtolower($file->attributes('driver'));
 514              if ($fDriver == 'mysqli') {
 515                  $fDriver = 'mysql';
 516              }
 517  
 518              if( $fCharset == $dbCharset && $fDriver == $dbDriver) {
 519                  $sqlfile = $file->data();
 520                  // Check that sql files exists before reading. Otherwise raise error for rollback
 521                  if ( !file_exists( $this->getPath('extension_administrator').DS.$sqlfile ) ) {
 522                      return false;
 523                  }
 524                  $buffer = file_get_contents($this->getPath('extension_administrator').DS.$sqlfile);
 525  
 526                  // Graceful exit and rollback if read not successful
 527                  if ( $buffer === false ) {
 528                      return false;
 529                  }
 530  
 531                  // Create an array of queries from the sql file
 532                  jimport('joomla.installer.helper');
 533                  $queries = JInstallerHelper::splitSql($buffer);
 534  
 535                  if (count($queries) == 0) {
 536                      // No queries to process
 537                      return 0;
 538                  }
 539  
 540                  // Process each query in the $queries array (split out of sql file).
 541                  foreach ($queries as $query)
 542                  {
 543                      $query = trim($query);
 544                      if ($query != '' && $query{0} != '#') {
 545                          $db->setQuery($query);
 546                          if (!$db->query()) {
 547                              JError::raiseWarning(1, 'JInstaller::install: '.JText::_('SQL Error')." ".$db->stderr(true));
 548                              return false;
 549                          }
 550                      }
 551                  }
 552              }
 553          }
 554  
 555          return (int) count($queries);
 556      }
 557  
 558      /**
 559       * Method to parse through a files element of the installation manifest and take appropriate
 560       * action.
 561       *
 562       * @access    public
 563       * @param    object    $element     The xml node to process
 564       * @param    int        $cid        Application ID of application to install to
 565       * @return    boolean    True on success
 566       * @since    1.5
 567       */
 568  	function parseFiles($element, $cid=0)
 569      {
 570          // Initialize variables
 571          $copyfiles = array ();
 572  
 573          // Get the client info
 574          jimport('joomla.application.helper');
 575          $client =& JApplicationHelper::getClientInfo($cid);
 576  
 577          if (!is_a($element, 'JSimpleXMLElement') || !count($element->children())) {
 578              // Either the tag does not exist or has no children therefore we return zero files processed.
 579              return 0;
 580          }
 581  
 582          // Get the array of file nodes to process
 583          $files = $element->children();
 584          if (count($files) == 0) {
 585              // No files to process
 586              return 0;
 587          }
 588  
 589          /*
 590           * Here we set the folder we are going to remove the files from.
 591           */
 592          if ($client) {
 593              $pathname = 'extension_'.$client->name;
 594              $destination = $this->getPath($pathname);
 595          } else {
 596              $pathname = 'extension_root';
 597              $destination = $this->getPath($pathname);
 598          }
 599  
 600          /*
 601           * Here we set the folder we are going to copy the files from.
 602           *
 603           * Does the element have a folder attribute?
 604           *
 605           * If so this indicates that the files are in a subdirectory of the source
 606           * folder and we should append the folder attribute to the source path when
 607           * copying files.
 608           */
 609          if ($folder = $element->attributes('folder')) {
 610              $source = $this->getPath('source').DS.$folder;
 611          } else {
 612              $source = $this->getPath('source');
 613          }
 614  
 615          // Process each file in the $files array (children of $tagName).
 616          foreach ($files as $file)
 617          {
 618              $path['src']    = $source.DS.$file->data();
 619              $path['dest']    = $destination.DS.$file->data();
 620  
 621              // Is this path a file or folder?
 622              $path['type']    = ( $file->name() == 'folder') ? 'folder' : 'file';
 623  
 624              /*
 625               * Before we can add a file to the copyfiles array we need to ensure
 626               * that the folder we are copying our file to exits and if it doesn't,
 627               * we need to create it.
 628               */
 629              if (basename($path['dest']) != $path['dest']) {
 630                  $newdir = dirname($path['dest']);
 631  
 632                  if (!JFolder::create($newdir)) {
 633                      JError::raiseWarning(1, 'JInstaller::install: '.JText::_('Failed to create directory').' "'.$newdir.'"');
 634                      return false;
 635                  }
 636              }
 637  
 638              // Add the file to the copyfiles array
 639              $copyfiles[] = $path;
 640          }
 641  
 642          return $this->copyFiles($copyfiles);
 643      }
 644  
 645      /**
 646       * Method to parse through a languages element of the installation manifest and take appropriate
 647       * action.
 648       *
 649       * @access    public
 650       * @param    object    $element     The xml node to process
 651       * @param    int        $cid        Application ID of application to install to
 652       * @return    boolean    True on success
 653       * @since    1.5
 654       */
 655  	function parseLanguages($element, $cid=0)
 656      {
 657          // Initialize variables
 658          $copyfiles = array ();
 659  
 660          // Get the client info
 661          jimport('joomla.application.helper');
 662          $client =& JApplicationHelper::getClientInfo($cid);
 663  
 664          if (!is_a($element, 'JSimpleXMLElement') || !count($element->children())) {
 665              // Either the tag does not exist or has no children therefore we return zero files processed.
 666              return 0;
 667          }
 668  
 669          // Get the array of file nodes to process
 670          $files = $element->children();
 671          if (count($files) == 0) {
 672              // No files to process
 673              return 0;
 674          }
 675  
 676          /*
 677           * Here we set the folder we are going to copy the files to.
 678           *
 679           * 'languages' Files are copied to JPATH_BASE/language/ folder
 680           */
 681          $destination = $client->path.DS.'language';
 682  
 683          /*
 684           * Here we set the folder we are going to copy the files from.
 685           *
 686           * Does the element have a folder attribute?
 687           *
 688           * If so this indicates that the files are in a subdirectory of the source
 689           * folder and we should append the folder attribute to the source path when
 690           * copying files.
 691           */
 692          if ($folder = $element->attributes('folder')) {
 693              $source = $this->getPath('source').DS.$folder;
 694          } else {
 695              $source = $this->getPath('source');
 696          }
 697  
 698          // Process each file in the $files array (children of $tagName).
 699          foreach ($files as $file)
 700          {
 701              /*
 702               * Language files go in a subfolder based on the language code, ie.
 703               *
 704               *         <language tag="en-US">en-US.mycomponent.ini</language>
 705               *
 706               * would go in the en-US subdirectory of the language folder.
 707               *
 708               * We will only install language files where a core language pack
 709               * already exists.
 710               */
 711              if ($file->attributes('tag') != '') {
 712                  $path['src']    = $source.DS.$file->data();
 713                  $path['dest']    = $destination.DS.$file->attributes('tag').DS.basename($file->data());
 714  
 715                  // If the language folder is not present, then the core pack hasn't been installed... ignore
 716                  if (!JFolder::exists(dirname($path['dest']))) {
 717                      continue;
 718                  }
 719              } else {
 720                  $path['src']    = $source.DS.$file->data();
 721                  $path['dest']    = $destination.DS.$file->data();
 722              }
 723  
 724              /*
 725               * Before we can add a file to the copyfiles array we need to ensure
 726               * that the folder we are copying our file to exits and if it doesn't,
 727               * we need to create it.
 728               */
 729              if (basename($path['dest']) != $path['dest']) {
 730                  $newdir = dirname($path['dest']);
 731  
 732                  if (!JFolder::create($newdir)) {
 733                      JError::raiseWarning(1, 'JInstaller::install: '.JText::_('Failed to create directory').' "'.$newdir.'"');
 734                      return false;
 735                  }
 736              }
 737  
 738              // Add the file to the copyfiles array
 739              $copyfiles[] = $path;
 740          }
 741  
 742          return $this->copyFiles($copyfiles);
 743      }
 744  
 745      /**
 746       * Method to parse through a media element of the installation manifest and take appropriate
 747       * action.
 748       *
 749       * @access    public
 750       * @param    object    $element     The xml node to process
 751       * @param    int        $cid        Application ID of application to install to
 752       * @return    boolean    True on success
 753       * @since    1.5
 754       */
 755  	function parseMedia($element, $cid=0)
 756      {
 757          // Initialize variables
 758          $copyfiles = array ();
 759  
 760          // Get the client info
 761          jimport('joomla.application.helper');
 762          $client =& JApplicationHelper::getClientInfo($cid);
 763  
 764          if (!is_a($element, 'JSimpleXMLElement') || !count($element->children())) {
 765              // Either the tag does not exist or has no children therefore we return zero files processed.
 766              return 0;
 767          }
 768  
 769          // Get the array of file nodes to process
 770          $files = $element->children();
 771          if (count($files) == 0) {
 772              // No files to process
 773              return 0;
 774          }
 775  
 776          /*
 777           * Here we set the folder we are going to copy the files to.
 778           *     Default 'media' Files are copied to the JPATH_BASE/media folder
 779           */
 780          $folder = ($element->attributes('destination')) ? DS.$element->attributes('destination') : null;
 781          $destination = JPath::clean(JPATH_ROOT.DS.'media'.$folder);
 782  
 783          /*
 784           * Here we set the folder we are going to copy the files from.
 785           *
 786           * Does the element have a folder attribute?
 787           *
 788           * If so this indicates that the files are in a subdirectory of the source
 789           * folder and we should append the folder attribute to the source path when
 790           * copying files.
 791           */
 792          if ($folder = $element->attributes('folder')) {
 793              $source = $this->getPath('source').DS.$folder;
 794          } else {
 795              $source = $this->getPath('source');
 796          }
 797  
 798          // Process each file in the $files array (children of $tagName).
 799          foreach ($files as $file)
 800          {
 801              $path['src']    = $source.DS.$file->data();
 802              $path['dest']    = $destination.DS.$file->data();
 803  
 804              // Is this path a file or folder?
 805              $path['type']    = ( $file->name() == 'folder') ? 'folder' : 'file';
 806  
 807              /*
 808               * Before we can add a file to the copyfiles array we need to ensure
 809               * that the folder we are copying our file to exits and if it doesn't,
 810               * we need to create it.
 811               */
 812              if (basename($path['dest']) != $path['dest']) {
 813                  $newdir = dirname($path['dest']);
 814  
 815                  if (!JFolder::create($newdir)) {
 816                      JError::raiseWarning(1, 'JInstaller::install: '.JText::_('Failed to create directory').' "'.$newdir.'"');
 817                      return false;
 818                  }
 819              }
 820  
 821              // Add the file to the copyfiles array
 822              $copyfiles[] = $path;
 823          }
 824  
 825          return $this->copyFiles($copyfiles);
 826      }
 827  
 828      /**
 829       * Method to parse the parameters of an extension, build the INI
 830       * string for it's default parameters, and return the INI string.
 831       *
 832       * @access    public
 833       * @return    string    INI string of parameter values
 834       * @since    1.5
 835       */
 836  	function getParams()
 837      {
 838          // Get the manifest document root element
 839          $root = & $this->_manifest->document;
 840  
 841          // Get the element of the tag names
 842          $element =& $root->getElementByPath('params');
 843          if (!is_a($element, 'JSimpleXMLElement') || !count($element->children())) {
 844              // Either the tag does not exist or has no children therefore we return zero files processed.
 845              return null;
 846          }
 847  
 848          // Get the array of parameter nodes to process
 849          $params = $element->children();
 850          if (count($params) == 0) {
 851              // No params to process
 852              return null;
 853          }
 854  
 855          // Process each parameter in the $params array.
 856          $ini = null;
 857          foreach ($params as $param) {
 858              if (!$name = $param->attributes('name')) {
 859                  continue;
 860              }
 861  
 862              if (!$value = $param->attributes('default')) {
 863                  continue;
 864              }
 865  
 866              $ini .= $name."=".$value."\n";
 867          }
 868          return $ini;
 869      }
 870  
 871      /**
 872       * Copy files from source directory to the target directory
 873       *
 874       * @access    public
 875       * @param    array $files array with filenames
 876       * @param    boolean $overwrite True if existing files can be replaced
 877       * @return    boolean True on success
 878       * @since    1.5
 879       */
 880  	function copyFiles($files, $overwrite=null)
 881      {
 882          /*
 883           * To allow for manual override on the overwriting flag, we check to see if
 884           * the $overwrite flag was set and is a boolean value.  If not, use the object
 885           * allowOverwrite flag.
 886           */
 887          if (is_null($overwrite) || !is_bool($overwrite)) {
 888              $overwrite = $this->_overwrite;
 889          }
 890  
 891          /*
 892           * $files must be an array of filenames.  Verify that it is an array with
 893           * at least one file to copy.
 894           */
 895          if (is_array($files) && count($files) > 0)
 896          {
 897              foreach ($files as $file)
 898              {
 899                  // Get the source and destination paths
 900                  $filesource    = JPath::clean($file['src']);
 901                  $filedest    = JPath::clean($file['dest']);
 902                  $filetype    = array_key_exists('type', $file) ? $file['type'] : 'file';
 903  
 904                  if (!file_exists($filesource)) {
 905                      /*
 906                       * The source file does not exist.  Nothing to copy so set an error
 907                       * and return false.
 908                       */
 909                      JError::raiseWarning(1, 'JInstaller::install: '.JText::sprintf('File does not exist', $filesource));
 910                      return false;
 911                  } elseif (file_exists($filedest) && !$overwrite) {
 912  
 913                          /*
 914                           * It's okay if the manifest already exists
 915                           */
 916                          if ($this->getPath( 'manifest' ) == $filesource) {
 917                              continue;
 918                          }
 919  
 920                          /*
 921                           * The destination file already exists and the overwrite flag is false.
 922                           * Set an error and return false.
 923                           */
 924                          JError::raiseWarning(1, 'JInstaller::install: '.JText::sprintf('WARNSAME', $filedest));
 925                          return false;
 926                  } else {
 927  
 928                      // Copy the folder or file to the new location.
 929                      if ( $filetype == 'folder') {
 930  
 931                          if (!(JFolder::copy($filesource, $filedest, null, $overwrite))) {
 932                              JError::raiseWarning(1, 'JInstaller::install: '.JText::sprintf('Failed to copy folder to', $filesource, $filedest));
 933                              return false;
 934                          }
 935  
 936                          $step = array ('type' => 'folder', 'path' => $filedest);
 937                      } else {
 938  
 939                          if (!(JFile::copy($filesource, $filedest))) {
 940                              JError::raiseWarning(1, 'JInstaller::install: '.JText::sprintf('Failed to copy file to', $filesource, $filedest));
 941                              return false;
 942                          }
 943  
 944                          $step = array ('type' => 'file', 'path' => $filedest);
 945                      }
 946  
 947                      /*
 948                       * Since we copied a file/folder, we want to add it to the installation step stack so that
 949                       * in case we have to roll back the installation we can remove the files copied.
 950                       */
 951                      $this->_stepStack[] = $step;
 952                  }
 953              }
 954          } else {
 955  
 956              /*
 957               * The $files variable was either not an array or an empty array
 958               */
 959              return false;
 960          }
 961          return count($files);
 962      }
 963  
 964      /**
 965       * Method to parse through a files element of the installation manifest and remove
 966       * the files that were installed
 967       *
 968       * @access    public
 969       * @param    object    $element     The xml node to process
 970       * @param    int        $cid        Application ID of application to remove from
 971       * @return    boolean    True on success
 972       * @since    1.5
 973       */
 974  	function removeFiles($element, $cid=0)
 975      {
 976          // Initialize variables
 977          $removefiles = array ();
 978          $retval = true;
 979  
 980          // Get the client info
 981          jimport('joomla.application.helper');
 982          $client =& JApplicationHelper::getClientInfo($cid);
 983  
 984          if (!is_a($element, 'JSimpleXMLElement') || !count($element->children())) {
 985              // Either the tag does not exist or has no children therefore we return zero files processed.
 986              return true;
 987          }
 988  
 989          // Get the array of file nodes to process
 990          $files = $element->children();
 991          if (count($files) == 0) {
 992              // No files to process
 993              return true;
 994          }
 995  
 996          /*
 997           * Here we set the folder we are going to remove the files from.  There are a few
 998           * special cases that need to be considered for certain reserved tags.
 999           */
1000          switch ($element->name())
1001          {
1002              case 'media':
1003                  if ($element->attributes('destination')) {
1004                      $folder = $element->attributes('destination');
1005                  } else {
1006                      $folder = '';
1007                  }
1008                  $source = $client->path.DS.'media'.DS.$folder;
1009                  break;
1010  
1011              case 'languages':
1012                  $source = $client->path.DS.'language';
1013                  break;
1014  
1015              default:
1016                  if ($client) {
1017                      $pathname = 'extension_'.$client->name;
1018                      $source = $this->getPath($pathname);
1019                  } else {
1020                      $pathname = 'extension_root';
1021                      $source = $this->getPath($pathname);
1022                  }
1023                  break;
1024          }
1025  
1026          // Process each file in the $files array (children of $tagName).
1027          foreach ($files as $file)
1028          {
1029              /*
1030               * If the file is a language, we must handle it differently.  Language files
1031               * go in a subdirectory based on the language code, ie.
1032               *
1033               *         <language tag="en_US">en_US.mycomponent.ini</language>
1034               *
1035               * would go in the en_US subdirectory of the languages directory.
1036               */
1037              if ($file->name() == 'language' && $file->attributes('tag') != '') {
1038                  $path = $source.DS.$file->attributes('tag').DS.basename($file->data());
1039  
1040                  // If the language folder is not present, then the core pack hasn't been installed... ignore
1041                  if (!JFolder::exists(dirname($path))) {
1042                      continue;
1043                  }
1044              } else {
1045                  $path = $source.DS.$file->data();
1046              }
1047  
1048              /*
1049               * Actually delete the files/folders
1050               */
1051              if (is_dir($path)) {
1052                  $val = JFolder::delete($path);
1053              } else {
1054                  $val = JFile::delete($path);
1055              }
1056  
1057              if ($val === false) {
1058                  $retval = false;
1059              }
1060          }
1061  
1062          return $retval;
1063      }
1064  
1065      /**
1066       * Copies the installation manifest file to the extension folder in the given client
1067       *
1068       * @access    public
1069       * @param    int        $cid    Where to copy the installfile [optional: defaults to 1 (admin)]
1070       * @return    boolean    True on success, False on error
1071       * @since    1.5
1072       */
1073  	function copyManifest($cid=1)
1074      {
1075          // Get the client info
1076          jimport('joomla.application.helper');
1077          $client =& JApplicationHelper::getClientInfo($cid);
1078  
1079          $path['src'] = $this->getPath('manifest');
1080  
1081          if ($client) {
1082              $pathname = 'extension_'.$client->name;
1083              $path['dest']  = $this->getPath($pathname).DS.basename($this->getPath('manifest'));
1084          } else {
1085              $pathname = 'extension_root';
1086              $path['dest']  = $this->getPath($pathname).DS.basename($this->getPath('manifest'));
1087          }
1088          return $this->copyFiles(array ($path), true);
1089      }
1090  
1091      /**
1092       * Tries to find the package manifest file
1093       *
1094       * @access private
1095       * @return boolean True on success, False on error
1096       * @since 1.0
1097       */
1098  	function _findManifest()
1099      {
1100          // Get an array of all the xml files from teh installation directory
1101          $xmlfiles = JFolder::files($this->getPath('source'), '.xml$', 1, true);
1102          // If at least one xml file exists
1103          if (!empty($xmlfiles)) {
1104              foreach ($xmlfiles as $file)
1105              {
1106                  // Is it a valid joomla installation manifest file?
1107                  $manifest = $this->_isManifest($file);
1108                  if (!is_null($manifest)) {
1109  
1110                      // If the root method attribute is set to upgrade, allow file overwrite
1111                      $root =& $manifest->document;
1112                      if ($root->attributes('method') == 'upgrade') {
1113                          $this->_overwrite = true;
1114                      }
1115  
1116                      // Set the manifest object and path
1117                      $this->_manifest =& $manifest;
1118                      $this->setPath('manifest', $file);
1119  
1120                      // Set the installation source path to that of the manifest file
1121                      $this->setPath('source', dirname($file));
1122                      return true;
1123                  }
1124              }
1125  
1126              // None of the xml files found were valid install files
1127              JError::raiseWarning(1, 'JInstaller::install: '.JText::_('ERRORNOTFINDJOOMLAXMLSETUPFILE'));
1128              return false;
1129          } else {
1130              // No xml files were found in the install folder
1131              JError::raiseWarning(1, 'JInstaller::install: '.JText::_('ERRORXMLSETUP'));
1132              return false;
1133          }
1134      }
1135  
1136      /**
1137       * Is the xml file a valid Joomla installation manifest file
1138       *
1139       * @access    private
1140       * @param    string    $file    An xmlfile path to check
1141       * @return    mixed    A JSimpleXML document, or null if the file failed to parse
1142       * @since    1.5
1143       */
1144      function &_isManifest($file)
1145      {
1146          // Initialize variables
1147          $null    = null;
1148          $xml    =& JFactory::getXMLParser('Simple');
1149  
1150          // If we cannot load the xml file return null
1151          if (!$xml->loadFile($file)) {
1152              // Free up xml parser memory and return null
1153              unset ($xml);
1154              return $null;
1155          }
1156  
1157          /*
1158           * Check for a valid XML root tag.
1159           * @todo: Remove backwards compatability in a future version
1160           * Should be 'install', but for backward compatability we will accept 'mosinstall'.
1161           */
1162          $root =& $xml->document;
1163          if (!is_object($root) || ($root->name() != 'install' && $root->name() != 'mosinstall')) {
1164              // Free up xml parser memory and return null
1165              unset ($xml);
1166              return $null;
1167          }
1168  
1169          // Valid manifest file return the object
1170          return $xml;
1171      }
1172  }


Generated: Wed Mar 28 15:54:07 2012 Cross-referenced by PHPXref 0.7.1