/common/libraries/plugin/pear/PEAR/Installer.php
PHP | 2079 lines | 1736 code | 97 blank | 246 comment | 285 complexity | 17d55bc8cd9ae1257d4265f620a19e0a MD5 | raw file
Possible License(s): GPL-3.0, MIT, GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * PEAR_Installer
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 3.0 of the PHP license
- * that is available through the world-wide-web at the following URI:
- * http://www.php.net/license/3_0.txt. If you did not receive a copy of
- * the PHP License and are unable to obtain it through the web, please
- * send a note to license@php.net so we can mail you a copy immediately.
- *
- * @category pear
- * @package PEAR
- * @author Stig Bakken <ssb@php.net>
- * @author Tomas V.V. Cox <cox@idecnet.com>
- * @author Martin Jansen <mj@php.net>
- * @author Greg Beaver <cellog@php.net>
- * @copyright 1997-2008 The PHP Group
- * @license http://www.php.net/license/3_0.txt PHP License 3.0
- * @version CVS: $Id: Installer.php 137 2009-11-09 13:24:37Z vanpouckesven $
- * @link http://pear.php.net/package/PEAR
- * @since File available since Release 0.1
- */
-
- /**
- * Used for installation groups in package.xml 2.0 and platform exceptions
- */
- require_once 'OS/Guess.php';
- require_once 'PEAR/Downloader.php';
-
- define('PEAR_INSTALLER_NOBINARY', - 240);
- /**
- * Administration class used to install PEAR packages and maintain the
- * installed package database.
- *
- * @category pear
- * @package PEAR
- * @author Stig Bakken <ssb@php.net>
- * @author Tomas V.V. Cox <cox@idecnet.com>
- * @author Martin Jansen <mj@php.net>
- * @author Greg Beaver <cellog@php.net>
- * @copyright 1997-2008 The PHP Group
- * @license http://www.php.net/license/3_0.txt PHP License 3.0
- * @version Release: 1.7.2
- * @link http://pear.php.net/package/PEAR
- * @since Class available since Release 0.1
- */
- class PEAR_Installer extends PEAR_Downloader
- {
- // {{{ properties
-
-
- /** name of the package directory, for example Foo-1.0
- * @var string
- */
- var $pkgdir;
-
- /** directory where PHP code files go
- * @var string
- */
- var $phpdir;
-
- /** directory where PHP extension files go
- * @var string
- */
- var $extdir;
-
- /** directory where documentation goes
- * @var string
- */
- var $docdir;
-
- /** installation root directory (ala PHP's INSTALL_ROOT or
- * automake's DESTDIR
- * @var string
- */
- var $installroot = '';
-
- /** debug level
- * @var int
- */
- var $debug = 1;
-
- /** temporary directory
- * @var string
- */
- var $tmpdir;
-
- /**
- * PEAR_Registry object used by the installer
- * @var PEAR_Registry
- */
- var $registry;
-
- /**
- * array of PEAR_Downloader_Packages
- * @var array
- */
- var $_downloadedPackages;
-
- /** List of file transactions queued for an install/upgrade/uninstall.
- *
- * Format:
- * array(
- * 0 => array("rename => array("from-file", "to-file")),
- * 1 => array("delete" => array("file-to-delete")),
- * ...
- * )
- *
- * @var array
- */
- var $file_operations = array();
-
- // }}}
-
-
- // {{{ constructor
-
-
- /**
- * PEAR_Installer constructor.
- *
- * @param object $ui user interface object (instance of PEAR_Frontend_*)
- *
- * @access public
- */
- function __construct(&$ui)
- {
- parent :: __construct();
- $this->setFrontendObject($ui);
- $this->debug = $this->config->get('verbose');
- }
-
- function setOptions($options)
- {
- $this->_options = $options;
- }
-
- function setConfig(&$config)
- {
- $this->config = &$config;
- $this->_registry = &$config->getRegistry();
- }
-
- // }}}
-
-
- function _removeBackups($files)
- {
- foreach ($files as $path)
- {
- $this->addFileOperation('removebackup', array($path));
- }
- }
-
- // {{{ _deletePackageFiles()
-
-
- /**
- * Delete a package's installed files, does not remove empty directories.
- *
- * @param string package name
- * @param string channel name
- * @param bool if true, then files are backed up first
- * @return bool TRUE on success, or a PEAR error on failure
- * @access protected
- */
- function _deletePackageFiles($package, $channel = false, $backup = false)
- {
- if (! $channel)
- {
- $channel = 'pear.php.net';
- }
- if (! strlen($package))
- {
- return $this->raiseError("No package to uninstall given");
- }
- if (strtolower($package) == 'pear' && $channel == 'pear.php.net')
- {
- // to avoid race conditions, include all possible needed files
- require_once 'PEAR/Task/Common.php';
- require_once 'PEAR/Task/Replace.php';
- require_once 'PEAR/Task/Unixeol.php';
- require_once 'PEAR/Task/Windowseol.php';
- require_once 'PEAR/PackageFile/v1.php';
- require_once 'PEAR/PackageFile/v2.php';
- require_once 'PEAR/PackageFile/Generator/v1.php';
- require_once 'PEAR/PackageFile/Generator/v2.php';
- }
- $filelist = $this->_registry->packageInfo($package, 'filelist', $channel);
- if ($filelist == null)
- {
- return $this->raiseError("$channel/$package not installed");
- }
- $ret = array();
- foreach ($filelist as $file => $props)
- {
- if (empty($props['installed_as']))
- {
- continue;
- }
- $path = $props['installed_as'];
- if ($backup)
- {
- $this->addFileOperation('backup', array($path));
- $ret[] = $path;
- }
- $this->addFileOperation('delete', array($path));
- }
- if ($backup)
- {
- return $ret;
- }
- return true;
- }
-
- // }}}
- // {{{ _installFile()
-
-
- /**
- * @param string filename
- * @param array attributes from <file> tag in package.xml
- * @param string path to install the file in
- * @param array options from command-line
- * @access private
- */
- function _installFile($file, $atts, $tmp_path, $options)
- {
- // {{{ return if this file is meant for another platform
- static $os;
- if (! isset($this->_registry))
- {
- $this->_registry = &$this->config->getRegistry();
- }
- if (isset($atts['platform']))
- {
- if (empty($os))
- {
- $os = new OS_Guess();
- }
- if (strlen($atts['platform']) && $atts['platform']{0} == '!')
- {
- $negate = true;
- $platform = substr($atts['platform'], 1);
- }
- else
- {
- $negate = false;
- $platform = $atts['platform'];
- }
- if ((bool) $os->matchSignature($platform) === $negate)
- {
- $this->log(3, "skipped $file (meant for $atts[platform], we are " . $os->getSignature() . ")");
- return PEAR_INSTALLER_SKIPPED;
- }
- }
- // }}}
-
-
- $channel = $this->pkginfo->getChannel();
- // {{{ assemble the destination paths
- switch ($atts['role'])
- {
- case 'src' :
- case 'extsrc' :
- $this->source_files ++;
- return;
- case 'doc' :
- case 'data' :
- case 'test' :
- $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . DIRECTORY_SEPARATOR . $this->pkginfo->getPackage();
- unset($atts['baseinstalldir']);
- break;
- case 'ext' :
- case 'php' :
- $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel);
- break;
- case 'script' :
- $dest_dir = $this->config->get('bin_dir', null, $channel);
- break;
- default :
- return $this->raiseError("Invalid role `$atts[role]' for file $file");
- }
- $save_destdir = $dest_dir;
- if (! empty($atts['baseinstalldir']))
- {
- $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
- }
- if (dirname($file) != '.' && empty($atts['install-as']))
- {
- $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
- }
- if (empty($atts['install-as']))
- {
- $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
- }
- else
- {
- $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
- }
- $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
-
- // Clean up the DIRECTORY_SEPARATOR mess
- $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
- list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), array(DIRECTORY_SEPARATOR,
- DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), array($dest_file, $orig_file));
- $final_dest_file = $installed_as = $dest_file;
- if (isset($this->_options['packagingroot']))
- {
- $installedas_dest_dir = dirname($final_dest_file);
- $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
- $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']);
- }
- else
- {
- $installedas_dest_dir = dirname($final_dest_file);
- $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
- }
- $dest_dir = dirname($final_dest_file);
- $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
- if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file)))
- {
- return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
- }
- // }}}
-
-
- if (empty($this->_options['register-only']) && (! file_exists($dest_dir) || ! is_dir($dest_dir)))
- {
- if (! $this->mkDirHier($dest_dir))
- {
- return $this->raiseError("failed to mkdir $dest_dir", PEAR_INSTALLER_FAILED);
- }
- $this->log(3, "+ mkdir $dest_dir");
- }
- // pretty much nothing happens if we are only registering the install
- if (empty($this->_options['register-only']))
- {
- if (empty($atts['replacements']))
- {
- if (! file_exists($orig_file))
- {
- return $this->raiseError("file $orig_file does not exist", PEAR_INSTALLER_FAILED);
- }
- if (! @copy($orig_file, $dest_file))
- {
- return $this->raiseError("failed to write $dest_file: $php_errormsg", PEAR_INSTALLER_FAILED);
- }
- $this->log(3, "+ cp $orig_file $dest_file");
- if (isset($atts['md5sum']))
- {
- $md5sum = md5_file($dest_file);
- }
- }
- else
- {
- // {{{ file with replacements
- if (! file_exists($orig_file))
- {
- return $this->raiseError("file does not exist", PEAR_INSTALLER_FAILED);
- }
- $contents = file_get_contents($orig_file);
- if ($contents === false)
- {
- $contents = '';
- }
- if (isset($atts['md5sum']))
- {
- $md5sum = md5($contents);
- }
- $subst_from = $subst_to = array();
- foreach ($atts['replacements'] as $a)
- {
- $to = '';
- if ($a['type'] == 'php-const')
- {
- if (preg_match('/^[a-z0-9_]+\\z/i', $a['to']))
- {
- eval("\$to = $a[to];");
- }
- else
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "invalid php-const replacement: $a[to]");
- }
- continue;
- }
- }
- elseif ($a['type'] == 'pear-config')
- {
- if ($a['to'] == 'master_server')
- {
- $chan = $this->_registry->getChannel($channel);
- if (! PEAR :: isError($chan))
- {
- $to = $chan->getServer();
- }
- else
- {
- $to = $this->config->get($a['to'], null, $channel);
- }
- }
- else
- {
- $to = $this->config->get($a['to'], null, $channel);
- }
- if (is_null($to))
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "invalid pear-config replacement: $a[to]");
- }
- continue;
- }
- }
- elseif ($a['type'] == 'package-info')
- {
- if ($t = $this->pkginfo->packageInfo($a['to']))
- {
- $to = $t;
- }
- else
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "invalid package-info replacement: $a[to]");
- }
- continue;
- }
- }
- if (! is_null($to))
- {
- $subst_from[] = $a['from'];
- $subst_to[] = $to;
- }
- }
- $this->log(3, "doing " . sizeof($subst_from) . " substitution(s) for $final_dest_file");
- if (sizeof($subst_from))
- {
- $contents = str_replace($subst_from, $subst_to, $contents);
- }
- $wp = @fopen($dest_file, "wb");
- if (! is_resource($wp))
- {
- return $this->raiseError("failed to create $dest_file: $php_errormsg", PEAR_INSTALLER_FAILED);
- }
- if (@fwrite($wp, $contents) === false)
- {
- return $this->raiseError("failed writing to $dest_file: $php_errormsg", PEAR_INSTALLER_FAILED);
- }
- fclose($wp);
-
- // }}}
- }
- // {{{ check the md5
- if (isset($md5sum))
- {
- if (strtolower($md5sum) === strtolower($atts['md5sum']))
- {
- $this->log(2, "md5sum ok: $final_dest_file");
- }
- else
- {
- if (empty($options['force']))
- {
- // delete the file
- if (file_exists($dest_file))
- {
- unlink($dest_file);
- }
- if (! isset($options['ignore-errors']))
- {
- return $this->raiseError("bad md5sum for file $final_dest_file", PEAR_INSTALLER_FAILED);
- }
- else
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "warning : bad md5sum for file $final_dest_file");
- }
- }
- }
- else
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "warning : bad md5sum for file $final_dest_file");
- }
- }
- }
- }
- // }}}
- // {{{ set file permissions
- if (! OS_WINDOWS)
- {
- if ($atts['role'] == 'script')
- {
- $mode = 0777 & ~ (int) octdec($this->config->get('umask'));
- $this->log(3, "+ chmod +x $dest_file");
- }
- else
- {
- $mode = 0666 & ~ (int) octdec($this->config->get('umask'));
- }
- if ($atts['role'] != 'src')
- {
- $this->addFileOperation("chmod", array($mode, $dest_file));
- if (! @chmod($dest_file, $mode))
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
- }
- }
- }
- }
- // }}}
- if ($atts['role'] == 'src')
- {
- rename($dest_file, $final_dest_file);
- $this->log(2, "renamed source file $dest_file to $final_dest_file");
- }
- else
- {
- $this->addFileOperation("rename", array($dest_file, $final_dest_file, $atts['role'] == 'ext'));
- }
- }
- // Store the full path where the file was installed for easy unistall
- if ($atts['role'] != 'script')
- {
- $loc = $this->config->get($atts['role'] . '_dir');
- }
- else
- {
- $loc = $this->config->get('bin_dir');
- }
- if ($atts['role'] != 'src')
- {
- $this->addFileOperation("installed_as", array($file, $installed_as, $loc,
- dirname(substr($installedas_dest_file, strlen($loc)))));
- }
-
- //$this->log(2, "installed: $dest_file");
- return PEAR_INSTALLER_OK;
- }
-
- // }}}
- // {{{ _installFile2()
-
-
- /**
- * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
- * @param string filename
- * @param array attributes from <file> tag in package.xml
- * @param string path to install the file in
- * @param array options from command-line
- * @access private
- */
- function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options)
- {
- $atts = $real_atts;
- if (! isset($this->_registry))
- {
- $this->_registry = &$this->config->getRegistry();
- }
-
- $channel = $pkg->getChannel();
- // {{{ assemble the destination paths
- if (! in_array($atts['attribs']['role'], PEAR_Installer_Role :: getValidRoles($pkg->getPackageType())))
- {
- return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . "' for file $file");
- }
- $role = &PEAR_Installer_Role :: factory($pkg, $atts['attribs']['role'], $this->config);
- $err = $role->setup($this, $pkg, $atts['attribs'], $file);
- if (PEAR :: isError($err))
- {
- return $err;
- }
- if (! $role->isInstallable())
- {
- return;
- }
- $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path);
- if (PEAR :: isError($info))
- {
- return $info;
- }
- else
- {
- list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info;
- }
- if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file)))
- {
- return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
- }
- $final_dest_file = $installed_as = $dest_file;
- if (isset($this->_options['packagingroot']))
- {
- $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']);
- }
- $dest_dir = dirname($final_dest_file);
- $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
- // }}}
-
-
- if (empty($this->_options['register-only']))
- {
- if (! file_exists($dest_dir) || ! is_dir($dest_dir))
- {
- if (! $this->mkDirHier($dest_dir))
- {
- return $this->raiseError("failed to mkdir $dest_dir", PEAR_INSTALLER_FAILED);
- }
- $this->log(3, "+ mkdir $dest_dir");
- }
- }
- $attribs = $atts['attribs'];
- unset($atts['attribs']);
- // pretty much nothing happens if we are only registering the install
- if (empty($this->_options['register-only']))
- {
- if (! count($atts))
- { // no tasks
- if (! file_exists($orig_file))
- {
- return $this->raiseError("file $orig_file does not exist", PEAR_INSTALLER_FAILED);
- }
- if (! @copy($orig_file, $dest_file))
- {
- return $this->raiseError("failed to write $dest_file: $php_errormsg", PEAR_INSTALLER_FAILED);
- }
- $this->log(3, "+ cp $orig_file $dest_file");
- if (isset($attribs['md5sum']))
- {
- $md5sum = md5_file($dest_file);
- }
- }
- else
- { // file with tasks
- if (! file_exists($orig_file))
- {
- return $this->raiseError("file $orig_file does not exist", PEAR_INSTALLER_FAILED);
- }
- $contents = file_get_contents($orig_file);
- if ($contents === false)
- {
- $contents = '';
- }
- if (isset($attribs['md5sum']))
- {
- $md5sum = md5($contents);
- }
- foreach ($atts as $tag => $raw)
- {
- $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag);
- $task = "PEAR_Task_$tag";
- $task = &new $task($this->config, $this, PEAR_TASK_INSTALL);
- if (! $task->isScript())
- { // scripts are only handled after installation
- $task->init($raw, $attribs, $pkg->getLastInstalledVersion());
- $res = $task->startSession($pkg, $contents, $final_dest_file);
- if ($res === false)
- {
- continue; // skip this file
- }
- if (PEAR :: isError($res))
- {
- return $res;
- }
- $contents = $res; // save changes
- }
- $wp = @fopen($dest_file, "wb");
- if (! is_resource($wp))
- {
- return $this->raiseError("failed to create $dest_file: $php_errormsg", PEAR_INSTALLER_FAILED);
- }
- if (fwrite($wp, $contents) === false)
- {
- return $this->raiseError("failed writing to $dest_file: $php_errormsg", PEAR_INSTALLER_FAILED);
- }
- fclose($wp);
- }
- }
- // {{{ check the md5
- if (isset($md5sum))
- {
- if (strtolower($md5sum) === strtolower($attribs['md5sum']))
- {
- $this->log(2, "md5sum ok: $final_dest_file");
- }
- else
- {
- if (empty($options['force']))
- {
- // delete the file
- if (file_exists($dest_file))
- {
- unlink($dest_file);
- }
- if (! isset($options['ignore-errors']))
- {
- return $this->raiseError("bad md5sum for file $final_dest_file", PEAR_INSTALLER_FAILED);
- }
- else
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "warning : bad md5sum for file $final_dest_file");
- }
- }
- }
- else
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "warning : bad md5sum for file $final_dest_file");
- }
- }
- }
- }
- else
- {
- $real_atts['attribs']['md5sum'] = md5_file($dest_file);
- }
- // }}}
- // {{{ set file permissions
- if (! OS_WINDOWS)
- {
- if ($role->isExecutable())
- {
- $mode = 0777 & ~ (int) octdec($this->config->get('umask'));
- $this->log(3, "+ chmod +x $dest_file");
- }
- else
- {
- $mode = 0666 & ~ (int) octdec($this->config->get('umask'));
- }
- if ($attribs['role'] != 'src')
- {
- $this->addFileOperation("chmod", array($mode, $dest_file));
- if (! @chmod($dest_file, $mode))
- {
- if (! isset($options['soft']))
- {
- $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
- }
- }
- }
- }
- // }}}
- if ($attribs['role'] == 'src')
- {
- rename($dest_file, $final_dest_file);
- $this->log(2, "renamed source file $dest_file to $final_dest_file");
- }
- else
- {
- $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension()));
- }
- }
- // Store the full path where the file was installed for easy uninstall
- if ($attribs['role'] != 'src')
- {
- $loc = $this->config->get($role->getLocationConfig(), null, $channel);
- $this->addFileOperation("installed_as", array($file, $installed_as, $loc,
- dirname(substr($installed_as, strlen($loc)))));
- }
-
- //$this->log(2, "installed: $dest_file");
- return PEAR_INSTALLER_OK;
- }
-
- // }}}
- // {{{ addFileOperation()
-
-
- /**
- * Add a file operation to the current file transaction.
- *
- * @see startFileTransaction()
- * @param string $type This can be one of:
- * - rename: rename a file ($data has 3 values)
- * - backup: backup an existing file ($data has 1 value)
- * - removebackup: clean up backups created during install ($data has 1 value)
- * - chmod: change permissions on a file ($data has 2 values)
- * - delete: delete a file ($data has 1 value)
- * - rmdir: delete a directory if empty ($data has 1 value)
- * - installed_as: mark a file as installed ($data has 4 values).
- * @param array $data For all file operations, this array must contain the
- * full path to the file or directory that is being operated on. For
- * the rename command, the first parameter must be the file to rename,
- * the second its new name, the third whether this is a PHP extension.
- *
- * The installed_as operation contains 4 elements in this order:
- * 1. Filename as listed in the filelist element from package.xml
- * 2. Full path to the installed file
- * 3. Full path from the php_dir configuration variable used in this
- * installation
- * 4. Relative path from the php_dir that this file is installed in
- */
- function addFileOperation($type, $data)
- {
- if (! is_array($data))
- {
- return $this->raiseError('Internal Error: $data in addFileOperation' . ' must be an array, was ' . gettype($data));
- }
- if ($type == 'chmod')
- {
- $octmode = decoct($data[0]);
- $this->log(3, "adding to transaction: $type $octmode $data[1]");
- }
- else
- {
- $this->log(3, "adding to transaction: $type " . implode(" ", $data));
- }
- $this->file_operations[] = array($type, $data);
- }
-
- // }}}
- // {{{ startFileTransaction()
-
-
- function startFileTransaction($rollback_in_case = false)
- {
- if (count($this->file_operations) && $rollback_in_case)
- {
- $this->rollbackFileTransaction();
- }
- $this->file_operations = array();
- }
-
- // }}}
- // {{{ commitFileTransaction()
-
-
- function commitFileTransaction()
- {
- $n = count($this->file_operations);
- $this->log(2, "about to commit $n file operations");
- // {{{ first, check permissions and such manually
- $errors = array();
- foreach ($this->file_operations as $tr)
- {
- list($type, $data) = $tr;
- switch ($type)
- {
- case 'rename' :
- if (! file_exists($data[0]))
- {
- $errors[] = "cannot rename file $data[0], doesn't exist";
- }
- // check that dest dir. is writable
- if (! is_writable(dirname($data[1])))
- {
- $errors[] = "permission denied ($type): $data[1]";
- }
- break;
- case 'chmod' :
- // check that file is writable
- if (! is_writable($data[1]))
- {
- $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]);
- }
- break;
- case 'delete' :
- if (! file_exists($data[0]))
- {
- $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
- }
- // check that directory is writable
- if (file_exists($data[0]))
- {
- if (! is_writable(dirname($data[0])))
- {
- $errors[] = "permission denied ($type): $data[0]";
- }
- else
- {
- // make sure the file to be deleted can be opened for writing
- $fp = false;
- if (! is_dir($data[0]) && (! is_writable($data[0]) || ! ($fp = @fopen($data[0], 'a'))))
- {
- $errors[] = "permission denied ($type): $data[0]";
- }
- elseif ($fp)
- {
- fclose($fp);
- }
- }
- }
- break;
- }
-
- }
- // }}}
- $m = sizeof($errors);
- if ($m > 0)
- {
- foreach ($errors as $error)
- {
- if (! isset($this->_options['soft']))
- {
- $this->log(1, $error);
- }
- }
- if (! isset($this->_options['ignore-errors']))
- {
- return false;
- }
- }
- $this->_dirtree = array();
- // {{{ really commit the transaction
- foreach ($this->file_operations as $i => $tr)
- {
- if (! $tr)
- {
- // support removal of non-existing backups
- continue;
- }
- list($type, $data) = $tr;
- switch ($type)
- {
- case 'backup' :
- if (! file_exists($data[0]))
- {
- $this->file_operations[$i] = false;
- break;
- }
- if (! @copy($data[0], $data[0] . '.bak'))
- {
- $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . '.bak ' . $php_errormsg);
- return false;
- }
- $this->log(3, "+ backup $data[0] to $data[0].bak");
- break;
- case 'removebackup' :
- if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak'))
- {
- unlink($data[0] . '.bak');
- $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
- }
- break;
- case 'rename' :
- if (file_exists($data[1]))
- {
- $test = @unlink($data[1]);
- }
- else
- {
- $test = null;
- }
- if (! $test && file_exists($data[1]))
- {
- if ($data[2])
- {
- $extra = ', this extension must be installed manually. Rename to "' . basename($data[1]) . '"';
- }
- else
- {
- $extra = '';
- }
- if (! isset($this->_options['soft']))
- {
- $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . $data[0] . $extra);
- }
- if (! isset($this->_options['ignore-errors']))
- {
- return false;
- }
- }
- // permissions issues with rename - copy() is far superior
- $perms = @fileperms($data[0]);
- if (! @copy($data[0], $data[1]))
- {
- $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . ' ' . $php_errormsg);
- return false;
- }
- // copy over permissions, otherwise they are lost
- @chmod($data[1], $perms);
- @unlink($data[0]);
- $this->log(3, "+ mv $data[0] $data[1]");
- break;
- case 'chmod' :
- if (! @chmod($data[1], $data[0]))
- {
- $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . decoct($data[0]) . ' ' . $php_errormsg);
- return false;
- }
- $octmode = decoct($data[0]);
- $this->log(3, "+ chmod $octmode $data[1]");
- break;
- case 'delete' :
- if (file_exists($data[0]))
- {
- if (! @unlink($data[0]))
- {
- $this->log(1, 'Could not delete ' . $data[0] . ' ' . $php_errormsg);
- return false;
- }
- $this->log(3, "+ rm $data[0]");
- }
- break;
- case 'rmdir' :
- if (file_exists($data[0]))
- {
- do
- {
- $testme = opendir($data[0]);
- while (false !== ($entry = readdir($testme)))
- {
- if ($entry == '.' || $entry == '..')
- {
- continue;
- }
- closedir($testme);
- break 2; // this directory is not empty and can't be
- // deleted
- }
- closedir($testme);
- if (! @rmdir($data[0]))
- {
- $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . $php_errormsg);
- return false;
- }
- $this->log(3, "+ rmdir $data[0]");
- }
- while (false);
- }
- break;
- case 'installed_as' :
- $this->pkginfo->setInstalledAs($data[0], $data[1]);
- if (! isset($this->_dirtree[dirname($data[1])]))
- {
- $this->_dirtree[dirname($data[1])] = true;
- $this->pkginfo->setDirtree(dirname($data[1]));
-
- while (! empty($data[3]) && dirname($data[3]) != $data[3] && $data[3] != '/' && $data[3] != '\\')
- {
- $this->pkginfo->setDirtree($pp = $this->_prependPath($data[3], $data[2]));
- $this->_dirtree[$pp] = true;
- $data[3] = dirname($data[3]);
- }
- }
- break;
- }
- }
- // }}}
- $this->log(2, "successfully committed $n file operations");
- $this->file_operations = array();
- return true;
- }
-
- // }}}
- // {{{ rollbackFileTransaction()
-
-
- function rollbackFileTransaction()
- {
- $n = count($this->file_operations);
- $this->log(2, "rolling back $n file operations");
- foreach ($this->file_operations as $tr)
- {
- list($type, $data) = $tr;
- switch ($type)
- {
- case 'backup' :
- if (file_exists($data[0] . '.bak'))
- {
- if (file_exists($data[0] && is_writable($data[0])))
- {
- unlink($data[0]);
- }
- @copy($data[0] . '.bak', $data[0]);
- $this->log(3, "+ restore $data[0] from $data[0].bak");
- }
- break;
- case 'removebackup' :
- if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak'))
- {
- unlink($data[0] . '.bak');
- $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
- }
- break;
- case 'rename' :
- @unlink($data[0]);
- $this->log(3, "+ rm $data[0]");
- break;
- case 'mkdir' :
- @rmdir($data[0]);
- $this->log(3, "+ rmdir $data[0]");
- break;
- case 'chmod' :
- break;
- case 'delete' :
- break;
- case 'installed_as' :
- $this->pkginfo->setInstalledAs($data[0], false);
- break;
- }
- }
- $this->pkginfo->resetDirtree();
- $this->file_operations = array();
- }
-
- // }}}
- // {{{ mkDirHier($dir)
-
-
- function mkDirHier($dir)
- {
- $this->addFileOperation('mkdir', array($dir));
- return parent :: mkDirHier($dir);
- }
-
- // }}}
- // {{{ download()
-
-
- /**
- * Download any files and their dependencies, if necessary
- *
- * @param array a mixed list of package names, local files, or package.xml
- * @param PEAR_Config
- * @param array options from the command line
- * @param array this is the array that will be populated with packages to
- * install. Format of each entry:
- *
- * <code>
- * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
- * 'info' => array() // parsed package.xml
- * );
- * </code>
- * @param array this will be populated with any error messages
- * @param false private recursion variable
- * @param false private recursion variable
- * @param false private recursion variable
- * @deprecated in favor of PEAR_Downloader
- */
- function download($packages, $options, &$config, &$installpackages, &$errors, $installed = false, $willinstall = false, $state = false)
- {
- // trickiness: initialize here
- parent :: PEAR_Downloader($this->ui, $options, $config);
- $ret = parent :: download($packages);
- $errors = $this->getErrorMsgs();
- $installpackages = $this->getDownloadedPackages();
- trigger_error("PEAR Warning: PEAR_Installer::download() is deprecated " . "in favor of PEAR_Downloader class", E_USER_WARNING);
- return $ret;
- }
-
- // }}}
- // {{{ _parsePackageXml()
-
-
- function _parsePackageXml(&$descfile, &$tmpdir)
- {
- if (substr($descfile, - 4) == '.xml')
- {
- $tmpdir = false;
- }
- else
- {
- // {{{ Decompress pack in tmp dir -------------------------------------
-
-
- // To allow relative package file names
- $descfile = realpath($descfile);
-
- if (PEAR :: isError($tmpdir = System :: mktemp('-d')))
- {
- return $tmpdir;
- }
- $this->log(3, '+ tmp dir created at ' . $tmpdir);
-
- // }}}
- }
- // Parse xml file -----------------------------------------------
- $pkg = new PEAR_PackageFile($this->config, $this->debug, $tmpdir);
- PEAR :: staticPushErrorHandling(PEAR_ERROR_RETURN);
- $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING);
- PEAR :: staticPopErrorHandling();
- if (PEAR :: isError($p))
- {
- if (is_array($p->getUserInfo()))
- {
- foreach ($p->getUserInfo() as $err)
- {
- $loglevel = $err['level'] == 'error' ? 0 : 1;
- if (! isset($this->_options['soft']))
- {
- $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']);
- }
- }
- }
- return $this->raiseError('Installation failed: invalid package file');
- }
- else
- {
- $descfile = $p->getPackageFile();
- }
- return $p;
- }
-
- // }}}
- /**
- * Set the list of PEAR_Downloader_Package objects to allow more sane
- * dependency validation
- * @param array
- */
- function setDownloadedPackages(&$pkgs)
- {
- PEAR :: pushErrorHandling(PEAR_ERROR_RETURN);
- $err = $this->analyzeDependencies($pkgs);
- PEAR :: popErrorHandling();
- if (PEAR :: isError($err))
- {
- return $err;
- }
- $this->_downloadedPackages = &$pkgs;
- }
-
- /**
- * Set the list of PEAR_Downloader_Package objects to allow more sane
- * dependency validation
- * @param array
- */
- function setUninstallPackages(&$pkgs)
- {
- $this->_downloadedPackages = &$pkgs;
- }
-
- function getInstallPackages()
- {
- return $this->_downloadedPackages;
- }
-
- // {{{ install()
-
-
- /**
- * Installs the files within the package file specified.
- *
- * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
- * or a pre-initialized packagefile object
- * @param array $options
- * recognized options:
- * - installroot : optional prefix directory for installation
- * - force : force installation
- * - register-only : update registry but don't install files
- * - upgrade : upgrade existing install
- * - soft : fail silently
- * - nodeps : ignore dependency conflicts/missing dependencies
- * - alldeps : install all dependencies
- * - onlyreqdeps : install only required dependencies
- *
- * @return array|PEAR_Error package info if successful
- */
-
- function install($pkgfile, $options = array())
- {
- $this->_options = $options;
- $this->_registry = &$this->config->getRegistry();
- if (is_object($pkgfile))
- {
- $dlpkg = &$pkgfile;
- $pkg = $pkgfile->getPackageFile();
- $pkgfile = $pkg->getArchiveFile();
- $descfile = $pkg->getPackageFile();
- $tmpdir = dirname($descfile);
- }
- else
- {
- $descfile = $pkgfile;
- $tmpdir = '';
- if (PEAR :: isError($pkg = &$this->_parsePackageXml($descfile, $tmpdir)))
- {
- return $pkg;
- }
- }
-
- if (realpath($descfile) != realpath($pkgfile))
- {
- $tar = new Archive_Tar($pkgfile);
- if (! $tar->extract($tmpdir))
- {
- return $this->raiseError("unable to unpack $pkgfile");
- }
- }
-
- $pkgname = $pkg->getName();
- $channel = $pkg->getChannel();
- if (isset($this->_options['packagingroot']))
- {
- $regdir = $this->_prependPath($this->config->get('php_dir', null, 'pear.php.net'), $this->_options['packagingroot']);
- $packrootphp_dir = $this->_prependPath($this->config->get('php_dir', null, $channel), $this->_options['packagingroot']);
- }
-
- if (isset($options['installroot']))
- {
- $this->config->setInstallRoot($options['installroot']);
- $this->_registry = &$this->config->getRegistry();
- $installregistry = &$this->_registry;
- $this->installroot = ''; // all done automagically now
- $php_dir = $this->config->get('php_dir', null, $channel);
- }
- else
- {
- $this->config->setInstallRoot(false);
- $this->_registry = &$this->config->getRegistry();
- if (isset($this->_options['packagingroot']))
- {
- $installregistry = &new PEAR_Registry($regdir);
- if (! $installregistry->channelExists($channel, true))
- {
- // we need to fake a channel-discover of this channel
- $chanobj = $this->_registry->getChannel($channel, true);
- $installregistry->addChannel($chanobj);
- }
- $php_dir = $packrootphp_dir;
- }
- else
- {
- $installregistry = &$this->_registry;
- $php_dir = $this->config->get('php_dir', null, $channel);
- }
- $this->installroot = '';
- }
-
- // {{{ checks to do when not in "force" mode
- if (empty($options['force']) && (file_exists($this->config->get('php_dir')) && is_dir($this->config->get('php_dir'))))
- {
- $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname);
- $instfilelist = $pkg->getInstallationFileList(true);
- if (PEAR :: isError($instfilelist))
- {
- return $instfilelist;
- }
- // ensure we have the most accurate registry
- $installregistry->flushFileMap();
- $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1');
- if (PEAR :: isError($test))
- {
- return $test;
- }
- if (sizeof($test))
- {
- $pkgs = $this->getInstallPackages();
- $found = false;
- foreach ($pkgs as $param)
- {
- if ($pkg->isSubpackageOf($param))
- {
- $found = true;
- break;
- …
Large files files are truncated, but you can click here to view the full file