Source for file package.php

Documentation is available at package.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Libraries
  4.  * @subpackage  Installer
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 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.base.adapterinstance');
  13.  
  14. /**
  15.  * Package installer
  16.  *
  17.  * @package     Joomla.Libraries
  18.  * @subpackage  Installer
  19.  * @since       3.1
  20.  */
  21. {
  22.     /**
  23.      * Method of system
  24.      *
  25.      * @var    string 
  26.      *
  27.      * @since  3.1
  28.      */
  29.     protected $route = 'install';
  30.  
  31.     /**
  32.      * <scriptfile> element of the extension manifest
  33.      *
  34.      * @var    object 
  35.      * @since  3.1
  36.      */
  37.     protected $scriptElement = null;
  38.  
  39.     /**
  40.      * Load language from a path
  41.      *
  42.      * @param   string  $path  The path of the language.
  43.      *
  44.      * @return  void 
  45.      *
  46.      * @since   3.1
  47.      */
  48.     public function loadLanguage($path)
  49.     {
  50.         $this->manifest $this->parent->getManifest();
  51.         $extension 'pkg_' strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->packagename'cmd'));
  52.         $lang JFactory::getLanguage();
  53.         $source $path;
  54.         $lang->load($extension '.sys'$sourcenullfalsetrue)
  55.             || $lang->load($extension '.sys'JPATH_SITEnullfalsetrue);
  56.     }
  57.  
  58.     /**
  59.      * Custom install method
  60.      *
  61.      * @return  int  The extension id
  62.      *
  63.      * @since   3.1
  64.      */
  65.     public function install()
  66.     {
  67.         // Get the extension manifest object
  68.         $this->manifest $this->parent->getManifest();
  69.  
  70.         /*
  71.          * ---------------------------------------------------------------------------------------------
  72.          * Manifest Document Setup Section
  73.          * ---------------------------------------------------------------------------------------------
  74.          */
  75.  
  76.         // Set the extensions name
  77.         $filter JFilterInput::getInstance();
  78.         $name = (string) $this->manifest->packagename;
  79.         $name $filter->clean($name'cmd');
  80.         $this->set('name'$name);
  81.  
  82.         $element 'pkg_' $filter->clean($this->manifest->packagename'cmd');
  83.         $this->set('element'$element);
  84.  
  85.         // Get the component description
  86.         $description = (string) $this->manifest->description;
  87.  
  88.         if ($description)
  89.         {
  90.             $this->parent->set('message'JText::_($description));
  91.         }
  92.         else
  93.         {
  94.             $this->parent->set('message''');
  95.         }
  96.  
  97.         // Set the installation path
  98.         $files $this->manifest->files;
  99.         $group = (string) $this->manifest->packagename;
  100.  
  101.         if (!empty($group))
  102.         {
  103.             $this->parent->setPath('extension_root'JPATH_MANIFESTS '/packages/' implode(DIRECTORY_SEPARATORexplode('/'$group)));
  104.         }
  105.         else
  106.         {
  107.             $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_PACK'JText::_('JLIB_INSTALLER_' strtoupper($this->route))));
  108.  
  109.             return false;
  110.         }
  111.  
  112.         /*
  113.          * If the package manifest already exists, then we will assume that the package is already
  114.          * installed.
  115.          */
  116.  
  117.         if (file_exists(JPATH_MANIFESTS '/packages/' basename($this->parent->getPath('manifest'))))
  118.         {
  119.             // Look for an update function or update tag
  120.             $updateElement $this->manifest->update;
  121.  
  122.             // If $this->upgrade has already been set, or an update property exists in the manifest, update the extensions
  123.             if ($this->parent->isUpgrade(|| $updateElement)
  124.             {
  125.                 // Use the update route for all packaged extensions
  126.                 $this->route = 'update';
  127.             }
  128.         }
  129.  
  130.         /**
  131.          * ---------------------------------------------------------------------------------------------
  132.          * Installer Trigger Loading
  133.          * ---------------------------------------------------------------------------------------------
  134.          */
  135.  
  136.         // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
  137.         $this->scriptElement = $this->manifest->scriptfile;
  138.         $manifestScript = (string) $this->manifest->scriptfile;
  139.  
  140.         if ($manifestScript)
  141.         {
  142.             $manifestScriptFile $this->parent->getPath('source''/' $manifestScript;
  143.  
  144.             if (is_file($manifestScriptFile))
  145.             {
  146.                 // Load the file
  147.                 include_once $manifestScriptFile;
  148.             }
  149.  
  150.             // Set the class name
  151.             $classname $element 'InstallerScript';
  152.  
  153.             if (class_exists($classname))
  154.             {
  155.                 // Create a new instance
  156.                 $this->parent->manifestClass new $classname($this);
  157.  
  158.                 // And set this so we can copy it later
  159.                 $this->set('manifest_script'$manifestScript);
  160.             }
  161.         }
  162.  
  163.         // Run preflight if possible (since we know we're not an update)
  164.         ob_start();
  165.         ob_implicit_flush(false);
  166.  
  167.         if ($this->parent->manifestClass && method_exists($this->parent->manifestClass'preflight'))
  168.         {
  169.             if ($this->parent->manifestClass->preflight($this->route$this=== false)
  170.             {
  171.                 // Preflight failed, rollback changes
  172.                 $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PACKAGE_INSTALL_CUSTOM_INSTALL_FAILURE'));
  173.  
  174.                 return false;
  175.             }
  176.         }
  177.  
  178.         // Create msg object; first use here
  179.         $msg ob_get_contents();
  180.         ob_end_clean();
  181.  
  182.         /*
  183.          * ---------------------------------------------------------------------------------------------
  184.          * Filesystem Processing Section
  185.          * ---------------------------------------------------------------------------------------------
  186.          */
  187.  
  188.         if ($folder $files->attributes()->folder)
  189.         {
  190.             $source $this->parent->getPath('source''/' $folder;
  191.         }
  192.         else
  193.         {
  194.             $source $this->parent->getPath('source');
  195.         }
  196.  
  197.         // Install all necessary files
  198.         if (count($this->manifest->files->children()))
  199.         {
  200.             $i 0;
  201.  
  202.             foreach ($this->manifest->files->children(as $child)
  203.             {
  204.                 $file $source '/' $child;
  205.  
  206.                 if (is_dir($file))
  207.                 {
  208.                     // If it's actually a directory then fill it up
  209.                     $package array();
  210.                     $package['dir'$file;
  211.                     $package['type'JInstallerHelper::detectType($file);
  212.                 }
  213.                 else
  214.                 {
  215.                     // If it's an archive
  216.                     $package JInstallerHelper::unpack($file);
  217.                 }
  218.                 $tmpInstaller new JInstaller;
  219.                 $installResult $tmpInstaller->{$this->route}($package['dir']);
  220.  
  221.                 if (!$installResult)
  222.                 {
  223.                     $this->parent->abort(
  224.                         JText::sprintf(
  225.                             'JLIB_INSTALLER_ABORT_PACK_INSTALL_ERROR_EXTENSION'JText::_('JLIB_INSTALLER_' strtoupper($this->route)),
  226.                             basename($file)
  227.                         )
  228.                     );
  229.  
  230.                     return false;
  231.                 }
  232.                 else
  233.                 {
  234.                     $results[$iarray(
  235.                         'name' => $tmpInstaller->manifest->name,
  236.                         'result' => $installResult
  237.                     );
  238.                 }
  239.                 $i++;
  240.             }
  241.         }
  242.         else
  243.         {
  244.             $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_FILES'JText::_('JLIB_INSTALLER_' strtoupper($this->route))));
  245.  
  246.             return false;
  247.         }
  248.  
  249.         // Parse optional tags
  250.         $this->parent->parseLanguages($this->manifest->languages);
  251.  
  252.         /*
  253.          * ---------------------------------------------------------------------------------------------
  254.          * Extension Registration
  255.          * ---------------------------------------------------------------------------------------------
  256.          */
  257.  
  258.         $row JTable::getInstance('extension');
  259.         $eid $row->find(array('element' => strtolower($this->get('element'))'type' => 'package'));
  260.  
  261.         if ($eid)
  262.         {
  263.             $row->load($eid);
  264.         }
  265.         else
  266.         {
  267.             $row->name $this->get('name');
  268.             $row->type 'package';
  269.             $row->element $this->get('element');
  270.  
  271.             // There is no folder for modules
  272.             $row->folder '';
  273.             $row->enabled 1;
  274.             $row->protected 0;
  275.             $row->access 1;
  276.             $row->client_id 0;
  277.  
  278.             // Custom data
  279.             $row->custom_data '';
  280.             $row->params $this->parent->getParams();
  281.         }
  282.         // Update the manifest cache for the entry
  283.         $row->manifest_cache $this->parent->generateManifestCache();
  284.  
  285.         if (!$row->store())
  286.         {
  287.             // Install failed, roll back changes
  288.             $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_ROLLBACK'$row->getError()));
  289.  
  290.             return false;
  291.         }
  292.  
  293.         /*
  294.          * ---------------------------------------------------------------------------------------------
  295.          * Finalization and Cleanup Section
  296.          * ---------------------------------------------------------------------------------------------
  297.          */
  298.  
  299.         // Run the custom method based on the route
  300.         ob_start();
  301.         ob_implicit_flush(false);
  302.  
  303.         if ($this->parent->manifestClass && method_exists($this->parent->manifestClass$this->route))
  304.         {
  305.             if ($this->parent->manifestClass->{$this->route}($this=== false)
  306.             {
  307.                 // Install failed, rollback changes
  308.                 $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_FILE_INSTALL_CUSTOM_INSTALL_FAILURE'));
  309.  
  310.                 return false;
  311.             }
  312.         }
  313.  
  314.         // Append messages
  315.         $msg .= ob_get_contents();
  316.         ob_end_clean();
  317.  
  318.         // Lastly, we will copy the manifest file to its appropriate place.
  319.         $manifest array();
  320.         $manifest['src'$this->parent->getPath('manifest');
  321.         $manifest['dest'JPATH_MANIFESTS '/packages/' basename($this->parent->getPath('manifest'));
  322.  
  323.         if (!$this->parent->copyFiles(array($manifest)true))
  324.         {
  325.             // Install failed, rollback changes
  326.             $this->parent->abort(
  327.                 JText::sprintf('JLIB_INSTALLER_ABORT_PACK_INSTALL_COPY_SETUP'JText::_('JLIB_INSTALLER_ABORT_PACK_INSTALL_NO_FILES'))
  328.             );
  329.  
  330.             return false;
  331.         }
  332.  
  333.         // If there is a manifest script, let's copy it.
  334.         if ($this->get('manifest_script'))
  335.         {
  336.             // First, we have to create a folder for the script if one isn't present
  337.             if (!file_exists($this->parent->getPath('extension_root')))
  338.             {
  339.                 JFolder::create($this->parent->getPath('extension_root'));
  340.             }
  341.  
  342.             $path['src'$this->parent->getPath('source''/' $this->get('manifest_script');
  343.             $path['dest'$this->parent->getPath('extension_root''/' $this->get('manifest_script');
  344.  
  345.             if (!file_exists($path['dest']|| $this->parent->isOverwrite())
  346.             {
  347.                 if (!$this->parent->copyFiles(array($path)))
  348.                 {
  349.                     // Install failed, rollback changes
  350.                     $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_PACKAGE_INSTALL_MANIFEST'));
  351.  
  352.                     return false;
  353.                 }
  354.             }
  355.         }
  356.  
  357.         // And now we run the postflight
  358.         ob_start();
  359.         ob_implicit_flush(false);
  360.  
  361.         if ($this->parent->manifestClass && method_exists($this->parent->manifestClass'postflight'))
  362.         {
  363.             $this->parent->manifestClass->postflight($this->route$this$results);
  364.         }
  365.  
  366.         // Append messages
  367.         $msg .= ob_get_contents();
  368.         ob_end_clean();
  369.  
  370.         if ($msg != '')
  371.         {
  372.             $this->parent->set('extension_message'$msg);
  373.         }
  374.         return $row->extension_id;
  375.     }
  376.  
  377.     /**
  378.      * Updates a package
  379.      *
  380.      * The only difference between an update and a full install
  381.      * is how we handle the database
  382.      *
  383.      * @return  void 
  384.      *
  385.      * @since   3.1
  386.      */
  387.     public function update()
  388.     {
  389.         $this->route = 'update';
  390.         $this->install();
  391.     }
  392.  
  393.     /**
  394.      * Custom uninstall method
  395.      *
  396.      * @param   integer  $id  The id of the package to uninstall.
  397.      *
  398.      * @return  boolean  True on success
  399.      *
  400.      * @since   3.1
  401.      */
  402.     public function uninstall($id)
  403.     {
  404.         $row null;
  405.         $retval true;
  406.  
  407.         $row JTable::getInstance('extension');
  408.         $row->load($id);
  409.  
  410.         if ($row->protected)
  411.         {
  412.             JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_WARNCOREPACK')JLog::WARNING'jerror');
  413.  
  414.             return false;
  415.         }
  416.  
  417.         $manifestFile JPATH_MANIFESTS '/packages/' $row->get('element''.xml';
  418.         $manifest new JInstallerManifestPackage($manifestFile);
  419.  
  420.         // Set the package root path
  421.         $this->parent->setPath('extension_root'JPATH_MANIFESTS '/packages/' $manifest->packagename);
  422.  
  423.         // Because packages may not have their own folders we cannot use the standard method of finding an installation manifest
  424.         if (!file_exists($manifestFile))
  425.         {
  426.             // TODO: Fail?
  427.             JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MISSINGMANIFEST')JLog::WARNING'jerror');
  428.  
  429.             return false;
  430.  
  431.         }
  432.  
  433.         $xml simplexml_load_file($manifestFile);
  434.  
  435.         // If we cannot load the XML file return false
  436.         if (!$xml)
  437.         {
  438.             JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_LOAD_MANIFEST')JLog::WARNING'jerror');
  439.  
  440.             return false;
  441.         }
  442.  
  443.         // Check for a valid XML root tag.
  444.         if ($xml->getName(!= 'extension')
  445.         {
  446.             JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_INVALID_MANIFEST')JLog::WARNING'jerror');
  447.  
  448.             return false;
  449.         }
  450.  
  451.         // If there is an manifest class file, let's load it
  452.         $this->scriptElement = $manifest->scriptfile;
  453.         $manifestScript = (string) $manifest->scriptfile;
  454.  
  455.         if ($manifestScript)
  456.         {
  457.             $manifestScriptFile $this->parent->getPath('extension_root''/' $manifestScript;
  458.  
  459.             if (is_file($manifestScriptFile))
  460.             {
  461.                 // Load the file
  462.                 include_once $manifestScriptFile;
  463.             }
  464.  
  465.             // Set the class name
  466.             $classname $row->element 'InstallerScript';
  467.  
  468.             if (class_exists($classname))
  469.             {
  470.                 // Create a new instance
  471.                 $this->parent->manifestClass new $classname($this);
  472.  
  473.                 // And set this so we can copy it later
  474.                 $this->set('manifest_script'$manifestScript);
  475.             }
  476.         }
  477.  
  478.         ob_start();
  479.         ob_implicit_flush(false);
  480.  
  481.         // Run uninstall if possible
  482.         if ($this->parent->manifestClass && method_exists($this->parent->manifestClass'uninstall'))
  483.         {
  484.             $this->parent->manifestClass->uninstall($this);
  485.         }
  486.  
  487.         $msg ob_get_contents();
  488.         ob_end_clean();
  489.  
  490.         if ($msg != '')
  491.         {
  492.             $this->parent->set('extension_message'$msg);
  493.         }
  494.  
  495.         $error false;
  496.  
  497.         foreach ($manifest->filelist as $extension)
  498.         {
  499.             $tmpInstaller new JInstaller;
  500.             $id $this->_getExtensionID($extension->type$extension->id$extension->client$extension->group);
  501.             $client JApplicationHelper::getClientInfo($extension->clienttrue);
  502.  
  503.             if ($id)
  504.             {
  505.                 if (!$tmpInstaller->uninstall($extension->type$id$client->id))
  506.                 {
  507.                     $error true;
  508.                     JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_NOT_PROPER'basename($extension->filename))JLog::WARNING'jerror');
  509.                 }
  510.             }
  511.             else
  512.             {
  513.                 JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_UNKNOWN_EXTENSION')JLog::WARNING'jerror');
  514.             }
  515.         }
  516.  
  517.         // Remove any language files
  518.         $this->parent->removeFiles($xml->languages);
  519.  
  520.         // Clean up manifest file after we're done if there were no errors
  521.         if (!$error)
  522.         {
  523.             JFile::delete($manifestFile);
  524.             $folder $this->parent->getPath('extension_root');
  525.  
  526.             if (JFolder::exists($folder))
  527.             {
  528.                 JFolder::delete($folder);
  529.             }
  530.             $row->delete();
  531.         }
  532.         else
  533.         {
  534.             JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_UNINSTALL_MANIFEST_NOT_REMOVED')JLog::WARNING'jerror');
  535.         }
  536.  
  537.         // Return the result up the line
  538.         return $retval;
  539.     }
  540.  
  541.     /**
  542.      * Gets the extension id.
  543.      *
  544.      * @param   string   $type    The extension type.
  545.      * @param   string   $id      The name of the extension (the element field).
  546.      * @param   integer  $client  The application id (0: Joomla CMS site; 1: Joomla CMS administrator).
  547.      * @param   string   $group   The extension group (mainly for plugins).
  548.      *
  549.      * @return  integer 
  550.      *
  551.      * @since   3.1
  552.      */
  553.     protected function _getExtensionID($type$id$client$group)
  554.     {
  555.         $db $this->parent->getDbo();
  556.  
  557.         $query $db->getQuery(true)
  558.             ->select('extension_id')
  559.             ->from('#__extensions')
  560.             ->where('type = ' $db->quote($type))
  561.             ->where('element = ' $db->quote($id));
  562.  
  563.         switch ($type)
  564.         {
  565.             case 'plugin':
  566.                 // Plugins have a folder but not a client
  567.                 $query->where('folder = ' $db->quote($group));
  568.                 break;
  569.  
  570.             case 'library':
  571.             case 'package':
  572.             case 'component':
  573.                 // Components, packages and libraries don't have a folder or client.
  574.                 // Included for completeness.
  575.                 break;
  576.  
  577.             case 'language':
  578.             case 'module':
  579.             case 'template':
  580.                 // Languages, modules and templates have a client but not a folder
  581.                 $client JApplicationHelper::getClientInfo($clienttrue);
  582.                 $query->where('client_id = ' . (int) $client->id);
  583.                 break;
  584.         }
  585.  
  586.         $db->setQuery($query);
  587.         $result $db->loadResult();
  588.  
  589.         // Note: For templates, libraries and packages their unique name is their key.
  590.         // This means they come out the same way they came in.
  591.         return $result;
  592.     }
  593.  
  594.     /**
  595.      * Refreshes the extension table cache
  596.      *
  597.      * @return  boolean  Result of operation, true if updated, false on failure
  598.      *
  599.      * @since   3.1
  600.      */
  601.     public function refreshManifestCache()
  602.     {
  603.         // Need to find to find where the XML file is since we don't store this normally
  604.         $manifestPath JPATH_MANIFESTS '/packages/' $this->parent->extension->element '.xml';
  605.         $this->parent->manifest $this->parent->isManifest($manifestPath);
  606.         $this->parent->setPath('manifest'$manifestPath);
  607.  
  608.         $manifest_details JInstaller::parseXMLInstallFile($this->parent->getPath('manifest'));
  609.         $this->parent->extension->manifest_cache json_encode($manifest_details);
  610.         $this->parent->extension->name $manifest_details['name'];
  611.  
  612.         try
  613.         {
  614.             return $this->parent->extension->store();
  615.         }
  616.         catch (RuntimeException $e)
  617.         {
  618.             JLog::add(JText::_('JLIB_INSTALLER_ERROR_PACK_REFRESH_MANIFEST_CACHE')JLog::WARNING'jerror');
  619.  
  620.             return false;
  621.         }
  622.     }
  623. }
  624.  
  625. /**
  626.  * Deprecated class placeholder. You should use JInstallerAdapterPackage instead.
  627.  *
  628.  * @package     Joomla.Libraries
  629.  * @subpackage  Installer
  630.  * @since       3.1
  631.  * @deprecated  4.0
  632.  * @codeCoverageIgnore
  633.  */
  634. {
  635. }

Documentation generated on Tue, 19 Nov 2013 15:10:02 +0100 by phpDocumentor 1.4.3